~ubuntu-branches/ubuntu/lucid/boinc/lucid-backports

« back to all changes in this revision

Viewing changes to lib/parse.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Rene Mayorga
  • Date: 2009-05-23 13:29:17 UTC
  • mfrom: (1.3.1 upstream) (9.1.1 experimental)
  • Revision ID: james.westby@ubuntu.com-20090523132917-3rvmkmkxbw17181o
Tags: 6.4.5+dfsg-2
* Uploaded to unstable
* Include a patch picked from Upstream SVN
   to avoid FTBFSs whith gcc 4.4 (Closes: #526666)
* remove CUDA dir that contais binary-only non DFSG software
* change section from boinc-dbg to debug
* set orig +dfsg since we remove non-dfsg software 
  when we pull the tag from upstream
  + Add Comments about this on README.Source
* Move schedtool to Recommends, (Closes: #532133)
* Add ru debconf templates translation, thanks
  to Yuri Kozlov <yuray@komyakino.ru> (Closes: #531205)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// This file is part of BOINC.
 
2
// http://boinc.berkeley.edu
 
3
// Copyright (C) 2008 University of California
 
4
//
 
5
// BOINC is free software; you can redistribute it and/or modify it
 
6
// under the terms of the GNU Lesser General Public License
 
7
// as published by the Free Software Foundation,
 
8
// either version 3 of the License, or (at your option) any later version.
 
9
//
 
10
// BOINC is distributed in the hope that it will be useful,
 
11
// but WITHOUT ANY WARRANTY; without even the implied warranty of
 
12
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 
13
// See the GNU Lesser General Public License for more details.
 
14
//
 
15
// You should have received a copy of the GNU Lesser General Public License
 
16
// along with BOINC.  If not, see <http://www.gnu.org/licenses/>.
 
17
 
 
18
// A very crude interface for parsing XML files;
 
19
// assumes all elements are either single-line or
 
20
// have start and end tags on separate lines.
 
21
// This is meant to be used ONLY for parsing XML files produced
 
22
// by the BOINC scheduling server or client.
 
23
// Could replace this with a more general parser.
 
24
 
 
25
#if defined(_WIN32) && !defined(__STDWX_H__) && !defined(_BOINC_WIN_) && !defined(_AFX_STDAFX_H_)
 
26
#include "boinc_win.h"
 
27
#endif
 
28
 
 
29
#ifndef _WIN32
 
30
#include "config.h"
 
31
#include <cstring>
 
32
#include <cstdlib>
 
33
#include <string>
 
34
#include <math.h>
 
35
#include <errno.h>
 
36
#if HAVE_IEEEFP_H
 
37
#include <ieeefp.h>
 
38
#endif
 
39
#endif
 
40
 
 
41
#include "error_numbers.h"
 
42
#include "str_util.h"
 
43
#include "parse.h"
 
44
 
 
45
#ifdef _USING_FCGI_
 
46
#include "boinc_fcgi.h"
 
47
#endif
 
48
 
 
49
using std::string;
 
50
 
 
51
 
 
52
 
 
53
// Parse a boolean; tag is of form "foobar"
 
54
// Accept either <foobar/> or <foobar>0|1</foobar>
 
55
//
 
56
bool parse_bool(const char* buf, const char* tag, bool& result) {
 
57
    char single_tag[256], start_tag[256];
 
58
    int x;
 
59
 
 
60
    sprintf(single_tag, "<%s/>", tag);
 
61
    if (match_tag(buf, single_tag)) {
 
62
        result = true;
 
63
        return true;
 
64
    }
 
65
    sprintf(start_tag, "<%s>", tag);
 
66
    if (parse_int(buf, start_tag, x)) {
 
67
        result = (x != 0);
 
68
        return true;
 
69
    }
 
70
    return false;
 
71
}
 
72
 
 
73
// parse a string of the form ...<tag attrs>string</tag>...;
 
74
// returns the "string" part.
 
75
// Does XML unescaping (replace &lt; with <)
 
76
// "string" may not include '<'
 
77
// Strips white space from ends.
 
78
// Use "<tag", not "<tag>", if there might be attributes
 
79
//
 
80
bool parse_str(const char* buf, const char* tag, char* dest, int destlen) {
 
81
    string str;
 
82
    const char* p;
 
83
    char tempbuf[1024];
 
84
    int len;
 
85
 
 
86
    p = strstr(buf, tag);
 
87
    if (!p) return false;
 
88
    p = strchr(p, '>');
 
89
    p++;
 
90
    const char* q = strchr(p, '<');
 
91
    if (!q) return false;
 
92
    len = (int)(q-p);
 
93
    if (len >= destlen) len = destlen-1;
 
94
    memcpy(tempbuf, p, len);
 
95
    tempbuf[len] = 0;
 
96
    strip_whitespace(tempbuf);
 
97
    xml_unescape(tempbuf, dest, destlen);
 
98
    return true;
 
99
}
 
100
 
 
101
bool parse_str(const char* buf, const char* tag, string& dest) {
 
102
    char tempbuf[1024];
 
103
    if (!parse_str(buf, tag, tempbuf, 1024)) return false;
 
104
    dest = tempbuf;
 
105
    return true;
 
106
}
 
107
 
 
108
// parse a string of the form 'xxx name="value" xxx';
 
109
// returns value in dest
 
110
//
 
111
void parse_attr(const char* buf, const char* name, char* dest, int len) {
 
112
    const char* p;
 
113
    const char *q;
 
114
 
 
115
    strcpy(dest, "");
 
116
    p = strstr(buf, name);
 
117
    if (!p) return;
 
118
    p = strchr(p, '"');
 
119
    if (!p) return;
 
120
    q = strchr(p+1, '"');
 
121
    if (!q) return;
 
122
    if (len > q-p) len = (int)(q-p);
 
123
    strlcpy(dest, p+1, len);
 
124
}
 
125
 
 
126
int copy_stream(FILE* in, FILE* out) {
 
127
    char buf[1024];
 
128
    int n, m;
 
129
    while (1) {
 
130
        n = (int)fread(buf, 1, 1024, in);
 
131
        m = (int)fwrite(buf, 1, n, out);
 
132
        if (m != n) return ERR_FWRITE;
 
133
        if (n < 1024) break;
 
134
    }
 
135
    return 0;
 
136
}
 
137
 
 
138
// append to a malloc'd string
 
139
//
 
140
int strcatdup(char*& p, char* buf) {
 
141
    p = (char*)realloc(p, strlen(p) + strlen(buf)+1);
 
142
    if (!p) {
 
143
        return ERR_MALLOC;
 
144
    }
 
145
    strcat(p, buf);
 
146
    return 0;
 
147
}
 
148
 
 
149
// Copy from a file to a malloc'd string until the end tag is reached
 
150
// Does NOT copy the start and end tags.
 
151
//
 
152
int dup_element_contents(FILE* in, const char* end_tag, char** pp) {
 
153
    char line[256];
 
154
    int bufsize = 4000000;
 
155
    int nused=0;        // not counting ending NULL
 
156
    char* buf = (char*)malloc(bufsize);
 
157
 
 
158
    // Start with a big buffer.
 
159
    // When done, copy to an exact-size buffer
 
160
    //
 
161
    while (fgets(line, 256, in)) {
 
162
        if (strstr(line, end_tag)) {
 
163
            *pp = (char*)malloc(nused+1);
 
164
            strcpy(*pp, buf);
 
165
            free(buf);
 
166
            return 0;
 
167
        }
 
168
        int n = strlen(line);
 
169
        if (nused + n >= bufsize) {
 
170
            bufsize *= 2;
 
171
            buf = (char*)realloc(buf, bufsize);
 
172
        }
 
173
        strcpy(buf+nused, line);
 
174
        nused += n;
 
175
    }
 
176
    free(buf);
 
177
    return ERR_XML_PARSE;
 
178
}
 
179
 
 
180
int dup_element(FILE* in, const char* tag_name, char** pp) {
 
181
    char buf[256], end_tag[256];
 
182
    int retval;
 
183
 
 
184
    sprintf(buf, "<%s>\n", tag_name);
 
185
    sprintf(end_tag, "</%s>", tag_name);
 
186
 
 
187
    char* p = strdup(buf);
 
188
    while (fgets(buf, 256, in)) {
 
189
        if (strstr(buf, end_tag)) {
 
190
            sprintf(buf, "</%s>\n", tag_name);
 
191
            retval = strcatdup(p, buf);
 
192
            if (retval) return retval;
 
193
            *pp = p;
 
194
            return 0;
 
195
        }
 
196
        retval = strcatdup(p, buf);
 
197
        if (retval) return retval;
 
198
    }
 
199
    return ERR_XML_PARSE;
 
200
}
 
201
 
 
202
// copy from a file to static buffer
 
203
//
 
204
int copy_element_contents(FILE* in, const char* end_tag, char* p, int len) {
 
205
    char buf[256];
 
206
    int n;
 
207
 
 
208
    strcpy(p, "");
 
209
    while (fgets(buf, 256, in)) {
 
210
        if (strstr(buf, end_tag)) {
 
211
            return 0;
 
212
        }
 
213
        n = (int)strlen(buf);
 
214
        if (n >= len-1) return ERR_XML_PARSE;
 
215
        strcat(p, buf);
 
216
        len -= n;
 
217
    }
 
218
    return ERR_XML_PARSE;
 
219
}
 
220
 
 
221
int copy_element_contents(FILE* in, const char* end_tag, string& str) {
 
222
    char buf[256];
 
223
 
 
224
    str = "";
 
225
    while (fgets(buf, 256, in)) {
 
226
        if (strstr(buf, end_tag)) {
 
227
            return 0;
 
228
        }
 
229
        str += buf;
 
230
    }
 
231
    return ERR_XML_PARSE;
 
232
}
 
233
 
 
234
// replace XML element contents (element must be present)
 
235
//
 
236
void replace_element_contents(
 
237
    char* buf, const char* start, const char* end, const char* replacement
 
238
) {
 
239
    char temp[4096], *p, *q;
 
240
 
 
241
    p = strstr(buf, start);
 
242
    p += strlen(start);
 
243
    q = strstr(p, end);
 
244
    strlcpy(temp, q, sizeof(temp));
 
245
    strcpy(p, replacement);
 
246
    strcat(p, temp);
 
247
}
 
248
 
 
249
// if the string contains a substring of the form X...Y,
 
250
// remove the first such.
 
251
bool remove_element(char* buf, const char* start, const char* end) {
 
252
    char* p, *q;
 
253
    p = strstr(buf, start);
 
254
    if (!p) return false;
 
255
    q = strstr(p+strlen(start), end);
 
256
    if (!q) return false;
 
257
    strcpy(p, q+strlen(end));
 
258
    return true;
 
259
}
 
260
 
 
261
// replace a substring.  Do at most one instance.
 
262
//
 
263
bool str_replace(char* str, const char* substr, const char* replacement) {
 
264
    char temp[4096], *p;
 
265
 
 
266
    p = strstr(str, substr);
 
267
    if (!p) return false;
 
268
    int n = (int)strlen(substr);
 
269
    strcpy(temp, p+n);
 
270
    strcpy(p, replacement);
 
271
    strcat(p, temp);
 
272
    return true;
 
273
}
 
274
    
 
275
// if the given XML has an element of the form
 
276
// <venue name="venue_name">
 
277
//   ...
 
278
// </venue>
 
279
// then return the contents of that element.
 
280
// Otherwise strip out all <venue> elements
 
281
//
 
282
void extract_venue(const char* in, const char* venue_name, char* out) {
 
283
    const char* p, *q;
 
284
    char* wp;
 
285
    char buf[256];
 
286
    sprintf(buf, "<venue name=\"%s\">", venue_name);
 
287
    p = strstr(in, buf);
 
288
    if (p) {
 
289
        // prefs contain the specified venue
 
290
        //
 
291
        p += strlen(buf);
 
292
        strcpy(out, p);
 
293
        wp = strstr(out, "</venue");
 
294
        if (wp) *wp = 0;
 
295
    } else {
 
296
        // prefs don't contain the specified venue
 
297
        //
 
298
        q = in;
 
299
        strcpy(out, "");
 
300
        while (1) {
 
301
                p = strstr(q, "<venue");
 
302
                if (!p) {
 
303
                strcat(out, q);
 
304
                break;
 
305
            }
 
306
                strncat(out, q, p-q);
 
307
                q = strstr(p, "</venue>");
 
308
                if (!q) break;
 
309
                q += strlen("</venue>");
 
310
        }
 
311
    }
 
312
}
 
313
 
 
314
// copy a line from the given string.
 
315
// kinda like fgets() when you're reading from a string
 
316
//
 
317
char* sgets(char* buf, int len, char*& in) {
 
318
    char* p;
 
319
 
 
320
    p = strstr(in, "\n");
 
321
    if (!p) return NULL;
 
322
    *p = 0;
 
323
    strlcpy(buf, in, len);
 
324
    *p = '\n';
 
325
    in = p+1;
 
326
    return buf;
 
327
}
 
328
 
 
329
// NOTE: these used to take std::string instead of char* args.
 
330
// But this performed poorly.
 
331
//
 
332
// NOTE: output buffer should be 6X size of input
 
333
//
 
334
void xml_escape(const char* in, char* out, int len) {
 
335
    char buf[256], *p;
 
336
 
 
337
    p = out;
 
338
 
 
339
    for (; *in; in++) {
 
340
        int x = (int) *in;
 
341
        x &= 0xff;   // just in case
 
342
        if (x == '<') {
 
343
            strcpy(p, "&lt;");
 
344
            p += 4;
 
345
        } else if (x == '&') {
 
346
            strcpy(p, "&amp;");
 
347
            p += 5;
 
348
        } else if (x>127) {
 
349
            sprintf(buf, "&#%d;", x);
 
350
            strcpy(p, buf);
 
351
            p += strlen(buf);
 
352
        } else if (x<32) {
 
353
            switch(x) {
 
354
            case 9:
 
355
            case 10:
 
356
            case 13:
 
357
                sprintf(buf, "&#%d;", x);
 
358
                strcpy(p, buf);
 
359
                p += strlen(buf);
 
360
                break;
 
361
            }
 
362
        } else {
 
363
            *p++ = x;
 
364
        }
 
365
        if (p > out + len - 8) break;
 
366
    }
 
367
    *p = 0;
 
368
}
 
369
 
 
370
// output buffer need not be larger than input
 
371
//
 
372
void xml_unescape(const char* in, char* out, int len) {
 
373
    char* p = out;
 
374
    while (*in) {
 
375
        if (*in != '&') {       // avoid strncmp's if possible
 
376
            *p++ = *in++;
 
377
        } else if (!strncmp(in, "&lt;", 4)) {
 
378
            *p++ = '<';
 
379
            in += 4;
 
380
        } else if (!strncmp(in, "&amp;", 5)) {
 
381
            *p++ = '&';
 
382
            in += 5;
 
383
        } else if (!strncmp(in, "&#", 2)) {
 
384
            in += 2;
 
385
            char c = atoi(in);
 
386
            *p++ = c;
 
387
            in = strchr(in, ';');
 
388
            if (in) in++;
 
389
        } else {
 
390
            *p++ = *in++;
 
391
        }
 
392
        if (p > out + len - 2) break;
 
393
    }
 
394
    *p = 0;
 
395
}
 
396
 
 
397
// we got an unrecognized line.
 
398
// If it has two <'s (e.g. <foo>xx</foo>) return 0.
 
399
// If it's of the form <foo/> return 0.
 
400
// If it's of the form <foo> then scan for </foo> and return 0.
 
401
// Otherwise return ERR_XML_PARSE
 
402
//
 
403
int skip_unrecognized(char* buf, MIOFILE& fin) {
 
404
    char* p, *q, buf2[256];
 
405
    std::string close_tag;
 
406
 
 
407
    p = strchr(buf, '<');
 
408
    if (!p) {
 
409
        return ERR_XML_PARSE;
 
410
    }
 
411
    if (strchr(p+1, '<')) {
 
412
        return 0;
 
413
    }
 
414
    q = strchr(p+1, '>');
 
415
    if (!q) {
 
416
        return ERR_XML_PARSE;
 
417
    }
 
418
    if (q[-1] == '/') return 0;
 
419
    *q = 0;
 
420
    close_tag = string("</") + string(p+1) + string(">");
 
421
    while (fin.fgets(buf2, 256)) {
 
422
        if (strstr(buf2, close_tag.c_str())) {
 
423
            return 0;
 
424
        }
 
425
        
 
426
    }
 
427
    return ERR_XML_PARSE;
 
428
}
 
429
 
 
430
XML_PARSER::XML_PARSER(MIOFILE* _f) {
 
431
    f = _f;
 
432
}
 
433
 
 
434
// read until find non-whitespace char.
 
435
// Return the char in the reference param
 
436
// Return true iff reached EOF
 
437
//
 
438
bool XML_PARSER::scan_nonws(int& first_char) {
 
439
    int c;
 
440
    while (1) {
 
441
        c = f->_getc();
 
442
        if (c == EOF) return true;
 
443
        if (isspace(c)) continue;
 
444
        first_char = c;
 
445
        return false;
 
446
    }
 
447
}
 
448
 
 
449
int XML_PARSER::scan_comment() {
 
450
    char buf[256];
 
451
    char* p = buf;
 
452
    while (1) {
 
453
        int c = f->_getc();
 
454
        if (c == EOF) return 2;
 
455
        *p++ = c;
 
456
        *p = 0;
 
457
        if (strstr(buf, "-->")) {
 
458
            return 1;
 
459
        }
 
460
        if (strlen(buf) > 32) {
 
461
            strcpy(buf, buf+16);
 
462
            p = buf;
 
463
        }
 
464
    }
 
465
}
 
466
 
 
467
// we just read a <; read until we find a >,
 
468
// and copy intervening text to buf.
 
469
// Return:
 
470
// 0 if got a tag
 
471
// 1 if got a comment (ignore)
 
472
// 2 if reached EOF
 
473
//
 
474
int XML_PARSER::scan_tag(
 
475
    char* tag_buf, int tag_len, char* attr_buf, int attr_len
 
476
) {
 
477
    int c;
 
478
    char* buf_start = tag_buf;
 
479
    bool found_space = false;
 
480
    for (int i=0; ; i++) {
 
481
        c = f->_getc();
 
482
        if (c == EOF) return 2;
 
483
        if (c == '>') {
 
484
            *tag_buf = 0;
 
485
            if (attr_buf) *attr_buf = 0;
 
486
            return 0;
 
487
        }
 
488
        if (isspace(c)) {
 
489
            found_space = true;
 
490
        }
 
491
        if (c == '/') {
 
492
            if (--tag_len > 0) {
 
493
                *tag_buf++ = c;
 
494
            }
 
495
        } else {
 
496
            if (found_space && attr_buf) {
 
497
                if (--attr_len > 0) {
 
498
                    *attr_buf++ = c;
 
499
                }
 
500
            } else {
 
501
                if (--tag_len > 0) {
 
502
                    *tag_buf++ = c;
 
503
                }
 
504
            }
 
505
        }
 
506
 
 
507
        // check for comment start
 
508
        //
 
509
        if (i==2 && !strncmp(buf_start, "!--", 3)) {
 
510
            return scan_comment();
 
511
        }
 
512
    }
 
513
}
 
514
 
 
515
// read and copy text to buf; stop when find a <;
 
516
// ungetc() that so we read it again
 
517
// Return true iff reached EOF
 
518
//
 
519
bool XML_PARSER::copy_until_tag(char* buf, int len) {
 
520
    int c;
 
521
    while (1) {
 
522
        c = f->_getc();
 
523
        if (c == EOF) return true;
 
524
        if (c == '<') {
 
525
            f->_ungetc(c);
 
526
            *buf = 0;
 
527
            return false;
 
528
        }
 
529
        if (--len > 0) {
 
530
            *buf++ = c;
 
531
        }
 
532
    }
 
533
}
 
534
 
 
535
// Scan something, either tag or text.
 
536
// Strip whitespace at start and end.
 
537
// Return true iff reached EOF
 
538
//
 
539
bool XML_PARSER::get(char* buf, int len, bool& is_tag, char* attr_buf, int attr_len) {
 
540
    bool eof;
 
541
    int c;
 
542
    
 
543
    while (1) {
 
544
        eof = scan_nonws(c);
 
545
        if (eof) return true;
 
546
        if (c == '<') {
 
547
            int retval = scan_tag(buf, len, attr_buf, attr_len);
 
548
            if (retval == 2) return true;
 
549
            if (retval == 1) continue;
 
550
            is_tag = true;
 
551
        } else {
 
552
            buf[0] = c;
 
553
            eof = copy_until_tag(buf+1, len-1);
 
554
            if (eof) return true;
 
555
            is_tag = false;
 
556
        }
 
557
        strip_whitespace(buf);
 
558
        return false;
 
559
    }
 
560
}
 
561
 
 
562
// We just parsed "parsed_tag".
 
563
// If it matches "start_tag", and is followed by a string
 
564
// and by the matching close tag, return the string in "buf",
 
565
// and return true.
 
566
//
 
567
bool XML_PARSER::parse_str(
 
568
    char* parsed_tag, const char* start_tag, char* buf, int len
 
569
) {
 
570
    bool is_tag, eof;
 
571
    char end_tag[256], tag[256], tmp[64000];
 
572
 
 
573
    // handle the archaic form <tag/>, which means empty string
 
574
    //
 
575
    strcpy(tag, start_tag);
 
576
    strcat(tag, "/");
 
577
    if (!strcmp(parsed_tag, tag)) {
 
578
        strcpy(buf, "");
 
579
        return true;
 
580
    }
 
581
 
 
582
    // check for start tag
 
583
    //
 
584
    if (strcmp(parsed_tag, start_tag)) return false;
 
585
 
 
586
    end_tag[0] = '/';
 
587
    strcpy(end_tag+1, start_tag);
 
588
 
 
589
    // get text after start tag
 
590
    //
 
591
    eof = get(tmp, 64000, is_tag);
 
592
    if (eof) return false;
 
593
 
 
594
    // if it's the end tag, return empty string
 
595
    //
 
596
    if (is_tag) {
 
597
        if (strcmp(tmp, end_tag)) {
 
598
            return false;
 
599
        } else {
 
600
            strcpy(buf, "");
 
601
            return true;
 
602
        }
 
603
    }
 
604
 
 
605
    eof = get(tag, sizeof(tag), is_tag);
 
606
    if (eof) return false;
 
607
    if (!is_tag) return false;
 
608
    if (strcmp(tag, end_tag)) return false;
 
609
    strlcpy(buf, tmp, len);
 
610
    return true;
 
611
}
 
612
 
 
613
bool XML_PARSER::parse_string(
 
614
    char* parsed_tag, const char* start_tag, string& str
 
615
) {
 
616
    char buf[8192];
 
617
    bool flag = parse_str(parsed_tag, start_tag, buf, sizeof(buf));
 
618
    if (!flag) return false;
 
619
    str = buf;
 
620
    return true;
 
621
}
 
622
 
 
623
// Same, for integers
 
624
//
 
625
bool XML_PARSER::parse_int(char* parsed_tag, const char* start_tag, int& i) {
 
626
    char buf[256], *end;
 
627
    bool is_tag, eof;
 
628
    char end_tag[256], tag[256];
 
629
 
 
630
    if (strcmp(parsed_tag, start_tag)) return false;
 
631
 
 
632
    end_tag[0] = '/';
 
633
    strcpy(end_tag+1, start_tag);
 
634
 
 
635
    eof = get(buf, sizeof(buf), is_tag);
 
636
    if (eof) return false;
 
637
    if (is_tag) {
 
638
        if (!strcmp(buf, end_tag)) {
 
639
            i = 0;      // treat <foo></foo> as <foo>0</foo>
 
640
            return true;
 
641
        } else {
 
642
            return false;
 
643
        }
 
644
    }
 
645
    int val = strtol(buf, &end, 0);
 
646
    if (errno == ERANGE) return false;
 
647
    if (end != buf+strlen(buf)) return false;
 
648
 
 
649
    eof = get(tag, sizeof(tag), is_tag);
 
650
    if (eof) return false;
 
651
    if (!is_tag) return false;
 
652
    if (strcmp(tag, end_tag)) return false;
 
653
    i = val;
 
654
    return true;
 
655
}
 
656
 
 
657
// Same, for doubles
 
658
//
 
659
bool XML_PARSER::parse_double(char* parsed_tag, const char* start_tag, double& x) {
 
660
    char buf[256], *end;
 
661
    bool is_tag, eof;
 
662
    char end_tag[256], tag[256];
 
663
 
 
664
    if (strcmp(parsed_tag, start_tag)) return false;
 
665
 
 
666
    end_tag[0] = '/';
 
667
    strcpy(end_tag+1, start_tag);
 
668
 
 
669
    eof = get(buf, sizeof(buf), is_tag);
 
670
    if (eof) return false;
 
671
    if (is_tag) {
 
672
        if (!strcmp(buf, end_tag)) {
 
673
            x = 0;      // treat <foo></foo> as <foo>0</foo>
 
674
            return true;
 
675
        } else {
 
676
            return false;
 
677
        }
 
678
    }
 
679
    double val = strtod(buf, &end);
 
680
    if (end != buf+strlen(buf)) return false;
 
681
 
 
682
    eof = get(tag, sizeof(tag), is_tag);
 
683
    if (eof) return false;
 
684
    if (!is_tag) return false;
 
685
    if (strcmp(tag, end_tag)) return false;
 
686
    x = val;
 
687
    return true;
 
688
}
 
689
 
 
690
// Same, for bools
 
691
//
 
692
bool XML_PARSER::parse_bool(char* parsed_tag, const char* start_tag, bool& b) {
 
693
    char buf[256], *end;
 
694
    bool is_tag, eof;
 
695
    char end_tag[256], tag[256];
 
696
 
 
697
    // handle the archaic form <tag/>, which means true
 
698
    //
 
699
    strcpy(tag, start_tag);
 
700
    strcat(tag, "/");
 
701
    if (!strcmp(parsed_tag, tag)) {
 
702
        b = true;
 
703
        return true;
 
704
    }
 
705
 
 
706
    // otherwise look for something of the form <tag>int</tag>
 
707
    //
 
708
    if (strcmp(parsed_tag, start_tag)) return false;
 
709
 
 
710
    eof = get(buf, sizeof(buf), is_tag);
 
711
    if (eof) return false;
 
712
    if (is_tag) return false;
 
713
    bool val = (strtol(buf, &end, 0) != 0);
 
714
    if (end != buf+strlen(buf)) return false;
 
715
 
 
716
    end_tag[0] = '/';
 
717
    strcpy(end_tag+1, start_tag);
 
718
    eof = get(tag, sizeof(tag), is_tag);
 
719
    if (eof) return false;
 
720
    if (!is_tag) return false;
 
721
    if (strcmp(tag, end_tag)) return false;
 
722
    b = val;
 
723
    return true;
 
724
}
 
725
 
 
726
// parse a start tag (optionally preceded by <?xml>)
 
727
//
 
728
bool XML_PARSER::parse_start(const char* start_tag) {
 
729
    char tag[256];
 
730
    bool eof, is_tag;
 
731
 
 
732
    eof = get(tag, sizeof(tag), is_tag);
 
733
    if (eof || !is_tag ) {
 
734
        return false;
 
735
    }
 
736
    if (strstr(tag, "?xml")) {
 
737
        eof = get(tag, sizeof(tag), is_tag);
 
738
        if (eof || !is_tag ) {
 
739
            return false;
 
740
        }
 
741
    }
 
742
    if (strcmp(tag, start_tag)) {
 
743
        return false;
 
744
    }
 
745
    return true;
 
746
}
 
747
 
 
748
// copy everything up to (but not including) the given end tag.
 
749
// The copied text may include XML tags.
 
750
// strips whitespace.
 
751
//
 
752
int XML_PARSER::element_contents(const char* end_tag, char* buf, int buflen) {
 
753
        int n=0;
 
754
        int retval=0;
 
755
    while (1) {
 
756
                if (n == buflen-1) {
 
757
                        retval = ERR_XML_PARSE;
 
758
                        break;
 
759
                }
 
760
        int c = f->_getc();
 
761
                if (c == EOF) {
 
762
                        retval = ERR_XML_PARSE;
 
763
                        break;
 
764
                }
 
765
                buf[n++] = c;
 
766
                buf[n] = 0;
 
767
                char* p = strstr(buf, end_tag);
 
768
                if (p) {
 
769
                        *p = 0;
 
770
                        break;
 
771
                }
 
772
    }
 
773
        buf[n] = 0;
 
774
    strip_whitespace(buf);
 
775
    return retval;
 
776
}
 
777
 
 
778
// We got an unexpected tag.
 
779
// If it's an end tag, do nothing.
 
780
// Otherwise skip until the end tag, if any
 
781
//
 
782
void XML_PARSER::skip_unexpected(
 
783
    const char* start_tag, bool verbose, const char* where
 
784
) {
 
785
    char tag[256], end_tag[256];
 
786
    bool is_tag;
 
787
 
 
788
    if (verbose) {
 
789
        fprintf(stderr, "Unrecognized XML in %s: %s\n", where, start_tag);
 
790
    }
 
791
    if (strchr(start_tag, '/')) return;
 
792
    sprintf(end_tag, "/%s", start_tag);
 
793
    while (!get(tag, sizeof(tag), is_tag)) {
 
794
        if (verbose) {
 
795
            fprintf(stderr, "Skipping: %s\n", tag);
 
796
        }
 
797
        if (!is_tag) continue;
 
798
        if (!strcmp(tag, end_tag)) return;
 
799
        skip_unexpected(tag, verbose, where);
 
800
    }
 
801
}
 
802
 
 
803
// sample use is shown below
 
804
 
 
805
#if 0
 
806
void parse(FILE* f) {
 
807
    char tag[256];
 
808
    bool is_tag, flag;
 
809
    MIOFILE mf;
 
810
    XML_PARSER xp(&mf);
 
811
    char name[256];
 
812
    int val;
 
813
    double x;
 
814
 
 
815
    mf.init_file(f);
 
816
    if (!xp.parse_start("blah")) {
 
817
        printf("missing start tag\n");
 
818
        return;
 
819
    }
 
820
    while (!xp.get(tag, sizeof(tag), is_tag)) {
 
821
        if (!is_tag) {
 
822
            printf("unexpected text: %s\n", tag);
 
823
            continue;
 
824
        }
 
825
        if (!strcmp(tag, "/blah")) {
 
826
            printf("success\n");
 
827
            return;
 
828
        } else if (xp.parse_str(tag, "str", name, sizeof(name))) {
 
829
            printf("got str: %s\n", name);
 
830
        } else if (xp.parse_int(tag, "int", val)) {
 
831
            printf("got int: %d\n", val);
 
832
        } else if (xp.parse_double(tag, "double", x)) {
 
833
            printf("got double: %f\n", x);
 
834
        } else if (xp.parse_bool(tag, "bool", flag)) {
 
835
            printf("got bool: %d\n", flag);
 
836
        } else {
 
837
            printf("unparsed tag: %s\n", tag);
 
838
            xp.skip_unexpected(tag, true, "xml test");
 
839
        }
 
840
    }
 
841
    printf("unexpected EOF\n");
 
842
}
 
843
 
 
844
int main() {
 
845
    FILE* f = fopen("foo.xml", "r");
 
846
    parse(f);
 
847
}
 
848
 
 
849
... and run it against, e.g.:
 
850
 
 
851
<?xml version="1.0" encoding="ISO-8859-1" ?>
 
852
<blah>
 
853
    <x>
 
854
    asdlfkj
 
855
      <x> fj</x>
 
856
    </x>
 
857
    <str>blah</str>
 
858
    <int>  6
 
859
    </int>
 
860
    <double>6.555</double>
 
861
    <bool>0</bool>
 
862
</blah>
 
863
 
 
864
#endif
 
865
const char *BOINC_RCSID_3f3de9eb18 = "$Id: parse.cpp 16478 2008-11-11 23:07:36Z davea $";