1
+
2
+
3
+ // to do:
4
+ // make work with stdin
5
+
6
+ // Jacob Lessing
7
+ // CPSC 223 Fall 2022
8
+
9
+ // This program parses a GPX File, outputing
10
+ // location, and time data for each trkpt
11
+
12
+ #include <stdio.h>
13
+ #include <stdlib.h>
14
+ #include <string.h>
15
+ #include <ctype.h>
16
+
17
+ // how many characters from stdin the program "remembers" as it scans
18
+ // 10 is sufficient as its larger than any attribute or tag name of interest
19
+ #define BUFFER_SIZE 10
20
+
21
+ int scan_for_attribute (char attribute []);
22
+ int scan_for_start_tag (char element_type []);
23
+ int print_attribute_value ();
24
+ int print_element_text ();
25
+
26
+ int scan_for_string (char target [], int ignore_quotes , int case_insensitive );
27
+
28
+ int main ()
29
+ {
30
+ // repeatedly scan for additional trkpt elements to parse
31
+ while (1 ) {
32
+ // will close file and exit program if no more trkpt elements are found
33
+ if (scan_for_start_tag ("<trkpt" )) {
34
+ return 0 ;
35
+ }
36
+
37
+ // scans, parses, and prints children and fields of trkpt
38
+ scan_for_attribute (" lat" );
39
+ print_attribute_value ();
40
+ printf ("," );
41
+
42
+ scan_for_attribute (" lon" );
43
+ print_attribute_value ();
44
+ printf ("," );
45
+
46
+ scan_for_start_tag ("<ele" );
47
+ print_element_text ();
48
+ printf ("," );
49
+
50
+ scan_for_start_tag ("<time" );
51
+ print_element_text ();
52
+ printf ("\n" );
53
+ }
54
+ }
55
+
56
+
57
+ // ************************************ //
58
+ // SCANNING FUNCTIONS //
59
+ // ************************************ //
60
+
61
+
62
+ // pre: atribute should be atribute name WITHOUT appended =
63
+ // post: reads stdin stream until TARGET ATRIBUTE is found
64
+ // returns 0 if target is found
65
+ // returns 1 if end of file is reached without match
66
+ int scan_for_attribute (char attribute []) {
67
+ int returned_value ;
68
+ char curr_char ;
69
+
70
+ // 1: scan for attribute name, but ignore matches inside quotes
71
+ // 0: make search case sensitive
72
+ returned_value = scan_for_string (attribute , 1 , 0 );
73
+
74
+ if (returned_value ) return 1 ; // end of file (EOF)
75
+ else {
76
+ if (fscanf (stdin , " %c" , & curr_char ) <= 0 ) return 1 ; // (EOF)
77
+ if (curr_char == '=' ) return 0 ; // target found
78
+ else scan_for_attribute (attribute ); // otherwise, search again
79
+ }
80
+
81
+ return 1 ;
82
+ }
83
+
84
+ // pre: takes element type preceeded by <
85
+ // post: scans stdin stream until desired tag is found
86
+ // returns 0 if target is found
87
+ // returns 1 if end of file is reached without match
88
+ int scan_for_start_tag (char element_type []) {
89
+ int returned_value ;
90
+ char curr_char ;
91
+
92
+ // 1: scan for attribute name, but ignore matches inside quotes
93
+ // 1: make search case insensitive
94
+
95
+ returned_value = scan_for_string (element_type , 1 , 1 );
96
+
97
+ // checks that identified attribute name is followed by ' ' or '>'
98
+ if (returned_value ) return 1 ; // end of file (EOF)
99
+ else {
100
+ if (fscanf (stdin , "%c" , & curr_char ) <= 0 ) return 1 ; // (EOF)
101
+ if (curr_char == ' ' || curr_char == '>' ) {
102
+ // re-add char to stream so it can be used later
103
+ if (curr_char == '>' ) ungetc ('>' , stdin );
104
+ if (curr_char == ' ' ) ungetc (' ' , stdin );
105
+ return 0 ; // target found
106
+ }
107
+ else scan_for_start_tag (element_type ); // otherwise, search again
108
+ }
109
+
110
+ return 1 ;
111
+ }
112
+
113
+
114
+ // ************************************ //
115
+ // PRINTING FUNCTIONS //
116
+ // ************************************ //
117
+
118
+ // pre: attribute must be first thing in quotes
119
+ // post: prints next attribute value
120
+ // returns 0 if full value is sucessfully printed
121
+ // returns 1 if file ends before closing "/' is encountered
122
+ int print_attribute_value () {
123
+ char curr_char ;
124
+
125
+ // value can be enclosed in " or '
126
+ char enclosing_char ;
127
+
128
+ // used as a boolean to indicate a state:
129
+ // 1 indicates stdin is inside an atribute value
130
+ // 0 indicates stdin is outside any atribute value
131
+ int is_inside_value = 0 ;
132
+
133
+ while (fscanf (stdin , "%c" , & curr_char ) > 0 ) {
134
+ switch (is_inside_value ) {
135
+ case 0 :
136
+ // search for start of attribute value
137
+ if (curr_char == '"' || curr_char == '\'' ) {
138
+ is_inside_value = 1 ;
139
+ enclosing_char = curr_char ;
140
+ }
141
+ break ;
142
+ case 1 :
143
+ // print characters until final quote is reached
144
+ if (curr_char == enclosing_char ) return 0 ;
145
+ else if (curr_char == ',' ) printf ("&comma" );
146
+ else printf ("%c" , curr_char );
147
+
148
+ break ;
149
+ }
150
+ }
151
+
152
+ // end of file reached
153
+ return 1 ;
154
+
155
+ }
156
+
157
+ // pre: element has no children & stdin is in start tag of desired element
158
+ // post: prints the element text of the current element
159
+ // returns 0 if full value is sucessfully printed
160
+ // returns 1 if file ends before printing is complete
161
+ int print_element_text () {
162
+ // >, outside of any string, marks end of start tag
163
+ if (scan_for_string (">" , 1 , 0 )) return 1 ;
164
+
165
+ // print all characters until start of end tag <
166
+ char curr_char ;
167
+ while (fscanf (stdin , "%c" , & curr_char ) > 0 ) {
168
+ if (curr_char == '<' ) return 0 ;
169
+ else if (curr_char == ',' ) printf ("&comma" );
170
+ else printf ("%c" , curr_char );
171
+ }
172
+
173
+ // end of file reached without closing ">"
174
+ return 1 ;
175
+ }
176
+
177
+
178
+ // ************************************ //
179
+ // HELPER FUNCTIONS //
180
+ // ************************************ //
181
+
182
+
183
+ // post: reads stdin stream until TARGET string is found
184
+ // returns 0 if target is found
185
+ // returns 1 if end of file is reached without match
186
+ // ignores characters in quotes when flag ignore_quotes == 1
187
+ // executes case-insensitive search when flag case_insensitive == 1
188
+ int scan_for_string (char target [], int ignore_quotes , int case_insensitive )
189
+ {
190
+ // stores BUFFER_SIZE most recent characters from input stream
191
+
192
+ // *** I wanted to initialize my buffer like this, but
193
+ // the code didn't work as a I expected ***
194
+ //char buffer[BUFFER_SIZE + 1];
195
+ //buffer[BUFFER_SIZE] = '\0';
196
+ char buffer [] = "xxxxxxxxxx" ;
197
+
198
+ // most recently read char from input
199
+ char curr_char ;
200
+
201
+ while (fscanf (stdin , "%c" , & curr_char ) > 0 ) {
202
+
203
+ // checks if character is quote, and skips quote if ignore_quotes == 1
204
+ if (ignore_quotes && (curr_char == '"' || curr_char == '\'' )) {
205
+ // flushes buffer
206
+ for (size_t i = 0 ; i < BUFFER_SIZE ; i ++ ) {
207
+ buffer [i ] = '`' ; // garbage character
208
+ }
209
+
210
+ // identifies if " or ' started quote
211
+ char enclosing_char = curr_char ;
212
+
213
+ // skips characters until corresponding quote,
214
+ // or end of file is reached
215
+ while (fscanf (stdin , "%c" , & curr_char ) > 0 ) {
216
+ if (curr_char == enclosing_char ) break ;
217
+ }
218
+
219
+ // if corresponding quote was found, execution of TARGET search continues
220
+ if (curr_char == enclosing_char ) continue ;
221
+
222
+ // otherwise, reached end of file without finding target
223
+ else return 1 ;
224
+ }
225
+
226
+ // clear space in buffer for new char
227
+ for (size_t i = 0 ; i < (BUFFER_SIZE - 1 ); i ++ ) {
228
+ buffer [i ] = buffer [i + 1 ];
229
+ }
230
+
231
+ // forces character to lowercase if case insensitive is flagged
232
+ if (case_insensitive ) curr_char = tolower (curr_char );
233
+
234
+ // append next input char to buffer
235
+ buffer [BUFFER_SIZE - 1 ] = curr_char ;
236
+
237
+ // check if buffer contains TARGET
238
+ if (strstr (buffer , target ) != NULL ) {
239
+ // found TARGET
240
+ return 0 ;
241
+ }
242
+ }
243
+
244
+ // reached end of file without finding TARGET
245
+ return 1 ;
246
+ }
0 commit comments