]>
Commit | Line | Data |
---|---|---|
ef416fc2 | 1 | /* |
7e86f2f6 | 2 | * CGI template function. |
ef416fc2 | 3 | * |
5e6c3df7 | 4 | * Copyright 2007-2015 by Apple Inc. |
7e86f2f6 | 5 | * Copyright 1997-2006 by Easy Software Products. |
ef416fc2 | 6 | * |
e3101897 | 7 | * Licensed under Apache License v2.0. See the file "LICENSE" for more information. |
ef416fc2 | 8 | */ |
9 | ||
10 | #include "cgi-private.h" | |
bd7854cb | 11 | #include <errno.h> |
2e4ff8af | 12 | #include <regex.h> |
ef416fc2 | 13 | |
14 | ||
15 | /* | |
16 | * Local functions... | |
17 | */ | |
18 | ||
bd7854cb | 19 | static void cgi_copy(FILE *out, FILE *in, int element, char term, |
20 | int indent); | |
ef416fc2 | 21 | static void cgi_puts(const char *s, FILE *out); |
a74454a7 | 22 | static void cgi_puturi(const char *s, FILE *out); |
ef416fc2 | 23 | |
24 | ||
25 | /* | |
26 | * 'cgiCopyTemplateFile()' - Copy a template file and replace all the | |
27 | * '{variable}' strings with the variable value. | |
28 | */ | |
29 | ||
30 | void | |
31 | cgiCopyTemplateFile(FILE *out, /* I - Output file */ | |
32 | const char *tmpl) /* I - Template file to read */ | |
33 | { | |
34 | FILE *in; /* Input file */ | |
35 | ||
36 | ||
355e94dc | 37 | fprintf(stderr, "DEBUG2: cgiCopyTemplateFile(out=%p, tmpl=\"%s\")\n", out, |
f301802f | 38 | tmpl ? tmpl : "(null)"); |
bd7854cb | 39 | |
91c84a35 MS |
40 | /* |
41 | * Range check input... | |
42 | */ | |
43 | ||
44 | if (!tmpl || !out) | |
45 | return; | |
46 | ||
ef416fc2 | 47 | /* |
48 | * Open the template file... | |
49 | */ | |
50 | ||
51 | if ((in = fopen(tmpl, "r")) == NULL) | |
bd7854cb | 52 | { |
53 | fprintf(stderr, "ERROR: Unable to open template file \"%s\" - %s\n", | |
f301802f | 54 | tmpl ? tmpl : "(null)", strerror(errno)); |
ef416fc2 | 55 | return; |
bd7854cb | 56 | } |
ef416fc2 | 57 | |
58 | /* | |
59 | * Parse the file to the end... | |
60 | */ | |
61 | ||
bd7854cb | 62 | cgi_copy(out, in, 0, 0, 0); |
ef416fc2 | 63 | |
64 | /* | |
65 | * Close the template file and return... | |
66 | */ | |
67 | ||
68 | fclose(in); | |
69 | } | |
70 | ||
71 | ||
72 | /* | |
73 | * 'cgiCopyTemplateLang()' - Copy a template file using a language... | |
74 | */ | |
75 | ||
76 | void | |
77 | cgiCopyTemplateLang(const char *tmpl) /* I - Base filename */ | |
78 | { | |
ef416fc2 | 79 | char filename[1024], /* Filename */ |
db1f069b MS |
80 | locale[16], /* Locale name */ |
81 | *locptr; /* Pointer into locale name */ | |
ef416fc2 | 82 | const char *directory, /* Directory for templates */ |
83 | *lang; /* Language */ | |
84 | FILE *in; /* Input file */ | |
85 | ||
86 | ||
355e94dc | 87 | fprintf(stderr, "DEBUG2: cgiCopyTemplateLang(tmpl=\"%s\")\n", |
f301802f | 88 | tmpl ? tmpl : "(null)"); |
bd7854cb | 89 | |
ef416fc2 | 90 | /* |
91 | * Convert the language to a locale name... | |
92 | */ | |
93 | ||
db1f069b MS |
94 | locale[0] = '\0'; |
95 | ||
ef416fc2 | 96 | if ((lang = getenv("LANG")) != NULL) |
97 | { | |
db1f069b MS |
98 | locale[0] = '/'; |
99 | strlcpy(locale + 1, lang, sizeof(locale) - 1); | |
ef416fc2 | 100 | |
db1f069b MS |
101 | if ((locptr = strchr(locale, '.')) != NULL) |
102 | *locptr = '\0'; /* Strip charset */ | |
ef416fc2 | 103 | } |
ef416fc2 | 104 | |
ef55b745 | 105 | fprintf(stderr, "DEBUG2: lang=\"%s\", locale=\"%s\"...\n", |
db1f069b | 106 | lang ? lang : "(null)", locale); |
bd7854cb | 107 | |
ef416fc2 | 108 | /* |
109 | * See if we have a template file for this language... | |
110 | */ | |
111 | ||
112 | directory = cgiGetTemplateDir(); | |
113 | ||
db1f069b MS |
114 | snprintf(filename, sizeof(filename), "%s%s/%s", directory, locale, tmpl); |
115 | if ((in = fopen(filename, "r")) == NULL) | |
ef416fc2 | 116 | { |
db1f069b | 117 | locale[3] = '\0'; |
ef416fc2 | 118 | |
db1f069b MS |
119 | snprintf(filename, sizeof(filename), "%s%s/%s", directory, locale, tmpl); |
120 | if ((in = fopen(filename, "r")) == NULL) | |
121 | { | |
ef416fc2 | 122 | snprintf(filename, sizeof(filename), "%s/%s", directory, tmpl); |
db1f069b MS |
123 | in = fopen(filename, "r"); |
124 | } | |
ef416fc2 | 125 | } |
126 | ||
355e94dc | 127 | fprintf(stderr, "DEBUG2: Template file is \"%s\"...\n", filename); |
bd7854cb | 128 | |
ef416fc2 | 129 | /* |
130 | * Open the template file... | |
131 | */ | |
132 | ||
db1f069b | 133 | if (!in) |
bd7854cb | 134 | { |
135 | fprintf(stderr, "ERROR: Unable to open template file \"%s\" - %s\n", | |
136 | filename, strerror(errno)); | |
ef416fc2 | 137 | return; |
bd7854cb | 138 | } |
ef416fc2 | 139 | |
140 | /* | |
141 | * Parse the file to the end... | |
142 | */ | |
143 | ||
bd7854cb | 144 | cgi_copy(stdout, in, 0, 0, 0); |
ef416fc2 | 145 | |
146 | /* | |
147 | * Close the template file and return... | |
148 | */ | |
149 | ||
150 | fclose(in); | |
151 | } | |
152 | ||
153 | ||
154 | /* | |
155 | * 'cgiGetTemplateDir()' - Get the templates directory... | |
156 | */ | |
157 | ||
158 | char * /* O - Template directory */ | |
159 | cgiGetTemplateDir(void) | |
160 | { | |
161 | const char *datadir; /* CUPS_DATADIR env var */ | |
162 | static char templates[1024] = ""; /* Template directory */ | |
163 | ||
164 | ||
165 | if (!templates[0]) | |
166 | { | |
167 | /* | |
168 | * Build the template directory pathname... | |
169 | */ | |
170 | ||
171 | if ((datadir = getenv("CUPS_DATADIR")) == NULL) | |
172 | datadir = CUPS_DATADIR; | |
173 | ||
174 | snprintf(templates, sizeof(templates), "%s/templates", datadir); | |
175 | } | |
176 | ||
177 | return (templates); | |
178 | } | |
179 | ||
180 | ||
181 | /* | |
182 | * 'cgiSetServerVersion()' - Set the server name and CUPS version... | |
183 | */ | |
184 | ||
185 | void | |
186 | cgiSetServerVersion(void) | |
187 | { | |
188 | cgiSetVariable("SERVER_NAME", getenv("SERVER_NAME")); | |
189 | cgiSetVariable("REMOTE_USER", getenv("REMOTE_USER")); | |
190 | cgiSetVariable("CUPS_VERSION", CUPS_SVERSION); | |
191 | ||
192 | #ifdef LC_TIME | |
193 | setlocale(LC_TIME, ""); | |
194 | #endif /* LC_TIME */ | |
195 | } | |
196 | ||
197 | ||
198 | /* | |
199 | * 'cgi_copy()' - Copy the template file, substituting as needed... | |
200 | */ | |
201 | ||
202 | static void | |
bd7854cb | 203 | cgi_copy(FILE *out, /* I - Output file */ |
204 | FILE *in, /* I - Input file */ | |
205 | int element, /* I - Element number (0 to N) */ | |
206 | char term, /* I - Terminating character */ | |
207 | int indent) /* I - Debug info indentation */ | |
ef416fc2 | 208 | { |
bd7854cb | 209 | int ch; /* Character from file */ |
210 | char op; /* Operation */ | |
211 | char name[255], /* Name of variable */ | |
212 | *nameptr, /* Pointer into name */ | |
213 | innername[255], /* Inner comparison name */ | |
214 | *innerptr, /* Pointer into inner name */ | |
215 | *s; /* String pointer */ | |
216 | const char *value; /* Value of variable */ | |
217 | const char *innerval; /* Inner value */ | |
218 | const char *outptr; /* Output string pointer */ | |
219 | char outval[1024], /* Formatted output string */ | |
220 | compare[1024]; /* Comparison string */ | |
221 | int result; /* Result of comparison */ | |
a74454a7 | 222 | int uriencode; /* Encode as URI */ |
2e4ff8af | 223 | regex_t re; /* Regular expression to match */ |
bd7854cb | 224 | |
225 | ||
355e94dc | 226 | fprintf(stderr, "DEBUG2: %*sStarting at file position %ld...\n", indent, "", |
bd7854cb | 227 | ftell(in)); |
ef416fc2 | 228 | |
229 | /* | |
230 | * Parse the file to the end... | |
231 | */ | |
232 | ||
233 | while ((ch = getc(in)) != EOF) | |
234 | if (ch == term) | |
235 | break; | |
236 | else if (ch == '{') | |
237 | { | |
238 | /* | |
239 | * Get a variable name... | |
240 | */ | |
241 | ||
a74454a7 | 242 | uriencode = 0; |
243 | ||
ef416fc2 | 244 | for (s = name; (ch = getc(in)) != EOF;) |
2e4ff8af | 245 | if (strchr("}]<>=!~ \t\n", ch)) |
ef416fc2 | 246 | break; |
a74454a7 | 247 | else if (s == name && ch == '%') |
248 | uriencode = 1; | |
ef416fc2 | 249 | else if (s > name && ch == '?') |
250 | break; | |
251 | else if (s < (name + sizeof(name) - 1)) | |
7e86f2f6 | 252 | *s++ = (char)ch; |
ef416fc2 | 253 | |
254 | *s = '\0'; | |
255 | ||
256 | if (s == name && isspace(ch & 255)) | |
257 | { | |
355e94dc | 258 | fprintf(stderr, "DEBUG2: %*sLone { at %ld...\n", indent, "", ftell(in)); |
bd7854cb | 259 | |
ef416fc2 | 260 | if (out) |
261 | { | |
262 | putc('{', out); | |
263 | putc(ch, out); | |
264 | } | |
265 | ||
266 | continue; | |
267 | } | |
268 | ||
bd7854cb | 269 | if (ch == '}') |
355e94dc | 270 | fprintf(stderr, "DEBUG2: %*s\"{%s}\" at %ld...\n", indent, "", name, |
bd7854cb | 271 | ftell(in)); |
272 | ||
ef416fc2 | 273 | /* |
274 | * See if it has a value... | |
275 | */ | |
276 | ||
277 | if (name[0] == '?') | |
278 | { | |
279 | /* | |
280 | * Insert value only if it exists... | |
281 | */ | |
282 | ||
283 | if ((nameptr = strrchr(name, '-')) != NULL && isdigit(nameptr[1] & 255)) | |
284 | { | |
285 | *nameptr++ = '\0'; | |
286 | ||
287 | if ((value = cgiGetArray(name + 1, atoi(nameptr) - 1)) != NULL) | |
288 | outptr = value; | |
289 | else | |
290 | { | |
291 | outval[0] = '\0'; | |
292 | outptr = outval; | |
293 | } | |
294 | } | |
295 | else if ((value = cgiGetArray(name + 1, element)) != NULL) | |
296 | outptr = value; | |
297 | else | |
298 | { | |
299 | outval[0] = '\0'; | |
300 | outptr = outval; | |
301 | } | |
302 | } | |
303 | else if (name[0] == '#') | |
304 | { | |
305 | /* | |
306 | * Insert count... | |
307 | */ | |
308 | ||
309 | if (name[1]) | |
310 | sprintf(outval, "%d", cgiGetSize(name + 1)); | |
311 | else | |
312 | sprintf(outval, "%d", element + 1); | |
313 | ||
314 | outptr = outval; | |
315 | } | |
316 | else if (name[0] == '[') | |
317 | { | |
318 | /* | |
319 | * Loop for # of elements... | |
320 | */ | |
321 | ||
322 | int i; /* Looping var */ | |
323 | long pos; /* File position */ | |
324 | int count; /* Number of elements */ | |
325 | ||
326 | ||
327 | if (isdigit(name[1] & 255)) | |
328 | count = atoi(name + 1); | |
329 | else | |
330 | count = cgiGetSize(name + 1); | |
331 | ||
332 | pos = ftell(in); | |
333 | ||
355e94dc | 334 | fprintf(stderr, "DEBUG2: %*sLooping on \"%s\" at %ld, count=%d...\n", |
bd7854cb | 335 | indent, "", name + 1, pos, count); |
336 | ||
ef416fc2 | 337 | if (count > 0) |
338 | { | |
339 | for (i = 0; i < count; i ++) | |
340 | { | |
bd7854cb | 341 | if (i) |
342 | fseek(in, pos, SEEK_SET); | |
343 | ||
344 | cgi_copy(out, in, i, '}', indent + 2); | |
ef416fc2 | 345 | } |
346 | } | |
347 | else | |
bd7854cb | 348 | cgi_copy(NULL, in, 0, '}', indent + 2); |
349 | ||
355e94dc | 350 | fprintf(stderr, "DEBUG2: %*sFinished looping on \"%s\"...\n", indent, |
bd7854cb | 351 | "", name + 1); |
ef416fc2 | 352 | |
353 | continue; | |
354 | } | |
f8b3a85b MS |
355 | else if (name[0] == '$') |
356 | { | |
357 | /* | |
358 | * Insert cookie value or nothing if not defined. | |
359 | */ | |
360 | ||
361 | if ((value = cgiGetCookie(name + 1)) != NULL) | |
362 | outptr = value; | |
363 | else | |
364 | { | |
365 | outval[0] = '\0'; | |
366 | outptr = outval; | |
367 | } | |
368 | } | |
ef416fc2 | 369 | else |
370 | { | |
371 | /* | |
372 | * Insert variable or variable name (if element is NULL)... | |
373 | */ | |
374 | ||
375 | if ((nameptr = strrchr(name, '-')) != NULL && isdigit(nameptr[1] & 255)) | |
376 | { | |
377 | *nameptr++ = '\0'; | |
378 | if ((value = cgiGetArray(name, atoi(nameptr) - 1)) == NULL) | |
379 | { | |
380 | snprintf(outval, sizeof(outval), "{%s}", name); | |
381 | outptr = outval; | |
382 | } | |
383 | else | |
384 | outptr = value; | |
385 | } | |
386 | else if ((value = cgiGetArray(name, element)) == NULL) | |
387 | { | |
388 | snprintf(outval, sizeof(outval), "{%s}", name); | |
389 | outptr = outval; | |
390 | } | |
391 | else | |
392 | outptr = value; | |
393 | } | |
394 | ||
395 | /* | |
396 | * See if the terminating character requires another test... | |
397 | */ | |
398 | ||
399 | if (ch == '}') | |
400 | { | |
401 | /* | |
402 | * End of substitution... | |
403 | */ | |
404 | ||
405 | if (out) | |
a74454a7 | 406 | { |
407 | if (uriencode) | |
408 | cgi_puturi(outptr, out); | |
88f9aafc | 409 | else if (!_cups_strcasecmp(name, "?cupsdconf_default")) |
355e94dc | 410 | fputs(outptr, stdout); |
a74454a7 | 411 | else |
412 | cgi_puts(outptr, out); | |
413 | } | |
ef416fc2 | 414 | |
415 | continue; | |
416 | } | |
417 | ||
418 | /* | |
419 | * OK, process one of the following checks: | |
420 | * | |
421 | * {name?exist:not-exist} Exists? | |
422 | * {name=value?true:false} Equal | |
423 | * {name<value?true:false} Less than | |
424 | * {name>value?true:false} Greater than | |
425 | * {name!value?true:false} Not equal | |
2e4ff8af | 426 | * {name~refex?true:false} Regex match |
ef416fc2 | 427 | */ |
428 | ||
7e86f2f6 | 429 | op = (char)ch; |
bd7854cb | 430 | |
ef416fc2 | 431 | if (ch == '?') |
432 | { | |
433 | /* | |
434 | * Test for existance... | |
435 | */ | |
436 | ||
f8b3a85b MS |
437 | if (name[0] == '?') |
438 | result = cgiGetArray(name + 1, element) != NULL; | |
439 | else if (name[0] == '#') | |
440 | result = cgiGetVariable(name + 1) != NULL; | |
441 | else | |
442 | result = cgiGetArray(name, element) != NULL; | |
443 | ||
444 | result = result && outptr[0]; | |
bd7854cb | 445 | compare[0] = '\0'; |
ef416fc2 | 446 | } |
447 | else | |
448 | { | |
449 | /* | |
450 | * Compare to a string... | |
451 | */ | |
452 | ||
ef416fc2 | 453 | for (s = compare; (ch = getc(in)) != EOF;) |
454 | if (ch == '?') | |
455 | break; | |
456 | else if (s >= (compare + sizeof(compare) - 1)) | |
457 | continue; | |
458 | else if (ch == '#') | |
459 | { | |
460 | sprintf(s, "%d", element + 1); | |
461 | s += strlen(s); | |
462 | } | |
463 | else if (ch == '{') | |
464 | { | |
465 | /* | |
466 | * Grab the value of a variable... | |
467 | */ | |
468 | ||
469 | innerptr = innername; | |
470 | while ((ch = getc(in)) != EOF && ch != '}') | |
471 | if (innerptr < (innername + sizeof(innername) - 1)) | |
7e86f2f6 | 472 | *innerptr++ = (char)ch; |
ef416fc2 | 473 | *innerptr = '\0'; |
474 | ||
475 | if (innername[0] == '#') | |
476 | sprintf(s, "%d", cgiGetSize(innername + 1)); | |
477 | else if ((innerptr = strrchr(innername, '-')) != NULL && | |
478 | isdigit(innerptr[1] & 255)) | |
479 | { | |
480 | *innerptr++ = '\0'; | |
481 | if ((innerval = cgiGetArray(innername, atoi(innerptr) - 1)) == NULL) | |
482 | *s = '\0'; | |
483 | else | |
7e86f2f6 | 484 | strlcpy(s, innerval, sizeof(compare) - (size_t)(s - compare)); |
ef416fc2 | 485 | } |
486 | else if (innername[0] == '?') | |
487 | { | |
488 | if ((innerval = cgiGetArray(innername + 1, element)) == NULL) | |
489 | *s = '\0'; | |
490 | else | |
7e86f2f6 | 491 | strlcpy(s, innerval, sizeof(compare) - (size_t)(s - compare)); |
ef416fc2 | 492 | } |
493 | else if ((innerval = cgiGetArray(innername, element)) == NULL) | |
7e86f2f6 | 494 | snprintf(s, sizeof(compare) - (size_t)(s - compare), "{%s}", innername); |
ef416fc2 | 495 | else |
7e86f2f6 | 496 | strlcpy(s, innerval, sizeof(compare) - (size_t)(s - compare)); |
ef416fc2 | 497 | |
498 | s += strlen(s); | |
499 | } | |
500 | else if (ch == '\\') | |
7e86f2f6 | 501 | *s++ = (char)getc(in); |
ef416fc2 | 502 | else |
7e86f2f6 | 503 | *s++ = (char)ch; |
ef416fc2 | 504 | |
505 | *s = '\0'; | |
506 | ||
507 | if (ch != '?') | |
bd7854cb | 508 | { |
509 | fprintf(stderr, | |
355e94dc | 510 | "DEBUG2: %*sBad terminator '%c' at file position %ld...\n", |
bd7854cb | 511 | indent, "", ch, ftell(in)); |
ef416fc2 | 512 | return; |
bd7854cb | 513 | } |
ef416fc2 | 514 | |
515 | /* | |
516 | * Do the comparison... | |
517 | */ | |
518 | ||
519 | switch (op) | |
520 | { | |
521 | case '<' : | |
88f9aafc | 522 | result = _cups_strcasecmp(outptr, compare) < 0; |
ef416fc2 | 523 | break; |
524 | case '>' : | |
88f9aafc | 525 | result = _cups_strcasecmp(outptr, compare) > 0; |
ef416fc2 | 526 | break; |
527 | case '=' : | |
88f9aafc | 528 | result = _cups_strcasecmp(outptr, compare) == 0; |
ef416fc2 | 529 | break; |
530 | case '!' : | |
88f9aafc | 531 | result = _cups_strcasecmp(outptr, compare) != 0; |
ef416fc2 | 532 | break; |
2e4ff8af MS |
533 | case '~' : |
534 | fprintf(stderr, "DEBUG: Regular expression \"%s\"\n", compare); | |
535 | ||
536 | if (regcomp(&re, compare, REG_EXTENDED | REG_ICASE)) | |
537 | { | |
538 | fprintf(stderr, | |
6daf3636 | 539 | "ERROR: Unable to compile regular expression \"%s\"!\n", |
2e4ff8af MS |
540 | compare); |
541 | result = 0; | |
542 | } | |
543 | else | |
544 | { | |
545 | regmatch_t matches[10]; | |
546 | ||
547 | result = 0; | |
548 | ||
549 | if (!regexec(&re, outptr, 10, matches, 0)) | |
550 | { | |
551 | int i; | |
552 | for (i = 0; i < 10; i ++) | |
553 | { | |
554 | fprintf(stderr, "DEBUG: matches[%d].rm_so=%d\n", i, | |
555 | (int)matches[i].rm_so); | |
556 | if (matches[i].rm_so < 0) | |
557 | break; | |
558 | ||
559 | result ++; | |
560 | } | |
561 | } | |
562 | ||
563 | regfree(&re); | |
564 | } | |
565 | break; | |
ef416fc2 | 566 | default : |
567 | result = 1; | |
568 | break; | |
569 | } | |
570 | } | |
571 | ||
bd7854cb | 572 | fprintf(stderr, |
355e94dc | 573 | "DEBUG2: %*sStarting \"{%s%c%s\" at %ld, result=%d...\n", |
bd7854cb | 574 | indent, "", name, op, compare, ftell(in), result); |
575 | ||
ef416fc2 | 576 | if (result) |
577 | { | |
578 | /* | |
579 | * Comparison true; output first part and ignore second... | |
580 | */ | |
581 | ||
355e94dc | 582 | fprintf(stderr, "DEBUG2: %*sOutput first part...\n", indent, ""); |
bd7854cb | 583 | cgi_copy(out, in, element, ':', indent + 2); |
584 | ||
355e94dc | 585 | fprintf(stderr, "DEBUG2: %*sSkip second part...\n", indent, ""); |
bd7854cb | 586 | cgi_copy(NULL, in, element, '}', indent + 2); |
ef416fc2 | 587 | } |
588 | else | |
589 | { | |
590 | /* | |
591 | * Comparison false; ignore first part and output second... | |
592 | */ | |
593 | ||
355e94dc | 594 | fprintf(stderr, "DEBUG2: %*sSkip first part...\n", indent, ""); |
bd7854cb | 595 | cgi_copy(NULL, in, element, ':', indent + 2); |
596 | ||
355e94dc | 597 | fprintf(stderr, "DEBUG2: %*sOutput second part...\n", indent, ""); |
bd7854cb | 598 | cgi_copy(out, in, element, '}', indent + 2); |
ef416fc2 | 599 | } |
bd7854cb | 600 | |
355e94dc | 601 | fprintf(stderr, "DEBUG2: %*sFinished \"{%s%c%s\", out=%p...\n", indent, "", |
bd7854cb | 602 | name, op, compare, out); |
ef416fc2 | 603 | } |
604 | else if (ch == '\\') /* Quoted char */ | |
605 | { | |
606 | if (out) | |
607 | putc(getc(in), out); | |
608 | else | |
609 | getc(in); | |
610 | } | |
611 | else if (out) | |
612 | putc(ch, out); | |
613 | ||
bd7854cb | 614 | if (ch == EOF) |
355e94dc | 615 | fprintf(stderr, "DEBUG2: %*sReturning at file position %ld on EOF...\n", |
bd7854cb | 616 | indent, "", ftell(in)); |
617 | else | |
618 | fprintf(stderr, | |
355e94dc | 619 | "DEBUG2: %*sReturning at file position %ld on character '%c'...\n", |
bd7854cb | 620 | indent, "", ftell(in), ch); |
621 | ||
622 | if (ch == EOF && term) | |
623 | fprintf(stderr, "ERROR: %*sSaw EOF, expected '%c'!\n", indent, "", term); | |
624 | ||
ef416fc2 | 625 | /* |
626 | * Flush any pending output... | |
627 | */ | |
628 | ||
629 | if (out) | |
630 | fflush(out); | |
631 | } | |
632 | ||
633 | ||
634 | /* | |
635 | * 'cgi_puts()' - Put a string to the output file, quoting as needed... | |
636 | */ | |
637 | ||
638 | static void | |
639 | cgi_puts(const char *s, /* I - String to output */ | |
640 | FILE *out) /* I - Output file */ | |
641 | { | |
642 | while (*s) | |
643 | { | |
644 | if (*s == '<') | |
5e6c3df7 | 645 | fputs("<", out); |
ef416fc2 | 646 | else if (*s == '>') |
647 | fputs(">", out); | |
648 | else if (*s == '\"') | |
649 | fputs(""", out); | |
ef55b745 MS |
650 | else if (*s == '\'') |
651 | fputs("'", out); | |
ef416fc2 | 652 | else if (*s == '&') |
653 | fputs("&", out); | |
654 | else | |
655 | putc(*s, out); | |
656 | ||
657 | s ++; | |
658 | } | |
659 | } | |
660 | ||
661 | ||
662 | /* | |
a74454a7 | 663 | * 'cgi_puturi()' - Put a URI string to the output file, quoting as needed... |
664 | */ | |
665 | ||
666 | static void | |
667 | cgi_puturi(const char *s, /* I - String to output */ | |
668 | FILE *out) /* I - Output file */ | |
669 | { | |
670 | while (*s) | |
671 | { | |
ef55b745 | 672 | if (strchr("%@&+ <>#=", *s) || *s < ' ' || *s & 128) |
a74454a7 | 673 | fprintf(out, "%%%02X", *s & 255); |
674 | else | |
675 | putc(*s, out); | |
676 | ||
677 | s ++; | |
678 | } | |
679 | } |