1 /*
2 * gracula 3.0
3 *
4 * Graphic Counter Language
5 *
6 * C source code
7 *
8 * Copyright 1999 G. Adam Stanislav
9 * All rights reserved
10 *
11 * This program is released under the terms of the Whiz Kid Technomagic
12 * No-Nonsense License. See the file NNS for details.
13 *
14 * Started: 11-Jan-1999
15 * Updated: 18-Jun-1999
16 *
17 * Compile with:
18 *
19 * gcc -O3 gcl.c gd.c -lm -o gracula
20 *
21 * or just type:
22 *
23 * make
24 *
25 * NOTE: You need several files from the "gd" package from Boutell.Com
26 * However, gd.c as distributed with this program has been slightly
27 * patched to accomodate specific needs of Graphic Counter Language.
28 *
29 * Please send bug fixes to gcl@whizkidtech.net. If you find a bug and
30 * cannot fix it, send a bug report, please. The more detailed the
31 * description of the bug, the easier it is for me to fix.
32 *
33 * NOTE: This program contains some Unix-specific code (such as file
34 * locking). Generally, the Unix-specific code can be modified
35 * to work under other operating systems (such as Windows), but
36 * it requires some work (unfortunately, Microsoft has decided
37 * to implement certain Unix features differently from the
38 * accepted practice -- don't blame me, blame them). To simplify
39 * porting of this code, any Unix-specific code is marked as
40 * such by a comment. Everything else is pure ANSI C.
41 *
42 * Look for the latest version at ftp.whizkidtech.net
43 *
44 * History:
45 *
46 * 22-Jun-1999 - released version 3.0
47 * Added signed and unsigned keywords
48 * Added the #? directive (include file)
49 * Added registers a-d
50 * Added the now function
51 * Added the random function
52 * Added the srandom function
53 * Added the increment keyword
54 * Added the fudge keyword
55 * Added the sigma keyword
56 * Added the #~ directive (space)
57 * Added the #; directive (dot)
58 * Added the box frame
59 * Added configurable group separators
60 * Extended the group keyword to accept group separator
61 * Added 16-integer stack
62 * Added push keyword
63 * Added pop keyword
64 * Added tos function
65 * Added conditionals (if, else)
66 * Added compound statements
67 * Added numeric expressions
68 * Added ternary statements
69 * Added array statements
70 * Added Unicode support
71 * Got rid of case sensitivity
72 * Added natural language processing
73 * Fixed an inhibitor bug that has been there since 1.00!
74 * Added relays
75 * Added the := (starts with) operator to inhibitors and relays
76 * Fixed a spurious string processing bug in lexical analyzer
77 * Added the Persian flaw, so read the docs!!!
78 *
79 * 30-May-1999 - released version 2.30
80 * Added the nocompile directive
81 * Added the -g option switch
82 * Added the -p option switch
83 * Added the print keyword
84 * Added input from environment vars and external programs
85 *
86 * 22-May-1999 - released version 2.20
87 * Changed name from gcl to gracula
88 * Changed counter from unsigned int to unsigned long long.
89 * This is optional as it may not work with compilers other
90 * than gcc, or different C libraries.
91 * Sped up keyword lookup by using a size-based switch.
92 * Added the group keyword.
93 * Added the reverse, reverse digits, and reverse commas keywords.
94 * Made more compatible with standard C (thanks to Frank Denis).
95 * Fixed some obscure bugs.
96 *
97 * 22-Mar-1999 - released version 2.10
98 * Added custom defaults, including custom default graphics.
99 * Added a few keywords: portable, default, nodefault.
100 * Fixed a problem 2.00 had with compiling under Linux.
101 * Changed "annualy" to "annually".
102 * Fixed minor bugs.
103 *
104 * 22-Feb-1999 - released version 2.00
105 * Added default graphic file names in specified directory.
106 * Added array graphic.
107 * Added colorize keyword.
108 * Added conditional inhibitors.
109 * Added URL redirection.
110 * Added silent mode.
111 * Added forking of another program in the background.
112 * Added daily, weekly, monthly, and annual counters.
113 * Added ability to adjust count manually.
114 * Added ability to display date, time, time zone.
115 * Added text output with SSI.
116 * Fixed minor bugs.
117 * Changed some ifs to switches for faster speed.
118 * Increased optimization in makefile for speed.
119 *
120 * 21-Jan-1999 - released version 1.00
121 * Original release.
122 *
123 * Acknowledgements:
124 *
125 * Special thanks to Joe Price of Nevaeh Technologies Inc. He pointed out
126 * two lines of code in version 2.00 which were FreeBSD specific and made
127 * it impossible to compile under Linux. He also agreed to test future
128 * versions under Linux before I release them.
129 *
130 * Thanks to Frank Denis for pointing out certain non-standard C
131 * extensions in v2.10. Those are now changed to comply with the standard.
132 *
133 * Thanks to Dominique Voillemot for testing gracula under Red Hat Linux,
134 * and for designing the Poorcount collection.
135 *
136 */
137 #include <stdarg.h>
138 #include <stdio.h>
139 #include <string.h>
140 #include <stdlib.h>
141 #include <time.h>
142 #include <ctype.h>
143 #include <sys/param.h> /* Unix specific */
144 #include <sys/file.h> /* Unix specific */
145 #include <unistd.h> /* Unix specific */
146 #include "gcl.h"
147
148 #include "gcldefaults.h"
149 #include "gcldefaults.c"
150
151 #if (GCLDEFAULTGROUP <= 0)
152 #undef GCLDEFAULTGROUP
153 #define GCLDEFAULTGROUP 3
154 #endif
155
156 /*
157 * Note on "graceful recovery." You will find comments about recovering
158 * gracefully throughout this code. It is common in computer languages
159 * to abort compilation or interpretation when a syntax error (or lack of
160 * allocatable memory) is encountered. This is the right thing to do
161 * (I suppose) under most circumstances.
162 *
163 * Alas, when working with CGI, aborting the interpreter would make
164 * the browser wait for input that would never come. The browser would
165 * give up eventually (one would hope), but might not show the rest of
166 * the web page while waiting. This is not good, IMHO.
167 *
168 * Hence, the idea of graceful recovery: It is better to feed the browser
169 * something than to let it wait. So, GCL will ALWAYS produce some output,
170 * even if it is just a one-pixel GIF. That is unless you use the -s (silent)
171 * switch, in which case it NEVER produces output.
172 */
173
174 static FILE *gclfile;
175 static FILE *gcldefaultfile = NULL;
176
177 static unsigned int lineno = 1;
178
179 static int lexstack = -1;
180 static counter_t lexvalue;
181 static char lexbuffer[LBSIZE];
182
183 static char const unexpected[] = "Unexpected end of file";
184 static char const colval[] = "Expected red, green, and blue, values.";
185 static char const expiration[] = "Expected expiration value (seconds from now)";
186 static char const expalign[] = "Expected alignment value";
187 static char const ashiftval[] = "Expected alignment offset";
188 static char const shiftvalue[] = "Expected shift value or none";
189 static char const shifttype[] = "Expected shift type or none";
190 static char const fileformat[] = "Expected image file format";
191 static char const exppath[] = "Expected path";
192 static char const padvalue[] = "Expected pad value";
193 static char const numexp[] = "Expected numeric expression";
194 static char const regops[] = "Expected `=', `+=', `-=', `*=', `/=', `%=', `&=', `|=', `^=', `++', or `--'";
195
196 static char from[] = "HTTP_FROM";
197 static char httpcookie[] = "HTTP_COOKIE";
198
199 static void noframe(gdImagePtr, int, int, int, int);
200 static void popup(gdImagePtr, int, int, int, int);
201 static void button(gdImagePtr, int, int, int, int);
202 static void defaultbutton(gdImagePtr, int, int, int, int);
203 static void shadow(gdImagePtr, int, int, int, int);
204 static void box(gdImagePtr, int, int, int, int);
205
206 /* Declare the overhead of various frame types */
207 static gclframe const frames[FRAMES] = {
208 { 0, 0, 0, 0, TRANSOK, noframe },
209 { 2, 2, 2, 2, NOTRANS, popup },
210 { 2, 2, 2, 2, NOTRANS, button },
211 { 3, 3, 3, 3, NOTRANS, defaultbutton },
212 { 2, 2, 3, 3, NOTRANS, shadow },
213 { 3, 3, 3, 3, NOTRANS, box }
214 };
215
216 static char const characters[] = "0123456789-%^@<>~;,:.$+[/";
217 static char const echars[ACCEPTABLECHARS] = "0123456789-%^@<>,~;:TZ+ .";
218 static char const pchars[ACCEPTABLECHARS] = "0123456789-%^@<>,~;%^@>~;";
219 /*
220 * Note that dash and minus are treated as separate entities. This
221 * allows for greater flexibility. But you can use the same
222 * graphic for both. In that case, you can use one file and
223 * create a symbolic link to it with a different name.
224 */
225 static char const * const defaultpicturename[] = {
226 "0",
227 "1",
228 "2",
229 "3",
230 "4",
231 "5",
232 "6",
233 "7",
234 "8",
235 "9",
236 "dash",
237 "colon",
238 "time",
239 "zone",
240 "minus",
241 "plus",
242 "space",
243 "dot",
244 "comma",
245 "head",
246 "tail",
247 "bkg",
248 "tile",
249 "array",
250 ""
251 };
252
253 static char const * const picname[] = {
254 "digit `0'",
255 "digit `1'",
256 "digit `2'",
257 "digit `3'",
258 "digit `4'",
259 "digit `5'",
260 "digit `6'",
261 "digit `7'",
262 "digit `8'",
263 "digit `9'",
264 "dash",
265 "colon",
266 "\"T\"",
267 "\"Z\"",
268 "minus",
269 "plus",
270 "space",
271 "dot",
272 "comma",
273 "head",
274 "tail",
275 "background",
276 "tile",
277 "array",
278 "picture directory"
279 };
280
281 static char const * const graphictypesnames[] = {
282 "head",
283 "tail",
284 "digits",
285 "commas",
286 "spaces",
287 "dots",
288 "dashes",
289 "colons",
290 "plusses",
291 "minuses",
292 "times",
293 "zones"
294 };
295
296 static char const * const definecharname[] = {
297 "comma",
298 "colon",
299 "dash",
300 "time",
301 "zone"
302 };
303
304 static char const * const definecharnameplural[] = {
305 "commas",
306 "colons",
307 "dashes",
308 "time character",
309 "zone character"
310 };
311
312 static char const * const framenames[] = {
313 "none",
314 "popup",
315 "button",
316 "defaultbutton",
317 "shadow",
318 "box"
319
320 };
321
322 static char pathbuffer[MAXPATHLEN];
323 static char *filename = NULL;
324 static char const * const graphictypes[] = {
325 "?",
326 "gif",
327 "gd",
328 "xbm"
329 };
330 static char const * const day[] = {
331 "Sun",
332 "Mon",
333 "Tue",
334 "Wed",
335 "Thu",
336 "Fri",
337 "Sat"
338 };
339
340 static char const * const month[] = {
341 "Jan",
342 "Feb",
343 "Mar",
344 "Apr",
345 "May",
346 "Jun",
347 "Jul",
348 "Aug",
349 "Sep",
350 "Oct",
351 "Nov",
352 "Dec"
353 };
354
355 static char const * const gcldefaultpads[] = {
356 "GCLDEFAULTTPAD",
357 "GCLDEFAULTBPAD",
358 "GCLDEFAULTLPAD",
359 "GCLDEFAULTRPAD"
360 };
361
362 static char const * const gcldefaultkern[] = {
363 "GCLDEFAULTKERNHEAD",
364 "GCLDEFAULTKERNTAIL",
365 "GCLDEFAULTKERNDIGITS",
366 "GCLDEFAULTKERNCOMMAS",
367 "GCLDEFAULTKERNSPACES",
368 "GCLDEFAULTKERNDOTS",
369 "GCLDEFAULTKERNDASHES",
370 "GCLDEFAULTKERNCOLONS",
371 "GCLDEFAULTKERNPLUSSES",
372 "GCLDEFAULTKERNMINUSES",
373 "GCLDEFAULTKERNTIMES",
374 "GCLDEFAULTKERNZONES"
375 };
376
377 static char const * const gcldefaulthalign[] = {
378 "GCLDEFAULTHALIGNHEAD",
379 "GCLDEFAULTHALIGNTAIL",
380 "GCLDEFAULTHALIGNDIGITS",
381 "GCLDEFAULTHALIGNCOMMAS",
382 "GCLDEFAULTHALIGNSPACES",
383 "GCLDEFAULTHALIGNDOTS",
384 "GCLDEFAULTHALIGNDASHES",
385 "GCLDEFAULTHALIGNCOLONS",
386 "GCLDEFAULTHALIGNPLUSSES",
387 "GCLDEFAULTHALIGNMINUSES",
388 "GCLDEFAULTHALIGNTIMES",
389 "GCLDEFAULTHALIGNZONES"
390 };
391
392 static char const * const gcldefaultvalign[] = {
393 "GCLDEFAULTVALIGNHEAD",
394 "GCLDEFAULTVALIGNTAIL",
395 "GCLDEFAULTVALIGNDIGITS",
396 "GCLDEFAULTVALIGNCOMMAS",
397 "GCLDEFAULTVALIGNSPACES",
398 "GCLDEFAULTVALIGNDOTS",
399 "GCLDEFAULTVALIGNDASHES",
400 "GCLDEFAULTVALIGNCOLONS",
401 "GCLDEFAULTVALIGNPLUSSES",
402 "GCLDEFAULTVALIGNMINUSES",
403 "GCLDEFAULTVALIGNTIMES",
404 "GCLDEFAULTVALIGNZONES"
405 };
406
407 static char const * const gcldefaulthashift[] = {
408 "GCLDEFAULTHASHIFTHEAD",
409 "GCLDEFAULTHASHIFTTAIL",
410 "GCLDEFAULTHASHIFTDIGITS",
411 "GCLDEFAULTHASHIFTCOMMAS",
412 "GCLDEFAULTHASHIFTSPACES",
413 "GCLDEFAULTHASHIFTDOTS",
414 "GCLDEFAULTHASHIFTDASHES",
415 "GCLDEFAULTHASHIFTCOLONS",
416 "GCLDEFAULTHASHIFTPLUSSES",
417 "GCLDEFAULTHASHIFTMINUSES",
418 "GCLDEFAULTHASHIFTTIMES",
419 "GCLDEFAULTHASHIFTZONES"
420 };
421
422 static char const * const gcldefaultvashift[] = {
423 "GCLDEFAULTVASHIFTHEAD",
424 "GCLDEFAULTVASHIFTTAIL",
425 "GCLDEFAULTVASHIFTDIGITS",
426 "GCLDEFAULTVASHIFTCOMMAS",
427 "GCLDEFAULTVASHIFTSPACES",
428 "GCLDEFAULTVASHIFTDOTS",
429 "GCLDEFAULTVASHIFTDASHES",
430 "GCLDEFAULTVASHIFTCOLONS",
431 "GCLDEFAULTVASHIFTPLUSSES",
432 "GCLDEFAULTVASHIFTMINUSES",
433 "GCLDEFAULTVASHIFTTIMES",
434 "GCLDEFAULTVASHIFTZONES"
435 };
436
437 static counter_t gclregs[NUMREGS] = {0};
438 static int slashnotneeded;
439 static time_t timer;
440 static struct tm *now;
441 static unsigned int weeks;
442 static gcldate today = { -1, -1, -1, -1 };
443 static gcltimezone gtz = { GCLDEFAULTTIMEZONE, GCLDEFAULTTIMEZONEOFFSET };
444 static gclreset rst = NEVER;
445 static int whatami = SHOWCOUNT;
446 static int seconds = 0;
447 static int zonehours = 0;
448 static int zoneminutes = 0;
449 static char *gclpath = NULL;
450 static char *gclprint = NULL;
451 static char *redirect = NULL;
452 static char *cookie = NULL;
453 static char *cookies = NULL;
454 static char *script = NULL;
455 static char *scriptname = NULL;
456 static cookiepair *cookiepairs = NULL;
457 static fi *includefile = NULL;
458 static gclredirection redirection = NOREDIRECTION;
459 static int gotcookies = 0;
460 static int numcookies = 0;
461 static int inhibited = 0;
462 static inhibit *firstinhibitor = NULL;
463 static inhibit *lastinhibitor = NULL;
464 static relay *firstrelayor = NULL;
465 static relay *lastrelayor = NULL;
466 static int nodefaultpicture[GRAPHICS] = { 0 };
467 static gclpic picture[GRAPHICS] = { {NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0} };
468 static rgbcolor tt = { TTRED, TTGREEN, TTBLUE };
469 static rgbcolor bkg = { BKGRED, BKGGREEN, BKGBLUE };
470 static rgbcolor invis = { INVISRED, INVISGREEN, INVISBLUE };
471 static int one = 1;
472 static int secure = 1;
473 static scounter_t increment = 1;
474 static scounter_t incrementrange[2] = { 1, 1 };
475 static int transparent = GCLDEFAULTTRANSPARENT;
476 static int warnings = 0;
477 static int vertical = GCLDEFAULTVERTICAL;
478 static int expires = GCLDEFAULTEXPIRES;
479 static unsigned int group = GCLDEFAULTGROUP;
480 static unsigned int groupseparator = GCLDEFAULTGROUPSEPARATOR;
481 static int revcom = GCLDEFAULTREVCOM;
482 static int revdig = GCLDEFAULTREVDIG;
483 static counter_t randomnumber;
484 static scounter_t mean;
485 static counter_t gclstack[16];
486 static unsigned int gclstackptr = 0;
487 static unsigned int numericerror = 0;
488 static unsigned int premature = 0;
489 static unsigned int insidenumericexpression = 0;
490 static gclalign alignflag = {
491 {
492 GCLDEFAULTHALIGNHEAD,
493 GCLDEFAULTHALIGNTAIL,
494 GCLDEFAULTHALIGNDIGITS,
495 GCLDEFAULTHALIGNCOMMAS,
496 GCLDEFAULTHALIGNSPACES,
497 GCLDEFAULTHALIGNDOTS,
498 GCLDEFAULTHALIGNDASHES,
499 GCLDEFAULTHALIGNCOLONS,
500 GCLDEFAULTHALIGNPLUSSES,
501 GCLDEFAULTHALIGNMINUSES,
502 GCLDEFAULTHALIGNTIMES,
503 GCLDEFAULTHALIGNZONES
504 },
505
506 {
507 GCLDEFAULTVALIGNHEAD,
508 GCLDEFAULTVALIGNTAIL,
509 GCLDEFAULTVALIGNDIGITS,
510 GCLDEFAULTVALIGNCOMMAS,
511 GCLDEFAULTVALIGNSPACES,
512 GCLDEFAULTVALIGNDOTS,
513 GCLDEFAULTVALIGNDASHES,
514 GCLDEFAULTVALIGNCOLONS,
515 GCLDEFAULTVALIGNPLUSSES,
516 GCLDEFAULTVALIGNMINUSES,
517 GCLDEFAULTVALIGNTIMES,
518 GCLDEFAULTVALIGNZONES
519 }
520 };
521
522 static gclalign const defaultalignflag = {
523 {
524 GCLDEFAULTHALIGNHEAD,
525 GCLDEFAULTHALIGNTAIL,
526 GCLDEFAULTHALIGNDIGITS,
527 GCLDEFAULTHALIGNCOMMAS,
528 GCLDEFAULTHALIGNSPACES,
529 GCLDEFAULTHALIGNDOTS,
530 GCLDEFAULTHALIGNDASHES,
531 GCLDEFAULTHALIGNCOLONS,
532 GCLDEFAULTHALIGNPLUSSES,
533 GCLDEFAULTHALIGNMINUSES,
534 GCLDEFAULTHALIGNTIMES,
535 GCLDEFAULTHALIGNZONES
536 },
537
538 {
539 GCLDEFAULTVALIGNHEAD,
540 GCLDEFAULTVALIGNTAIL,
541 GCLDEFAULTVALIGNDIGITS,
542 GCLDEFAULTVALIGNCOMMAS,
543 GCLDEFAULTVALIGNSPACES,
544 GCLDEFAULTVALIGNDOTS,
545 GCLDEFAULTVALIGNDASHES,
546 GCLDEFAULTVALIGNCOLONS,
547 GCLDEFAULTVALIGNPLUSSES,
548 GCLDEFAULTVALIGNMINUSES,
549 GCLDEFAULTVALIGNTIMES,
550 GCLDEFAULTVALIGNZONES
551 }
552 };
553
554 static gclalign ashift = {
555 {
556 GCLDEFAULTHASHIFTHEAD,
557 GCLDEFAULTHASHIFTTAIL,
558 GCLDEFAULTHASHIFTDIGITS,
559 GCLDEFAULTHASHIFTCOMMAS,
560 GCLDEFAULTHASHIFTSPACES,
561 GCLDEFAULTHASHIFTDOTS,
562 GCLDEFAULTHASHIFTDASHES,
563 GCLDEFAULTHASHIFTCOLONS,
564 GCLDEFAULTHASHIFTPLUSSES,
565 GCLDEFAULTHASHIFTMINUSES,
566 GCLDEFAULTHASHIFTTIMES,
567 GCLDEFAULTHASHIFTZONES
568 },
569
570 {
571 GCLDEFAULTVASHIFTHEAD,
572 GCLDEFAULTVASHIFTTAIL,
573 GCLDEFAULTVASHIFTDIGITS,
574 GCLDEFAULTVASHIFTCOMMAS,
575 GCLDEFAULTVASHIFTSPACES,
576 GCLDEFAULTVASHIFTDOTS,
577 GCLDEFAULTVASHIFTDASHES,
578 GCLDEFAULTVASHIFTCOLONS,
579 GCLDEFAULTVASHIFTPLUSSES,
580 GCLDEFAULTVASHIFTMINUSES,
581 GCLDEFAULTVASHIFTTIMES,
582 GCLDEFAULTVASHIFTZONES
583 }
584 };
585
586 static gclalign const defaultashift = {
587 {
588 GCLDEFAULTHASHIFTHEAD,
589 GCLDEFAULTHASHIFTTAIL,
590 GCLDEFAULTHASHIFTDIGITS,
591 GCLDEFAULTHASHIFTCOMMAS,
592 GCLDEFAULTHASHIFTSPACES,
593 GCLDEFAULTHASHIFTDOTS,
594 GCLDEFAULTHASHIFTDASHES,
595 GCLDEFAULTHASHIFTCOLONS,
596 GCLDEFAULTHASHIFTPLUSSES,
597 GCLDEFAULTHASHIFTMINUSES,
598 GCLDEFAULTHASHIFTTIMES,
599 GCLDEFAULTHASHIFTZONES
600 },
601
602 {
603 GCLDEFAULTVASHIFTHEAD,
604 GCLDEFAULTVASHIFTTAIL,
605 GCLDEFAULTVASHIFTDIGITS,
606 GCLDEFAULTVASHIFTCOMMAS,
607 GCLDEFAULTVASHIFTSPACES,
608 GCLDEFAULTVASHIFTDOTS,
609 GCLDEFAULTVASHIFTDASHES,
610 GCLDEFAULTVASHIFTCOLONS,
611 GCLDEFAULTVASHIFTPLUSSES,
612 GCLDEFAULTVASHIFTMINUSES,
613 GCLDEFAULTVASHIFTTIMES,
614 GCLDEFAULTVASHIFTZONES
615 }
616 };
617
618 static int hshiftflag = GCLDEFAULTHSHIFTFLAG;
619 static int vshiftflag = GCLDEFAULTVSHIFTFLAG;
620 static int hshift = GCLDEFAULTHSHIFT;
621 #undef vshift
622 static int vshift = GCLDEFAULTVSHIFT;
623 static unsigned int frametype = GCLDEFAULTFRAMETYPE;
624 static int kern[GRAPHICTYPES] = {
625 GCLDEFAULTKERNHEAD,
626 GCLDEFAULTKERNTAIL,
627 GCLDEFAULTKERNDIGITS,
628 GCLDEFAULTKERNCOMMAS,
629 GCLDEFAULTKERNSPACES,
630 GCLDEFAULTKERNDOTS,
631 GCLDEFAULTKERNDASHES,
632 GCLDEFAULTKERNCOLONS,
633 GCLDEFAULTKERNPLUSSES,
634 GCLDEFAULTKERNMINUSES,
635 GCLDEFAULTKERNTIMES,
636 GCLDEFAULTKERNZONES
637 };
638
639 static int const defaultkern[GRAPHICTYPES] = {
640 GCLDEFAULTKERNHEAD,
641 GCLDEFAULTKERNTAIL,
642 GCLDEFAULTKERNDIGITS,
643 GCLDEFAULTKERNCOMMAS,
644 GCLDEFAULTKERNSPACES,
645 GCLDEFAULTKERNDOTS,
646 GCLDEFAULTKERNDASHES,
647 GCLDEFAULTKERNCOLONS,
648 GCLDEFAULTKERNPLUSSES,
649 GCLDEFAULTKERNMINUSES,
650 GCLDEFAULTKERNTIMES,
651 GCLDEFAULTKERNZONES
652 };
653
654 static unsigned int pad[NUMPADS] = {
655 GCLDEFAULTTPAD,
656 GCLDEFAULTBPAD,
657 GCLDEFAULTLPAD,
658 GCLDEFAULTRPAD
659 };
660 static unsigned int mindigits = 1;
661 static int optimize = 0;
662 static int silent = 0;
663 static unsigned int complevel = 0;
664 static unsigned skip = 0;
665 static unsigned reduce = 0;
666 static counter_t numericvalue;
667
668 static int insertcomments = 0;
669 static int compileonly = 0;
670 static int debugging = 0;
671 static int nocompile = 0;
672 static int gclnocompile = 0;
673 static int verbose = 0;
674 static int localuse = 0;
675 static int mdoverride = 0;
676 static int help = 0;
677 static int outputtext = 0;
678 static int make = 0;
679 static int portable = 0;
680 static int shellcount = 0;
681 static int nocommas = 0;
682 static int publish = 0;
683 static int gallery = 0;
684 static int issigned = 0;
685 static int issigma = 0;
686
687 static unsigned char definechar[DEFINECHAR+1] = GCLDEFAULTDEFINECHAR;
688 static unsigned char const definedchar[DEFINECHAR] = GCLDEFAULTDEFINECHAR;
689
690 static int rgbwarning(int);
691 static void cleanup(void);
692 static void addinhibitor(char *, int, gclcondition, gclinhibitor, int);
693 static void freeinhibitors(void);
694 static void addrelayor(char*, int, gclcondition, gclrelayor, char*, int);
695 static void freerelayors(void);
696 static void htmlputc(unsigned char);
697 static int timesprint(char *, int);
698 static int zonesprint(char *);
699 static int datesprint(char *);
700 static void makedefaults(void);
701 static void openarraypicture(int);
702 static void openpicture(int);
703 static counter_t getrandomnumber(int);
704 static void setincrementrange(scounter_t, scounter_t);
705 static int statement(void);
706 static int expression(void);
707
printfilename(void)708 static void printfilename(void) {
709 if (filename || includefile && includefile->filename)
710 fprintf(stderr, "%s: ", includefile && includefile->filename ? includefile->filename : filename);
711 }
712
gclwarning(char * msg,...)713 static void gclwarning(char *msg, ...) {
714 va_list vl;
715
716 if (warnings) {
717 printfilename();
718 fprintf(stderr, "GCL Warning (line %u): ", lineno);
719 if (msg != NULL) {
720 va_start(vl, msg);
721 vfprintf(stderr, msg, vl);
722 va_end(vl);
723 fprintf(stderr, ".\n");
724 }
725 }
726 }
727
gcldebug(char * msg,...)728 static void gcldebug(char *msg, ...) {
729 va_list vl;
730
731 if (debugging) {
732 printfilename();
733 fprintf(stderr, "GCL Debug: ");
734 if (msg != NULL) {
735 va_start(vl, msg);
736 vfprintf(stderr, msg, vl);
737 va_end(vl);
738 fprintf(stderr, ".\n");
739 }
740 }
741 }
742
uninclude(void)743 static int uninclude(void) {
744 register fi *temp;
745
746 if (includefile == NULL)
747 return EOF;
748
749 fclose(gclfile);
750 gclfile = includefile->fh;
751 temp = includefile;
752 lineno = includefile->lineno;
753 includefile = includefile->prev;
754 if (temp->filename) free(temp->filename);
755 free(temp);
756 return '}';
757 }
758
nonblank(void)759 static int nonblank(void) {
760 register int c;
761
762 for (;;) {
763 c = getc(gclfile);
764
765 if (c == EOF)
766 return uninclude();
767 else if (c == '\n') lineno++;
768 else if ((unsigned int)c > ' ')
769 return c;
770 }
771 }
772
773 /* Lexically analyze GCL file */
lexanal(void)774 static int lexanal(void) {
775 int chars = 0;
776 register int c, d;
777 register int i;
778
779 if (lexstack >= 0) {
780 c = lexstack;
781 lexstack = -1;
782 if (c < 256) ungetc(c, gclfile);
783 else return c;
784 }
785
786 for (;;) {
787 chars = 0;
788 c = nonblank();
789
790 if (c == EOF) return EOF;
791
792 /* Check for a hash mark (or is it an octothorp?) */
793 else if (c == '#') {
794 c = getc(gclfile);
795 if (c == '!') {
796 for(; (chars < LBSIZE) && (c != '\n') && (c != EOF); chars++) {
797 c = getc(gclfile);
798 lexbuffer[chars] = (char)c;
799 } /* for */
800 lineno++;
801 lexbuffer[chars-1] = '\0';
802
803 /* Skip trailing garbage */
804 for (chars--;chars;chars--) {
805 if (lexbuffer[chars-1] <= ' ')
806 lexbuffer[chars-1] = '\0';
807 else break;
808 }
809
810 /* If the line buffer is too small, skip to EOL or EOF.
811 In a typical language we would issue an error message
812 but since we work with CGI, we try to recover gracefully. */
813 while ((c != '\n') && (c != EOF))
814 c = getc(gclfile);
815
816 /* Ignore if just `#!' */
817 if (chars == 2)
818 continue;
819
820 return GCLPATH;
821 }
822 else for (lexvalue = 0; lexvalue < GRAPHICS; lexvalue++)
823 if (c == characters[lexvalue])
824 return GCLGRAPHICNUMBER;
825 if (c == '?')
826 return FILEINCLUDE;
827 while ((c != '\n') && !feof(gclfile)) /* comment, skip to EOL */
828 c = getc(gclfile);
829 } /* '#' */
830
831 else if (c == '@')
832 return TODAY;
833
834 /* Check for an integer */
835 else if (isdigit(c)) {
836 do {
837 lexbuffer[chars++] = (char)c;
838 c = getc(gclfile);
839 } while (isdigit(c) && chars < (LBSIZE-1));
840
841 if (c != EOF)
842 ungetc(c, gclfile);
843
844 lexbuffer[chars] = '\0';
845 lexvalue = (counter_t)strtoul(lexbuffer, NULL, 10);
846 return INTEGER;
847 } /* integer */
848
849 /*
850 * Check for a quoted string.
851 *
852 * A string must not extend beyond the end of the line.
853 * If it does, we try to recover gracefully by
854 * assuming the string ends there.
855 *
856 * If that assumption is incorrect, we will probably
857 * get a syntax error soon anyway.
858 */
859 else if (c == '\"') {
860 c = 0;
861 for (; (chars < (LBSIZE)); chars++) {
862 c = d = getc(gclfile);
863 /*
864 * In GCL, if a line ends with a backslash,
865 * skip to the next non-empty line.
866 * That line, however, may start with
867 * a backslash. That special case was
868 * not handled properly in versions
869 * prior to 2.30. It is now...
870 */
871 while (c == '\\') {
872 if ((d = getc(gclfile)) == '\n') {
873 while (d == '\n') {
874 lineno++;
875 d = getc(gclfile);
876 }
877 c = d;
878 }
879 else c = 0;
880 } /* while (c == '\\') */
881 if ((d == EOF) || (c == '\"') || (c == '\n')) break;
882 lexbuffer[chars] = (d == '\t') ? ' ' : (char)d;
883 } /* for */
884
885 lexbuffer[chars] = '\0';
886 if (c == '\n')
887 lineno++;
888
889 return STRING;
890 } /* quoted string */
891
892 /* Check for an environment string */
893 else if (c == '$') {
894 register int bracket;
895 register char *env;
896
897 switch (c = getc(gclfile)) {
898 case '{':
899 bracket = '}';
900 c = getc(gclfile);
901 break;
902 case '(':
903 bracket = ')';
904 c = getc(gclfile);
905 break;
906 default:
907 bracket = 0;
908 break;
909 }
910
911 for (; chars < (LBSIZE-1); c = getc(gclfile)) {
912 if ((c == bracket) ||
913 (c == EOF) ||
914 (c == '\n') ||
915 ((bracket == 0) && (!isalnum(c))))
916 break;
917
918 lexbuffer[chars++] = c;
919 }
920 if (bracket == 0)
921 ungetc(c, gclfile);
922 lexbuffer[chars] = '\0';
923
924 env = getenv(lexbuffer);
925
926 if (env && *env) {
927 strncpy(lexbuffer, env, LBSIZE-1);
928 lexbuffer[LBSIZE] = '\0';
929 }
930 else
931 lexbuffer[0] = '\0';
932
933 lexvalue = strtoul(lexbuffer, NULL, 0);
934 return GCLENV;
935 }
936
937 /* Check for a command string */
938 else if (c == '`') {
939 register FILE *pipe;
940
941 for (c = d = getc(gclfile); (chars < LBSIZE - 1); c = d = getc(gclfile)) {
942 /* See comment above about backslashes. */
943 while (c == '\\') {
944 if ((d = getc(gclfile)) == '\n') {
945 while (d == '\n') {
946 d = getc(gclfile);
947 lineno++;
948 }
949 c = d;
950 }
951 else c = 0;
952 }
953 if ((d == EOF) || (c == '`') || (c == '\n')) break;
954 /*
955 * Note that while in regular strings
956 * we replace tabs with spaces, here
957 * we do not. We let the shell deal
958 * with them.
959 */
960 lexbuffer[chars++] = d;
961 }
962 lexbuffer[chars] = '\0';
963 if (c == '\n') lineno++;
964
965 /* Unix specific */
966 if ((pipe = popen(lexbuffer, "r")) != NULL) {
967 for (chars = 0, c = getc(pipe);
968 (chars < LBSIZE) && (c != EOF);
969 c = getc(pipe))
970 lexbuffer[chars++] = c < ' ' ? ' ' : c;
971 lexbuffer[chars - (chars && lexbuffer[chars-1] == ' ')] = '\0';
972 pclose(pipe);
973 }
974 else lexbuffer[0] = '\0';
975
976 lexvalue = strtoul(lexbuffer, NULL, 0);
977 return GCLENV;
978 }
979
980 /*
981 * Try unquoted string. It can consist of alphabetic characters,
982 * as well as any character with its hight bit set. This allows
983 * us to process UTF-8 encoded Unicode text, as well as text
984 * created to the ISO 8859 series of standards.
985 */
986 else if (isalpha(c) || (c > 0x7F)) {
987 for (; (chars < (LBSIZE-1)) && (isalpha(c) || (c > 0x7F)); chars++, c = getc(gclfile))
988 lexbuffer[chars] = isalpha(c) ? (char)tolower(c) : c;
989
990 lexbuffer[chars] = '\0';
991 if (c != EOF)
992 ungetc(c, gclfile);
993
994 /* Hopefully, it is a keyword */
995 for (i = 1; i < FRAMES; i++) {
996 lvtoken(framenames[i], i, FRAMETYPE);
997 }
998
999 /*
1000 * Speed the rest of it up by using a switch based on the length
1001 * of the keyword.
1002 *
1003 * This makes the code admittedly less readable, but it executes
1004 * faster, especially since we already have the size in chars
1005 * and do not have to calculate it.
1006 */
1007 switch (chars) {
1008 case 1:
1009 switch (c = tolower(*lexbuffer) - 'a') {
1010 case REGA:
1011 case REGB:
1012 case REGC:
1013 case REGD:
1014 lexvalue = c;
1015 return GCLREGISTER;
1016 }
1017 break;
1018 case 2:
1019 lvtoken("gd", GDSOURCE, PICTYPE);
1020 lvtoken("up", UP, VSHIFT);
1021 token( "if", AK);
1022 token( "or", LOR);
1023 break;
1024 case 3:
1025 lvtoken("gif", GIFSOURCE, PICTYPE);
1026 lvtoken("xbm", XBMSOURCE, PICTYPE);
1027 lvtoken("stz", STZ, TIMEZONE);
1028 lvtoken("utc", UTC, TIMEZONE);
1029 lvtoken("top", TOP, TOPBOTTOM);
1030 lvtoken("now", timer, INTEGER);
1031 token( "bkg", BACKGROUND);
1032 token( "pad", PAD);
1033 token( "end", '}');
1034 token( "tri", TRI);
1035 if (strcmp(lexbuffer, "pop") == 0) {
1036 gclstackptr--;
1037 gclstackptr &= 0x0F;
1038 lexvalue = gclstack[gclstackptr];
1039 return INTEGER;
1040 }
1041 if (strcmp(lexbuffer, "tos") == 0) {
1042 lexvalue = gclstack[(gclstackptr - 1) & 0x0F];
1043 return INTEGER;
1044 }
1045 token( "and", LAND);
1046 token( "xor", LXOR);
1047 break;
1048 case 4:
1049 lvtoken("left", LEFT, HSHIFT);
1050 lvtoken("down", DOWN, VSHIFT);
1051 lvtoken("none", 0, NONE);
1052 lvtoken("head", HEAD, COUNTER);
1053 lvtoken("tail", TAIL, COUNTER);
1054 lvtoken("time", DEFINETIME, TEXTCHAR);
1055 lvtoken("zone", DEFINEZONE, TEXTCHAR);
1056 lvtoken("dash", DEFINEDASH, TEXTCHAR);
1057 lvtoken("when", WHEN, CONDITION);
1058 lvtoken("dots", DOTS, COUNTER);
1059 token( "kern", KERN);
1060 token( "from", FROM);
1061 token( "fork", FORK);
1062 token( "push", GCLPUSH);
1063 token( "then", TAK);
1064 token( "else", INAK);
1065 token( "plus", '+');
1066 token( "sign", CMP);
1067 break;
1068 case 5:
1069 lvtoken("right", RIGHT, HSHIFT);
1070 lvtoken("times", TIMES, COUNTER);
1071 lvtoken("zones", ZONES, COUNTER);
1072 lvtoken("daily", DAILY, TIMEPERIOD);
1073 lvtoken("comma", DEFINECOMMA, TEXTCHAR);
1074 lvtoken("colon", DEFINECOLON, TEXTCHAR);
1075 lvtoken("count", COUNT, GCLREGISTER);
1076 lvtoken("relay", RELAY, RELAYOR);
1077 lvtoken("serve", SERVE, RELAYOR);
1078 token( "group", GROUP);
1079 token( "invis", INVIS);
1080 token( "trans", TRANSPARENT);
1081 token( "frame", FRAME);
1082 token( "align", TOKALIGN);
1083 token( "shift", SHIFT);
1084 token( "reset", PER);
1085 token( "print", GCLPRINT);
1086 token( "fudge", GCLFUDGE);
1087 token( "sigma", GCLSIGMA);
1088 token( "begin", '{');
1089 token( "times", '*');
1090 token( "minus", '-');
1091 token( "equal", '=');
1092 break;
1093 case 6:
1094 lvtoken("middle", MIDDLE, VALIGN);
1095 lvtoken("bottom", BOTTOM, TOPBOTTOM);
1096 lvtoken("center", CENTER, HALIGN);
1097 lvtoken("digits", DIGITS, COUNTER);
1098 lvtoken("commas", COMMAS, COUNTER);
1099 lvtoken("spaces", SPACES, COUNTER);
1100 lvtoken("dashes", DASHES, COUNTER);
1101 lvtoken("colons", COLONS, COUNTER);
1102 lvtoken("unless", UNLESS, CONDITION);
1103 lvtoken("yearly", ANNUALY, TIMEPERIOD);
1104 lvtoken("weekly", WEEKLY, TIMEPERIOD);
1105 lvtoken("random", getrandomnumber(0), INTEGER);
1106 token( "secure", SECURE);
1107 token( "cookie", COOKIE);
1108 token( "silent", SILENT);
1109 /*
1110 * This counts on compiler optimization
1111 * to save space, working on the
1112 * assumption the two occurences of
1113 * "unsigned" will be merged into one...
1114 */
1115 token("unsigned" + 2, SIGNEDCOUNTER);
1116 token( "equals", '=');
1117 token( "lesser", '<');
1118 token( "larger", '>');
1119 token( "modulo", '%');
1120 break;
1121 case 7:
1122 lvtoken("plusses", PLUSSES, COUNTER);
1123 lvtoken("minuses", MINUSES, COUNTER);
1124 lvtoken("inhibit", INHIBIT, INHIBITOR);
1125 lvtoken("concede", CONCEDE, INHIBITOR);
1126 lvtoken("annualy", ANNUALY, TIMEPERIOD);
1127 lvtoken("monthly", MONTHLY, TIMEPERIOD);
1128 lvtoken("srandom", getrandomnumber(1), INTEGER);
1129 token( "expires", EXPIRES);
1130 token( "seconds", SECONDS);
1131 token( "default", USEDEFAULT);
1132 token( "reverse", GCLREVERSE);
1133 token( "divided", '/');
1134 token( "smaller", '<');
1135 token( "greater", '>');
1136 token( "modulus", '%');
1137 token( "include", FILEINCLUDE);
1138 break;
1139 case 8:
1140 lvtoken("annually", ANNUALY, TIMEPERIOD);
1141 token( "vertical", VERTICAL);
1142 token( "optimize", OPTIMIZE);
1143 token( "colorize", TEDTURNER);
1144 token( "redirect", REDIRECT);
1145 token( "portable", PORTABLEGCL);
1146 token( "unsigned", UNSIGNEDCOUNTER);
1147 token( "negative", '-');
1148 token( "positive", '+');
1149 break;
1150 case 9:
1151 token( "mindigits", MINDIGITS);
1152 token( "nodefault", NODEFAULT);
1153 token( "nocompile", NOCOMPILE);
1154 token( "increment", GCLINCREMENT);
1155 token( "otherwise", INAK);
1156 case 10:
1157 token( "horizontal", HORIZONTAL);
1158 token( "multiplied", '*');
1159 break;
1160 } /* Just ignore anything else. */
1161 } /* unquoted string */
1162 else { /* possible operator, or error */
1163 lexbuffer[0] = c;
1164 lexbuffer[1] = '\0';
1165 lexbuffer[2] = '\0';
1166
1167 switch (c) {
1168 case '+':
1169 switch (c = nonblank()) {
1170 case '+':
1171 lexbuffer[1] = c;
1172 return INC;
1173 case '=':
1174 lexbuffer[1] = c;
1175 return ADD;
1176 default:
1177 ungetc(c, gclfile);
1178 return '+';
1179 }
1180 break;
1181 case '-':
1182 switch (c = nonblank()) {
1183 case '-':
1184 lexbuffer[1] = c;
1185 return DEC;
1186 case '=':
1187 lexbuffer[1] = c;
1188 return SUB;
1189 default:
1190 ungetc(c, gclfile);
1191 return '-';
1192 }
1193 break;
1194 case '>':
1195 switch (c = nonblank()) {
1196 case '>':
1197 lexbuffer[1] = c;
1198 return SHR;
1199 case '=':
1200 lexbuffer[1] = c;
1201 return GE;
1202 default:
1203 ungetc(c, gclfile);
1204 return '>';
1205 }
1206 break;
1207 case '<':
1208 switch (c = nonblank()) {
1209 case '<':
1210 lexbuffer[1] = c;
1211 return SHL;
1212 case '=':
1213 lexbuffer[1] = c;
1214 return LE;
1215 case '>':
1216 lexbuffer[1] = c;
1217 return CMP;
1218 default:
1219 ungetc(c, gclfile);
1220 return '<';
1221 }
1222 break;
1223 case '&':
1224 switch (c = nonblank()) {
1225 case '&':
1226 lexbuffer[1] = c;
1227 return LAND;
1228 case '=':
1229 lexbuffer[1] = c;
1230 return BAND;
1231 default:
1232 ungetc(c, gclfile);
1233 return '&';
1234 }
1235 break;
1236 case '|':
1237 switch (c = nonblank()) {
1238 case '|':
1239 lexbuffer[1] = c;
1240 return LOR;
1241 case '=':
1242 lexbuffer[1] = c;
1243 return BOR;
1244 default:
1245 ungetc(c, gclfile);
1246 return '|';
1247 }
1248 break;
1249 case '^':
1250 switch (c = nonblank()) {
1251 case '^':
1252 lexbuffer[1] = c;
1253 return LXOR;
1254 case '=':
1255 lexbuffer[1] = c;
1256 return XOR;
1257 default:
1258 ungetc(c, gclfile);
1259 return '^';
1260 }
1261 break;
1262 case '*':
1263 case '/':
1264 case '%':
1265 case '!':
1266 case '=':
1267 case ':':
1268 switch (c = nonblank()) {
1269 case '=':
1270 lexbuffer[1] = '=';
1271 switch (lexbuffer[0]) {
1272 case '*':
1273 return MUL;
1274 case '/':
1275 return DIV;
1276 case '%':
1277 return MOD;
1278 case '!':
1279 return NE;
1280 case '=':
1281 return EQU;
1282 case ':':
1283 return PASSIGN;
1284 }
1285 break;
1286 default:
1287 ungetc(c, gclfile);
1288 /* fall through */
1289 }
1290 /* fall through */
1291 return lexbuffer[0];
1292 /* Ignore punctuation */
1293 case ',':
1294 case '.':
1295 case ';':
1296 case '\'':
1297 if (!insidenumericexpression) {
1298 chars = 0;
1299 break;
1300 }
1301 /* else fall through */
1302 default:
1303 return c;
1304 }
1305 }
1306 } /* for(;;) */
1307 }
1308
syntax(char const * errmsg)1309 static int syntax(char const *errmsg) {
1310 printfilename();
1311 fprintf(stderr, errmsg == lexbuffer ?
1312 "GCL Syntax error in line %u: `%s'.\n" :
1313 "GCL Syntax error in line %u (`%s'): %s.\n", lineno, lexbuffer, errmsg);
1314
1315 return 1;
1316 }
1317
getinteger(void)1318 static int getinteger(void) {
1319 register int l;
1320
1321 if (reduce) {
1322 reduce = 0;
1323 return INTEGER;
1324 }
1325
1326 switch (lex) {
1327 case GCLREGISTER:
1328 lexvalue = gclregs[lexvalue];
1329 /* fall through */
1330 case GCLENV:
1331 case INTEGER:
1332 numericvalue = lexvalue;
1333 return INTEGER;
1334 case SIGNEDCOUNTER:
1335 numericvalue = issigned != 0;
1336 return INTEGER;
1337 case UNSIGNEDCOUNTER:
1338 numericvalue = issigned == 0;
1339 return INTEGER;
1340 default:
1341 return l;
1342 }
1343 }
1344
unaryexpression(void)1345 static int unaryexpression(void) {
1346 register int op;
1347 register int l;
1348
1349 /*
1350 * Do not try to "optimize" this by just using switch (l = getinteger()).
1351 * While that would work, it would cause problems later on if an expression
1352 * is immediately followed by an assignment statement!
1353 */
1354 switch (l = getinteger()) {
1355 /*
1356 * Following the philosophy of graceful recovery, we accept such
1357 * "weird" constructs as "++++--!!~--~-+A" without blinking an eye.
1358 */
1359 case INC: /* ++ */
1360 case DEC: /* -- */
1361 l = '+';
1362 /* fall through */
1363 case '+':
1364 case '-':
1365 case '~':
1366 case '!':
1367 case '\\':
1368 case CMP:
1369 numericerror = 1;
1370 op = l;
1371 switch (l = unaryexpression()) {
1372 case INTEGER:
1373 if ((op == '-') || (issigned && (op == '\\') && ((scounter_t)numericvalue < 0)))
1374 numericvalue = -numericvalue;
1375 else if (op == '~') numericvalue = ~numericvalue;
1376 else if (op == '!') numericvalue = !numericvalue;
1377 else if (op == CMP) numericvalue =
1378 issigned && ((scounter_t)numericvalue > 0) || !issigned && (numericvalue > 0) ? 1 :
1379 numericvalue == 0 ? 0 : -1;
1380 return INTEGER;
1381 case EOF:
1382 return EOF;
1383 default:
1384 /* Only show this error once when called recursively */
1385 if (numericerror) {
1386 numericerror = 0;
1387 syntax("Expected integral value");
1388 }
1389 return l;
1390 }
1391 break;
1392 case '(':
1393 switch (expression()) {
1394 case INTEGER:
1395 switch (lex) {
1396 default:
1397 unputlex(l);
1398 syntax("Missing parenthesis");
1399 /* fall through */
1400 case ')':
1401 return INTEGER;
1402 }
1403 break;
1404 case EOF:
1405 syntax(unexpected);
1406 return EOF;
1407 default:
1408 syntax(numexp);
1409 return l;
1410 }
1411 break;
1412 /* Default may include INTEGER */
1413 default:
1414 return l;
1415 }
1416 }
1417
mulexpression(void)1418 static int mulexpression(void) {
1419 register int l, op;
1420 register counter_t temp;
1421
1422 for (;;) switch (l = unaryexpression()) {
1423 case INTEGER:
1424 temp = numericvalue;
1425 switch (op = lexanal()) {
1426 case '*':
1427 case '/':
1428 case '%':
1429 switch (l = unaryexpression()) {
1430 case INTEGER:
1431 switch (op) {
1432 case '*':
1433 numericvalue *= temp;
1434 break;
1435 case '/':
1436 if (numericvalue) {
1437 if (!issigned)
1438 numericvalue = temp / numericvalue;
1439 else
1440 numericvalue = (scounter_t)temp / (scounter_t)numericvalue;
1441 }
1442 else numericvalue = temp;
1443 break;
1444 case '%':
1445 if (numericvalue) {
1446 if (!issigned)
1447 numericvalue = temp % numericvalue;
1448 else
1449 numericvalue = (scounter_t)temp % (scounter_t)numericvalue;
1450 }
1451 else numericvalue = temp;
1452 break;
1453 }
1454 reduce = 1;
1455 continue;
1456 case EOF:
1457 syntax(unexpected);
1458 return INTEGER;
1459 default:
1460 unputlex(l);
1461 syntax(numexp);
1462 return INTEGER;
1463 }
1464 break;
1465 default:
1466 unputlex(op);
1467 return INTEGER;
1468 }
1469 break;
1470 default:
1471 return l;
1472 }
1473 }
1474
addexpression(void)1475 static int addexpression(void) {
1476 register int l, op;
1477 register counter_t temp;
1478
1479 for (;;) switch (l = mulexpression()) {
1480 case INTEGER:
1481 temp = numericvalue;
1482 switch (op = lexanal()) {
1483 case INC:
1484 case DEC: /* --, i.e. + */
1485 case '+':
1486 case '-':
1487 switch (l = mulexpression()) {
1488 case INTEGER:
1489 numericvalue = temp + (op == '-' ? -numericvalue : numericvalue);
1490 reduce = 1;
1491 continue;
1492 case EOF:
1493 syntax(unexpected);
1494 return INTEGER;
1495 default:
1496 unputlex(l);
1497 syntax(numexp);
1498 return INTEGER;
1499 }
1500 break;
1501 default:
1502 unputlex(op);
1503 return INTEGER;
1504 }
1505 break;
1506 default:
1507 return l;
1508 }
1509 }
1510
shiftexpression(void)1511 static int shiftexpression(void) {
1512 register int l, op;
1513 register counter_t temp;
1514
1515 switch (l = addexpression()) {
1516 case INTEGER:
1517 temp = numericvalue;
1518 switch (op = lexanal()) {
1519 case SHL:
1520 case SHR:
1521 switch (l = shiftexpression()) {
1522 case INTEGER:
1523 switch (op) {
1524 case SHL:
1525 numericvalue = temp << numericvalue;
1526 break;
1527 case SHR:
1528 if (!issigned)
1529 numericvalue = temp >> numericvalue;
1530 else
1531 numericvalue = (scounter_t)temp >> numericvalue;
1532 break;
1533 }
1534 return INTEGER;
1535 default:
1536 unputlex(l);
1537 break;
1538 }
1539 break;
1540 default:
1541 unputlex(op);
1542 break;
1543 }
1544 numericvalue = temp;
1545 return INTEGER;
1546 default:
1547 return l;
1548 }
1549 }
1550
ltgtexpression(void)1551 static int ltgtexpression(void) {
1552 register int l, op;
1553 register counter_t temp;
1554
1555 switch (l = shiftexpression()) {
1556 case INTEGER:
1557 temp = numericvalue;
1558 switch (op = lexanal()) {
1559 case '<':
1560 case '>':
1561 case LE:
1562 case GE:
1563 case CMP:
1564 switch (l = ltgtexpression()) {
1565 case INTEGER:
1566 switch (op) {
1567 case '<':
1568 if (!issigned)
1569 numericvalue = temp < numericvalue;
1570 else
1571 numericvalue = (scounter_t)temp < (scounter_t)numericvalue;
1572 break;
1573 case '>':
1574 if (!issigned)
1575 numericvalue = temp > numericvalue;
1576 else
1577 numericvalue = (scounter_t)temp > (scounter_t)numericvalue;
1578 break;
1579 case LE:
1580 if (!issigned)
1581 numericvalue = temp <= numericvalue;
1582 else
1583 numericvalue = (scounter_t)temp <= (scounter_t)numericvalue;
1584 break;
1585 case GE:
1586 if (!issigned)
1587 numericvalue = temp >= numericvalue;
1588 else
1589 numericvalue = (scounter_t)temp >= (scounter_t)numericvalue;
1590 break;
1591 case CMP:
1592 if (!issigned)
1593 numericvalue = temp > numericvalue ? 1 : temp == numericvalue ? 0 : -1;
1594 else
1595 numericvalue = (scounter_t)temp > (scounter_t)numericvalue ? 1 : temp == numericvalue ? 0 : -1;
1596 break;
1597 }
1598 return INTEGER;
1599 default:
1600 unputlex(l);
1601 break;
1602 }
1603 break;
1604 default:
1605 unputlex(op);
1606 break;
1607 }
1608 numericvalue = temp;
1609 return INTEGER;
1610 default:
1611 return l;
1612 }
1613 }
1614
eqexpression(void)1615 static int eqexpression(void) {
1616 register int l, op;
1617 register counter_t temp;
1618
1619 switch (l = ltgtexpression()) {
1620 case INTEGER:
1621 temp = numericvalue;
1622 switch (op = lexanal()) {
1623 case '=':
1624 case EQU:
1625 case NE:
1626 switch (l = eqexpression()) {
1627 case INTEGER:
1628 switch (op) {
1629 default:
1630 numericvalue = temp == numericvalue;
1631 break;
1632 case NE:
1633 numericvalue = temp != numericvalue;
1634 break;
1635 }
1636 return INTEGER;
1637 default:
1638 unputlex(l);
1639 break;
1640 }
1641 break;
1642 default:
1643 unputlex(op);
1644 break;
1645 }
1646 numericvalue = temp;
1647 return INTEGER;
1648 default:
1649 return l;
1650 }
1651 }
1652
bandexpression(void)1653 static int bandexpression(void) {
1654 register int l, op;
1655 register counter_t temp;
1656
1657 for (;;) switch (l = eqexpression()) {
1658 case INTEGER:
1659 temp = numericvalue;
1660 switch (op = lexanal()) {
1661 case '&':
1662 switch (l = eqexpression()) {
1663 case INTEGER:
1664 numericvalue &= temp;
1665 reduce = 1;
1666 continue;
1667 case EOF:
1668 syntax(unexpected);
1669 return INTEGER;
1670 default:
1671 unputlex(l);
1672 syntax(numexp);
1673 return INTEGER;
1674 }
1675 break;
1676 default:
1677 unputlex(op);
1678 return INTEGER;
1679 }
1680 break;
1681 default:
1682 return l;
1683 }
1684 }
1685
xorexpression(void)1686 static int xorexpression(void) {
1687 register int l, op;
1688 register counter_t temp;
1689
1690 for (;;) switch (l = bandexpression()) {
1691 case INTEGER:
1692 temp = numericvalue;
1693 switch (op = lexanal()) {
1694 case '^':
1695 switch (l = bandexpression()) {
1696 case INTEGER:
1697 numericvalue ^= temp;
1698 reduce = 1;
1699 continue;
1700 case EOF:
1701 syntax(unexpected);
1702 return INTEGER;
1703 default:
1704 unputlex(l);
1705 syntax(numexp);
1706 return INTEGER;
1707 }
1708 break;
1709 default:
1710 unputlex(op);
1711 return INTEGER;
1712 }
1713 break;
1714 default:
1715 return l;
1716 }
1717 }
1718
borexpression(void)1719 static int borexpression(void) {
1720 register int l, op;
1721 register counter_t temp;
1722
1723 for (;;) switch (l = xorexpression()) {
1724 case INTEGER:
1725 temp = numericvalue;
1726 switch (op = lexanal()) {
1727 case '|':
1728 switch (l = xorexpression()) {
1729 case INTEGER:
1730 numericvalue |= temp;
1731 reduce = 1;
1732 continue;
1733 case EOF:
1734 syntax(unexpected);
1735 return INTEGER;
1736 default:
1737 unputlex(l);
1738 syntax(numexp);
1739 return INTEGER;
1740 }
1741 break;
1742 default:
1743 unputlex(op);
1744 return INTEGER;
1745 }
1746 break;
1747 default:
1748 return l;
1749 }
1750 }
1751
landexpression(void)1752 static int landexpression(void) {
1753 register int l, op;
1754 register counter_t temp;
1755
1756 for (;;) switch (l = borexpression()) {
1757 case INTEGER:
1758 temp = numericvalue;
1759 switch (op = lexanal()) {
1760 case LAND:
1761 switch (l = borexpression()) {
1762 case INTEGER:
1763 numericvalue = temp && numericvalue;
1764 reduce = 1;
1765 continue;
1766 case EOF:
1767 syntax(unexpected);
1768 return INTEGER;
1769 default:
1770 unputlex(l);
1771 syntax(numexp);
1772 return INTEGER;
1773 }
1774 break;
1775 default:
1776 unputlex(op);
1777 return INTEGER;
1778 }
1779 break;
1780 default:
1781 return l;
1782 }
1783 }
1784
lxorexpression(void)1785 static int lxorexpression(void) {
1786 register int l, op;
1787 register counter_t temp;
1788
1789 for (;;) switch (l = landexpression()) {
1790 case INTEGER:
1791 temp = numericvalue;
1792 switch (op = lexanal()) {
1793 case LXOR:
1794 switch (l = landexpression()) {
1795 case INTEGER:
1796 numericvalue = temp && !numericvalue || !temp && numericvalue;
1797 reduce = 1;
1798 continue;
1799 case EOF:
1800 syntax(unexpected);
1801 return INTEGER;
1802 default:
1803 unputlex(l);
1804 syntax(numexp);
1805 return INTEGER;
1806 }
1807 break;
1808 default:
1809 unputlex(op);
1810 return INTEGER;
1811 }
1812 break;
1813 default:
1814 return l;
1815 }
1816 }
1817
lorexpression(void)1818 static int lorexpression(void) {
1819 register int l, op;
1820 register counter_t temp;
1821
1822 for (;;) switch (l = lxorexpression()) {
1823 case INTEGER:
1824 temp = numericvalue;
1825 switch (op = lexanal()) {
1826 case LOR:
1827 switch (l = lxorexpression()) {
1828 case INTEGER:
1829 numericvalue = temp || numericvalue;
1830 reduce = 1;
1831 continue;
1832 case EOF:
1833 syntax(unexpected);
1834 return INTEGER;
1835 default:
1836 unputlex(l);
1837 syntax(numexp);
1838 return INTEGER;
1839 }
1840 break;
1841 default:
1842 unputlex(op);
1843 return INTEGER;
1844 }
1845 break;
1846 default:
1847 return l;
1848 }
1849 }
1850
expression(void)1851 int expression(void) {
1852 register int l;
1853
1854 reduce = 0;
1855
1856 insidenumericexpression++;
1857 l = lorexpression();
1858 insidenumericexpression--;
1859 if (l == INTEGER) {
1860 register counter_t cond, true;
1861
1862 switch (lex) {
1863 case '?':
1864 cond = numericvalue;
1865 switch (l = expression()) {
1866 case INTEGER:
1867 true = numericvalue;
1868 switch (lex) {
1869 case ':':
1870 switch (l = expression()) {
1871 case INTEGER:
1872 if (cond) numericvalue = true;
1873 break;
1874 default:
1875 syntax(numexp);
1876 unputlex(l);
1877 if (cond) numericvalue = cond;
1878 }
1879 break;
1880 default:
1881 unputlex(l);
1882 if (cond) numericvalue = cond;
1883 break;
1884 }
1885 break;
1886 default:
1887 unputlex(l);
1888 syntax(numexp);
1889 break;
1890 }
1891 break;
1892 default:
1893 unputlex(l);
1894 break;
1895 }
1896
1897 return INTEGER;
1898 }
1899 return l;
1900 }
1901
parserror(void)1902 static void parserror(void) {
1903 fprintf(stderr, "GCL Error: Parser out of memory in line %u.", lineno);
1904 if (nocompile == 0) {
1905 fprintf(stderr, " Compilation aborted.");
1906 nocompile = 1;
1907 }
1908 fprintf(stderr, "\n");
1909 }
1910
1911 /* Parse GCL file */
parse(void)1912 static int parse(void) {
1913 for (;;) switch (statement()) {
1914 case 1:
1915 return 1;
1916 case EOF:
1917 if (complevel) {
1918 strcpy(lexbuffer, "{' without `}");
1919 syntax("Programmer needs a vacation");
1920 return EOF;
1921 }
1922 else return 0;
1923 case '}':
1924 if (complevel) {
1925 complevel--;
1926 return '}';
1927 }
1928 syntax("Programmer way out of control");
1929 break;
1930 }
1931 }
1932
condition(gclrelayor r,char * url,gclcondition cond)1933 static int condition(gclrelayor r, char *url, gclcondition cond) {
1934 register int l, op;
1935 register char *tempstr;
1936
1937 switch (lex) {
1938 case FROM:
1939 switch (lex) {
1940 case GCLENV:
1941 case STRING:
1942 if (!skip) addrelayor(from, 0, cond, r, url, '=');
1943 break;
1944 case EOF:
1945 if (!skip && url) free(url);
1946 return syntax(unexpected);
1947 default:
1948 if (!skip && url) free(url);
1949 synterr("Expected email address");
1950 }
1951 break;
1952 case COOKIE:
1953 switch (lex) {
1954 case GCLENV:
1955 case STRING:
1956 if (!skip) {
1957 tempstr = strdup(lexbuffer);
1958 if (tempstr == NULL)
1959 parserror();
1960 }
1961 switch (lex) {
1962 case '=':
1963 case PASSIGN:
1964 op = l;
1965 switch (lex) {
1966 case GCLENV:
1967 case STRING:
1968 if (!skip) addrelayor(tempstr, 1, cond, r, url, op);
1969 break;
1970 case EOF:
1971 if (!skip) {
1972 if (tempstr) free(tempstr);
1973 if (url) free(url);
1974 }
1975 return syntax(unexpected);
1976 default:
1977 if (!skip) {
1978 if (tempstr) free(tempstr);
1979 if (url) free(url);
1980 }
1981 synterr("Expected cookie value (text string)");
1982 }
1983 break;
1984 case EOF:
1985 if (!skip) {
1986 if (tempstr) free(tempstr);
1987 if (url) free(url);
1988 }
1989 return syntax(unexpected);
1990 default:
1991 if (!skip) {
1992 if (tempstr) free(tempstr);
1993 if (url) free(url);
1994 }
1995 synterr("Expected `='");
1996 }
1997 break;
1998 case EOF:
1999 if (!skip && url) free(url);
2000 return syntax(unexpected);
2001 default:
2002 if (!skip && url) free(url);
2003 synterr("Expected cookie name");
2004 }
2005 break;
2006 case GCLENV:
2007 case STRING:
2008 if (!skip) {
2009 tempstr = strdup(lexbuffer);
2010 if (tempstr == NULL)
2011 parserror();
2012 }
2013 switch (lex) {
2014 case '=':
2015 case PASSIGN:
2016 op = l;
2017 switch (lex) {
2018 case GCLENV:
2019 case STRING:
2020 if (!skip) addrelayor(tempstr, 0, cond, r, url, op);
2021 break;
2022 case EOF:
2023 if (!skip) {
2024 if (tempstr) free(tempstr);
2025 if (url) free(url);
2026 }
2027 return syntax(unexpected);
2028 default:
2029 if (!skip && tempstr) free(tempstr);
2030 synterr("Expected environment variable value");
2031 }
2032 break;
2033 case EOF:
2034 if (!skip) {
2035 if (tempstr) free(tempstr);
2036 if (url) free(url);
2037 }
2038 return syntax(unexpected);
2039 default:
2040 if (!skip) {
2041 if (tempstr) free(tempstr);
2042 if (url) free(url);
2043 }
2044 synterr("Expected `='");
2045 }
2046 break;
2047 case EOF:
2048 if (!skip && url) free(url);
2049 return syntax(unexpected);
2050 default:
2051 if (!skip && url) free(url);
2052 synterr("Expected environment variable name");
2053 }
2054 return 0;
2055 }
2056
statement(void)2057 static int statement(void) {
2058 register int l, m;
2059 register counter_t temp;
2060 register int op;
2061 register char *tempstr;
2062 register gclinhibitor tempinhibitor;
2063 rgbcolor temprgb;
2064 register fi *fitemp;
2065
2066 switch (lex) {
2067 case GCLPATH:
2068 if (!skip) {
2069 if (gclpath != NULL)
2070 free(gclpath);
2071 gclpath = strdup(lexbuffer);
2072 if (gclpath == NULL) {
2073 lineno--;
2074 parserror();
2075 lineno++;
2076 }
2077 }
2078 break;
2079 case GCLGRAPHICNUMBER:
2080 temp = lexvalue;
2081 lex;
2082 if (l == NODEFAULT) {
2083 if (!skip) nodefaultpicture[temp] = 1;
2084 }
2085 else if (l == USEDEFAULT) {
2086 if (!skip) nodefaultpicture[temp] = 0;
2087 }
2088 else {
2089 if (!skip) {
2090 if (picture[temp].graphic != NULL) {
2091 free(picture[temp].graphic);
2092 picture[temp].graphic = NULL;
2093 }
2094 nodefaultpicture[temp] = 0;
2095 picture[temp].gtype = 0;
2096 }
2097 switch (l) {
2098 case EOF:
2099 return syntax(unexpected);
2100 case NONE:
2101 break;
2102 case GCLENV:
2103 case STRING:
2104 if (!skip) {
2105 picture[temp].graphic = strdup(lexbuffer);
2106 if (picture[temp].graphic == NULL)
2107 parserror();
2108 }
2109 switch (lex) {
2110 case PICTYPE:
2111 if (!skip && picture[temp].graphic)
2112 picture[temp].gtype = lexvalue;
2113 break;
2114 case EOF:
2115 if (!skip && picture[temp].graphic) {
2116 free(picture[temp].graphic);
2117 picture[temp].graphic = NULL;
2118 }
2119 return syntax(unexpected);
2120 default:
2121 if (!skip && picture[temp].graphic) {
2122 free(picture[temp].graphic);
2123 picture[temp].graphic = NULL;
2124 }
2125 synterr(fileformat);
2126 }
2127 break;
2128 case '[':
2129 switch (signedinteger) {
2130 case INTEGER:
2131 if (!skip) picture[temp].x = numericvalue;
2132 switch (signedinteger) {
2133 case INTEGER:
2134 if (!skip) picture[temp].y = numericvalue;
2135 switch (signedinteger) {
2136 case INTEGER:
2137 if (!skip) picture[temp].dx = numericvalue;
2138 switch (signedinteger) {
2139 case INTEGER:
2140 if (!skip) picture[temp].dy = numericvalue;
2141 switch (lex) {
2142 default:
2143 /* Accept this error gracefully */
2144 switch (l) {
2145 case EOF:
2146 syntax(unexpected);
2147 break; /* no return here */
2148 default:
2149 syntax("Expected `]'");
2150 unputlex(l);
2151 break;
2152 }
2153 /* fall through */
2154 case ']':
2155 switch (temp) {
2156 case PICTUREDIRECTORY:
2157 case ARRAYPICTURE:
2158 syntax("Expected path, got array");
2159 break;
2160 default:
2161 if (!skip) picture[temp].isarray = 1;
2162 break;
2163 }
2164 break;
2165 }
2166 break;
2167 case EOF:
2168 return syntax(unexpected);
2169 default:
2170 synterr("Expected y dimension");
2171 }
2172 break;
2173 case EOF:
2174 return syntax(unexpected);
2175 default:
2176 synterr("Expected x dimension");
2177 }
2178 break;
2179 case EOF:
2180 return syntax(unexpected);
2181 default:
2182 synterr("Expected starting y coordinate");
2183 }
2184 break;
2185 case EOF:
2186 return syntax(unexpected);
2187 default:
2188 synterr("Expected starting x coordinate");
2189 }
2190 break;
2191 default:
2192 synterr(exppath);
2193 }
2194 }
2195 break;
2196 case BACKGROUND:
2197 temprgb = bkg;
2198 switch (signedinteger){
2199 case INTEGER:
2200 if (!skip) bkg.red = rgbwarning(numericvalue);
2201 switch (signedinteger){
2202 case INTEGER:
2203 if (!skip) bkg.green = rgbwarning(numericvalue);
2204 switch (signedinteger) {
2205 case INTEGER:
2206 if (!skip) bkg.blue = rgbwarning(numericvalue);
2207 break;
2208 case EOF:
2209 if (!skip) {
2210 bkg.red = temprgb.red;
2211 bkg.green = temprgb.green;
2212 }
2213 return syntax(unexpected);
2214 default:
2215 if (!skip) {
2216 bkg.red = temprgb.red;
2217 bkg.green = temprgb.green;
2218 }
2219 synterr(colval);
2220 }
2221 break;
2222 case EOF:
2223 if (!skip) bkg.red = temprgb.red;
2224 return syntax(unexpected);
2225 default:
2226 if (!skip) bkg.red = temprgb.red;
2227 synterr(colval);
2228 }
2229 break;
2230 case USEDEFAULT:
2231 if (!skip) {
2232 bkg.red = BKGRED;
2233 bkg.green = BKGGREEN;
2234 bkg.blue = BKGBLUE;
2235 }
2236 break;
2237 case EOF:
2238 return syntax(unexpected);
2239 default:
2240 synterr(colval);
2241 }
2242 break;
2243 case INVIS:
2244 temprgb = invis;
2245 switch (signedinteger) {
2246 case INTEGER:
2247 invis.red = rgbwarning(numericvalue);
2248 switch (signedinteger) {
2249 case INTEGER:
2250 if (!skip) invis.green = rgbwarning(numericvalue);
2251 switch (signedinteger) {
2252 case INTEGER:
2253 if (!skip) invis.blue = rgbwarning(numericvalue);
2254 break;
2255 case EOF:
2256 if (!skip) {
2257 invis.red = temprgb.red;
2258 invis.green = temprgb.green;
2259 }
2260 return syntax(unexpected);
2261 default:
2262 if (!skip) {
2263 invis.red = temprgb.red;
2264 invis.green = temprgb.green;
2265 }
2266 synterr(colval);
2267 }
2268 break;
2269 case EOF:
2270 if (!skip) invis.red = temprgb.red;
2271 return syntax(unexpected);
2272 default:
2273 if (!skip) invis.red = temprgb.red;
2274 synterr(colval);
2275 }
2276 break;
2277 case USEDEFAULT:
2278 if (!skip) {
2279 invis.red = INVISRED;
2280 invis.green = INVISGREEN;
2281 invis.blue = INVISBLUE;
2282 }
2283 break;
2284 case EOF:
2285 return syntax(unexpected);
2286 default:
2287 synterr(colval);
2288 }
2289 break;
2290 case TRANSPARENT:
2291 switch (lex) {
2292 case NONE:
2293 if (!skip) transparent = 0;
2294 break;
2295 case USEDEFAULT:
2296 if (!skip) transparent = GCLDEFAULTTRANSPARENT;
2297 break;
2298 default:
2299 if (!skip) transparent = 1;
2300 unputlex(l);
2301 break;
2302 }
2303 break;
2304 case EXPIRES:
2305 switch (signedinteger) {
2306 case INTEGER:
2307 if (!skip) expires = numericvalue;
2308 /*
2309 * See RFC 2068 for the reasons behind this condition.
2310 * Of course, it is hard to imagine a counter that should
2311 * be cached for more than a year. :-)
2312 */
2313 if (!skip && (expires > SECONDSINAYEAR))
2314 expires = SECONDSINAYEAR;
2315 break;
2316 case NONE:
2317 /*
2318 * Just what should "none" mean in this context?
2319 * Most likely, "never expires." So, we use
2320 * the highest value permitted by RFC 2068.
2321 */
2322 if (!skip) expires = SECONDSINAYEAR;
2323 break;
2324 case USEDEFAULT:
2325 if (!skip) expires = GCLDEFAULTEXPIRES;
2326 break;
2327 case EOF:
2328 return syntax(unexpected);
2329 default:
2330 synterr(expiration);
2331 }
2332 break;
2333 case TOKALIGN:
2334 switch (lex) {
2335 case COUNTER:
2336 temp = lexvalue;
2337 switch (lex) {
2338 case VALIGN:
2339 case TOPBOTTOM:
2340 if (!skip) valignflag[temp] = lexvalue;
2341 switch (signedinteger) {
2342 case INTEGER:
2343 if (!skip) vashift[temp] = numericvalue;
2344 break;
2345 default:
2346 if (!skip) vashift[temp] = 0;
2347 unputlex(l);
2348 break;
2349 }
2350 break;
2351 case HALIGN:
2352 case HSHIFT:
2353 if (!skip) halignflag[temp] = lexvalue;
2354 switch(signedinteger) {
2355 case INTEGER:
2356 if (!skip) hashift[temp] = numericvalue;
2357 break;
2358 default:
2359 if (!skip) hashift[temp] = 0;
2360 unputlex(l);
2361 break;
2362 }
2363 break;
2364 case USEDEFAULT:
2365 if (!skip) {
2366 valignflag[temp] = defaultalignflag.v[temp];
2367 halignflag[temp] = defaultalignflag.h[temp];
2368 vashift[temp] = defaultashift.v[temp];
2369 hashift[temp] = defaultashift.h[temp];
2370 }
2371 break;
2372 case NONE:
2373 if (!skip) valignflag[temp] = halignflag[temp] = vashift[temp] = hashift[temp] = 0;
2374 break;
2375 default:
2376 synterr("Expected alignment type");
2377 }
2378 break;
2379 case VALIGN:
2380 case TOPBOTTOM:
2381 if (!skip) {
2382 valignflag[HEAD] = valignflag[DIGITS] = valignflag[COMMAS] = valignflag[DASHES] = valignflag[COLONS] = valignflag[PLUSSES] = valignflag[MINUSES] = valignflag[TIMES] = valignflag[ZONES] = valignflag[TAIL] = lexvalue;
2383 vashift[HEAD] = vashift[DIGITS] = vashift[COMMAS] = vashift[DASHES] = vashift[COLONS] = vashift[PLUSSES] = vashift[MINUSES] = vashift[TIMES] = vashift[ZONES] = vashift[TAIL] = 0;
2384 }
2385 break;
2386 case HALIGN:
2387 case HSHIFT:
2388 if (!skip) {
2389 halignflag[HEAD] = halignflag[DIGITS] = halignflag[COMMAS] = halignflag[DASHES] = halignflag[COLONS] = halignflag[PLUSSES] = halignflag[MINUSES] = halignflag[TIMES] = halignflag[ZONES] = halignflag[TAIL] = lexvalue;
2390 hashift[HEAD] = hashift[DIGITS] = hashift[COMMAS] = hashift[DASHES] = hashift[COLONS] = hashift[PLUSSES] = hashift[MINUSES] = hashift[TIMES] = hashift[ZONES] = hashift[TAIL] = 0;
2391 }
2392 break;
2393 case USEDEFAULT:
2394 if (!skip) {
2395 alignflag = defaultalignflag;
2396 ashift = defaultashift;
2397 }
2398 break;
2399 case NONE:
2400 if (!skip) {
2401 memset((void *)&alignflag, 0, sizeof(gclalign));
2402 memset((void *)&ashift, 0, sizeof(gclalign));
2403 }
2404 break;
2405 case EOF:
2406 return syntax(unexpected);
2407 default:
2408 synterr("Expected alignment type");
2409 }
2410 break;
2411 case SHIFT:
2412 switch (lex) {
2413 case HSHIFT:
2414 if (!skip) hshiftflag = lexvalue;
2415 switch (signedinteger) {
2416 case INTEGER:
2417 if (!skip) hshift = numericvalue;
2418 break;
2419 case NONE:
2420 if (!skip) {
2421 hshift = 0;
2422 hshiftflag = 0;
2423 }
2424 break;
2425 case USEDEFAULT:
2426 if (!skip) {
2427 hshift = GCLDEFAULTHSHIFT;
2428 hshiftflag = GCLDEFAULTHSHIFTFLAG;
2429 }
2430 break;
2431 case EOF:
2432 return syntax(unexpected);
2433 default:
2434 synterr(shiftvalue);
2435 }
2436 break;
2437 case VSHIFT:
2438 if (!skip) vshiftflag = lexvalue;
2439 switch (signedinteger) {
2440 case INTEGER:
2441 if (!skip) vshift = numericvalue;
2442 break;
2443 case NONE:
2444 if (!skip) {
2445 vshift = 0;
2446 vshiftflag = 0;
2447 }
2448 break;
2449 case USEDEFAULT:
2450 if (!skip) {
2451 vshift = GCLDEFAULTVSHIFT;
2452 vshiftflag = GCLDEFAULTVSHIFTFLAG;
2453 }
2454 break;
2455 case EOF:
2456 return syntax(unexpected);
2457 default:
2458 synterr(shiftvalue);
2459 }
2460 break;
2461 case NONE:
2462 if (!skip)
2463 vshiftflag =
2464 hshiftflag =
2465 vshift =
2466 hshift = 0;
2467 break;
2468 case USEDEFAULT:
2469 if (!skip) {
2470 vshiftflag = GCLDEFAULTVSHIFTFLAG;
2471 hshiftflag = GCLDEFAULTHSHIFTFLAG;
2472 vshift = GCLDEFAULTVSHIFT;
2473 hshift = GCLDEFAULTHSHIFT;
2474 }
2475 break;
2476 case EOF:
2477 return syntax(unexpected);
2478 default:
2479 synterr(shifttype);
2480 }
2481 break;
2482 case FRAME:
2483 switch (signedinteger) {
2484 case NONE:
2485 case FRAMETYPE:
2486 numericvalue = lexvalue;
2487 case INTEGER:
2488 if (!skip) {
2489 frametype = numericvalue;
2490 if (frametype >= FRAMES) {
2491 gclwarning("Overriding `frame %u' with `frame %s'", frametype, framenames[frametype % FRAMES]);
2492 frametype %= FRAMES;
2493 }
2494 }
2495 break;
2496 case USEDEFAULT:
2497 if (!skip) frametype = GCLDEFAULTFRAMETYPE;
2498 break;
2499 case EOF:
2500 return syntax(unexpected);
2501 default:
2502 synterr("Expected frame type");
2503 }
2504 break;
2505 case VERTICAL:
2506 switch (lex) {
2507 case USEDEFAULT:
2508 if (!skip) vertical = GCLDEFAULTVERTICAL;
2509 break;
2510 default:
2511 if (!skip) vertical = 1;
2512 unputlex(l);
2513 break;
2514 }
2515 break;
2516 case HORIZONTAL:
2517 switch (lex) {
2518 case USEDEFAULT:
2519 if (!skip) vertical = GCLDEFAULTVERTICAL;
2520 break;
2521 default:
2522 if (!skip) vertical = 0;
2523 unputlex(l);
2524 break;
2525 }
2526 break;
2527 case KERN:
2528 switch (signedinteger) {
2529 case INTEGER:
2530 if (!skip) kern[HEAD] = kern[TAIL] = kern[DIGITS] = kern[COMMAS] = kern[SPACES] = kern[DOTS] = kern[DASHES] = kern[COLONS] = kern[PLUSSES] = kern[MINUSES] = kern[TIMES] = kern[ZONES] = (op == '-') ? -numericvalue : numericvalue;
2531 break;
2532 case NONE:
2533 if (!skip) memset(kern, 0, GRAPHICTYPES * sizeof(int));
2534 break;
2535 case COUNTER:
2536 temp = lexvalue;
2537 switch (signedinteger) {
2538 case NONE:
2539 case INTEGER:
2540 if (!skip) kern[temp] = numericvalue;
2541 break;
2542 case USEDEFAULT:
2543 if (!skip) kern[temp] = defaultkern[temp];
2544 break;
2545 case EOF:
2546 return syntax(unexpected);
2547 default:
2548 synterr("Expected kern value or none");
2549 }
2550 break;
2551 case USEDEFAULT:
2552 if (!skip) memcpy(kern, defaultkern, GRAPHICTYPES * sizeof(int));
2553 break;
2554 case EOF:
2555 return syntax(unexpected);
2556 default:
2557 synterr("Expected kern value or none");
2558 }
2559 break;
2560 case PAD:
2561 switch (signedinteger) {
2562 case NONE:
2563 case INTEGER:
2564 if (!skip) tpad = bpad = lpad = rpad = numericvalue;
2565 break;
2566 case VPAD:
2567 temp = lexvalue;
2568 switch (signedinteger) {
2569 case NONE:
2570 numericvalue = lexvalue;
2571 case INTEGER:
2572 if (!skip) switch (temp) {
2573 case TOP:
2574 tpad = numericvalue;
2575 break;
2576 case BOTTOM:
2577 bpad = numericvalue;
2578 break;
2579 }
2580 break;
2581 case USEDEFAULT:
2582 if (!skip) switch (temp) {
2583 case TOP:
2584 tpad = GCLDEFAULTTPAD;
2585 break;
2586 case BOTTOM:
2587 bpad = GCLDEFAULTBPAD;
2588 break;
2589 }
2590 break;
2591 case EOF:
2592 return syntax(unexpected);
2593 default:
2594 synterr(padvalue);
2595 }
2596 break;
2597 case HPAD:
2598 temp = lexvalue;
2599 switch (signedinteger) {
2600 case NONE:
2601 numericvalue = lexvalue;
2602 case INTEGER:
2603 if (!skip) switch (temp) {
2604 case LEFT:
2605 lpad = numericvalue;
2606 break;
2607 case RIGHT:
2608 rpad = numericvalue;
2609 break;
2610 }
2611 break;
2612 case USEDEFAULT:
2613 if (!skip) switch (temp) {
2614 case LEFT:
2615 lpad = GCLDEFAULTLPAD;
2616 break;
2617 case RIGHT:
2618 rpad = GCLDEFAULTRPAD;
2619 break;
2620 }
2621 break;
2622 case EOF:
2623 return syntax(unexpected);
2624 default:
2625 synterr(padvalue);
2626 }
2627 break;
2628 case USEDEFAULT:
2629 if (!skip) {
2630 tpad = GCLDEFAULTTPAD;
2631 bpad = GCLDEFAULTBPAD;
2632 lpad = GCLDEFAULTLPAD;
2633 rpad = GCLDEFAULTRPAD;
2634 }
2635 break;
2636 case EOF:
2637 return syntax(unexpected);
2638 default:
2639 synterr("Expected direction, none, default, or pad value");
2640 }
2641 break;
2642 case MINDIGITS:
2643 switch(signedinteger) {
2644 case NONE:
2645 numericvalue = lexvalue;
2646 case INTEGER:
2647 if (!skip) mindigits = numericvalue ? numericvalue > MAXDIGITS ? MAXDIGITS : numericvalue : 1;
2648 break;
2649 case USEDEFAULT:
2650 if (!skip) mindigits = 1;
2651 break;
2652 case EOF:
2653 return syntax(unexpected);
2654 default:
2655 synterr("Expected minimum number of digits");
2656 }
2657 break;
2658 case OPTIMIZE:
2659 switch (lex) {
2660 case NONE:
2661 if (!skip) optimize = 0;
2662 break;
2663 case USEDEFAULT:
2664 if (!skip) optimize = GCLDEFAULTOPTIMIZE;
2665 break;
2666 default:
2667 unputlex(l);
2668 if (!skip) optimize = 1;
2669 break;
2670 }
2671 break;
2672 case SECURE:
2673 switch (lex) {
2674 case NONE:
2675 if (!skip) secure = 0;
2676 break;
2677 default:
2678 unputlex(l);
2679 if (!skip) secure = 1;
2680 break;
2681 }
2682 break;
2683 case COOKIE:
2684 if (!skip && (cookie != NULL)) {
2685 free(cookie);
2686 cookie = NULL;
2687 }
2688 switch (lex) {
2689 case NONE:
2690 break;
2691 case '=':
2692 case PASSIGN:
2693 switch (lex) {
2694 case GCLENV:
2695 case STRING:
2696 if (!skip) {
2697 cookie = strdup(lexbuffer);
2698 if (cookie == NULL)
2699 parserror();
2700 }
2701 break;
2702 case EOF:
2703 return syntax(unexpected);
2704 default:
2705 synterr("Expected cookie string");
2706 }
2707 break;
2708 case EOF:
2709 return syntax(unexpected);
2710 default:
2711 synterr("Expected `='");
2712 }
2713 break;
2714 case INHIBITOR:
2715 tempinhibitor = (gclinhibitor)lexvalue;
2716 switch (lex) {
2717 case NONE:
2718 if (!skip) freeinhibitors();
2719 break;
2720 case CONDITION:
2721 temp = lexvalue;
2722 switch (lex) {
2723 case FROM:
2724 switch (lex) {
2725 case GCLENV:
2726 case STRING:
2727 if (!skip) addinhibitor(from, 0, (gclcondition)temp, tempinhibitor, '=');
2728 break;
2729 case EOF:
2730 return syntax(unexpected);
2731 default:
2732 synterr("Expected email address");
2733 }
2734 break;
2735 case COOKIE:
2736 switch (lex) {
2737 case GCLENV:
2738 case STRING:
2739 if (!skip) {
2740 tempstr = strdup(lexbuffer);
2741 if (tempstr == NULL)
2742 parserror();
2743 }
2744 switch (lex) {
2745 case '=':
2746 case PASSIGN:
2747 op = l;
2748 switch (lex) {
2749 case GCLENV:
2750 case STRING:
2751 if (!skip) addinhibitor(tempstr, 1, (gclcondition)temp, tempinhibitor, op);
2752 break;
2753 case EOF:
2754 if (!skip && tempstr) free(tempstr);
2755 return syntax(unexpected);
2756 default:
2757 if (!skip &&tempstr) free(tempstr);
2758 synterr("Expected cookie value (text string)");
2759 }
2760 break;
2761 case EOF:
2762 if (!skip && tempstr) free(tempstr);
2763 return syntax(unexpected);
2764 default:
2765 if (!skip && tempstr) free(tempstr);
2766 synterr("Expected `='");
2767 }
2768 break;
2769 case EOF:
2770 return syntax(unexpected);
2771 default:
2772 synterr("Expected cookie name");
2773 }
2774 break;
2775 case GCLENV:
2776 case STRING:
2777 if (!skip) {
2778 tempstr = strdup(lexbuffer);
2779 if (tempstr == NULL)
2780 parserror();
2781 }
2782 switch (lex) {
2783 case '=':
2784 case PASSIGN:
2785 op = l;
2786 switch (lex) {
2787 case GCLENV:
2788 case STRING:
2789 if (!skip) addinhibitor(tempstr, 0, (gclcondition)temp, tempinhibitor, op);
2790 break;
2791 case EOF:
2792 if (!skip && tempstr) free(tempstr);
2793 return syntax(unexpected);
2794 default:
2795 if (!skip && tempstr) free(tempstr);
2796 synterr("Expected environment variable value");
2797 }
2798 break;
2799 case EOF:
2800 if (!skip && tempstr) free(tempstr);
2801 return syntax(unexpected);
2802 default:
2803 if (!skip && tempstr) free(tempstr);
2804 synterr("Expected `='");
2805 }
2806 break;
2807 case EOF:
2808 return syntax(unexpected);
2809 default:
2810 synterr("Expected environment variable name");
2811 }
2812 break;
2813 case EOF:
2814 return syntax(unexpected);
2815 default:
2816 synterr("Expected `none', `unless', or `when'");
2817 }
2818 break;
2819 case RELAYOR:
2820 if (lexvalue == SERVE) switch (lex) {
2821 case NONE:
2822 if (!skip) freerelayors();
2823 break;
2824 case CONDITION:
2825 return condition(SERVE, NULL, lexvalue);
2826 case EOF:
2827 return syntax(unexpected);
2828 default:
2829 synterr("Expected `none', `unless', or `when'");
2830 }
2831 else switch (lex) {
2832 case NONE:
2833 if (!skip) freerelayors();
2834 break;
2835 case STRING:
2836 if (!skip) {
2837 tempstr = strdup(lexbuffer);
2838 if (tempstr == NULL)
2839 parserror();
2840 }
2841 switch (lex) {
2842 case CONDITION:
2843 return condition(RELAY, tempstr, lexvalue);
2844 case EOF:
2845 if (!skip && tempstr) free(tempstr);
2846 return syntax(unexpected);
2847 default:
2848 if (!skip && tempstr) free(tempstr);
2849 synterr("Expected `unless' or `when'");
2850 }
2851 break;
2852 case EOF:
2853 return syntax(unexpected);
2854 default:
2855 synterr("Expected URL or `none'");
2856 }
2857 break;
2858 case TEXTCHAR:
2859 temp = lexvalue;
2860 switch (lex) {
2861 case NONE:
2862 if (!skip) definechar[temp] = '\0';
2863 break;
2864 case '=':
2865 case PASSIGN:
2866 l = lexanal();
2867 switch(l) {
2868 case GCLREGISTER:
2869 lexvalue = gclregs[lexvalue];
2870 l = INTEGER;
2871 /* fall through */
2872 case GCLENV:
2873 if (issigned && ((scounter_t)lexvalue < 0)) lexvalue = -lexvalue;
2874 }
2875 if ((l == STRING) && (strlen(lexbuffer) <= 1)) {
2876 if (!skip) definechar[temp] = lexbuffer[0] < ' ' ? '\0' : (unsigned char)lexbuffer[0];
2877 }
2878 else if (l == INTEGER) {
2879 if (!skip) definechar[temp] = (lexvalue & 0xFF) < ' ' ? '\0' : (unsigned char)(lexvalue & 0xFF);
2880 }
2881 else if (l == GCLENV) {
2882 register unsigned int val = lexvalue;
2883 register unsigned char c = (unsigned char)lexbuffer[0];
2884 switch (lex) {
2885 case '!':
2886 if (!skip) definechar[temp] = (val & 0xFF) < ' ' ? '\0' : (unsigned char)(val & 0xFF);
2887 break;
2888 default:
2889 unputlex(l);
2890 if (!skip) definechar[temp] = c < ' ' ? '\0' : c;
2891 break;
2892 }
2893 }
2894 else if (l < ' ') {
2895 if (!skip) definechar[temp] = '\0';
2896 }
2897 else if (l <= 255) {
2898 if (!skip) definechar[temp] = (unsigned char)l;
2899 }
2900 else {
2901 syntax(lexbuffer);
2902 unputlex(l);
2903 }
2904 break;
2905 case USEDEFAULT:
2906 if (!skip) definechar[temp] = definedchar[temp];
2907 break;
2908 case EOF:
2909 return syntax(unexpected);
2910 default:
2911 synterr("Expected `none' or `='");
2912 }
2913 break;
2914 case TEDTURNER:
2915 switch (signedinteger) {
2916 case NONE:
2917 if (!skip) tt.red = tt.green = tt.blue = 0;
2918 break;
2919 case USEDEFAULT:
2920 if (!skip) {
2921 tt.red = TTRED;
2922 tt.green = TTGREEN;
2923 tt.blue = TTBLUE;
2924 }
2925 break;
2926 case INTEGER:
2927 temprgb.red = rgbwarning(numericvalue);
2928 switch (signedinteger) {
2929 case INTEGER:
2930 temprgb.green = rgbwarning(numericvalue);
2931 switch (signedinteger) {
2932 case INTEGER:
2933 if (!skip) {
2934 tt.red = temprgb.red;
2935 tt.green = temprgb.green;
2936 tt.blue = rgbwarning(numericvalue);
2937 }
2938 else rgbwarning(numericvalue);
2939 break;
2940 case EOF:
2941 return syntax(unexpected);
2942 default:
2943 synterr("Expected blue value");
2944 }
2945 break;
2946 case EOF:
2947 return syntax(unexpected);
2948 default:
2949 synterr("Expected green value");
2950 }
2951 break;
2952 case EOF:
2953 return syntax(unexpected);
2954 default:
2955 synterr("Expected red value or `none'");
2956 }
2957 break;
2958 case SILENT:
2959 if ((lex) == NONE) {
2960 if (!skip) silent = 0;
2961 }
2962 else {
2963 if (!skip) silent = 1;
2964 unputlex(l);
2965 }
2966 break;
2967 case REDIRECT:
2968 if (!skip) {
2969 if (redirect) {
2970 free(redirect);
2971 redirect = NULL;
2972 }
2973 redirection = NOREDIRECTION;
2974 }
2975 switch (lex) {
2976 case GCLENV:
2977 case STRING:
2978 if (!skip) {
2979 redirect = strdup(lexbuffer);
2980 if (redirect == NULL)
2981 parserror();
2982 }
2983 switch(lex) {
2984 case '!':
2985 if (!skip && redirect)
2986 redirection = UNINHIBITEDREDIRECTION;
2987 break;
2988 default:
2989 /* Not an error */
2990 if (!skip && redirect)
2991 redirection = REDIRECTORINHIBIT;
2992 unputlex(l);
2993 break;
2994 }
2995 case NONE:
2996 case USEDEFAULT:
2997 break;
2998 case EOF:
2999 return syntax(unexpected);
3000 default:
3001 synterr("Expected `none' or URL");
3002 }
3003 break;
3004 case TODAY:
3005 switch (lex) {
3006 case INTEGER:
3007 today.year = lexvalue;
3008 switch (lex) {
3009 case INTEGER:
3010 today.month = lexvalue;
3011 switch (lex) {
3012 case INTEGER:
3013 today.day = lexvalue;
3014 switch (lex) {
3015 case INTEGER:
3016 today.week = lexvalue;
3017 break;
3018 /* Ignore any errors since they are not programmer's (hopefully!) */
3019 default:
3020 unputlex(l);
3021 break;
3022 }
3023 break;
3024 default:
3025 unputlex(l);
3026 break;
3027 }
3028 break;
3029 default:
3030 unputlex(l);
3031 break;
3032 }
3033 break;
3034 default:
3035 unputlex(l);
3036 break;
3037 }
3038 break;
3039 case PER:
3040 switch (lex) {
3041 case NONE:
3042 case USEDEFAULT:
3043 if (!skip) rst = NEVER;
3044 break;
3045 case TIMEPERIOD:
3046 if (!skip) rst = lexvalue;
3047 break;
3048 case EOF:
3049 return syntax(unexpected);
3050 default:
3051 synterr("Expected `none', `daily', `weekly', `monthly', or `annually'");
3052 }
3053 break;
3054 case TIMEZONE:
3055 if (!skip) {
3056 gtz.tz = (gcltzone)lexvalue;
3057 gtz.secs = 0;
3058 }
3059 switch (lex) {
3060 case '+':
3061 case '-':
3062 op = l;
3063 switch (signedinteger) {
3064 case INTEGER:
3065 if (!skip) gtz.secs = (long)(op == '-' ? -numericvalue : numericvalue);
3066 break;
3067 case EOF:
3068 return syntax(unexpected);
3069 default:
3070 synterr("Expected time zone offset in seconds");
3071 }
3072 break;
3073 case USEDEFAULT:
3074 if (!skip) {
3075 gtz.tz = GCLDEFAULTTIMEZONE;
3076 gtz.secs = GCLDEFAULTTIMEZONEOFFSET;
3077 }
3078 break;
3079 default:
3080 unputlex(l);
3081 break;
3082 }
3083 break;
3084 case SECONDS:
3085 switch (lex) {
3086 case NONE:
3087 if (!skip) seconds = 0;
3088 break;
3089 case USEDEFAULT:
3090 if (!skip) seconds = GCLDEFAULTSHOWSECONDS;
3091 break;
3092 default:
3093 if (!skip) seconds = 1;
3094 unputlex(l);
3095 break;
3096 }
3097 break;
3098 case FORK:
3099 switch (lex) {
3100 case NONE:
3101 case USEDEFAULT:
3102 if (!skip && script) {
3103 free(script);
3104 script = NULL;
3105 }
3106 break;
3107 case GCLENV:
3108 case STRING:
3109 if (!skip) {
3110 if (script)
3111 free(script);
3112 script = strdup(lexbuffer);
3113 if (script == NULL)
3114 parserror();
3115 }
3116 break;
3117 case EOF:
3118 return syntax(unexpected);
3119 default:
3120 synterr("Expected script path or `none'");
3121 }
3122 break;
3123 case PORTABLEGCL:
3124 switch (lex) {
3125 case NONE:
3126 case USEDEFAULT:
3127 if (!skip) portable = 0;
3128 break;
3129 default:
3130 if (!skip) portable = 1;
3131 unputlex(l);
3132 break;
3133 }
3134 break;
3135 /*
3136 * The group keyword can be followed by an integer.
3137 * In that case it tells us how many digits to group.
3138 *
3139 * It can also be followed by commas, spaces, or dots.
3140 * That tells us what kind of group separator to use.
3141 *
3142 * Or it can be followed by both in unspecified order.
3143 */
3144 case GROUP:
3145 switch (signedinteger) {
3146 case INTEGER:
3147 if (!skip) {
3148 if ((scounter_t)numericvalue <= 0) {
3149 gclwarning("Overriding `group " sinteger "' with `group default'", numericvalue);
3150 numericvalue = GCLDEFAULTGROUP;
3151 }
3152 group = numericvalue;
3153 }
3154 switch (lex) {
3155 case COUNTER:
3156 switch (lexvalue) {
3157 case COMMAS:
3158 case SPACES:
3159 case DOTS:
3160 if (!skip) groupseparator = lexvalue;
3161 break;
3162 default:
3163 unputlex(l);
3164 break;
3165 }
3166 break;
3167 default:
3168 unputlex(l);
3169 break;
3170 }
3171 break;
3172 case NONE:
3173 case USEDEFAULT:
3174 if (!skip) {
3175 group = GCLDEFAULTGROUP;
3176 groupseparator = GCLDEFAULTGROUPSEPARATOR;
3177 }
3178 break;
3179 case COUNTER:
3180 switch (lexvalue) {
3181 case COMMAS:
3182 case SPACES:
3183 case DOTS:
3184 if (!skip) groupseparator = lexvalue;
3185 switch (signedinteger) {
3186 case INTEGER:
3187 if (!skip) {
3188 if ((scounter_t)numericvalue <= 0) {
3189 gclwarning("Overriding `group " sinteger "' with `group default'", numericvalue);
3190 numericvalue = GCLDEFAULTGROUP;
3191 }
3192 group = numericvalue;
3193 }
3194 break;
3195 default:
3196 unputlex(l);
3197 break;
3198 }
3199 break;
3200 default:
3201 synterr("Expected group value, group separator, or `default'");
3202 }
3203 break;
3204 case EOF:
3205 return syntax(unexpected);
3206 default:
3207 synterr("Expected group value, group separator, or `default'");
3208 }
3209 break;
3210 case GCLREVERSE:
3211 switch (lex) {
3212 case COUNTER:
3213 switch (lexvalue) {
3214 case DIGITS:
3215 switch (lex) {
3216 case NONE:
3217 if (!skip) revdig = 0;
3218 break;
3219 case USEDEFAULT:
3220 if (!skip) revdig = GCLDEFAULTREVDIG;
3221 break;
3222 default:
3223 if (!skip) revdig = 1;
3224 unputlex(l);
3225 break;
3226 }
3227 break;
3228 case COMMAS:
3229 switch (lex) {
3230 case NONE:
3231 if (!skip) revcom = 0;
3232 break;
3233 case USEDEFAULT:
3234 if (!skip) revcom = GCLDEFAULTREVCOM;
3235 break;
3236 default:
3237 if (!skip) revcom = 1;
3238 unputlex(l);
3239 break;
3240 }
3241 break;
3242 default:
3243 synterr("Expected `digits', `commas', `default', `none', or next keyword");
3244 }
3245 break;
3246 case NONE:
3247 if (!skip) revdig = revcom = 0;
3248 break;
3249 case USEDEFAULT:
3250 if (!skip) {
3251 revdig = GCLDEFAULTREVDIG;
3252 revcom = GCLDEFAULTREVCOM;
3253 }
3254 break;
3255 default:
3256 if (!skip) revdig = revcom = 1;
3257 unputlex(l);
3258 break;
3259 }
3260 break;
3261 case GCLPRINT:
3262 if (!skip) {
3263 if (gclprint != NULL) {
3264 free(gclprint);
3265 gclprint = NULL;
3266 }
3267 shellcount = 0;
3268 }
3269 switch (lex) {
3270 case NONE:
3271 case USEDEFAULT:
3272 break;
3273 case GCLENV:
3274 case STRING:
3275 if (!skip) {
3276 gclprint = strdup(lexbuffer);
3277 if (gclprint == NULL)
3278 parserror();
3279 }
3280 switch (lex) {
3281 case '!':
3282 if (!skip) shellcount = 1;
3283 break;
3284 default:
3285 unputlex(l);
3286 break;
3287 }
3288 break;
3289 case EOF:
3290 return syntax(unexpected);
3291 default:
3292 synterr("Expected a string, environment variable, or command");
3293 }
3294 break;
3295 case NOCOMPILE:
3296 switch (lex) {
3297 case NONE:
3298 case USEDEFAULT:
3299 if (!skip) gclnocompile = 0;
3300 break;
3301 default:
3302 unputlex(l);
3303 if (!skip) gclnocompile = 1;
3304 break;
3305 }
3306 break;
3307 case SIGNEDCOUNTER:
3308 if (!skip) issigned = 1;
3309 break;
3310 case UNSIGNEDCOUNTER:
3311 if (!skip) issigned = 0;
3312 break;
3313 case FILEINCLUDE:
3314 switch (lex) {
3315 case GCLENV:
3316 case STRING:
3317 if (!skip) {
3318 fitemp = includefile;
3319 includefile = malloc(sizeof(fi));
3320 if (includefile == NULL)
3321 parserror();
3322 else {
3323 includefile->fh = gclfile;
3324 gclfile = fopen(lexbuffer, "r");
3325 if (gclfile == NULL) {
3326 gclfile = includefile->fh;
3327 free(includefile);
3328 includefile = fitemp;
3329 gclwarning(NULL);
3330 perror(lexbuffer);
3331 }
3332 else {
3333 includefile->prev = fitemp;
3334 includefile->lineno = lineno;
3335 lineno = 1;
3336 includefile->filename = strdup(lexbuffer);
3337 /* Imply squiggles */
3338 unputlex('{');
3339 return statement();
3340 }
3341 }
3342 }
3343 break;
3344 case EOF:
3345 return syntax(unexpected);
3346 default:
3347 synterr("Expected include path");
3348 }
3349 break;
3350 case GCLREGISTER:
3351 temp = lexvalue;
3352 if (!skip && (lexvalue == COUNT)) {
3353 shellcount = 0;
3354 if (gclprint != NULL) {
3355 free(gclprint);
3356 gclprint = NULL;
3357 }
3358 }
3359 switch (lex) {
3360 case '=':
3361 case PASSIGN:
3362 switch (signedinteger) {
3363 case INTEGER:
3364 if (!skip) gclregs[temp] = numericvalue;
3365 break;
3366 case EOF:
3367 return syntax(unexpected);
3368 default:
3369 synterr(numexp);
3370 }
3371 break;
3372 case ADD:
3373 switch (signedinteger) {
3374 case INTEGER:
3375 if (!skip) gclregs[temp] += numericvalue;
3376 break;
3377 case EOF:
3378 return syntax(unexpected);
3379 default:
3380 synterr(numexp);
3381 }
3382 break;
3383 case INC:
3384 if (!skip) gclregs[temp]++;
3385 break;
3386 case SUB:
3387 switch (signedinteger) {
3388 case INTEGER:
3389 if (!skip) gclregs[temp] -= numericvalue;
3390 break;
3391 case EOF:
3392 return syntax(unexpected);
3393 default:
3394 synterr(numexp);
3395 }
3396 break;
3397 case DEC:
3398 if (!skip) gclregs[temp]--;
3399 break;
3400 case BAND:
3401 switch (signedinteger) {
3402 case INTEGER:
3403 if (!skip) gclregs[temp] &= numericvalue;
3404 break;
3405 case EOF:
3406 return syntax(unexpected);
3407 default:
3408 synterr(numexp);
3409 }
3410 break;
3411 case BOR:
3412 switch (signedinteger) {
3413 case INTEGER:
3414 if (!skip) gclregs[temp] |= numericvalue;
3415 break;
3416 case EOF:
3417 return syntax(unexpected);
3418 default:
3419 synterr(numexp);
3420 }
3421 break;
3422 case MUL:
3423 switch (signedinteger) {
3424 case INTEGER:
3425 if (!skip) gclregs[temp] *= numericvalue;
3426 break;
3427 case EOF:
3428 return syntax(unexpected);
3429 default:
3430 synterr(numexp);
3431 }
3432 break;
3433 case DIV:
3434 switch (signedinteger) {
3435 case INTEGER:
3436 if (!skip) {
3437 if (numericvalue != 0) {
3438 if (!issigned)
3439 gclregs[temp] /= numericvalue;
3440 else
3441 gclregs[temp] = (scounter_t)gclregs[temp] / (scounter_t)numericvalue;
3442 }
3443 }
3444 break;
3445 case EOF:
3446 return syntax(unexpected);
3447 default:
3448 synterr(numexp);
3449 }
3450 break;
3451 case MOD:
3452 switch (signedinteger) {
3453 case INTEGER:
3454 if (!skip && (numericvalue != 0)) {
3455 if (!issigned)
3456 gclregs[temp] %= numericvalue;
3457 else
3458 gclregs[temp] = (scounter_t)gclregs[temp] % (scounter_t)numericvalue;
3459 }
3460 break;
3461 case EOF:
3462 return syntax(unexpected);
3463 default:
3464 synterr(numexp);
3465 }
3466 break;
3467 case XOR:
3468 switch (signedinteger) {
3469 case INTEGER:
3470 if (!skip) gclregs[temp] ^= numericvalue;
3471 break;
3472 case EOF:
3473 return syntax(unexpected);
3474 default:
3475 synterr(numexp);
3476 }
3477 break;
3478 case EOF:
3479 return syntax(unexpected);
3480 default:
3481 synterr(regops);
3482 }
3483 break;
3484 case GCLINCREMENT:
3485 switch (signedinteger) {
3486 case INTEGER:
3487 if (!skip) setincrementrange(numericvalue, numericvalue);
3488 break;
3489 case '[':
3490 switch (signedinteger) {
3491 case INTEGER:
3492 temp = numericvalue;
3493 switch(signedinteger) {
3494 case INTEGER:
3495 if (!skip) setincrementrange(temp, numericvalue);
3496 switch (lex) {
3497 case ']':
3498 break;
3499 case EOF:
3500 return syntax(unexpected);
3501 default:
3502 /* Complain but accept it */
3503 synterr("Expected `]'");
3504 }
3505 break;
3506 case EOF:
3507 return syntax(unexpected);
3508 default:
3509 synterr("Expected increment upper range");
3510 }
3511 break;
3512 case EOF:
3513 return syntax(unexpected);
3514 default:
3515 synterr("Expected increment lower range");
3516 }
3517 break;
3518 case EOF:
3519 return syntax(unexpected);
3520 default:
3521 synterr("Expected increment value or range");
3522 }
3523 break;
3524 case GCLFUDGE:
3525 switch (signedinteger) {
3526 case INTEGER:
3527 if (issigned && ((scounter_t)numericvalue < 0))
3528 numericvalue = -numericvalue;
3529 temp = (numericvalue & 0x03FF) * 2 - 1;
3530 if (!skip) setincrementrange(1, temp ? temp : 1);
3531 break;
3532 case NONE:
3533 case USEDEFAULT:
3534 if (!skip) setincrementrange(1, 1);
3535 break;
3536 case EOF:
3537 return syntax(unexpected);
3538 default:
3539 synterr("Expected fudge factor");
3540 }
3541 break;
3542 case GCLSIGMA:
3543 switch (signedinteger) {
3544 case INTEGER:
3545 temp = numericvalue;
3546 switch (signedinteger) {
3547 case INTEGER:
3548 if (!skip) {
3549 setincrementrange(temp, -temp);
3550 issigma = 1;
3551 mean = numericvalue;
3552 }
3553 break;
3554 case EOF:
3555 return syntax(unexpected);
3556 default:
3557 synterr("Expected mean value");
3558 }
3559 break;
3560 case EOF:
3561 return syntax(unexpected);
3562 default:
3563 synterr("Expected sigma value");
3564 }
3565 break;
3566 case GCLPUSH:
3567 switch (signedinteger) {
3568 case INTEGER:
3569 if (!skip) {
3570 gclstack[gclstackptr++] = numericvalue;
3571 gclstackptr &= 0x0F;
3572 }
3573 break;
3574 case EOF:
3575 return syntax(unexpected);
3576 default:
3577 synterr("Nothing to push");
3578 }
3579 break;
3580 case AK:
3581 switch (signedinteger) {
3582 case INTEGER:
3583 temp = numericvalue == 0;
3584 skip += temp;
3585 if (lex != TAK) unputlex(l);
3586 premature++;
3587 if (statement() == EOF) return EOF;
3588 premature--;
3589 skip -= temp;
3590 switch (lex) {
3591 case INAK:
3592 skip += !temp;
3593 premature++;
3594 if (statement() == EOF) return EOF;
3595 premature--;
3596 skip -= !temp;
3597 break;
3598 default:
3599 unputlex(l);
3600 break;
3601 }
3602 break;
3603 case EOF:
3604 return syntax(unexpected);
3605 default:
3606 synterr("Expected logical expression");
3607 }
3608 break;
3609 case TRI:
3610 switch (signedinteger) {
3611 case INTEGER:
3612 temp = numericvalue;
3613 premature++;
3614 skip += (scounter_t)temp >= 0;
3615 if (statement() == EOF)
3616 return EOF;
3617 skip -= (scounter_t)temp >= (scounter_t)0;
3618 skip += temp != 0;
3619 if (statement() == EOF)
3620 return EOF;
3621 skip -= temp != 0;
3622 skip += (scounter_t)temp <= 0;
3623 if (statement() == EOF)
3624 return EOF;
3625 skip -= (scounter_t)temp <= 0;
3626 premature--;
3627 break;
3628 case EOF:
3629 return syntax(unexpected);
3630 default:
3631 synterr("Expected ternary expression");
3632 }
3633 break;
3634 case '[':
3635 op = 0;
3636 switch (signedinteger) {
3637 case INTEGER:
3638 temp = numericvalue;
3639 m = 0;
3640 gcldebug("Array condition = " integer, numericvalue);
3641 for (;;) {
3642 register unsigned int eq;
3643
3644 switch (signedinteger) {
3645 case ']':
3646 if (!op)
3647 gclwarning("No statements in array");
3648 gcldebug("Processed %u statement%s in array", op, "s" + (op == 1));
3649 return 0;
3650 default:
3651 syntax(numexp);
3652 return 0;
3653 case INTEGER:
3654 op++;
3655 eq = temp != numericvalue;
3656 if (!eq) m = 1;
3657 gcldebug("Statement %u %s condition", op, eq ? "does not match" : "matches");
3658 skip += eq;
3659 premature++;
3660 if (statement() == EOF)
3661 return EOF;
3662 premature--;
3663 skip -= eq;
3664 break;
3665 case USEDEFAULT:
3666 op++;
3667 gcldebug("Statement %u %s condition", op, m ? "does not match" : "matches");
3668 skip += m;
3669 premature++;
3670 if (statement() == EOF)
3671 return EOF;
3672 premature--;
3673 skip -= m;
3674 break;
3675 case EOF:
3676 return syntax(unexpected);
3677 }
3678 }
3679 break;
3680 case ']':
3681 /* Empty array */
3682 gclwarning("Empty array statement");
3683 break;
3684 case EOF:
3685 return syntax(unexpected);
3686 default:
3687 synterr(numexp);
3688 }
3689 break;
3690 case '{':
3691 complevel++;
3692 parse();
3693 break;
3694 case '}':
3695 return '}';
3696 default:
3697 /* Do not use the "synterr" macro here to prevent endless loop. */
3698 syntax(lexbuffer);
3699 break;
3700 case EOF:
3701 if (premature) {
3702 premature = 0;
3703 return syntax(unexpected);
3704 }
3705 return EOF;
3706 break;
3707 }
3708 return 0;
3709 }
3710
printstring(char const * str,const int ispath)3711 static int printstring(char const *str, const int ispath) {
3712 int i;
3713 register int bytes;
3714 char const *strptr;
3715
3716 fputc('\"', gclfile);
3717
3718 bytes = 2;
3719
3720 if (ispath) {
3721 if (publish && *str) {
3722 bytes += fprintf(gclfile, "/usr/local/share/gracula/pix");
3723 strptr = str;
3724 for (i = 0; str[i]; i++) if (str[i] == '/')
3725 strptr = (char const *)(str + i);
3726 if (*strptr != '/') {
3727 bytes++;
3728 fputc('/', gclfile);
3729 }
3730 }
3731 else {
3732 realpath(str, pathbuffer);
3733 strptr = (char const *)pathbuffer;
3734 }
3735 }
3736 else
3737 strptr = str;
3738
3739 for (i = 0; strptr[i]; i++) switch (strptr[i]) {
3740 case '\"':
3741 case '\\':
3742 fputc('\\', gclfile);
3743 bytes++;
3744 default:
3745 fputc(strptr[i], gclfile);
3746 bytes++;
3747 }
3748
3749 fputc('\"', gclfile);
3750 return bytes;
3751 }
3752
3753 /* Compile a new GCL file */
compile(void)3754 static void compile(void) {
3755 int i;
3756 register int bytes;
3757 register int neednonewline;
3758 register int commentstring;
3759 register inhibit *tempinhibitor;
3760 register relay *temprelayor;
3761
3762 if (gclpath && *gclpath && !publish) {
3763 bytes = fprintf(gclfile, "#!%s\n", gclpath);
3764 if (gclpath) {
3765 free(gclpath);
3766 gclpath = NULL;
3767 }
3768 }
3769 else bytes = 0;
3770
3771 if (publish) {
3772 register char *env;
3773
3774 bytes += fprintf(gclfile,
3775 "#!/usr/local/bin/gracula\n"
3776 "###############################################################################\n"
3777 "############### CHANGE THE ABOVE PATH AS NEEDED FOR YOUR SYSTEM ###############\n"
3778 "###############################################################################\n"
3779 "##\n");
3780
3781 env = getenv("GCLSCRIPTNAME");
3782 if (!env || !*env) env = scriptname;
3783 if (env && *env)
3784 bytes += fprintf(gclfile, "##\t%s\n##\n", env);
3785
3786 env = getenv("GCLAUTHOR");
3787 if (env && *env)
3788 bytes += fprintf(gclfile, "##\tCopyright (c) %i %s\n"
3789 "##\tAll rights reserved.\n##\n",
3790 now->tm_year + 1900, env);
3791
3792 bytes += fprintf(gclfile,
3793 "## This is a sample GCL (Graphic Counter Language) script. You can use it for\n"
3794 "## the creation of graphic counters or timers, such as those used on web pages.\n"
3795 "##\n"
3796 "## To run this script, you need a GCL compiler/interpreter, which you can\n"
3797 "## obtain from:\n"
3798 "##\n"
3799 "##\thttp://www.whizkidtech.net/gcl/\n"
3800 "##\n"
3801 "## Please make sure you have at least version " GCLRELEASEVERSION " of gracula.\n"
3802 "##\n"
3803 "## NOTES:\n"
3804 "##\n"
3805 "##\t1. You may need to edit any paths in this script to match the paths\n"
3806 "##\t on your system. Hint: Use sed. Or use these paths. They are the\n"
3807 "##\t recommended defaults.\n"
3808 "##\n"
3809 "##\t2. Any line in this script starting with two octothorps (`##')\n"
3810 "##\t is a comment. Any line starting with one is a compiler directive.\n"
3811 "##\t Blank lines are ignored.\n"
3812 "##\n"
3813 "##\t3. It is strongly suggested you use a COPY of this file as your script.\n"
3814 "##\t This is because gracula will overwrite it, and you will lose all\n"
3815 "##\t these nice comments.\n"
3816 "##\n"
3817 "##\t4. Since this script needs to be executed by the shell, and read and\n"
3818 "##\t written by gracula, it is important to have the necessary file access\n"
3819 "##\t permissions set. Using `chmod 777 %s' will do.\n"
3820 "##\n"
3821 "###############################################################################\n\n",
3822 scriptname && *scriptname ? scriptname : "scriptname");
3823 }
3824
3825 if (cookie && !publish) {
3826 if (*cookie) {
3827 bytes += fprintf(gclfile, "cookie = ");
3828 bytes += printstring(cookie, 0);
3829 bytes += fprintf(gclfile, "\n");
3830 }
3831 }
3832
3833 if (insertcomments)
3834 bytes += fprintf(gclfile,
3835 "###############################################################################\n"
3836 "##\n"
3837 "## Determine where to find the graphics.\n"
3838 "##\n"
3839 "###############################################################################\n\n");
3840 neednonewline = 1;
3841 commentstring = 1;
3842 for (i = 0; i < GRAPHICS; i++) {
3843 if (insertcomments &&
3844 (picture[i].isarray ||
3845 (picture[i].graphic && picture[i].gtype && *(picture[i].graphic)))) {
3846 bytes += fprintf(gclfile, "\n## Define `#%c' (%s)" + neednonewline, characters[i], picname[i]);
3847 bytes += fprintf(gclfile, publish && !picture[i].isarray ? " ===> CHANGE THE PATH BELOW AS NEEDED <===\n" : ":\n");
3848 neednonewline = 0;
3849 commentstring = 0;
3850 }
3851
3852 if (picture[i].isarray) {
3853 bytes += fprintf(gclfile, "#%c [%i, %i, %i, %i]\n", characters[i], picture[i].x, picture[i].y, picture[i].dx, picture[i].dy);
3854 }
3855 else if (picture[i].graphic && picture[i].gtype && *(picture[i].graphic)) {
3856 bytes += fprintf(gclfile, "#%c ", characters[i]);
3857 bytes += printstring(picture[i].graphic, 1);
3858 bytes += fprintf(gclfile, " %s\n", graphictypes[picture[i].gtype]);
3859 }
3860 else if (insertcomments) {
3861 if (((i < ARRAYPICTURE) || !publish) && !(picture[PICTUREDIRECTORY].graphic && picture[PICTUREDIRECTORY].gtype && *(picture[PICTUREDIRECTORY].graphic)))
3862 bytes += fprintf(gclfile, "\n## Graphic `#%c' (%s) not used in this script.\n" + commentstring, characters[i], picname[i]);
3863 if (publish)
3864 nodefaultpicture[i] = 0;
3865 neednonewline = 0;
3866 commentstring = 1;
3867 }
3868
3869 if (nodefaultpicture[i])
3870 bytes += fprintf(gclfile, "#%c nodefault\n", characters[i]);
3871 }
3872
3873 if (portable && !publish) {
3874 if (insertcomments)
3875 bytes += fprintf(gclfile, "\n"
3876 "###############################################################################\n"
3877 "##\n"
3878 "## Compile portable code.\n"
3879 "##\n"
3880 "## This option will guarantee you keep all your other options when porting this\n"
3881 "## source file to an environment where gcl may have been compiled with.\n"
3882 "## different defaults from your current environment.\n"
3883 "##\n"
3884 "## If you are not planning to move to a different environment, you should turn\n"
3885 "## this option off (\"portable none\") to speed up processing.\n"
3886 "##\n"
3887 "###############################################################################\n\n");
3888 bytes += fprintf(gclfile, "portable\n");
3889 }
3890
3891 if (!secure && !publish) {
3892 if (insertcomments)
3893 bytes += fprintf(gclfile, "\n"
3894 "###############################################################################\n"
3895 "##\n"
3896 "## Turn security protection OFF.\n"
3897 "##\n"
3898 "## This option allows you, and ANYONE ELSE, to change the count from the\n"
3899 "## command line.\n"
3900 "##\n"
3901 "## Do not use this option, except in controlled and safe environment.\n"
3902 "##\n"
3903 "###############################################################################\n\n");
3904 bytes += fprintf(gclfile, "secure none\n");
3905 }
3906 else if (portable && !publish) {
3907 if (insertcomments)
3908 bytes += fprintf(gclfile, "\n"
3909 "###############################################################################\n"
3910 "##\n"
3911 "## Turn security protection ON.\n"
3912 "##\n"
3913 "## This is the default. It is only listed here, so you know it is on.\n"
3914 "##\n"
3915 "###############################################################################\n\n");
3916 bytes += fprintf(gclfile, "secure\n");
3917 }
3918
3919 if (portable || (bkg.red != BKGRED) || (bkg.green != BKGGREEN) || (bkg.blue != BKGBLUE)) {
3920 if (insertcomments)
3921 bytes += fprintf(gclfile, "\n"
3922 "###############################################################################\n"
3923 "##\n"
3924 "## Define the color of the background (the frame layer).\n"
3925 "##\n"
3926 "###############################################################################\n\n");
3927 bytes += fprintf(gclfile, "bkg %i %i %i\n", bkg.red, bkg.green, bkg.blue);
3928 }
3929
3930 if (portable || (invis.red != INVISRED) || (invis.green != INVISGREEN) || (invis.blue != INVISBLUE)) {
3931 if (insertcomments)
3932 bytes += fprintf(gclfile, "\n"
3933 "###############################################################################\n"
3934 "##\n"
3935 "## Define the \"invisible\" color. This color is used for transparent pixels.\n"
3936 "## It is always used in the counter layer, optionally in the image layer.\n"
3937 "##\n"
3938 "###############################################################################\n\n");
3939 bytes += fprintf(gclfile, "invis %u %u %u\n", invis.red, invis.green, invis.blue);
3940 }
3941
3942 if ((portable || (kern[HEAD] != GCLDEFAULTKERNHEAD)) && (kern[HEAD] == kern[TAIL]) && (kern[HEAD] == kern[DIGITS]) && (kern[HEAD] == kern[COMMAS]) && (kern[HEAD] == kern[SPACES]) && (kern[HEAD] == kern[DOTS]) && (kern[HEAD] == kern[DASHES]) && (kern[HEAD] == kern[COLONS]) && (kern[HEAD] == kern[PLUSSES]) && (kern[HEAD] == kern[MINUSES]) && (kern[HEAD] == kern[TIMES]) && (kern[HEAD] == kern[ZONES])) {
3943 if (insertcomments)
3944 bytes += fprintf(gclfile, "\n"
3945 "###############################################################################\n"
3946 "##\n"
3947 "## Define the kerning value.\n"
3948 "##\n"
3949 "## This value determines the number of pixels to insert between adjacent\n"
3950 "## digits, or between a digit and a comma, head and a digit, a digit and tail.\n"
3951 "##\n"
3952 "## Kerning value may also be negative. This helps with non-rectangular images.\n"
3953 "## But be careful here. If you overdo your negative kerning, you may be\n"
3954 "## rejected by Inspector Kern who makes sure you do not end up with negative\n"
3955 "## width or height!\n"
3956 "##\n"
3957 "###############################################################################\n\n");
3958 bytes += fprintf(gclfile, "kern %i\n", kern[HEAD]);
3959 }
3960 else {
3961 if (portable || (kern[HEAD] != GCLDEFAULTKERNHEAD)) {
3962 if (insertcomments)
3963 bytes += fprintf(gclfile, "\n"
3964 "###############################################################################\n"
3965 "##\n"
3966 "## Define the head kerning value.\n"
3967 "##\n"
3968 "## This value determines the number of pixels to insert after the head image.\n"
3969 "##\n"
3970 "###############################################################################\n\n");
3971 bytes += fprintf(gclfile, "kern head %i\n", kern[HEAD]);
3972 }
3973 if (portable || (kern[TAIL] != GCLDEFAULTKERNTAIL)) {
3974 if (insertcomments)
3975 bytes += fprintf(gclfile, "\n"
3976 "###############################################################################\n"
3977 "##\n"
3978 "## Define the tail kerning value.\n"
3979 "##\n"
3980 "## This value determines the number of pixels to insert before the tail image.\n"
3981 "##\n"
3982 "###############################################################################\n\n");
3983 bytes += fprintf(gclfile, "kern tail %i\n", kern[TAIL]);
3984 }
3985 if (portable || (kern[DIGITS] != GCLDEFAULTKERNDIGITS)) {
3986 if (insertcomments)
3987 bytes += fprintf(gclfile, "\n"
3988 "###############################################################################\n"
3989 "##\n"
3990 "## Define the digits kerning value.\n"
3991 "##\n"
3992 "## This value determines the number of pixels to insert between digits.\n"
3993 "##\n"
3994 "###############################################################################\n\n");
3995 bytes += fprintf(gclfile, "kern digits %i\n", kern[DIGITS]);
3996 }
3997 if (portable || (kern[COMMAS] != GCLDEFAULTKERNCOMMAS)) {
3998 if (insertcomments)
3999 bytes += fprintf(gclfile, "\n"
4000 "###############################################################################\n"
4001 "##\n"
4002 "## Define the commas kerning value.\n"
4003 "##\n"
4004 "## This value determines the number of pixels to insert around commas.\n"
4005 "##\n"
4006 "###############################################################################\n\n");
4007 bytes += fprintf(gclfile, "kern commas %i\n", kern[COMMAS]);
4008 }
4009 if (portable || (kern[SPACES] != GCLDEFAULTKERNSPACES)) {
4010 if (insertcomments)
4011 bytes += fprintf(gclfile, "\n"
4012 "###############################################################################\n"
4013 "##\n"
4014 "## Define the spaces kerning value.\n"
4015 "##\n"
4016 "## This value determines the number of pixels to insert around spaces. This\n"
4017 "## value is typically 0.\n"
4018 "##\n"
4019 "###############################################################################\n\n");
4020 bytes += fprintf(gclfile, "kern spaces %i\n", kern[SPACES]);
4021 }
4022 if (portable || (kern[DOTS] != GCLDEFAULTKERNDOTS)) {
4023 if (insertcomments)
4024 bytes += fprintf(gclfile, "\n"
4025 "###############################################################################\n"
4026 "##\n"
4027 "## Define the dots kerning value.\n"
4028 "##\n"
4029 "## This value determines the number of pixels to insert around dots.\n"
4030 "##\n"
4031 "###############################################################################\n\n");
4032 bytes += fprintf(gclfile, "kern dots %i\n", kern[DOTS]);
4033 }
4034 if (portable || (kern[DASHES] != GCLDEFAULTKERNDASHES)) {
4035 if (insertcomments)
4036 bytes += fprintf(gclfile, "\n"
4037 "###############################################################################\n"
4038 "##\n"
4039 "## Define the dashes kerning value.\n"
4040 "##\n"
4041 "## This value determines the number of pixels to insert around dashes.\n"
4042 "##\n"
4043 "###############################################################################\n\n");
4044 bytes += fprintf(gclfile, "kern dashes %i\n", kern[DASHES]);
4045 }
4046 if (portable || (kern[COLONS] != GCLDEFAULTKERNCOLONS)) {
4047 if (insertcomments)
4048 bytes += fprintf(gclfile, "\n"
4049 "###############################################################################\n"
4050 "##\n"
4051 "## Define the colons kerning value.\n"
4052 "##\n"
4053 "## This value determines the number of pixels to insert around colons.\n"
4054 "##\n"
4055 "###############################################################################\n\n");
4056 bytes += fprintf(gclfile, "kern colons %i\n", kern[COLONS]);
4057 }
4058 if (portable || (kern[PLUSSES] != GCLDEFAULTKERNPLUSSES)) {
4059 if (insertcomments)
4060 bytes += fprintf(gclfile, "\n"
4061 "###############################################################################\n"
4062 "##\n"
4063 "## Define the plusses kerning value.\n"
4064 "##\n"
4065 "## This value determines the number of pixels to insert around plusses.\n"
4066 "##\n"
4067 "###############################################################################\n\n");
4068 bytes += fprintf(gclfile, "kern plusses %i\n", kern[PLUSSES]);
4069 }
4070 if (portable || (kern[MINUSES] != GCLDEFAULTKERNMINUSES)) {
4071 if (insertcomments)
4072 bytes += fprintf(gclfile, "\n"
4073 "###############################################################################\n"
4074 "##\n"
4075 "## Define the minuses kerning value.\n"
4076 "##\n"
4077 "## This value determines the number of pixels to insert around minuses.\n"
4078 "##\n"
4079 "###############################################################################\n\n");
4080 bytes += fprintf(gclfile, "kern minuses %i\n", kern[MINUSES]);
4081 }
4082 if (portable || (kern[TIMES] != GCLDEFAULTKERNTIMES)) {
4083 if (insertcomments)
4084 bytes += fprintf(gclfile, "\n"
4085 "###############################################################################\n"
4086 "##\n"
4087 "## Define the times kerning value.\n"
4088 "##\n"
4089 "## This value determines the number of pixels to insert around times (`T').\n"
4090 "##\n"
4091 "###############################################################################\n\n");
4092 bytes += fprintf(gclfile, "kern times %i\n", kern[TIMES]);
4093 }
4094 if (portable || (kern[ZONES] != GCLDEFAULTKERNZONES)) {
4095 if (insertcomments)
4096 bytes += fprintf(gclfile, "\n"
4097 "###############################################################################\n"
4098 "##\n"
4099 "## Define the zones kerning value.\n"
4100 "##\n"
4101 "## This value determines the number of pixels to insert around zones (`Z').\n"
4102 "##\n"
4103 "###############################################################################\n\n");
4104 bytes += fprintf(gclfile, "kern zones %i\n", kern[ZONES]);
4105 }
4106 }
4107
4108 if ((portable || optimize) && !publish) {
4109 if (insertcomments)
4110 bytes += fprintf(gclfile, "\n"
4111 "###############################################################################\n"
4112 "##\n"
4113 "## Turn o%s optimization.\n"
4114 "##\n"
4115 "## Optimization gives priority to colors of the counter over the colors of the\n"
4116 "## background. However, it slows down processing somewhat. It should not be on\n"
4117 "## if the total number of colors is less than 256.\n"
4118 "##\n"
4119 "###############################################################################\n\n",
4120 optimize ? "n" : "ff");
4121 bytes += fprintf(gclfile, optimize ? "optimize\n" : "optimize none\n");
4122 }
4123
4124 if (portable || (tt.red != TTRED) || (tt.green != TTGREEN) || (tt.blue != TTBLUE)) {
4125 if (insertcomments)
4126 bytes += fprintf(gclfile, "\n"
4127 "###############################################################################\n"
4128 "##\n"
4129 "## Turn o%s colorization.\n"
4130 "##\n"
4131 "## Colorization changes the first occurence of black in the array image to\n"
4132 "## the color specified below. If black is not found, it will use the nearest\n"
4133 "## match. However, it will not work if black is the transparent color.\n"
4134 "##\n"
4135 "## This option is useful when you want to reuse the same images in different\n"
4136 "## counters, but use different colors in each.\n"
4137 "##\n"
4138 "###############################################################################\n\n",
4139 tt.red || tt.green || tt.blue ? "n" : "ff");
4140 bytes += fprintf(gclfile, "colorize %u %u %u\n", tt.red, tt.green, tt.blue);
4141 }
4142
4143 if (portable || ((transparent != GCLDEFAULTTRANSPARENT) && !frametype)) {
4144 if (insertcomments)
4145 bytes += fprintf(gclfile, "\n"
4146 "###############################################################################\n"
4147 "##\n"
4148 "## Declare transparency of the frame background.\n"
4149 "##\n"
4150 "## Ignored if frame type declared.\n"
4151 "##\n"
4152 "###############################################################################\n\n");
4153 bytes += fprintf(gclfile, transparent ? "trans\n" : "trans none\n");
4154 }
4155
4156 if (portable || (frametype != GCLDEFAULTFRAMETYPE)) {
4157 if (insertcomments)
4158 bytes += fprintf(gclfile, "\n"
4159 "###############################################################################\n"
4160 "##\n"
4161 "## Define the type of frame to use.\n"
4162 "##\n"
4163 "###############################################################################\n\n");
4164 bytes += fprintf(gclfile, "frame %s\n", framenames[frametype]);
4165 }
4166
4167 if (insertcomments & (portable || (tpad != GCLDEFAULTTPAD) || (bpad != GCLDEFAULTBPAD) || (lpad != GCLDEFAULTLPAD) || (rpad != GCLDEFAULTRPAD)))
4168 bytes += fprintf(gclfile, "\n"
4169 "###############################################################################\n"
4170 "##\n"
4171 "## Define the padding around the sides of the counter layer.\n"
4172 "##\n"
4173 "###############################################################################\n\n");
4174 if ((portable || (tpad != GCLDEFAULTTPAD)) && (tpad == bpad) && (tpad == lpad) && (tpad == rpad)) {
4175 bytes += fprintf(gclfile, "pad %u\n", tpad);
4176 }
4177 else {
4178 if (portable || (tpad != GCLDEFAULTTPAD)) {
4179 bytes += fprintf(gclfile, "pad top %u\n", tpad);
4180 }
4181
4182 if (portable || (bpad != GCLDEFAULTBPAD)) {
4183 bytes += fprintf(gclfile, "pad bottom %u\n", bpad);
4184 }
4185
4186 if (portable || (lpad != GCLDEFAULTLPAD)) {
4187 bytes += fprintf(gclfile, "pad left %u\n", lpad);
4188 }
4189
4190 if (portable || (rpad != GCLDEFAULTRPAD)) {
4191 bytes += fprintf(gclfile, "pad right %u\n", rpad);
4192 }
4193 }
4194
4195 if (portable || (group != GCLDEFAULTGROUP)) {
4196 if (insertcomments)
4197 bytes += fprintf(gclfile, "\n"
4198 "###############################################################################\n"
4199 "##\n"
4200 "## Define the size of group of digits separated by a comma, space, or dot.\n"
4201 "##\n"
4202 "###############################################################################\n\n");
4203 bytes += fprintf(gclfile, "group %u\n", group);
4204 }
4205
4206 /*
4207 * The 3 if (1) will make transition to the use of spaces as default
4208 * more painless. It will be deleted once the default has changed.
4209 */
4210 if (1 || portable || (groupseparator != GCLDEFAULTGROUPSEPARATOR)) {
4211 if (insertcomments) {
4212 bytes += fprintf(gclfile, "\n"
4213 "###############################################################################\n"
4214 "##\n"
4215 "## Define the group separator.\n");
4216 if (1 || publish) bytes += fprintf(gclfile,
4217 "##\n"
4218 "## Uncomment the group separator you want to use. Comment out the rest.\n");
4219 bytes += fprintf(gclfile,
4220 "##\n"
4221 "###############################################################################\n\n");
4222 }
4223 bytes += fprintf(gclfile, "## group %s\n" + 3, groupseparator == COMMAS ? "commas" :
4224 groupseparator == DOTS ? "dots" : "spaces");
4225 if (1 || publish) {
4226 if (groupseparator != COMMAS)
4227 bytes += fprintf(gclfile, "## group %s\n", "commas");
4228 if (groupseparator != DOTS)
4229 bytes += fprintf(gclfile, "## group %s\n", "dots");
4230 if (groupseparator != SPACES)
4231 bytes += fprintf(gclfile, "## group %s\n", "spaces");
4232 }
4233 }
4234
4235 if ((portable || (expires != GCLDEFAULTEXPIRES)) && !publish) {
4236 if (insertcomments)
4237 bytes += fprintf(gclfile, "\n"
4238 "###############################################################################\n"
4239 "##\n"
4240 "## Define the number of seconds from \"now\" the counter should expire from\n"
4241 "## browser cache. A negative value will make it always expired. However, some\n"
4242 "## browsers may ignore this value.\n"
4243 "##\n"
4244 "###############################################################################\n\n");
4245 bytes += fprintf(gclfile, "expires %i\n", expires);
4246 }
4247
4248 if (portable || (vertical != GCLDEFAULTVERTICAL)) {
4249 if (insertcomments)
4250 bytes += fprintf(gclfile, "\n"
4251 "###############################################################################\n"
4252 "##\n"
4253 "## Declare counter orientation.\n"
4254 "##\n"
4255 "###############################################################################\n\n");
4256 bytes += fprintf(gclfile, vertical ? "vertical\n" : "horizontal\n");
4257 }
4258
4259 /* Commutate hashifts and vashifts if they are all non-zero */
4260 if (hashift[HEAD] && hashift[DIGITS] && hashift[COMMAS] && hashift[TAIL] && hashift[DASHES] && hashift[COLONS] && hashift[PLUSSES] && hashift[MINUSES] && hashift[TIMES] && hashift[ZONES]) {
4261 register int delta;
4262
4263 delta = !halignflag[DIGITS] ? hashift[DIGITS] :
4264 !halignflag[COMMAS] ? hashift[COMMAS] :
4265 !halignflag[HEAD] ? hashift[HEAD] :
4266 !halignflag[DASHES] ? hashift[DASHES] :
4267 !halignflag[COLONS] ? hashift[COLONS] :
4268 !halignflag[PLUSSES] ? hashift[PLUSSES] :
4269 !halignflag[MINUSES] ? hashift[MINUSES] :
4270 !halignflag[TIMES] ? hashift[TIMES] :
4271 !halignflag[ZONES] ? hashift[ZONES] :
4272 !halignflag[TAIL] ? hashift[TAIL] : hashift[DIGITS];
4273
4274 for (i = 0; i < GRAPHICTYPES; i++)
4275 hashift[i] -= delta;
4276 }
4277
4278 if (vashift[HEAD] && vashift[DIGITS] && vashift[COMMAS] && vashift[TAIL] && vashift[DASHES] && vashift[COLONS] && vashift[PLUSSES] && vashift[MINUSES] && vashift[TIMES] && vashift[ZONES]) {
4279 register int delta;
4280
4281 delta = !valignflag[DIGITS] ? vashift[DIGITS] :
4282 !valignflag[COMMAS] ? vashift[COMMAS] :
4283 !valignflag[HEAD] ? vashift[HEAD] :
4284 !valignflag[DASHES] ? vashift[DASHES] :
4285 !valignflag[COLONS] ? vashift[COLONS] :
4286 !valignflag[PLUSSES] ? vashift[PLUSSES] :
4287 !valignflag[TIMES] ? vashift[TIMES] :
4288 !valignflag[ZONES] ? vashift[ZONES] :
4289 !valignflag[TAIL] ? vashift[TAIL] : vashift[DIGITS];
4290
4291 for (i = 0; i < GRAPHICTYPES; i++)
4292 vashift[i] -= delta;
4293 }
4294
4295 if (insertcomments && (portable || (halignflag[HEAD] != GCLDEFAULTHALIGNHEAD) || (halignflag[DIGITS] != GCLDEFAULTHALIGNDIGITS) || (halignflag[COMMAS] != GCLDEFAULTHALIGNCOMMAS) || (halignflag[TAIL] != GCLDEFAULTHALIGNTAIL) || (hashift[HEAD] != GCLDEFAULTHASHIFTHEAD) || (hashift[DIGITS] != GCLDEFAULTHASHIFTDIGITS) || (hashift[COMMAS] != GCLDEFAULTHASHIFTCOMMAS) || (hashift[TAIL] != GCLDEFAULTHASHIFTTAIL) || (hashift[DASHES] != GCLDEFAULTHASHIFTDASHES) || (hashift[COLONS] != GCLDEFAULTHASHIFTCOLONS) || (hashift[PLUSSES] != GCLDEFAULTHASHIFTPLUSSES) || (hashift[MINUSES] != GCLDEFAULTHASHIFTMINUSES) || (hashift[TIMES] != GCLDEFAULTHASHIFTTIMES) || (hashift[ZONES] != GCLDEFAULTHASHIFTZONES))) {
4296 bytes += fprintf(gclfile, "\n"
4297 "###############################################################################\n"
4298 "##\n"
4299 "## Define horizontal alignment.\n"
4300 "##\n");
4301 if (!vertical) bytes += fprintf(gclfile,
4302 "## Ignored by GCL interpreter because this counter is not vertical. You should\n"
4303 "## comment it out unless you plan to change the counter into a vertical one at\n"
4304 "## some later time.\n"
4305 "##\n");
4306 bytes += fprintf(gclfile,
4307 "###############################################################################\n\n");
4308 }
4309
4310 if ((hashift[HEAD] == hashift[DIGITS]) &&
4311 (hashift[HEAD] == hashift[COMMAS]) &&
4312 (hashift[HEAD] == hashift[TAIL]) &&
4313 (hashift[HEAD] == hashift[DASHES]) &&
4314 (hashift[HEAD] == hashift[COLONS]) &&
4315 (hashift[HEAD] == hashift[PLUSSES]) &&
4316 (hashift[HEAD] == hashift[MINUSES]) &&
4317 (hashift[HEAD] == hashift[TIMES]) &&
4318 (hashift[HEAD] == hashift[ZONES]) &&
4319 (halignflag[HEAD] == halignflag[DIGITS]) &&
4320 (halignflag[HEAD] == halignflag[COMMAS]) &&
4321 (halignflag[HEAD] == halignflag[TAIL]) &&
4322 (halignflag[HEAD] == halignflag[DASHES]) &&
4323 (halignflag[HEAD] == halignflag[COLONS]) &&
4324 (halignflag[HEAD] == halignflag[PLUSSES]) &&
4325 (halignflag[HEAD] == halignflag[MINUSES]) &&
4326 (halignflag[HEAD] == halignflag[TIMES]) &&
4327 (halignflag[HEAD] == halignflag[ZONES])) {
4328 if (portable || (halignflag[HEAD] != GCLDEFAULTHALIGNHEAD)) {
4329 if (publish && !vertical)
4330 bytes += fprintf(gclfile, "## ");
4331 switch (halignflag[HEAD]) {
4332 case LEFT:
4333 bytes += fprintf(gclfile, "align left\n");
4334 break;
4335 case CENTER:
4336 bytes += fprintf(gclfile, "align center\n");
4337 break;
4338 case RIGHT:
4339 bytes += fprintf(gclfile, "align right\n");
4340 break;
4341 }
4342 }
4343 }
4344 else for (i = 0; i < GRAPHICTYPES; i++) if (portable || (halignflag[i] != defaultalignflag.h[i]) || (hashift[i] != defaultashift.h[i])) {
4345 if (publish && !vertical)
4346 bytes += fprintf(gclfile, "## ");
4347 switch(halignflag[i]) {
4348 case LEFT:
4349 bytes += fprintf(gclfile, "align %s left", graphictypesnames[i]);
4350 bytes += fprintf(gclfile, " %+i\n" + (hashift[i] == 0) * 4, hashift[i]);
4351 break;
4352 case CENTER:
4353 bytes += fprintf(gclfile, "align %s center", graphictypesnames[i]);
4354 bytes += fprintf(gclfile, " %+i\n" + (hashift[i] == 0) * 4, hashift[i]);
4355 break;
4356 case RIGHT:
4357 bytes += fprintf(gclfile, "align %s right", graphictypesnames[i]);
4358 bytes += fprintf(gclfile, " %+i\n" + (hashift[i] == 0) * 4, hashift[i]);
4359 break;
4360 }
4361 }
4362
4363 if (insertcomments && (portable || (valignflag[HEAD] != GCLDEFAULTVALIGNHEAD) || (valignflag[DIGITS] != GCLDEFAULTVALIGNDIGITS) || (valignflag[COMMAS] != GCLDEFAULTVALIGNCOMMAS) || (valignflag[TAIL] != GCLDEFAULTVALIGNTAIL) || (vashift[HEAD] != GCLDEFAULTVASHIFTHEAD) || (vashift[DIGITS] != GCLDEFAULTVASHIFTDIGITS) || (vashift[COMMAS] != GCLDEFAULTVASHIFTCOMMAS) || (vashift[TAIL] != GCLDEFAULTVASHIFTTAIL) || (vashift[DASHES] != GCLDEFAULTVASHIFTDASHES) || (vashift[COLONS] != GCLDEFAULTVASHIFTCOLONS) || (vashift[PLUSSES] != GCLDEFAULTVASHIFTPLUSSES) || (vashift[MINUSES] != GCLDEFAULTVASHIFTMINUSES) || (vashift[TIMES] != GCLDEFAULTVASHIFTTIMES) || (vashift[ZONES] != GCLDEFAULTVASHIFTZONES))) {
4364 bytes += fprintf(gclfile, "\n"
4365 "###############################################################################\n"
4366 "##\n"
4367 "## Define vertical alignment.\n"
4368 "##\n");
4369 if (vertical) bytes += fprintf(gclfile,
4370 "## Ignored by GCL interpreter because this counter is vertical. You should\n"
4371 "## comment it out unless you plan to change the counter to a horizontal one at\n"
4372 "## some later time.\n"
4373 "##\n");
4374 bytes += fprintf(gclfile,
4375 "###############################################################################\n\n");
4376 }
4377
4378 if ((vashift[HEAD] == vashift[DIGITS]) &&
4379 (vashift[HEAD] == vashift[COMMAS]) &&
4380 (vashift[HEAD] == vashift[TAIL]) &&
4381 (vashift[HEAD] == vashift[DASHES]) &&
4382 (vashift[HEAD] == vashift[COLONS]) &&
4383 (vashift[HEAD] == vashift[PLUSSES]) &&
4384 (vashift[HEAD] == vashift[MINUSES]) &&
4385 (vashift[HEAD] == vashift[TIMES]) &&
4386 (vashift[HEAD] == vashift[ZONES]) &&
4387 (valignflag[HEAD] == valignflag[DIGITS]) &&
4388 (valignflag[HEAD] == valignflag[COMMAS]) &&
4389 (valignflag[HEAD] == valignflag[TAIL]) &&
4390 (valignflag[HEAD] == valignflag[DASHES]) &&
4391 (valignflag[HEAD] == valignflag[COLONS]) &&
4392 (valignflag[HEAD] == valignflag[PLUSSES]) &&
4393 (valignflag[HEAD] == valignflag[MINUSES]) &&
4394 (valignflag[HEAD] == valignflag[TIMES]) &&
4395 (valignflag[HEAD] == valignflag[ZONES])) {
4396 if (portable || (valignflag[HEAD] != GCLDEFAULTVALIGNHEAD)) {
4397 if (publish && vertical)
4398 bytes += fprintf(gclfile, "## ");
4399 switch (valignflag[HEAD]) {
4400 case TOP:
4401 bytes += fprintf(gclfile, "align top\n");
4402 break;
4403 case MIDDLE:
4404 bytes += fprintf(gclfile, "align middle\n");
4405 break;
4406 case BOTTOM:
4407 bytes += fprintf(gclfile, "align bottom\n");
4408 break;
4409 }
4410 }
4411 }
4412 else for (i = 0; i < GRAPHICTYPES; i++) if (portable || (valignflag[i] != defaultalignflag.v[i]) || (vashift[i] != defaultashift.v[i])) {
4413 if (publish && vertical)
4414 bytes += fprintf(gclfile, "## ");
4415 switch (valignflag[i]) {
4416 case TOP:
4417 bytes += fprintf(gclfile, "align %s top", graphictypesnames[i]);
4418 bytes += fprintf(gclfile, " %+i\n" + (vashift[i] == 0) * 4, vashift[i]);
4419 break;
4420 case MIDDLE:
4421 bytes += fprintf(gclfile, "align %s middle", graphictypesnames[i]);
4422 bytes += fprintf(gclfile, " %+i\n" + (vashift[i] == 0) * 4, vashift[i]);
4423 break;
4424 case BOTTOM:
4425 bytes += fprintf(gclfile, "align %s bottom", graphictypesnames[i]);
4426 bytes += fprintf(gclfile, " %+i\n" + (vashift[i] == 0) * 4, vashift[i]);
4427 break;
4428 }
4429 }
4430
4431 if ((portable && !publish) || vshift) {
4432 if (insertcomments) {
4433 bytes += fprintf(gclfile, "\n"
4434 "###############################################################################\n"
4435 "##\n"
4436 "## Define the number of pixels to shift the counter vertically relative to the.\n"
4437 "## background graphic.\n"
4438 "##\n");
4439 if (bkgpicture.graphic == NULL) bytes += fprintf(gclfile,
4440 "## Since no background graphic is defined, you should comment this shift out.\n"
4441 "##\n");
4442 bytes += fprintf(gclfile,
4443 "###############################################################################\n\n");
4444 }
4445 switch (vshiftflag) {
4446 case UP:
4447 bytes += fprintf(gclfile, "shift up %u\n", vshift);
4448 break;
4449 case DOWN:
4450 bytes += fprintf(gclfile, "shift down %u\n", vshift);
4451 break;
4452 }
4453 }
4454
4455 if ((portable && !publish) || hshift) {
4456 if (insertcomments) {
4457 bytes += fprintf(gclfile, "\n"
4458 "###############################################################################\n"
4459 "##\n"
4460 "## Define the number of pixels to shift the counter horizontally relative to.\n"
4461 "## background graphic.\n"
4462 "##\n");
4463 if (bkgpicture.graphic == NULL) bytes += fprintf(gclfile,
4464 "## Since no background graphic is defined, you should comment this shift out.\n"
4465 "##\n");
4466 bytes += fprintf(gclfile,
4467 "###############################################################################\n\n");
4468 }
4469 switch (hshiftflag) {
4470 case LEFT:
4471 bytes += fprintf(gclfile, "shift left %u\n", hshift);
4472 break;
4473 case RIGHT:
4474 bytes += fprintf(gclfile, "shift right %u\n", hshift);
4475 break;
4476 }
4477 }
4478
4479 if (portable || revcom || revdig) {
4480 if (insertcomments) {
4481 bytes += fprintf(gclfile, "\n"
4482 "###############################################################################\n"
4483 "##\n"
4484 "## %sake the counter or timer print in reverse (%s).\n"
4485 "##\n"
4486 "###############################################################################\n\n",
4487 (revcom || revdig) ? "M" : "Do not m",
4488 vertical ? "bottom to top" : "right to left");
4489 }
4490 bytes += fprintf(gclfile, revcom && revdig ? "reverse\n" :
4491 revcom ? portable ? "reverse digits none reverse commas\n" : "reverse commas\n" :
4492 revdig ? portable ? "reverse digits reverse commas none\n" : "reverse digits\n" :
4493 "reverse none\n");
4494 }
4495
4496 if (portable || (mindigits > 1)) {
4497 if (insertcomments)
4498 bytes += fprintf(gclfile, "\n"
4499 "###############################################################################\n"
4500 "##\n"
4501 "## Define minimum number of digits to draw.\n"
4502 "##\n"
4503 "## If the counter value is too small for the minimum number of digits, it will\n"
4504 "## be left-padded with zeros.\n"
4505 "##\n"
4506 "## The acceptable range is 1 - %u.\n"
4507 "##\n"
4508 "###############################################################################\n\n", MAXDIGITS);
4509 bytes += fprintf(gclfile, "mindigits %i\n", mindigits);
4510 }
4511
4512 /*
4513 * Process inhibitors. This is only necessary if -i was not specified
4514 * on the command line, since that option overrides any inhibitors
4515 * defined in the source file.
4516 */
4517 if (one && firstinhibitor) {
4518 register char *e;
4519 register int match;
4520
4521 /*
4522 * Note: Because of the way strcmp works,
4523 * match == 0 means TRUE (we have a match),
4524 * match != 0 means FALSE (we don't have a match).
4525 */
4526
4527 tempinhibitor = firstinhibitor;
4528
4529 while (tempinhibitor != NULL) {
4530 if (tempinhibitor->cookie == 0) {
4531 e = getenv(tempinhibitor->env);
4532 if (e)
4533 match = tempinhibitor->op == '=' ? strcmp(tempinhibitor->val, e) :
4534 strncmp(tempinhibitor->val, e, strlen(tempinhibitor->val));
4535 else
4536 match = 1;
4537 } /* not a cookie */
4538 else {
4539 match = 1; /* i.e., FALSE */
4540
4541 for (i = 0; i < numcookies; i++) {
4542 if (!strcmp(tempinhibitor->env, cookiepairs[i].name) &&
4543 (tempinhibitor->op == '=' ?
4544 !strcmp(tempinhibitor->val, cookiepairs[i].value) :
4545 !strncmp(tempinhibitor->val, cookiepairs[i].value, strlen(tempinhibitor->val)))) {
4546 match = 0;
4547 break;
4548 }
4549 } /* for */
4550 } /* cookie */
4551
4552 if ( (when(tempinhibitor->condition) && (match == 0)) ||
4553 (unless(tempinhibitor->condition) && (match != 0)) )
4554 inhibited = (int)tempinhibitor->inhibitor;
4555 /* otherwise, keep "inhibited" unchanged */
4556
4557 tempinhibitor = tempinhibitor->next;
4558 } /* while */
4559 }
4560
4561 if (!publish) {
4562 /* Write inhibitors to the source file in proper sequence */
4563 tempinhibitor = firstinhibitor;
4564
4565 if (insertcomments && (portable || firstinhibitor))
4566 bytes += fprintf(gclfile, "\n"
4567 "###############################################################################\n"
4568 "##\n"
4569 "## Declare inhibitors.\n"
4570 "##\n"
4571 "###############################################################################\n\n");
4572 if (portable && !firstinhibitor)
4573 bytes += fprintf(gclfile, "inhibit none\n");
4574 else while (tempinhibitor != NULL) {
4575 if (tempinhibitor->cookie != 0) {
4576 bytes += fprintf(gclfile, "%s %s cookie ",
4577 tempinhibitor->inhibitor == CONCEDE ? "concede" : "inhibit",
4578 when(tempinhibitor->condition) ? "when" : "unless");
4579 bytes += printstring(tempinhibitor->env, 0);
4580 bytes += fprintf(gclfile, tempinhibitor->op == '=' ? " = " : " := ");
4581 bytes += printstring(tempinhibitor->val, 0);
4582 bytes += fprintf(gclfile, "\n");
4583 }
4584
4585 else if (tempinhibitor->env == from) {
4586 bytes += fprintf(gclfile, "%s %s from ",
4587 tempinhibitor->inhibitor == CONCEDE ? "concede" : "inhibit",
4588 when(tempinhibitor->condition) ? "when" : "unless");
4589 bytes += printstring(tempinhibitor->val, 0);
4590 bytes += fprintf(gclfile, "\n");
4591 }
4592
4593 else {
4594 bytes += fprintf(gclfile, "%s %s ",
4595 tempinhibitor->inhibitor == CONCEDE ? "concede" : "inhibit",
4596 when(tempinhibitor->condition) ? "when" : "unless");
4597 bytes += printstring(tempinhibitor->env, 0);
4598 bytes += fprintf(gclfile, tempinhibitor->op == '=' ? " = " : " := ");
4599 bytes += printstring(tempinhibitor->val, 0);
4600 bytes += fprintf(gclfile, "\n");
4601 }
4602
4603 tempinhibitor = tempinhibitor->next;
4604 } /* while */
4605
4606 /* Write relays to the source file in proper sequence */
4607 temprelayor = firstrelayor;
4608
4609 if (insertcomments && (portable || firstrelayor))
4610 bytes += fprintf(gclfile, "\n"
4611 "###############################################################################\n"
4612 "##\n"
4613 "## Declare relays.\n"
4614 "##\n"
4615 "###############################################################################\n\n");
4616 if (portable && !firstrelayor)
4617 bytes += fprintf(gclfile, "relay none\n");
4618 else while (temprelayor != NULL) {
4619 if (temprelayor->relayor == SERVE)
4620 bytes += fprintf(gclfile, "serve");
4621 else {
4622 bytes += fprintf(gclfile, "relay ");
4623 bytes += printstring(temprelayor->url, 0);
4624 }
4625
4626 if (temprelayor->cookie != 0) {
4627 bytes += fprintf(gclfile, "%s %s cookie " + 2,
4628 when(temprelayor->condition) ? "when" : "unless");
4629 bytes += printstring(temprelayor->env, 0);
4630 bytes += fprintf(gclfile, temprelayor->op == '=' ? " = " : " := ");
4631 }
4632
4633 else if (temprelayor->env == from) {
4634 bytes += fprintf(gclfile, "%s %s from " + 2,
4635 when(temprelayor->condition) ? "when" : "unless");
4636 }
4637
4638 else {
4639 bytes += fprintf(gclfile, "%s %s " + 2,
4640 when(temprelayor->condition) ? "when" : "unless");
4641 bytes += printstring(temprelayor->env, 0);
4642 bytes += fprintf(gclfile, temprelayor->op == '=' ? " = " : " := ");
4643 }
4644
4645 bytes += printstring(temprelayor->val, 0);
4646 bytes += fprintf(gclfile, "\n");
4647
4648 temprelayor = temprelayor->next;
4649 } /* while */
4650 } /* !publish */
4651
4652 if ((portable && !publish) || script) {
4653 if (insertcomments)
4654 bytes += fprintf(gclfile, "\n"
4655 "###############################################################################\n"
4656 "##\n"
4657 "## Fork a background script or program.\n"
4658 "##\n"
4659 "###############################################################################\n\n");
4660 bytes += fprintf(gclfile, "fork ");
4661 bytes += script ? printstring(script, 0) : fprintf(gclfile, "none");
4662 bytes += fprintf(gclfile, "\n");
4663 }
4664
4665 if (silent) {
4666 if (insertcomments)
4667 bytes += fprintf(gclfile, "\n"
4668 "###############################################################################\n"
4669 "##\n"
4670 "## Do not produce any output.\n"
4671 "##\n"
4672 "###############################################################################\n\n");
4673 bytes += fprintf(gclfile, "silent")
4674 + fprintf(gclfile, (portable || redirect) && !insertcomments ? " " : "\n");
4675 }
4676
4677 if (portable || redirect) {
4678 if (insertcomments)
4679 bytes += fprintf(gclfile, "\n"
4680 "###############################################################################\n"
4681 "##\n"
4682 "## Redirect browser to a different URL. Must contain the full URL, starting\n"
4683 "## with \"http://\" or \"ftp://\" and such. Typically combined with \"silent.\"\n"
4684 "##\n"
4685 "## May be followed by an exclamation point to turn off inhibition when using\n"
4686 "## the `-r' command line override.\n"
4687 "##\n"
4688 "## Without the exclamation point, GCL interprets the \"redirect\" keyword as\n"
4689 "## \"redirect as well as inhibit\".\n"
4690 "##\n"
4691 "###############################################################################\n\n");
4692 bytes += fprintf(gclfile, "redirect ");
4693 bytes += redirect ? printstring(redirect, 0) : fprintf(gclfile, "none");
4694 if (redirect && uninhibitedredirection(redirection))
4695 bytes += fprintf(gclfile, "!");
4696 bytes += fprintf(gclfile, "\n");
4697 }
4698
4699 for (i = DEFINECOMMA; i < DEFINECHAR; i++) {
4700 if (definechar[i] == '\0') {
4701 if (insertcomments)
4702 bytes += fprintf(gclfile, "\n"
4703 "###############################################################################\n"
4704 "##\n"
4705 "## Do not use %s in text %sers.\n"
4706 "##\n"
4707 "###############################################################################\n\n", definecharnameplural[i], i == DEFINECOMMA ? "count" : "tim");
4708 bytes += fprintf(gclfile, "%s none\n", definecharname[i]);
4709 }
4710 else if ((portable && !publish) || (definechar[i] != definedchar[i])) {
4711 if (insertcomments)
4712 bytes += fprintf(gclfile, "\n"
4713 "###############################################################################\n"
4714 "##\n"
4715 "## Declare the %s character for text %sers.\n"
4716 "##\n"
4717 "###############################################################################\n\n", definecharname[i], i == DEFINECOMMA ? "count" : "tim");
4718 bytes += fprintf(gclfile, "%s = %u\t## `%c'\n", definecharname[i], (unsigned int)definechar[i], definechar[i]);
4719 }
4720 }
4721 if (portable || seconds) {
4722 if (insertcomments)
4723 bytes += fprintf(gclfile, "\n"
4724 "###############################################################################\n"
4725 "##\n"
4726 "## %show seconds in timers.\n"
4727 "##\n"
4728 "###############################################################################\n\n",
4729 seconds ? "S" : "Do not s");
4730 bytes += fprintf(gclfile, seconds ? "seconds\n" : "seconds none\n");
4731 }
4732
4733 if (((portable || (gtz.secs != GCLDEFAULTTIMEZONEOFFSET) || (gtz.tz != GCLDEFAULTTIMEZONE))) && !publish) {
4734 if (insertcomments)
4735 bytes += fprintf(gclfile, "\n"
4736 "###############################################################################\n"
4737 "##\n"
4738 "## Specify time zone.\n"
4739 "##\n"
4740 "###############################################################################\n\n");
4741 bytes += fprintf(gclfile, gtz.tz == STZ ? "stz" : "utc");
4742 bytes += fprintf(gclfile, gtz.secs ? " %+i\n" : "\n", gtz.secs);
4743 }
4744
4745 if ((portable && !publish) || rst) {
4746 if (insertcomments)
4747 bytes += fprintf(gclfile, "\n"
4748 "###############################################################################\n"
4749 "##\n"
4750 "## Determine how often to reset.\n"
4751 "##\n"
4752 "###############################################################################\n\n");
4753 bytes += fprintf(gclfile, "reset ");
4754 switch (rst) {
4755 case WEEKLY:
4756 bytes += fprintf(gclfile, "weekly");
4757 break;
4758 case DAILY:
4759 bytes += fprintf(gclfile, "daily");
4760 break;
4761 case MONTHLY:
4762 bytes += fprintf(gclfile, "monthly");
4763 break;
4764 case ANNUALY:
4765 bytes += fprintf(gclfile, "annually");
4766 break;
4767 default:
4768 bytes += fprintf(gclfile, "none");
4769 break;
4770 }
4771 bytes += fprintf(gclfile, publish ? "\n" : " ");
4772 }
4773
4774 if (!publish) {
4775 if (incrementrange[0] != incrementrange[1]) {
4776 if ((incrementrange[0] == 1) && (incrementrange[1] < 0x07FF) && (incrementrange[1] & 1)) {
4777 if (insertcomments)
4778 bytes += fprintf(gclfile, "\n"
4779 "###############################################################################\n"
4780 "##\n"
4781 "## Define the fudge factor. The counter will be increased by a random value\n"
4782 "## between 1 and fudge * 2 - 1. The actual number of hits will be very close to\n"
4783 "## to count / fudge, so you can still get a good overall idea of the real count.\n"
4784 "##\n"
4785 "###############################################################################\n\n");
4786 bytes += fprintf(gclfile, "fudge %i\n", (int)((incrementrange[1] + 1) / 2));
4787 }
4788 else if (issigma) {
4789 if (insertcomments)
4790 bytes += fprintf(gclfile, "\n"
4791 "###############################################################################\n"
4792 "##\n"
4793 "## Define the sigma. The counter will be a random value between mean +/- sigma.\n"
4794 "## The first integer is sigma, the second mean. Useful for emulation of certain\n"
4795 "## kind of statistical data.\n"
4796 "##\n"
4797 "###############################################################################\n\n");
4798 bytes += fprintf(gclfile, "sigma " sinteger ", " sinteger "\n", incrementrange[1], mean);
4799 }
4800 else {
4801 if (insertcomments)
4802 bytes += fprintf(gclfile, "\n"
4803 "###############################################################################\n"
4804 "##\n"
4805 "## Set increment range. Unless inhibited, the counter will be increased by\n"
4806 "## at least the lower value and at most the higher.\n"
4807 "##\n"
4808 "###############################################################################\n\n");
4809 bytes += fprintf(gclfile, "increment [" sinteger ", " sinteger "]\n",
4810 incrementrange[0], incrementrange[1]);
4811 }
4812 }
4813 else if (increment != 1) {
4814 if (insertcomments)
4815 bytes += fprintf(gclfile, "\n"
4816 "###############################################################################\n"
4817 "##\n"
4818 "## Set increment. Unless inhibited, the counter will be increased by its value.\n"
4819 "##\n"
4820 "###############################################################################\n\n");
4821 bytes += fprintf(gclfile, "increment " sinteger "\n", increment);
4822 }
4823
4824
4825 bytes += fprintf(gclfile, "@ %u %u %u %u\n", now->tm_year, now->tm_mon, now->tm_mday, weeks);
4826
4827 if (insertcomments)
4828 bytes += fprintf(gclfile, "\n"
4829 "###############################################################################\n"
4830 "##\n"
4831 "## Declare the current value of the counter.\n"
4832 "##\n"
4833 "###############################################################################\n\n");
4834 if (issigned || insertcomments)
4835 bytes += fprintf(gclfile, "unsigned " + issigned * 2);
4836 bytes += fprintf(gclfile, issigned ? "count = " sinteger "\n" : "count = " integer "\n", issigma ? (counter_t)mean : ((counter_t)((counter_t)count + (scounter_t)(one && !inhibited) * increment)));
4837 } /* !publish */
4838
4839 /* The following is Unix specific */
4840 if (gclfile != stdout)
4841 ftruncate(fileno(gclfile), bytes);
4842 }
4843
noframe(gdImagePtr image,int bgcolor,int invisible,int width,int height)4844 static void noframe(gdImagePtr image, int bgcolor, int invisible, int width, int height) {
4845 /* This is frame 0 (noframe). It does nothing. */
4846 }
4847
popup(gdImagePtr image,int bgcolor,int invisible,int width,int height)4848 static void popup(gdImagePtr image, int bgcolor, int invisible, int width, int height) {
4849 /*
4850 * Create a frame in the style of a popup window.
4851 * This code is based on my button.c CGI program
4852 * used to create buttons and popup windows on
4853 * line at http://www.whizkidtech.net/
4854 */
4855 int dark, light, white, black;
4856
4857 black = gdImageColorAllocate(image, 0, 0, 0);
4858 white = gdImageColorAllocate(image, 255, 255, 255);
4859 dark = gdImageColorAllocate(image, bkg.red >> 1, bkg.green >> 1, bkg.blue >> 1);
4860 light = gdImageColorAllocate(image, (bkg.red + 255) >> 1, (bkg.green + 255) >> 1, (bkg.blue + 255) >> 1);
4861
4862 gdImageLine(image, 0, height - 1, 0, 0, light);
4863 gdImageLine(image, 0, 0, width - 1, 0, light);
4864 gdImageLine(image, width - 1, 0, width - 1, height - 1, black);
4865 gdImageLine(image, width - 1, height - 1, 1, height - 1, black);
4866 gdImageLine(image, 1, height - 2, 1, 1, white);
4867 gdImageLine(image, 1, 1, width - 2, 1, white);
4868 gdImageLine(image, width - 2, 1, width - 2, height - 2, dark);
4869 gdImageLine(image, width - 2, height - 2, 1, height - 2, dark);
4870 }
4871
button(gdImagePtr image,int bgcolor,int invisible,int width,int height)4872 static void button(gdImagePtr image, int bgcolor, int invisible, int width, int height) {
4873 /*
4874 * Create a button-style frame. Based on the same
4875 * code as popup(), and only subtly different.
4876 */
4877 int dark, light, white, black;
4878
4879 black = gdImageColorAllocate(image, 0, 0, 0);
4880 white = gdImageColorAllocate(image, 255, 255, 255);
4881 dark = gdImageColorAllocate(image, bkg.red >> 1, bkg.green >> 1, bkg.blue >> 1);
4882 light = gdImageColorAllocate(image, (bkg.red + 255) >> 1, (bkg.green + 255) >> 1, (bkg.blue + 255) >> 1);
4883
4884 gdImageLine(image, 0, height - 1, 0, 0, white);
4885 gdImageLine(image, 0, 0, width - 1, 0, white);
4886 gdImageLine(image, width - 1, 0, width - 1, height - 1, black);
4887 gdImageLine(image, width - 1, height - 1, 1, height - 1, black);
4888 gdImageLine(image, 1, height - 2, 1, 1, light);
4889 gdImageLine(image, 1, 1, width - 2, 1, light);
4890 gdImageLine(image, width - 2, 1, width - 2, height - 2, dark);
4891 gdImageLine(image, width - 2, height - 2, 1, height - 2, dark);
4892 }
4893
defaultbutton(gdImagePtr image,int bgcolor,int invisible,int width,int height)4894 static void defaultbutton(gdImagePtr image, int bgcolor, int invisible, int width, int height) {
4895 /*
4896 * Create a button-style frame. Based on the same
4897 * code as button(), but adds a black frame.
4898 */
4899 int dark, light, white, black;
4900
4901 black = gdImageColorAllocate(image, 0, 0, 0);
4902 white = gdImageColorAllocate(image, 255, 255, 255);
4903 dark = gdImageColorAllocate(image, bkg.red >> 1, bkg.green >> 1, bkg.blue >> 1);
4904 light = gdImageColorAllocate(image, (bkg.red + 255) >> 1, (bkg.green + 255) >> 1, (bkg.blue + 255) >> 1);
4905
4906 gdImageRectangle(image, 0, 0, width - 1, height - 1, black);
4907 gdImageLine(image, 1, height - 2, 1, 1, white);
4908 gdImageLine(image, 1, 1, width - 2, 1, white);
4909 gdImageLine(image, width - 2, 1, width - 2, height - 2, black);
4910 gdImageLine(image, width - 2, height - 2, 2, height - 2, black);
4911 gdImageLine(image, 2, height - 3, 2, 2, light);
4912 gdImageLine(image, 2, 2, width - 3, 2, light);
4913 gdImageLine(image, width - 3, 2, width - 3, height - 3, dark);
4914 gdImageLine(image, width - 3, height - 3, 2, height - 3, dark);
4915 }
4916
shadow(gdImagePtr image,int bgcolor,int invisible,int width,int height)4917 static void shadow(gdImagePtr image, int bgcolor, int invisible, int width, int height) {
4918 /*
4919 * Create a "shadow" frame. Derived from popup(), but adds
4920 * some shadow on the dark side.
4921 */
4922 int dark, light, white, black;
4923
4924 black = gdImageColorAllocate(image, 0, 0, 0);
4925 white = gdImageColorAllocate(image, 255, 255, 255);
4926 dark = gdImageColorAllocate(image, bkg.red >> 1, bkg.green >> 1, bkg.blue >> 1);
4927 light = gdImageColorAllocate(image, (bkg.red + 255) >> 1, (bkg.green + 255) >> 1, (bkg.blue + 255) >> 1);
4928
4929 gdImageLine(image, 0, height - 1, 0, 0, light);
4930 gdImageLine(image, 0, 0, width - 1, 0, light);
4931 gdImageLine(image, width - 2, 1, width - 2, height - 2, black);
4932 gdImageLine(image, width - 2, height - 2, 2, height - 2, black);
4933 gdImageLine(image, 1, height - 2, 1, 1, white);
4934 gdImageLine(image, 1, 1, width - 2, 1, white);
4935 gdImageLine(image, width - 3, 2, width - 3, height - 3, dark);
4936 gdImageLine(image, width - 3, height - 3, 2, height - 3, dark);
4937 gdImageLine(image, width - 1, 1, width - 1, height - 1, black);
4938 gdImageLine(image, width - 1, height - 1, 1, height - 1, black);
4939 }
4940
box(gdImagePtr image,int bgcolor,int invisible,int width,int height)4941 static void box(gdImagePtr image, int bgcolor, int invisible, int width, int height) {
4942 int dark, light, black;
4943
4944 black = gdImageColorAllocate(image, 0, 0, 0);
4945 dark = gdImageColorAllocate(image, bkg.red >> 1, bkg.green >> 1, bkg.blue >> 1);
4946 light = gdImageColorAllocate(image, (bkg.red + 255) >> 1, (bkg.green + 255) >> 1, (bkg.blue + 255) >> 1);
4947
4948 gdImageLine(image, 0, height - 1, 0, 0, light);
4949 gdImageLine(image, 0, 0, width - 1, 0, light);
4950 gdImageLine(image, width - 2, 1, width - 2, height - 2, black);
4951 gdImageLine(image, width - 2, height - 2, 2, height - 2, black);
4952 gdImageLine(image, 1, height - 2, 1, 1, light);
4953 gdImageLine(image, 1, 1, width - 2, 1, light);
4954 gdImageLine(image, 2, height -3, 2, 2, black);
4955 gdImageLine(image, 2, 2, width - 3, 2, black);
4956 gdImageLine(image, width - 3, 2, width - 3, height - 3, dark);
4957 gdImageLine(image, width - 3, height - 3, 2, height - 3, dark);
4958 gdImageLine(image, width - 1, 1, width - 1, height - 1, black);
4959 gdImageLine(image, width - 1, height - 1, 1, height - 1, black);
4960 }
4961
4962 /*
4963 * Want to contribute with your own unique frame?
4964 * Send me your code for inclusion in future versions
4965 * of GCL!
4966 *
4967 * Don't know how to code? Describe your frame in
4968 * minute details, so I can code it.
4969 */
4970
relaying(void)4971 static int relaying(void) {
4972 register relay *temprelay;
4973 register char *url = NULL;
4974 int i, match;
4975
4976 for (temprelay = firstrelayor; temprelay != NULL; temprelay = temprelay->next) {
4977 if (temprelay->cookie != 0) for (i = 0, match = 0; i < numcookies && !match; i++) {
4978 if (!strcmp(temprelay->env, cookiepairs[i].name) &&
4979 (temprelay->op == '=' ?
4980 !strcmp(temprelay->val, cookiepairs[i].value) :
4981 !strncmp(temprelay->val, cookiepairs[i].value, strlen(cookiepairs[i].value)))) {
4982 match = 1;
4983 }
4984 }
4985 else {
4986 register char *strptr = getenv(temprelay->env);
4987 match = strptr != NULL &&
4988 (temprelay->op == '=' ? strcmp(temprelay->val, strptr) == 0 :
4989 strncmp(temprelay->val, strptr, strlen(strptr)));
4990 }
4991 if (match && when(temprelay->condition) || !match && unless(temprelay->condition)) {
4992 url = temprelay->relayor == SERVE ? NULL : temprelay->url;
4993 }
4994 }
4995
4996 if (url != NULL) {
4997 gcldebug("Relaying to `%s'", url);
4998 printf("Location: %s\n\n", url);
4999 return 1;
5000 }
5001 return 0;
5002 }
5003
5004 /* Interpret GCL code */
interpret(void)5005 static void interpret(void) {
5006 gdImagePtr counter;
5007 gdImagePtr image;
5008 register gclpic *grouppicture;
5009 int width, height;
5010 int widest, tallest;
5011 int bx, by, cx, cy;
5012 int rejected;
5013 int bgcolor;
5014 int invisible;
5015 register int digits;
5016 register int nondigits;
5017 int commas = 0;
5018 int spaces = 0;
5019 int dots = 0;
5020 int dashes = 0;
5021 int colons = 0;
5022 int plusses = 0;
5023 int minuses = 0;
5024 int times = 0;
5025 int zones = 0;
5026 int signedcounter = 0;
5027 register int lastprinted;
5028 register int delta;
5029 int i, j;
5030 int x, y;
5031 char buffer[MAXDIGITS+1];
5032
5033 if (relaying()) return;
5034
5035 if (redirect) {
5036 gcldebug("Redirecting to `%s'", redirect);
5037 printf("Location: %s\n", redirect);
5038 if (silent)
5039 printf("\n");
5040 }
5041
5042 if (silent) {
5043 gcldebug("My mouth is sealed");
5044 return;
5045 }
5046
5047 /*
5048 * It would be rather complicated trying
5049 * to create a complex image in one step.
5050 *
5051 * We divide the process into four steps,
5052 * creating three different layers in the
5053 * first three steps, combining them in
5054 * the forth.
5055 */
5056
5057 /* STEP ONE - create the counter layer */
5058
5059 /*
5060 * Probably the easiest way to do this is in two
5061 * passes.
5062 *
5063 * In pass 1 we:
5064 *
5065 * o figure out how many digits
5066 * we need to display,
5067 *
5068 * o open the input graphics,
5069 *
5070 * o calculate the total width and height
5071 * of the final graphic.
5072 *
5073 * In pass 2 we produce the graphic counter.
5074 */
5075
5076 /* P A S S O N E */
5077 if (gallery) {
5078 digits = 19;
5079 strcpy(buffer, "0123456789~-;%,><^@");
5080 nocommas = 1;
5081 }
5082 else if (whatami != SHOWCOUNT) {
5083 nocommas = 1;
5084 switch (whatami) {
5085 case SHOWTIME:
5086 digits = timesprint(buffer, 0);
5087 break;
5088 case SHOWDATE:
5089 digits = datesprint(buffer);
5090 break;
5091 case SHOWDATE | SHOWTIME:
5092 digits = datesprint(buffer);
5093 digits += timesprint(buffer + digits, 1);
5094 break;
5095 case SHOWZONE:
5096 digits = zonesprint(buffer);
5097 break;
5098 case SHOWTIME | SHOWZONE:
5099 digits = timesprint(buffer, 0);
5100 digits += zonesprint(buffer + digits);
5101 break;
5102 case SHOWDATE | SHOWZONE:
5103 digits = datesprint(buffer);
5104 digits += zonesprint(buffer + digits);
5105 break;
5106 case SHOWDATE | SHOWTIME | SHOWZONE:
5107 digits = datesprint(buffer);
5108 digits += timesprint(buffer + digits, 1);
5109 digits += zonesprint(buffer + digits);
5110 break;
5111 }
5112 }
5113 else if (gclprint != NULL) {
5114 register unsigned char *strptr = gclprint;
5115
5116 for (digits = 0; (digits <= MAXDIGITS) && *strptr; strptr++) {
5117 for (i = 0; i < ACCEPTABLECHARS; i++) {
5118 if (*strptr == echars[i]) {
5119 buffer[digits++] = pchars[i];
5120 break;
5121 }
5122 }
5123 }
5124 nocommas = 1;
5125 free(gclprint);
5126 gclprint = NULL;
5127 }
5128 else {
5129 digits = sprintf(buffer, issigned ? scounteger : counteger, outputtext ? 1 : mindigits > MAXDIGITS ? MAXDIGITS : mindigits, count);
5130 if (*buffer == '-') {
5131 signedcounter = 1;
5132 *buffer = '<';
5133 }
5134 gcldebug(issigned ? "Counter = " sinteger : "Counter = " integer, count);
5135 gcldebug("Digits = %i", digits);
5136 }
5137
5138 if (outputtext != 0) {
5139 register unsigned char separator = groupseparator == COMMAS ? comma :
5140 groupseparator == DOTS ? '.' : ' ';
5141
5142 gcldebug("Creating text output (`-t' specified)");
5143 if (localuse == 0)
5144 printf("Content-Type: text/html\n\n");
5145 for (i = 0; i < digits; i++) {
5146 if ((nocommas == 0) && (i > signedcounter) && (separator >= ' ') && (((digits - i) % group) == 0))
5147 htmlputc(separator);
5148 switch (buffer[i]) {
5149 default:
5150 htmlputc(buffer[i]);
5151 break;
5152 case '%':
5153 htmlputc(colon);
5154 break;
5155 case '-':
5156 htmlputc(dash);
5157 break;
5158 case '<':
5159 htmlputc('-');
5160 break;
5161 case '>':
5162 htmlputc('+');
5163 break;
5164 case '^':
5165 htmlputc(timechar);
5166 break;
5167 case '@':
5168 htmlputc(zone);
5169 break;
5170 case ',':
5171 htmlputc(comma);
5172 break;
5173 case '~':
5174 htmlputc(' ');
5175 break;
5176 case ';':
5177 htmlputc('.');
5178 break;
5179 }
5180 }
5181 return;
5182 }
5183
5184 /*
5185 * If we are to display digits in reverse, we need to swap
5186 * the contents of the buffer.
5187 *
5188 * Note: This works for both an even and an odd number of
5189 * digits, since with an odd number of digits, the middle
5190 * digit remains the same.
5191 */
5192 if (revdig != 0) {
5193 register char tmp;
5194 register int digs = digits - 1;
5195
5196 for (i = (digits / 2) - 1; i >= 0; i--) {
5197 tmp = buffer[i];
5198 buffer[i] = buffer[digs - i];
5199 buffer[digs - i] = tmp;
5200 }
5201 }
5202
5203 for (i = signedcounter; i < digits; i++) switch (buffer[i]) {
5204 case '%':
5205 colons++;
5206 break;
5207 case '-':
5208 dashes++;
5209 break;
5210 case '<':
5211 minuses++;
5212 break;
5213 case '>':
5214 plusses++;
5215 break;
5216 case '^':
5217 times++;
5218 break;
5219 case '@':
5220 zones++;
5221 break;
5222 case ',':
5223 commas++;
5224 break;
5225 case '~':
5226 spaces++;
5227 break;
5228 case ';':
5229 dots++;
5230 break;
5231 }
5232
5233 nondigits = colons + dashes + minuses + plusses + times + zones + commas + spaces + dots;
5234 digits -= nondigits;
5235
5236 openarraypicture(1);
5237 openpicture(HEADPICTURE);
5238 openpicture(TAILPICTURE);
5239
5240 /*
5241 * Note that the following has no influence on the number of nondigits.
5242 * That is because these commas are not in the buffer but are added
5243 * algorithmically (although Al Gore has nothing to do with it :).
5244 */
5245 if (nocommas == 0)
5246 commas = (digits - 1 - signedcounter) / group;
5247
5248 i = groupseparator == COMMAS ? COMMA :
5249 groupseparator == DOTS ? DOT : SPACE;
5250
5251 if (commas)
5252 openpicture(i);
5253
5254 grouppicture = &picture[i];
5255
5256 if (!grouppicture->iscreated) {
5257 commas = 0;
5258 nocommas = 1;
5259 }
5260 else {
5261 grouppicture->isused = 1;
5262 if (!nocommas)
5263 gcldebug("Image will contain %i group separator%s", commas, "s" + (commas == 1));
5264 }
5265
5266 rejected = 0;
5267 for (;;) {
5268 register int kerning;
5269
5270 lastprinted = HEAD;
5271
5272 if (headpicture.iscreated) {
5273 kerning = kern[HEAD];
5274 widest = width = headpicture.dx;
5275 tallest = height = headpicture.dy;
5276 }
5277 else
5278 width = height = widest = tallest = kerning = 0;
5279
5280 if (!nocommas) {
5281 if (vertical && (width < grouppicture->dx))
5282 width = grouppicture->dx;
5283 else if (!vertical && (height < grouppicture->dy))
5284 height = grouppicture->dy;
5285 if (widest < grouppicture->dx)
5286 widest = grouppicture->dx;
5287 if (tallest < grouppicture->dy)
5288 tallest = grouppicture->dy;
5289 }
5290
5291 for (i = 0; i < digits + nondigits; i++) {
5292 if (i && !nocommas &&
5293 (((revcom == 0) && (buffer[i-1] != '<') && (((digits - i) % group) == 0)) ||
5294 ((revcom != 0) && (buffer[i] != '<')&& (((i % group) == 0))))) {
5295 if (lastprinted != HEAD) kerning += kern[groupseparator];
5296 lastprinted = groupseparator;
5297 if (vertical)
5298 height += grouppicture->dy;
5299 else
5300 width += grouppicture->dx;
5301 }
5302
5303 for (j = 0; j <= COMMA; j++) if (buffer[i] == characters[j])
5304 break;
5305 gcldebug("Digit[%i] = %c", i, characters[j]);
5306
5307 /*
5308 * If we have not used this image, open it.
5309 * But remember, it may not have been listed,
5310 * or it may not exist.
5311 */
5312 if (picture[j].isused == 0) {
5313 openpicture(j);
5314 picture[j].isused = 1;
5315 } /* picture not used */
5316
5317 if (picture[j].iscreated) {
5318 switch (buffer[i]) {
5319 case '%':
5320 if (lastprinted != HEAD) kerning += kern[COLONS];
5321 lastprinted = COLONS;
5322 break;
5323 case '-':
5324 if (lastprinted != HEAD) kerning += kern[DASHES];
5325 lastprinted = DASHES;
5326 break;
5327 case '<':
5328 if (lastprinted != HEAD) kerning += kern[MINUSES];
5329 lastprinted = MINUSES;
5330 break;
5331 case '>':
5332 if (lastprinted != HEAD) kerning += kern[PLUSSES];
5333 lastprinted = PLUSSES;
5334 break;
5335 case '^':
5336 if (lastprinted != HEAD) kerning += kern[TIMES];
5337 lastprinted = TIMES;
5338 break;
5339 case '@':
5340 if (lastprinted != HEAD) kerning += kern[ZONES];
5341 lastprinted = ZONES;
5342 break;
5343 case ',':
5344 if (lastprinted != HEAD) kerning += kern[COMMAS];
5345 lastprinted = COMMAS;
5346 break;
5347 case '~':
5348 if (lastprinted != HEAD) kerning += kern[SPACES];
5349 lastprinted = SPACES;
5350 break;
5351 case ';':
5352 if (lastprinted != HEAD) kerning += kern[DOTS];
5353 lastprinted = DOTS;
5354 break;
5355 default:
5356 if (lastprinted != HEAD) kerning += kern[lastprinted];
5357 lastprinted = DIGITS;
5358 break;
5359 }
5360
5361 if (vertical) {
5362 if (width < picture[j].dx)
5363 width = picture[j].dx;
5364 height += picture[j].dy;
5365 }
5366 else {
5367 width += picture[j].dx;
5368 if (height < picture[j].dy)
5369 height = picture[j].dy;
5370 }
5371 if (widest < picture[j].dx)
5372 widest = picture[j].dx;
5373 if (tallest < picture[j].dy)
5374 tallest = picture[j].dy;
5375 } /* image dimensions */
5376 } /* for each digit and non-digit */
5377
5378 if (tailpicture.iscreated) {
5379 if (lastprinted != HEAD)
5380 kerning += kern[TAIL];
5381
5382 if (vertical) {
5383 if (width < tailpicture.dx)
5384 width = tailpicture.dx;
5385 height += tailpicture.dy;
5386 }
5387 else {
5388 width += tailpicture.dx;
5389 if (height < tailpicture.dy)
5390 height = tailpicture.dy;
5391 }
5392 if (widest < tailpicture.dx)
5393 widest = tailpicture.dx;
5394 if (tallest < tailpicture.dy)
5395 tallest = tailpicture.dy;
5396 }
5397
5398 if (lastprinted == HEAD)
5399 kerning = 0;
5400
5401 if (vertical)
5402 height += kerning;
5403 else
5404 width += kerning;
5405
5406 /* Call Inspector Kern */
5407 if ((width < widest) || (height < tallest)) {
5408 if (debugging) {
5409 gcldebug(NULL);
5410 fprintf(stderr, "Inspector Kern says: \"Forget it, Buster!\"\n");
5411 gcldebug("Overriding specified kerning and trying again");
5412 }
5413 if (kern[DIGITS] < 0)
5414 kern[DIGITS] = 0;
5415 else if (kern[COMMAS] < 0)
5416 kern[COMMAS] = 0;
5417 else if (kern[DOTS] < 0)
5418 kern[DOTS] = 0;
5419 else if (kern[DASHES] < 0)
5420 kern[DASHES] = 0;
5421 else if (kern[COLONS] < 0)
5422 kern[COLONS] = 0;
5423 else if (kern[PLUSSES] < 0)
5424 kern[PLUSSES] = 0;
5425 else if (kern[MINUSES] < 0)
5426 kern[MINUSES] = 0;
5427 else if (kern[TIMES] < 0)
5428 kern[TIMES] = 0;
5429 else if (kern[ZONES] < 0)
5430 kern[ZONES] = 0;
5431 else if (kern[SPACES] < 0)
5432 kern[SPACES] = 0;
5433 else kern[HEAD] = kern[TAIL] = 0;
5434 rejected = 1;
5435 }
5436 else {
5437 if (debugging) {
5438 gcldebug(NULL);
5439 fprintf(stderr, rejected ? "Inspector Kern says: \"Much better!\"\n" :
5440 "Inspector Kern approved.\n");
5441 }
5442 break;
5443 } /* Inspector Kern */
5444 } /* for(;;) */
5445
5446 /*
5447 * At this point "width" and "height" would be the
5448 * actual dimensions of the counter layer if not for
5449 * the alignment shift feature of GCL.
5450 *
5451 * Because this feature may increase the counter layer,
5452 * we need to do three more things before proceding to
5453 * pass two:
5454 *
5455 * 1. Calculate the "origin" of each graphic - this may
5456 * turn out to be negative.
5457 *
5458 * 2. Adjust origins so none is negative, and at least one
5459 * equals to zero.
5460 *
5461 * 3. Calculate the new height or width.
5462 *
5463 * The "origin" refers to the topmost pixels in a horizontal
5464 * counter; the leftmost pixels in a vertical one.
5465 *
5466 * NOTE: We reverse the sign of vertical alignment shift
5467 * (i.e. we subtract it, not add) because GCL defines
5468 * a negative vertical shift as shifting down, while
5469 * GIF (and computer graphics in general) increases
5470 * downwards.
5471 */
5472
5473 if (vertical) {
5474 if (headpicture.iscreated) {
5475 headpicture.origin = (halignflag[HEAD] == 0) ?
5476 (width - headpicture.dx) / 2 :
5477 (halignflag[HEAD] > 0) ? width - headpicture.dx : 0;
5478 headpicture.origin += hashift[HEAD];
5479 }
5480
5481 for (i = 0; i <10; i++) if (picture[i].iscreated) {
5482 picture[i].origin = (halignflag[DIGITS] == 0) ?
5483 (width - picture[i].dx) / 2 :
5484 (halignflag[DIGITS] > 0) ? width - picture[i].dx : 0;
5485 picture[i].origin += hashift[DIGITS];
5486 }
5487
5488 if (commapicture.iscreated) {
5489 commapicture.origin = (halignflag[COMMAS] == 0) ?
5490 (width - commapicture.dx) / 2 :
5491 (halignflag[COMMAS] > 0) ? width - commapicture.dx : 0;
5492 commapicture.origin += hashift[COMMAS];
5493 }
5494
5495 if (dotpicture.iscreated) {
5496 dotpicture.origin = (halignflag[DOTS] == 0) ?
5497 (width - dotpicture.dx) / 2 :
5498 (halignflag[DOTS] > 0) ? width - dotpicture.dx : 0;
5499 dotpicture.origin += hashift[DOTS];
5500 }
5501
5502 if (spacepicture.iscreated) {
5503 spacepicture.origin = (halignflag[SPACES] == 0) ?
5504 (width - spacepicture.dx) / 2 :
5505 (halignflag[SPACES] > 0) ? width - spacepicture.dx : 0;
5506 spacepicture.origin += hashift[SPACES];
5507 }
5508
5509 if (tailpicture.iscreated) {
5510 tailpicture.origin = (halignflag[TAIL] == 0) ?
5511 (width - tailpicture.dx) / 2 :
5512 (halignflag[TAIL] > 0) ? width - tailpicture.dx : 0;
5513 tailpicture.origin += hashift[TAIL];
5514 }
5515
5516 if (dashpicture.iscreated) {
5517 dashpicture.origin = (halignflag[DASHES] == 0) ?
5518 (width - dashpicture.dx) / 2 :
5519 (halignflag[DASHES] > 0) ? width - dashpicture.dx : 0;
5520 dashpicture.origin += hashift[DASHES];
5521 }
5522
5523 if (colonpicture.iscreated) {
5524 colonpicture.origin = (halignflag[COLONS] == 0) ?
5525 (width - colonpicture.dx) / 2 :
5526 (halignflag[COLONS] > 0) ? width - colonpicture.dx : 0;
5527 colonpicture.origin += hashift[COLONS];
5528 }
5529
5530 if (pluspicture.iscreated) {
5531 pluspicture.origin = (halignflag[PLUSSES] == 0) ?
5532 (width - pluspicture.dx) / 2 :
5533 (halignflag[PLUSSES] > 0) ? width - pluspicture.dx : 0;
5534 pluspicture.origin += hashift[PLUSSES];
5535 }
5536
5537 if (minuspicture.iscreated) {
5538 minuspicture.origin = (halignflag[MINUSES] == 0) ?
5539 (width - minuspicture.dx) / 2 :
5540 (halignflag[MINUSES] > 0) ? width - minuspicture.dx : 0;
5541 minuspicture.origin += hashift[MINUSES];
5542 }
5543
5544 if (timepicture.iscreated) {
5545 timepicture.origin = (halignflag[TIMES] == 0) ?
5546 (width - timepicture.dx) / 2 :
5547 (halignflag[TIMES] > 0) ? width - timepicture.dx : 0;
5548 timepicture.origin += hashift[TIMES];
5549 }
5550
5551 if (zonepicture.iscreated) {
5552 zonepicture.origin = (halignflag[ZONES] == 0) ?
5553 (width - zonepicture.dx) / 2 :
5554 (halignflag[ZONES] > 0) ? width - zonepicture.dx : 0;
5555 zonepicture.origin += hashift[TIMES];
5556 }
5557 }
5558 else { /* horizontal */
5559 if (headpicture.iscreated) {
5560 headpicture.origin = (valignflag[HEAD] == 0) ?
5561 (height - headpicture.dy) / 2 :
5562 (valignflag[HEAD] > 0) ? height - headpicture.dy : 0;
5563 headpicture.origin -= vashift[HEAD];
5564 }
5565
5566 for (i = 0; i < 10; i++) if (picture[i].iscreated) {
5567 picture[i].origin = (valignflag[DIGITS] == 0) ?
5568 (height - picture[i].dy) / 2 :
5569 (valignflag[DIGITS] > 0) ? height - picture[i].dy : 0;
5570 picture[i].origin -= vashift[DIGITS];
5571 }
5572
5573 if (commapicture.iscreated) {
5574 commapicture.origin = (valignflag[COMMAS] == 0) ?
5575 (height - commapicture.dy) / 2 :
5576 (valignflag[COMMAS] > 0) ? height - commapicture.dy : 0;
5577 commapicture.origin -= vashift[COMMAS];
5578 }
5579
5580 if (dotpicture.iscreated) {
5581 dotpicture.origin = (valignflag[DOTS] == 0) ?
5582 (height - dotpicture.dy) / 2 :
5583 (valignflag[DOTS] > 0) ? height - dotpicture.dy : 0;
5584 dotpicture.origin -= vashift[DOTS];
5585 }
5586
5587 if (spacepicture.iscreated) {
5588 spacepicture.origin = (valignflag[SPACES] == 0) ?
5589 (height - spacepicture.dy) / 2 :
5590 (valignflag[SPACES] > 0) ? height - spacepicture.dy : 0;
5591 spacepicture.origin -= vashift[SPACES];
5592 }
5593
5594 if (tailpicture.iscreated) {
5595 tailpicture.origin = (valignflag[TAIL] == 0) ?
5596 (height - tailpicture.dy) / 2 :
5597 (valignflag[TAIL] > 0) ? height - tailpicture.dy : 0;
5598 tailpicture.origin -= vashift[TAIL];
5599 }
5600
5601 if (dashpicture.iscreated) {
5602 dashpicture.origin = (valignflag[DASHES] == 0) ?
5603 (height - dashpicture.dy) / 2 :
5604 (valignflag[DASHES] > 0) ? height - dashpicture.dy : 0;
5605 dashpicture.origin -= vashift[DASHES];
5606 }
5607
5608 if (colonpicture.iscreated) {
5609 colonpicture.origin = (valignflag[COLONS] == 0) ?
5610 (height - colonpicture.dy) / 2 :
5611 (valignflag[COLONS] > 0) ? height - colonpicture.dy : 0;
5612 colonpicture.origin -= vashift[COLONS];
5613 }
5614
5615 if (pluspicture.iscreated) {
5616 pluspicture.origin = (valignflag[PLUSSES] == 0) ?
5617 (height - pluspicture.dy) / 2 :
5618 (valignflag[PLUSSES] > 0) ? height - pluspicture.dy : 0;
5619 pluspicture.origin -= vashift[PLUSSES];
5620 }
5621
5622 if (minuspicture.iscreated) {
5623 minuspicture.origin = (valignflag[MINUSES] == 0) ?
5624 (height - minuspicture.dy) / 2 :
5625 (valignflag[MINUSES] > 0) ? height - minuspicture.dy : 0;
5626 minuspicture.origin -= vashift[MINUSES];
5627 }
5628
5629 if (timepicture.iscreated) {
5630 timepicture.origin = (valignflag[TIMES] == 0) ?
5631 (height - timepicture.dy) / 2 :
5632 (valignflag[TIMES] > 0) ? height - timepicture.dy : 0;
5633 timepicture.origin -= vashift[TIMES];
5634 }
5635
5636 if (zonepicture.iscreated) {
5637 zonepicture.origin = (valignflag[ZONES] == 0) ?
5638 (height - zonepicture.dy) / 2 :
5639 (valignflag[ZONES] > 0) ? height - zonepicture.dy : 0;
5640 zonepicture.origin -= vashift[TIMES];
5641 }
5642 }
5643
5644 delta = 0x7FFFFFFF;
5645
5646 for (i = 0; i <= TAILPICTURE; i++)
5647 if (picture[i].iscreated && (delta > picture[i].origin))
5648 delta = picture[i].origin;
5649
5650 for (i = 0; i <= TAILPICTURE; i++) if (picture[i].iscreated) {
5651 picture[i].origin -= delta;
5652
5653 if (vertical) {
5654 if (width < (picture[i].dx + picture[i].origin))
5655 width = picture[i].dx + picture[i].origin;
5656 }
5657 else if (height < (picture[i].dy + picture[i].origin))
5658 height = picture[i].dy + picture[i].origin;
5659 }
5660
5661 /*
5662 * If width or height is still zero or less, we make them equal
5663 * to one.
5664 */
5665 if (width <= 0) width = 1;
5666 if (height <= 0) height = 1;
5667
5668 /* P A S S T W O */
5669 counter = gdImageCreate(width, height);
5670 gcldebug("Creating counter layer (width = %i, height = %i)", width, height);
5671 invisible = gdImageColorAllocate(counter, invis.red, invis.green, invis.blue);
5672 gdImageColorTransparent(counter, invisible);
5673
5674 lastprinted = HEAD;
5675
5676 if (vertical) {
5677 y = 0;
5678 if (headpicture.iscreated) {
5679 x = headpicture.origin;
5680 gcldebug("Copying head vertically at x = %i, y = %i", x, y);
5681 gdImageCopy(counter,
5682 headpicture.image ? headpicture.image : arraypicture.image,
5683 x,
5684 y,
5685 headpicture.x,
5686 headpicture.y,
5687 headpicture.dx,
5688 headpicture.dy);
5689 y += headpicture.dy + kern[HEAD];
5690 } /* head printed */
5691
5692 for (i = 0; i < digits + nondigits; i++) {
5693 /* "print" a group separator where appropriate */
5694 if (i && !nocommas &&
5695 (((revcom == 0) && (buffer[i-1] != '<') && (((digits - i) % group) == 0)) ||
5696 ((revcom != 0) && (buffer[i] != '<') && (((i % group) == 0))))) {
5697 x = grouppicture->origin;
5698 if (lastprinted != HEAD)
5699 y += kern[groupseparator];
5700 lastprinted = groupseparator;
5701 gcldebug("Copying group separator vertically at x = %i, y = %i", x, y);
5702 gdImageCopy(counter,
5703 grouppicture->image ? grouppicture->image : arraypicture.image,
5704 x,
5705 y,
5706 grouppicture->x,
5707 grouppicture->y,
5708 grouppicture->dx,
5709 grouppicture->dy);
5710 y += grouppicture->dy;
5711 } /* group separator */
5712
5713 /* find the digit or non-digit */
5714 for (j = 0; j <= COMMA; j++) if (buffer[i] == characters[j])
5715 break;
5716 if (picture[j].iscreated) {
5717 /* Apply vertical kerning */
5718 switch (buffer[i]) {
5719 case '%':
5720 if (lastprinted != HEAD)
5721 y += kern[COLONS];
5722 lastprinted = COLONS;
5723 break;
5724 case '-':
5725 if (lastprinted != HEAD)
5726 y += kern[DASHES];
5727 lastprinted = DASHES;
5728 break;
5729 case '<':
5730 if (lastprinted != HEAD)
5731 y += kern[MINUSES];
5732 lastprinted = MINUSES;
5733 break;
5734 case '>':
5735 if (lastprinted != HEAD)
5736 y += kern[PLUSSES];
5737 lastprinted = PLUSSES;
5738 break;
5739 case '^':
5740 if (lastprinted != HEAD)
5741 y += kern[TIMES];
5742 lastprinted = TIMES;
5743 break;
5744 case '@':
5745 if (lastprinted != HEAD)
5746 y += kern[ZONES];
5747 lastprinted = ZONES;
5748 break;
5749 case ',':
5750 if (lastprinted != HEAD)
5751 y += kern[COMMAS];
5752 lastprinted = COMMAS;
5753 break;
5754 case '~':
5755 if (lastprinted != HEAD)
5756 y += kern[SPACES];
5757 lastprinted = SPACES;
5758 break;
5759 case ';':
5760 if (lastprinted != HEAD)
5761 y += kern[DOTS];
5762 lastprinted = DOTS;
5763 default:
5764 /*
5765 * If a digit was preceded by a non-digit
5766 * use the kerning of the non-digit.
5767 */
5768 if (lastprinted != HEAD)
5769 y += kern[lastprinted];
5770 lastprinted = DIGITS;
5771 break;
5772 }
5773
5774 /* fit the digit or non-digit horizontally */
5775 x = picture[j].origin;
5776 gcldebug("Copying %s vertically at x = %i, y = %i", picname[j], x, y);
5777 gdImageCopy(counter,
5778 picture[j].image ? picture[j].image : arraypicture.image,
5779 x,
5780 y,
5781 picture[j].x,
5782 picture[j].y,
5783 picture[j].dx,
5784 picture[j].dy);
5785 y += picture[j].dy;
5786 } /* image exists */
5787 } /* digits and non-digits printed */
5788
5789 if (tailpicture.iscreated) {
5790 x = tailpicture.origin;
5791 if (lastprinted != HEAD)
5792 y += kern[TAIL];
5793 gcldebug("Copying tail vertically at x = %i, y = %i", x, y);
5794 gdImageCopy(counter,
5795 tailpicture.image ? tailpicture.image : arraypicture.image,
5796 x,
5797 y,
5798 tailpicture.x,
5799 tailpicture.y,
5800 tailpicture.dx,
5801 tailpicture.dy);
5802 } /* tail printed */
5803 } /* vertical counter */
5804 else {
5805 x = 0;
5806 if (headpicture.iscreated) {
5807 y = headpicture.origin;
5808 gcldebug("Copying head horizontally at x = %i, y = %i", x, y);
5809 gdImageCopy(counter,
5810 headpicture.image ? headpicture.image : arraypicture.image,
5811 x,
5812 y,
5813 headpicture.x,
5814 headpicture.y,
5815 headpicture.dx,
5816 headpicture.dy);
5817 x += headpicture.dx + kern[HEAD];
5818 } /* head printed */
5819
5820 for (i = 0; i < digits + nondigits; i++) {
5821 /* "print" a group separator where appropriate */
5822 if (i && !nocommas &&
5823 (((revcom == 0) && (buffer[i-1] != '<') && (((digits - i) % group) == 0)) ||
5824 ((revcom != 0) && (buffer[i] != '<') && (((i % group) == 0))))) {
5825 y = grouppicture->origin;
5826 if (lastprinted != HEAD)
5827 x += kern[groupseparator];
5828 lastprinted = groupseparator;
5829 gcldebug("Copying group separator horizontally at x = %i, y = %i", x, y);
5830 gdImageCopy(counter,
5831 grouppicture->image ? grouppicture->image : arraypicture.image,
5832 x,
5833 y,
5834 grouppicture->x,
5835 grouppicture->y,
5836 grouppicture->dx,
5837 grouppicture->dy);
5838 x += grouppicture->dx;
5839 } /* group separator */
5840
5841 /* find out what digit or non-digit to use */
5842 for (j = 0; j <= COMMA; j++) if (buffer[i] == characters[j])
5843 break;
5844 if (picture[j].iscreated) {
5845 switch (buffer[i]) {
5846 case '%':
5847 if (lastprinted != HEAD)
5848 x += kern[COLONS];
5849 lastprinted = COLONS;
5850 break;
5851 case '-':
5852 if (lastprinted != HEAD)
5853 x += kern[DASHES];
5854 lastprinted = DASHES;
5855 break;
5856 case '<':
5857 if (lastprinted != HEAD)
5858 x += kern[MINUSES];
5859 lastprinted = MINUSES;
5860 break;
5861 case '>':
5862 if (lastprinted != HEAD)
5863 x += kern[PLUSSES];
5864 lastprinted = PLUSSES;
5865 break;
5866 case '^':
5867 if (lastprinted != HEAD)
5868 x += kern[TIMES];
5869 lastprinted = TIMES;
5870 break;
5871 case '@':
5872 if (lastprinted != HEAD)
5873 x += kern[ZONES];
5874 lastprinted = ZONES;
5875 break;
5876 case ',':
5877 if (lastprinted != HEAD)
5878 x += kern[COMMAS];
5879 lastprinted = COMMAS;
5880 break;
5881 case '~':
5882 if (lastprinted != HEAD)
5883 x += kern[SPACES];
5884 lastprinted = SPACES;
5885 break;
5886 case ';':
5887 if (lastprinted != HEAD)
5888 x += kern[DOTS];
5889 lastprinted = DOTS;
5890 break;
5891 default:
5892 if (lastprinted != HEAD)
5893 x += kern[lastprinted];
5894 lastprinted = DIGITS;
5895 }
5896 /* fit the digit vertically */
5897 y = picture[j].origin;
5898 /* now copy it */
5899 gdImageCopy(counter,
5900 picture[j].image ? picture[j].image : arraypicture.image,
5901 x,
5902 y,
5903 picture[j].x,
5904 picture[j].y,
5905 picture[j].dx,
5906 picture[j].dy);
5907 gcldebug("Copying %s horizontally at x = %i, y = %i", picname[j], x, y);
5908 x += picture[j].dx;
5909 } /* image exists */
5910 } /* digits printed */
5911
5912 if (tailpicture.iscreated) {
5913 y = tailpicture.origin;
5914 if (lastprinted != HEAD)
5915 x += kern[TAIL];
5916 gcldebug("Copying tail horizontally at x = %i, y = %i", x, y);
5917 gdImageCopy(counter,
5918 tailpicture.image ? tailpicture.image : arraypicture.image,
5919 x,
5920 y,
5921 tailpicture.x,
5922 tailpicture.y,
5923 tailpicture.dx,
5924 tailpicture.dy);
5925 } /* tail printed */
5926 } /* horizontal counter */
5927
5928 /* Destroy individual digits, comma, head, and tail */
5929 for (i = 0; i <= TAILPICTURE; i++) if (picture[i].image && (picture[i].image != defaultimage[i])) {
5930 gdImageDestroy(picture[i].image);
5931 picture[i].image = NULL;
5932 gcldebug("Destroyed %s image", picname[i]);
5933 }
5934
5935 /* STEP TWO - create the background layer */
5936
5937 /*
5938 * This one is simple: If a background graphic
5939 * is defined, open it.
5940 */
5941
5942 openpicture(BKGPICTURE);
5943
5944 /* STEP THREE - create the frame layer */
5945
5946 /*
5947 * The frame layer is underneath the other two layers.
5948 * The simplest frame layer is nothing but plain
5949 * background, perhaps transparent.
5950 *
5951 * We can also make it quite fancy. But remember:
5952 * Because of the structure of a GIF file, we only
5953 * have 256 colors to work with in the whole graphic.
5954 *
5955 * We start step three by calculating the size of the
5956 * frame layer.
5957 *
5958 * First of all, the frame layer must be large enough
5959 * to encompass the counter and the "background" graphic.
5960 *
5961 * We already have the dimensions of the counter layer
5962 * in the width and height variables.
5963 */
5964
5965 if (bkgpicture.iscreated) {
5966 if (width < bkgpicture.dx)
5967 width = bkgpicture.dx;
5968 if (height < bkgpicture.dy)
5969 height = bkgpicture.dy;
5970
5971 /*
5972 * "width" and "height" now contain the dimmensions
5973 * of the window that exactly encompasses the counter
5974 * and the background layers centered over each other.
5975 * Let this window be called the focus window.
5976 *
5977 * Now calculate the position of the counter and background
5978 * layers inside the focus window, disregarding any shifts.
5979 * Do this by simply centering the two layers within the
5980 * focus window.
5981 *
5982 * Remember we are still within the "if" statement here.
5983 */
5984
5985 bx = (width - bkgpicture.dx) / 2;
5986 by = (height - bkgpicture.dy) / 2;
5987 }
5988 cx = (width - gdImageSX(counter)) / 2;
5989 cy = (height - gdImageSY(counter)) / 2;
5990
5991 /* Apply any shifts. Do it only if we have a background layer. */
5992 if (bkgpicture.iscreated) {
5993 register int temp;
5994
5995 if (vshiftflag) {
5996 if (vshiftflag < 0) {
5997 /*
5998 * Shifting the counter layer up. This is effectively the
5999 * same as shifting the background layer down, and easier
6000 * to compute that way.
6001 */
6002 by += vshift;
6003
6004 /*
6005 * We may now be out of bounds of the focus window.
6006 * Adjust its height.
6007 */
6008 if (height < (by + bkgpicture.dy))
6009 height = by + bkgpicture.dy;
6010 }
6011 else {
6012 /* Shifting the counter layer down. */
6013
6014 cy += vshift;
6015
6016 /* Adjust height */
6017 if (height < (cy + gdImageSY(counter)))
6018 height = cy + gdImageSY(counter);
6019 }
6020
6021 /*
6022 * This may have made the focus window too big.
6023 * So, cut off any empty space on top.
6024 */
6025 temp = cy;
6026 if (temp > by)
6027 temp = by;
6028 height -= temp;
6029 by -= temp;
6030 cy -= temp;
6031 }
6032
6033 if(hshiftflag) {
6034 if (hshiftflag < 0) {
6035 /*
6036 * Shifting the counter layer left.
6037 * Same as shifting the background layer right.
6038 */
6039 bx += hshift;
6040 if (width < (bx + gdImageSX(bkgpicture.image)))
6041 width = bx + gdImageSX(bkgpicture.image);
6042 }
6043 else {
6044 /* Shifting the counter layer right */
6045 cx += hshift;
6046 if (width < (cx + gdImageSX(counter)))
6047 width = cx + gdImageSX(counter);
6048 }
6049
6050 temp = cx;
6051 if (temp > bx)
6052 temp = bx;
6053 width -= temp;
6054 bx -= temp;
6055 cx -= temp;
6056 }
6057 }
6058
6059 /*
6060 * Now, make room for any padding.
6061 *
6062 * Finally, add the dimensions of any actual frame.
6063 */
6064
6065 width += lpad + rpad + frames[frametype].left + frames[frametype].right;
6066 height += tpad + bpad + frames[frametype].top + frames[frametype].bottom;
6067 bx += lpad + frames[frametype].left;
6068 cx += lpad + frames[frametype].left;
6069 by += tpad + frames[frametype].top;
6070 cy += tpad + frames[frametype].top;
6071
6072 /*
6073 * Now we have enough information to create the image
6074 * of the frame layer.
6075 *
6076 * Since this is the same image where all three layers
6077 * will merge, we just refer to it as "image."
6078 *
6079 * But at this point it is just the frame layer, its
6080 * name notwithstanding.
6081 */
6082
6083 image = gdImageCreate(width, height);
6084 invisible = transrequired(frames[frametype]) ||
6085 (transok(frames[frametype]) && transparent) ?
6086 gdImageColorAllocate(image, invis.red, invis.green, invis.blue) : -1;
6087 gdImageColorTransparent(image, invisible);
6088 bgcolor = gdImageColorAllocate(image, bkg.red, bkg.green, bkg.blue);
6089
6090 /*
6091 * At last we have everything we need to build the final
6092 * image.
6093 *
6094 * But we have a dilemma. It stems from the fact GIF
6095 * images are limited to 256 colors, including the
6096 * possibly transparent background.
6097 *
6098 * That is not a problem: The gd library we are using
6099 * can easily reduce the number of colors as more images
6100 * are being added. But that is where the dilemma comes from:
6101 *
6102 * To get a sharp image, we should favor the colors
6103 * of the counter over those of the background,
6104 * and the colors of the background over those of the
6105 * frame.
6106 *
6107 * Yet, to place the frame underneath the background
6108 * we need to draw the frame before the background.
6109 * And to have the background under the counter, we
6110 * need to copy the counter last. This is the exact
6111 * opposite of what we need.
6112 *
6113 * Our two options are the trade between speed and
6114 * quality.
6115 *
6116 * If we opt for speed, we draw the frame first, the
6117 * counter last. We can do this if all of our graphic
6118 * source files are optimized, i.e., their total
6119 * number of colors does not exceed 256, or if the
6120 * color reduction still results in a pleasing image.
6121 *
6122 * If, on the other hand, we choose quality, we need
6123 * to copy the counter to the image first, the frame
6124 * last. After that, we re-copy the other images in
6125 * reversed order. That means that, save for the frame,
6126 * all images are copied twice.
6127 *
6128 * Thus we can obtain quality at the cost of some speed,
6129 * or speed while possibly losing some quality.
6130 *
6131 * Which way does GCL choose? Well, it does not. I am
6132 * a strong believer in user choices, rather than
6133 * programmer choices.
6134 *
6135 * My solution: By default, GCL chooses speed, but if
6136 * you enter the "optimize" keyword in the source code,
6137 * GCL chooses quality. You can also type "optimize none"
6138 * to opt for speed explicitly.
6139 */
6140
6141 if (optimize) {
6142 /* Copy the counter image to force its color palette */
6143 gdImageCopy(image, counter, cx, cy,
6144 0, 0, gdImageSX(counter), gdImageSY(counter));
6145
6146 /* Copy the background image to add its palette to image */
6147 if (bkgpicture.iscreated)
6148 gdImageCopy(image,
6149 bkgpicture.image ? bkgpicture.image : arraypicture.image,
6150 bx,
6151 by,
6152 bkgpicture.x,
6153 bkgpicture.y,
6154 bkgpicture.dx,
6155 bkgpicture.dy);
6156 }
6157
6158 /* Draw any frame */
6159 frames[frametype].draw(image, bgcolor, invisible, width, height);
6160
6161 /* Add the tile, if any */
6162 openpicture(TILE);
6163 /*
6164 * That may not have been enough: If all we got is a reference
6165 * to the array image, we must create a separate gdImage. This
6166 * is because gd 1.3 will not tile from a partial image.
6167 */
6168 if (tilepicture.isarray) {
6169 tilepicture.image = gdImageCreate(tilepicture.dx, tilepicture.dy);
6170 if (tilepicture.image != NULL) {
6171 gdImageCopy(tilepicture.image,
6172 arraypicture.image,
6173 0,
6174 0,
6175 tilepicture.x,
6176 tilepicture.y,
6177 tilepicture.dx,
6178 tilepicture.dy);
6179 /*
6180 * The following line is not necessary.
6181 * So it is commented out. But I keep it
6182 * there, albeit as a comment, as it may
6183 * come handy in some future version. In that
6184 * case I want to be reminded it is NOT there.
6185 */
6186 /* tilepicture.isarray = tilepicture.x = tilepicture.y = 0; */
6187 }
6188 }
6189
6190 if (tilepicture.image != NULL) {
6191 gdImageSetTile(image, tilepicture.image);
6192
6193 gdImageFilledRectangle(image, frames[frametype].left, frames[frametype].top,
6194 width - frames[frametype].right - 1,
6195 height - frames[frametype].bottom - 1, gdTiled);
6196
6197 if (tilepicture.image != tileimage) {
6198 gdImageDestroy(tilepicture.image);
6199 tilepicture.image = NULL;
6200 gcldebug("Tile image destroyed");
6201 }
6202 }
6203
6204 /* Copy the background image over the frame image */
6205 if (bkgpicture.iscreated) {
6206 gdImageCopy(image,
6207 bkgpicture.image ? bkgpicture.image : arraypicture.image,
6208 bx,
6209 by,
6210 bkgpicture.x,
6211 bkgpicture.y,
6212 bkgpicture.dx,
6213 bkgpicture.dy);
6214
6215 /* Destroy it */
6216 if (bkgpicture.image && (bkgpicture.image != bkgimage)) {
6217 gdImageDestroy(bkgpicture.image);
6218 bkgpicture.image = NULL;
6219 gcldebug("Background image destroyed");
6220 }
6221 }
6222
6223 /* Copy the counter image over everything else */
6224 gdImageCopy(image, counter, cx, cy,
6225 0, 0, gdImageSX(counter), gdImageSY(counter));
6226
6227 /* Destroy it */
6228 gdImageDestroy(counter);
6229 counter = NULL;
6230 gcldebug("Counter image destroyed");
6231
6232 /* Send it out */
6233 if (!localuse) {
6234 if (expires <= 0)
6235 printf("Cache-Control: no-cache\n");
6236 if (expires >= 0) {
6237 now = gmtime(&timer);
6238 printf("Last-Modified: %s, %i %s %i %.2i:%.2i:%.2i GMT\n",
6239 day[now->tm_wday], now->tm_mday, month[now->tm_mon],
6240 now->tm_year + 1900, now->tm_hour, now->tm_min, now->tm_sec);
6241 }
6242 timer += expires;
6243 now = gmtime(&timer);
6244 printf("Expires: %s, %i %s %i %.2i:%.2i:%.2i GMT\n"
6245 "Content-Type: image/gif\n\n",
6246 day[now->tm_wday], now->tm_mday, month[now->tm_mon],
6247 now->tm_year + 1900, now->tm_hour, now->tm_min, now->tm_sec);
6248 }
6249 gdImageGif(image, stdout);
6250 fflush(stdout);
6251
6252 /* Clean up */
6253 gdImageDestroy(image);
6254 image = NULL;
6255 gcldebug("Output image destroyed");
6256
6257 for (i = 0; i < GRAPHICS; i++) {
6258 if (picture[i].graphic) {
6259 free (picture[i].graphic);
6260 picture[i].graphic = NULL;
6261 }
6262 if (picture[i].image && (picture[i].image != defaultimage[i])) {
6263 gdImageDestroy(picture[i].image);
6264 picture[i].image = NULL;
6265 gcldebug("Destroyed %s image", picname[i]);
6266 }
6267 }
6268
6269 }
6270
main(int argc,char * argv[])6271 int main(int argc, char *argv[]) {
6272 int i, j;
6273 int retval;
6274 int parser;
6275 scounter_t cmdcount = -1;
6276 int noredirect = 0;
6277 int nosilent = 0;
6278 int cmdwhatami = SHOWCOUNT;
6279 time_t whattime;
6280 #ifdef __FreeBSD__
6281 #define gmtoff now->tm_gmtoff
6282 #else
6283 long gmtoff;
6284 #endif
6285
6286 timer = time(NULL);
6287 randomnumber = -timer;
6288
6289 if (argc > 1) {
6290 for (i = 1; i < argc; i++) {
6291 if (argv[i][0] == '-') {
6292 if (argv[i][1] == '\0')
6293 fprintf(stderr, "GCL Warning: Dangling dash in command line argument %i.\n", i);
6294 else for (j = 1; argv[i][j]; j++) switch (argv[i][j]) {
6295 case '0':
6296 case '1':
6297 case '2':
6298 case '3':
6299 case '4':
6300 case '5':
6301 case '6':
6302 case '7':
6303 case '8':
6304 case '9':
6305 mdoverride = argv[i][j] - '0';
6306 break;
6307 case 'a':
6308 cmdwhatami |= SHOWDATE;
6309 break;
6310 case 'A':
6311 cmdwhatami &= ~SHOWDATE;
6312 break;
6313 case 'c':
6314 compileonly = 1;
6315 break;
6316 case 'C':
6317 compileonly = 0;
6318 break;
6319 case 'd':
6320 debugging = 1;
6321 break;
6322 case 'D':
6323 debugging = 0;
6324 break;
6325 case 'e':
6326 insertcomments = 1;
6327 break;
6328 case 'E':
6329 insertcomments = 0;
6330 break;
6331 case 'g':
6332 gallery = 1;
6333 break;
6334 case 'G':
6335 gallery = 0;
6336 break;
6337 case 'i':
6338 one = 0;
6339 break;
6340 case 'I':
6341 one = 1;
6342 break;
6343 case 'k':
6344 make = 1;
6345 break;
6346 case 'K':
6347 make = 0;
6348 break;
6349 case 'l':
6350 localuse = 1;
6351 break;
6352 case 'L':
6353 localuse = 0;
6354 break;
6355 case 'm':
6356 cmdwhatami |= SHOWTIME;
6357 break;
6358 case 'M':
6359 cmdwhatami &= ~SHOWTIME;
6360 break;
6361 case 'n':
6362 nocompile = 1;
6363 break;
6364 case 'N':
6365 nocompile = 0;
6366 break;
6367 case 'o':
6368 nocommas = 1;
6369 break;
6370 case 'O':
6371 nocommas = 0;
6372 break;
6373 case 'p':
6374 publish = 1;
6375 break;
6376 case 'P':
6377 publish = 0;
6378 break;
6379 case 'r':
6380 noredirect = 1;
6381 break;
6382 case 'R':
6383 noredirect = 0;
6384 break;
6385 case 's':
6386 nosilent = 1;
6387 break;
6388 case 'S':
6389 nosilent = 0;
6390 break;
6391 case 't':
6392 outputtext = 1;
6393 break;
6394 case 'T':
6395 outputtext = 0;
6396 break;
6397 case 'v':
6398 verbose = 1;
6399 break;
6400 case 'V':
6401 verbose = 0;
6402 break;
6403 default:
6404 fprintf(stderr, "GCL Warning: Ignoring unknown option `-%c'.\n", argv[i][j]);
6405 help |= 1;
6406 break;
6407 case 'h':
6408 help |= 2;
6409 break;
6410 case 'H':
6411 help &= ~2;
6412 break;
6413 case 'w':
6414 warnings = 1;
6415 break;
6416 case 'W':
6417 warnings = 0;
6418 break;
6419 case 'z':
6420 cmdwhatami |= SHOWZONE;
6421 break;
6422 case 'Z':
6423 cmdwhatami &= ~SHOWZONE;
6424 break;
6425 } /* switch */
6426 } /* '-' */
6427 else if (isdigit(argv[i][0]))
6428 cmdcount = atoi(argv[i]);
6429 else if (filename)
6430 fprintf(stderr, "GCL Warning: Ignoring unknown option `%s'.\n", argv[i]);
6431 else
6432 filename = argv[i];
6433 } /* for */
6434
6435 if (verbose) {
6436 fprintf(stderr, "GCL (Graphic Counter Language), v." GCLVERSION ":\n\n"
6437 "\tCopyright 1999 G. Adam Stanislav.\n"
6438 "\tAll rights reserved.\n\n"
6439 "\tFor more information visit\n"
6440 "\thttp://www.whizkidtech.net/gcl/\n\n"
6441 "\tFor current version visit\n"
6442 "\tftp://ftp.whizkidtech.net/cgi/gcl/\n\n"
6443 "\tFor license information read the file NNL, or visit\n"
6444 "\thttp://www.whizkidtech.net/nnl/\n\n");
6445
6446 if (!help) fprintf(stderr,
6447 "\tFor command line options enter\n\n"
6448 "\t\tgracula -h\n\n");
6449 }
6450
6451 if (help) {
6452 fprintf(stderr, "GCL Usage: gracula [-acdeghiklmnoprstvwz0..9] [<number>] [filename]\n\n"
6453 "\t-0 do not override minimum digits,\n"
6454 "\t-1..9 override minimum digits,\n"
6455 "\t-a show current date,\n"
6456 "\t-c compile only,\n"
6457 "\t-d debugging mode on,\n"
6458 "\t-e elaborate (insert comments),\n"
6459 "\t-g gallery (also good as test mode),\n"
6460 "\t-h help,\n"
6461 "\t-i inhibit (do not increase count),\n"
6462 "\t-k make (create custom version),\n"
6463 "\t-l local use,\n"
6464 "\t-m show current time,\n"
6465 "\t-n no compilation,\n"
6466 "\t-o omit commas,\n"
6467 "\t-p publish script to stdout,\n"
6468 "\t-r do not redirect,\n"
6469 "\t-s do not stay silent,\n"
6470 "\t-t text output (SSI),\n"
6471 "\t-v version,\n"
6472 "\t-w warnings on,\n"
6473 "\t-z show time zone,\n"
6474 "\t<number> Set counter to number,\n"
6475 "\tfilename GCL code file.\n\n"
6476 "\tUsing capital letters turns an option OFF (default).\n");
6477 if (help & 2)
6478 return 0;
6479 else if (localuse)
6480 return 3;
6481 } /* help */
6482 } /* argc > 1 */
6483
6484 if (nocompile)
6485 publish = 0;
6486 else if (publish) {
6487 register char *strptr;
6488
6489 insertcomments = compileonly = portable = 1;
6490 if (filename && *filename) {
6491 for (scriptname = strptr = filename; *strptr; strptr++)
6492 if (*strptr == '/') scriptname = strptr + 1;
6493 }
6494 }
6495
6496 if (localuse) {
6497 nosilent = noredirect = 1;
6498 }
6499
6500 if (filename) {
6501 gclfile = fopen(filename, "r+");
6502 if (gclfile == NULL) {
6503 perror(filename);
6504
6505 /*
6506 * Remember, this is CGI: We MUST
6507 * produce some output even if
6508 * we have no input file.
6509 *
6510 * Normally, we would just create
6511 * an error page, but we are not
6512 * making HTML code here. We need
6513 * to send a GIF out, even if all
6514 * we "show" is one transparent
6515 * pixel.
6516 */
6517
6518 if (!localuse) {
6519 gcldebug("Attempting to produce default GIF output");
6520 if (cmdcount >= 0)
6521 count = (counter_t)cmdcount;
6522 if (mdoverride) {
6523 mindigits = mdoverride;
6524 gcldebug("Overriding minimum digits: %i", mdoverride);
6525 }
6526 if (noredirect && redirect) {
6527 free(redirect);
6528 redirect = NULL;
6529 }
6530 if (nosilent)
6531 silent = 0;
6532 interpret();
6533 }
6534 cleanup();
6535 return 2;
6536 } /* error opening file */
6537 else
6538 flock(fileno(gclfile), LOCK_EX); /* Unix specific */
6539 } /* filename */
6540 else gclfile = stdin; /* no filename specified */
6541
6542 gcldebug("Entering the parser");
6543 parser = parse();
6544
6545 if ((gclprint != NULL) && ((cmdcount >= 0) || publish)) {
6546 free(gclprint);
6547 gclprint = NULL;
6548 shellcount = 0;
6549 }
6550
6551 /* Turn off compilation if not a counter, if make, or if "print" used */
6552 nocompile |= cmdwhatami | whatami | make | (gclnocompile && !publish) | (gclprint != NULL);
6553 /* Also turn off interpretation if make */
6554 compileonly |= make;
6555
6556 if (shellcount && gclprint) {
6557 count = strtoul(gclprint, NULL, 0);
6558 free(gclprint);
6559 gclprint = NULL;
6560 }
6561
6562 #ifdef __FreeBSD__
6563 whattime = timer + (time_t)gtz.secs;
6564 now = gtz.tz == STZ ? localtime(&whattime) : gmtime(&whattime);
6565 #else
6566 gmtoff = gtz.tz == STZ ? timer - mktime(gmtime(&timer)) : 0;
6567 #endif
6568
6569 zoneminutes = (gmtoff + gtz.secs) / 60;
6570 zonehours = zoneminutes / 60;
6571 if (zoneminutes < 0)
6572 zoneminutes = -zoneminutes;
6573 zoneminutes %= 60;
6574
6575 #ifndef __FreeBSD__
6576 whattime = timer + (time_t)gtz.secs;
6577 now = gtz.tz == STZ ? localtime(&whattime) : gmtime(&whattime);
6578 #endif
6579
6580 /*
6581 * C library does not give us a clue as to what week we are in.
6582 * But the time() function returns the number of seconds elapsed
6583 * since 1-1-1970 0:00:00. That happened to be a Thursday.
6584 * Three days later was a Sunday. We need to SUBTRACT three days
6585 * from the number of seconds elapsed, and divide the result by
6586 * the number of seconds in a week. To make it easier on the
6587 * microprocessor (division can take some time), we subtract
6588 * a number of additional weeks to bring us closer to our own time.
6589 *
6590 * The numbers used here will result in the number of weeks elapsed
6591 * since Sunday, 18 May 1997, 0:00:00 of the time zone used.
6592 *
6593 * We also need to adjust for whatever time zone the counter is
6594 * supposed to work.
6595 *
6596 * Note: This is not perfect and needs to be refined: It assumes
6597 * week starts on a Sunday. That is not true in all countries.
6598 */
6599 weeks = (whattime - 24*60*60*9999 + gmtoff) / (24*60*60*7);
6600
6601 if (rst > NEVER) {
6602 if (today.year != now->tm_year) {
6603 count = 1;
6604 }
6605 else if (today.month != now->tm_mon) {
6606 if (rst >= MONTHLY)
6607 count = 1;
6608 }
6609 else if ((today.day != now->tm_mday) && (rst == DAILY))
6610 count = 1;
6611 }
6612 else if (rst < NEVER) { /* i.e., WEEKLY */
6613 if (today.week != weeks)
6614 count = 1;
6615 }
6616
6617 if (gotcookies) {
6618 /*
6619 * Parse cookies
6620 *
6621 * This section may look somewhat confusing if you
6622 * are not thoroughly familiar with C pointers.
6623 *
6624 * HTTP cookies come to us as one big string
6625 * of pairs of name and value. The name is separated
6626 * from the value by an equal sign; the pairs are
6627 * separated, but not terminated, by a semicolon.
6628 *
6629 * As usual, we deal with errors (out of memory, in
6630 * this case) gracefully: We proceed with the program
6631 * at the cost of increasing the counter value when we
6632 * may have been asked not to...
6633 *
6634 * Note that if getenv() fails, that is not an error.
6635 * It simply means no cookie is set.
6636 */
6637 register char *e;
6638
6639 gcldebug("Looking into cookie jar");
6640 e = getenv(httpcookie);
6641 if (e) {
6642 cookies = strdup(e);
6643
6644 if (cookies == NULL) {
6645 gotcookies = 0;
6646 gclwarning("Not enough memory to read HTTP cookies");
6647 }
6648 else {
6649 for (i = 0; cookies[i]; i++) if (cookies[i] == '=')
6650 numcookies++;
6651 gcldebug("Found %i cookie%s", numcookies, "s" + (numcookies == 1));
6652
6653 cookiepairs = malloc(numcookies * sizeof(cookiepair));
6654 if (cookiepairs == NULL) {
6655 numcookies = gotcookies = 0;
6656 free(cookies);
6657 cookies = NULL;
6658 gclwarning("Not enough memory to analyze HTTP cookies");
6659 }
6660 else {
6661 for (i = 0, cookiepairs[0].name = e = cookies; *e; e++) {
6662 if (*e == ';') {
6663 *e = '\0';
6664 cookiepairs[i].name = e + 1;
6665 }
6666 else if (*e == '=') {
6667 *e = '\0';
6668 cookiepairs[i++].value = e + 1;
6669 }
6670 }
6671 }
6672 }
6673 }
6674 else gcldebug("Jar empty");
6675 }
6676
6677 if (!parser) {
6678 if (publish && (gclfile != stdin)) {
6679 flock(fileno(gclfile), LOCK_UN); /* Unix specific */
6680 fclose(gclfile);
6681 gclfile = stdout;
6682 }
6683 else if (gclfile == stdin)
6684 gclfile = stdout;
6685 else
6686 rewind(gclfile);
6687 if (!nocompile) {
6688 gcldebug("Entering the compiler");
6689 if (!secure && (cmdcount >= 0)) {
6690 if (warnings)
6691 fprintf(stderr, "GCL Warning: Changing count from " integer " to " integer ".\n", count, (counter_t)cmdcount);
6692 count = (counter_t)cmdcount;
6693 }
6694 if (noredirect && (redirectorinhibit(redirection)))
6695 one = 0;
6696 compile();
6697 gcldebug("Returned from the compiler");
6698 }
6699 else gcldebug("Skipping compilation (`-n' selected)");
6700
6701 if (gclfile != stdout) {
6702 flock(fileno(gclfile), LOCK_UN); /* Unix specific */
6703 fclose(gclfile);
6704 }
6705
6706 if (issigma) {
6707 count = mean + increment;
6708 }
6709
6710 if (script && !make && !publish) switch (fork()) { /* Unix specific */
6711 case 0:
6712 sprintf(lexbuffer, issigned ?
6713 "GCLCOUNT=" sinteger:
6714 "GCLCOUNT=" integer, count);
6715 putenv(lexbuffer);
6716 if (issigma == 0) {
6717 sprintf(lexbuffer, issigned ?
6718 "GCLNEXT=" sinteger:
6719 "GCLNEXT=" integer, (counter_t)(count + increment * (one && !inhibited && !nocompile)));
6720 putenv(lexbuffer);
6721 }
6722 putenv("GCLVER=" GCLVERSION);
6723 if (gclfile != stdout) {
6724 realpath(filename, lexbuffer); /* Unix specific */
6725 setenv("GCLFILE", lexbuffer, 1);
6726 }
6727 if (cookie)
6728 setenv("GCLCOOKIE", cookie, 1);
6729 system(script);
6730 return 0;
6731 default:
6732 break;
6733 }
6734
6735 if (!compileonly) {
6736 gcldebug("Entering the interpreter");
6737 if (mdoverride) {
6738 mindigits = mdoverride;
6739 gcldebug("Overriding minimum digits: %i", mdoverride);
6740 }
6741 if (cmdcount >= 0)
6742 count = (counter_t)cmdcount;
6743 if (noredirect && redirect) {
6744 free(redirect);
6745 redirect = NULL;
6746 }
6747 if (nosilent)
6748 silent = 0;
6749 whatami = cmdwhatami;
6750 interpret();
6751 gcldebug("Done interpreting");
6752 }
6753 else gcldebug("Skipping interpretation (`-c' selected)");
6754
6755 if (make)
6756 makedefaults();
6757
6758 retval = 0;
6759 } /* !parse() */
6760 else {
6761 if (gclfile != stdin) {
6762 flock(fileno(gclfile), LOCK_UN); /* Unix specific */
6763 fclose(gclfile);
6764 }
6765
6766 if (!compileonly) {
6767 gcldebug("Skipping the compiler");
6768 gcldebug("Entering the interpreter");
6769 if (cmdcount >= 0)
6770 count = (counter_t)cmdcount;
6771 whatami = cmdwhatami;
6772 interpret();
6773 gcldebug("Done interpreting");
6774 }
6775 retval = 1;
6776 } /* syntax errors */
6777
6778 cleanup();
6779
6780 gcldebug("Done. Returning (%i) to system", retval);
6781
6782 return retval;
6783 }
6784
rgbwarning(int color)6785 static int rgbwarning(int color) {
6786 if (color > 255)
6787 gclwarning("Color value %u is out of range. Converting to %u", color, color & 0xFF);
6788 return color & 0xFF;
6789 }
6790
cleanup(void)6791 static void cleanup(void) {
6792 register int i;
6793
6794 if (gclpath) {
6795 free(gclpath);
6796 gclpath = NULL;
6797 }
6798
6799 if (script) {
6800 free(script);
6801 script = NULL;
6802 }
6803
6804 if (cookie) {
6805 free(cookie);
6806 cookie = NULL;
6807 }
6808
6809 if (cookiepairs) {
6810 free(cookiepairs);
6811 cookiepairs = NULL;
6812 }
6813
6814 if (redirect) {
6815 free(redirect);
6816 redirect = NULL;
6817 }
6818
6819 if (gclprint) {
6820 free(gclprint);
6821 gclprint = NULL;
6822 }
6823
6824 for (i = 0; i < GRAPHICS; i++) if (picture[i].graphic) {
6825 free(picture[i].graphic);
6826 }
6827 memset(picture, 0, sizeof(picture));
6828
6829 freeinhibitors();
6830 freerelayors();
6831 }
6832
addinhibitor(char * env,int iscookie,gclcondition condition,gclinhibitor inh,int op)6833 static void addinhibitor(char *env, int iscookie, gclcondition condition, gclinhibitor inh, int op) {
6834 register inhibit *temp;
6835
6836 if (env == NULL) {
6837 parserror();
6838 return;
6839 }
6840
6841 temp = (inhibit *)malloc(sizeof(inhibit));
6842 if (temp == NULL) {
6843 if (env != from)
6844 free(env);
6845 parserror();
6846 return;
6847 }
6848
6849 temp->val = strdup(lexbuffer);
6850 if (temp->val == NULL) {
6851 free(temp);
6852 if (env != from)
6853 free(env);
6854 parserror();
6855 return;
6856 }
6857
6858 temp->env = env;
6859 temp->condition = condition;
6860 temp->inhibitor = inh;
6861 temp->cookie = iscookie;
6862 temp->op = op;
6863 temp->next = NULL;
6864
6865 if (firstinhibitor == NULL)
6866 firstinhibitor = lastinhibitor = temp;
6867 else {
6868 lastinhibitor->next = temp;
6869 lastinhibitor = temp;
6870 }
6871
6872 gotcookies |= iscookie != 0;
6873 }
6874
freeinhibitors(void)6875 static void freeinhibitors(void) {
6876 while (firstinhibitor != NULL) {
6877 lastinhibitor = firstinhibitor->next;
6878 if (firstinhibitor->env != from)
6879 free(firstinhibitor->env);
6880 free(firstinhibitor->val);
6881 free(firstinhibitor);
6882 firstinhibitor = lastinhibitor;
6883 }
6884
6885 gotcookies &= ~1;
6886 }
6887
addrelayor(char * env,int iscookie,gclcondition condition,gclrelayor rel,char * url,int op)6888 static void addrelayor(char *env, int iscookie, gclcondition condition, gclrelayor rel, char *url, int op) {
6889 register relay *temp;
6890
6891 if (env == NULL) {
6892 parserror();
6893 if (url) free(url);
6894 return;
6895 }
6896
6897 temp = (relay *)malloc(sizeof(relay));
6898 if (temp == NULL) {
6899 if (env != from)
6900 free(env);
6901 if (url) free(url);
6902 parserror();
6903 return;
6904 }
6905
6906 temp->val = strdup(lexbuffer);
6907 if (temp->val == NULL) {
6908 free(temp);
6909 if (env != from)
6910 free(env);
6911 if (url) free(url);
6912 parserror();
6913 return;
6914 }
6915
6916 temp->env = env;
6917 temp->condition = condition;
6918 temp->relayor = rel;
6919 temp->cookie = iscookie;
6920 temp->url = url;
6921 temp->op = op;
6922 temp->next = NULL;
6923
6924 if (firstrelayor == NULL)
6925 firstrelayor = lastrelayor = temp;
6926 else {
6927 lastrelayor->next = temp;
6928 lastrelayor = temp;
6929 }
6930
6931 gotcookies |= (iscookie != 0) << 1;
6932 }
6933
freerelayors(void)6934 static void freerelayors(void) {
6935 while (firstrelayor != NULL) {
6936 lastrelayor = firstrelayor->next;
6937 if (firstrelayor->env != from)
6938 free(firstrelayor->env);
6939 if (firstrelayor->url != NULL)
6940 free(firstrelayor->url);
6941 free(firstrelayor->val);
6942 free(firstrelayor);
6943 firstrelayor = lastrelayor;
6944 }
6945
6946 gotcookies &= ~2;
6947 }
6948
htmlputc(unsigned char c)6949 static void htmlputc(unsigned char c) {
6950 if (c) {
6951 if (localuse)
6952 fputc(c, stdout);
6953 else switch (c) {
6954 case ' ':
6955 printf(" ");
6956 break;
6957 case '<':
6958 printf("<");
6959 break;
6960 case '>':
6961 printf(">");
6962 break;
6963 case '&':
6964 printf("&");
6965 break;
6966 case '"':
6967 printf(""");
6968 break;
6969 default:
6970 if ((c == '$') ||
6971 (c == '#') ||
6972 (c == '%') ||
6973 (c == '@') ||
6974 (c >= 127))
6975 printf("&#%u;", (unsigned int)c);
6976 else
6977 fputc(c, stdout);
6978 break;
6979 }
6980 }
6981 }
6982
timesprint(char * buffer,int t)6983 static int timesprint(char *buffer, int t) {
6984 register int digits;
6985
6986 digits = sprintf(buffer, "^%.2i%%%.2i" + !t, now->tm_hour, now->tm_min);
6987 if (seconds)
6988 digits += sprintf(buffer + digits, "%%%.2i", now->tm_sec);
6989 return digits;
6990 }
6991
zonesprint(char * buffer)6992 static int zonesprint(char *buffer) {
6993 if (zonehours || zoneminutes) {
6994 register int digits;
6995
6996 digits = sprintf(buffer, zoneminutes ? "%+.2i%%%02i" : "%+.2i", zonehours, zoneminutes);
6997 if (*buffer == '-')
6998 *buffer = '<';
6999 else if (*buffer == '+')
7000 *buffer = '>';
7001 return digits;
7002 }
7003 else
7004 return sprintf(buffer, "@");
7005 }
7006
datesprint(char * buffer)7007 static int datesprint(char *buffer) {
7008 return sprintf(buffer, "%i-%.2i-%.2i", now->tm_year + 1900, now->tm_mon + 1, now->tm_mday);
7009 }
7010
dd(char const * const name,int const value)7011 static void dd(char const * const name, int const value) {
7012 fprintf(gcldefaultfile, value < 0 ? "\n#define\t%s\t(%i)" : "\n#define\t%s\t%i", name, value);
7013 }
7014
dds(char const * const name,char const * const value)7015 static void dds(char const * const name, char const * const value) {
7016 fprintf(gcldefaultfile, "\n#define\t%s\t\"%s\"", name, value);
7017 }
7018
ddc(char const * const name,char const * const value)7019 static void ddc(char const * const name, char const * const value) {
7020 fprintf(gcldefaultfile, "\n#define\t%s\t%s", name, value);
7021 }
7022
makedefaults(void)7023 static void makedefaults(void) {
7024 int i, j, k;
7025 register gdImagePtr imgptr;
7026
7027 gcldebug("Creating new defaults");
7028
7029 rename("gcldefaults.h", "gcldefaults.h.old");
7030
7031 gcldefaultfile = fopen("gcldefaults.h", "w");
7032
7033 if (gcldefaultfile == NULL) {
7034 fprintf(stderr, "GCL Make: Can't create gcldefaults.h\n");
7035 return;
7036 }
7037
7038 fprintf(gcldefaultfile, "/*\n * Graphic Counter Language\n *\n * Customized defaults\n *\n * Automaticaly created by GCL " GCLVERSION "\n *\n * Copyright 1999 G. Adam Stanislav.\n * All rights reserved.\n */\n\n#ifndef\tGCLDEFAULTS_H\n#define\tGCLDEFAULTS_H\n");
7039 dd("GCLDEFAULTOPTIMIZE", optimize);
7040 ddc("GCLDEFAULTTIMEZONE", gtz.tz == STZ ? "STZ" : "UTC");
7041 dd("GCLDEFAULTTIMEZONEOFFSET", gtz.secs);
7042 fprintf(gcldefaultfile, "L");
7043 dd("GCLDEFAULTSHOWSECONDS", seconds);
7044 dd("GCLDEFAULTTRANSPARENT", transparent);
7045 dd("GCLDEFAULTVERTICAL", vertical);
7046 dd("GCLDEFAULTEXPIRES", expires);
7047 for (i = 0; i < NUMPADS; i++)
7048 dd(gcldefaultpads[i], pad[i]);
7049 for (i = 0; i < GRAPHICTYPES; i++)
7050 dd(gcldefaultkern[i], kern[i]);
7051 dd("GCLDEFAULTFRAMETYPE", frametype);
7052 for (i = 0; i < GRAPHICTYPES; i++)
7053 ddc(gcldefaulthalign[i], halignflag[i] < 0 ? "LEFT" : halignflag[i] == 0 ? "CENTER" : "RIGHT");
7054 for (i = 0; i < GRAPHICTYPES; i++)
7055 ddc(gcldefaultvalign[i], valignflag[i] < 0 ? "TOP" : valignflag[i] == 0 ? "MIDDLE" : "BOTTOM");
7056 for (i = 0; i < GRAPHICTYPES; i++)
7057 dd(gcldefaulthashift[i], hashift[i]);
7058 for (i = 0; i < GRAPHICTYPES; i++)
7059 dd(gcldefaultvashift[i], vashift[i]);
7060 ddc("GCLDEFAULTHSHIFTFLAG", hshiftflag < 0 ? "LEFT" : hshiftflag == 0 ? "0" : "RIGHT");
7061 ddc("GCLDEFAULTVSHIFTFLAG", vshiftflag < 0 ? "UP" : vshiftflag == 0 ? "0" : "DOWN" );
7062 dd("GCLDEFAULTHSHIFT", hshift);
7063 dd("GCLDEFAULTVSHIFT", vshift);
7064 dd("GCLDEFAULTGROUP", group);
7065 ddc("GCLDEFAULTGROUPSEPARATOR", groupseparator == COMMAS ? "COMMAS" :
7066 groupseparator == DOTS ? "DOTS" : "SPACES");
7067 dd("GCLDEFAULTREVCOM", revcom);
7068 dd("GCLDEFAULTREVDIG", revdig);
7069 fprintf(gcldefaultfile, "\n");
7070
7071 dds("GCLDEFAULTDEFINECHAR", definechar);
7072 fprintf(gcldefaultfile, "\n");
7073
7074 dd("BKGRED", bkg.red);
7075 dd("BKGGREEN", bkg.green);
7076 dd("BKGBLUE", bkg.blue);
7077 dd("INVISRED", invis.red);
7078 dd("INVISGREEN", invis.green);
7079 dd("INVISBLUE", invis.blue);
7080 dd("TTRED", tt.red);
7081 dd("TTGREEN", tt.green);
7082 dd("TTBLUE", tt.blue);
7083
7084 fprintf(gcldefaultfile, "\n\n#endif\t/* GCLDEFAULTS_H not defined */\n");
7085 fclose(gcldefaultfile);
7086
7087 rename("gcldefaults.c", "gcldefaults.c.old");
7088 gcldefaultfile = fopen("gcldefaults.c", "w");
7089
7090 if (gcldefaultfile == NULL) {
7091 fprintf(stderr, "GCL Make: Can't create gcldefaults.c\n");
7092 return;
7093 }
7094
7095 fprintf(gcldefaultfile, "/*\n * Graphic Counter Language\n *\n * C defaults source file\n *\n * Automatically created by GCL " GCLVERSION "\n *\n * Copyright 1999 G. Adam Stanislav\n * All rights reserved\n */");
7096
7097 openarraypicture(0);
7098
7099 for (i = 0; i < ARRAYPICTURE; i++) {
7100 openpicture(i);
7101
7102 if (picture[i].iscreated) {
7103 fprintf(gcldefaultfile, "\n\n/* Define %s image. */", picname[i]);
7104 imgptr = picture[i].isarray ? arraypicture.image : picture[i].image;
7105
7106 for (j = 0; j < picture[i].dy; j++) {
7107 fprintf(gcldefaultfile, "\nstatic unsigned char defpic_%i_%i[%i] = {", i, j, picture[i].dx);
7108
7109 for (k = 0; k < picture[i].dx; k++) {
7110 fprintf(gcldefaultfile, ",\n\t%i" + (k == 0), imgptr->pixels[j][k + picture[i].x]);
7111 }
7112
7113 fprintf(gcldefaultfile, "\n};");
7114 }
7115
7116 fprintf(gcldefaultfile, "\n\nstatic unsigned char *defpic_%i[%i] = {", i, picture[i].dy);
7117
7118 for (j = 0; j < picture[i].dy; j++) {
7119 fprintf(gcldefaultfile, ",\n\tdefpic_%i_%i" + (j == 0), i, j);
7120 }
7121
7122 fprintf(gcldefaultfile, "\n};\n\nstatic gdImage img_%i = {\n\tdefpic_%i,\n\t%i,\n\t%i,\n\t%i,\n\t{", i, i, picture[i].dx, picture[i].dy, imgptr->colorsTotal);
7123
7124 for (j = 0; j < imgptr->colorsTotal; j++)
7125 fprintf(gcldefaultfile, ",\n\t\t%i" + (j == 0), imgptr->red[j]);
7126
7127 fprintf(gcldefaultfile, "\n\t},\n\t{");
7128
7129 for (j = 0; j < imgptr->colorsTotal; j++)
7130 fprintf(gcldefaultfile, ",\n\t\t%i" + (j == 0), imgptr->green[j]);
7131
7132 fprintf(gcldefaultfile, "\n\t},\n\t{");
7133
7134 for (j = 0; j < imgptr->colorsTotal; j++)
7135 fprintf(gcldefaultfile, ",\n\t\t%i" + (j == 0), imgptr->blue[j]);
7136
7137 fprintf(gcldefaultfile, "\n\t},\n\t{");
7138
7139 for (j = 0; j < gdMaxColors; j++)
7140 fprintf(gcldefaultfile, ",\n\t\t%i" + (j == 0), imgptr->open[j]);
7141
7142 fprintf(gcldefaultfile, "\n\t},\n\t%i,\n\tNULL,\n\t0,\n\tNULL,\n\tNULL,\n\t{ 0 },\n\t{ 0 },\n\t0,\n\t0,\n\tNULL,\n\t0\n};", imgptr->transparent);
7143 }
7144 }
7145 fprintf(gcldefaultfile, "\n\nstatic gdImagePtr const defaultimage[GRAPHICS] = {");
7146
7147 for (i = 0; i < ARRAYPICTURE; i++) {
7148 if (picture[i].iscreated)
7149 fprintf(gcldefaultfile, ",\n\t&img_%i" + (i == 0), i);
7150 else
7151 fprintf(gcldefaultfile, ",\n\tNULL" + (i == 0));
7152 }
7153
7154 for (;i < GRAPHICS; i++)
7155 fprintf(gcldefaultfile, ",\n\tNULL");
7156
7157 fprintf(gcldefaultfile, "\n};\n\n");
7158 fclose(gcldefaultfile);
7159 }
7160
createimage(int inumber)7161 static void createimage(int inumber) {
7162 register FILE *tempfile;
7163
7164 if (picture[inumber].graphic != NULL) {
7165 tempfile = fopen(picture[inumber].graphic, "rb");
7166 if (tempfile != NULL) {
7167 switch (picture[inumber].gtype) {
7168 case GIFSOURCE:
7169 picture[inumber].image = gdImageCreateFromGif(tempfile);
7170 gcldebug("Creating %s image from GIF", picname[inumber]);
7171 break;
7172 case GDSOURCE:
7173 picture[inumber].image = gdImageCreateFromGd(tempfile);
7174 gcldebug("Creating %s image from GD", picname[inumber]);
7175 break;
7176 case XBMSOURCE:
7177 picture[inumber].image = gdImageCreateFromXbm(tempfile);
7178 gcldebug("Creating %s image from Xbm", picname[inumber]);
7179 break;
7180 } /* picture type */
7181 fclose(tempfile);
7182 if (picture[inumber].image == NULL)
7183 gclwarning("Failed to create %s image", picname[inumber]);
7184 gcldebug(picture[inumber].image == NULL ?
7185 "Failed to create %s image" :
7186 "Successfully created %s image", picname[inumber]);
7187 } /* picture opened */
7188 else {
7189 gclwarning("Failed to open %s picture file `%s'", picname[inumber], picture[inumber].graphic);
7190 gcldebug("Failed to open %s picture file `%s'", picname[inumber], picture[inumber].graphic);
7191 }
7192
7193 free (picture[inumber].graphic);
7194 picture[inumber].graphic = NULL;
7195 } /* picture defined */
7196 }
7197
openarraypicture(int turner)7198 static void openarraypicture(int turner) {
7199 register int i;
7200 register int ted;
7201
7202 slashnotneeded = (picturedirectory.graphic != NULL) &&
7203 (picturedirectory.graphic[strlen(picturedirectory.graphic) - 1] == '/');
7204
7205 if ((arraypicture.graphic == NULL) && (picturedirectory.graphic != NULL)) {
7206 sprintf(pathbuffer, "%s%sarray.%s",
7207 picturedirectory.graphic,
7208 "/" + slashnotneeded,
7209 graphictypes[picturedirectory.gtype]);
7210 if (access(pathbuffer, F_OK) == 0) {
7211 arraypicture.graphic = strdup(pathbuffer);
7212 if (arraypicture.graphic == NULL)
7213 fprintf(stderr, "GCL Interpreter: Not enough memory: `%s'.\n", pathbuffer);
7214 else
7215 arraypicture.gtype = picturedirectory.gtype;
7216 }
7217 }
7218
7219 createimage(ARRAYPICTURE);
7220
7221 if (arraypicture.image == NULL) for (i = 0; i < GRAPHICS; i++)
7222 picture[i].isarray = 0;
7223 else if (turner && (tt.red || tt.green || tt.blue)) {
7224 ted = gdImageColorExact(arraypicture.image, 0, 0, 0);
7225
7226 if (ted < 0)
7227 ted = gdImageColorClosest(arraypicture.image, 0, 0, 0);
7228
7229 if ((ted >= 0) && (ted != gdImageGetTransparent(arraypicture.image))) {
7230 arraypicture.image->red[ted] = tt.red;
7231 arraypicture.image->green[ted] = tt.green;
7232 arraypicture.image->blue[ted] = tt.blue;
7233 }
7234 }
7235
7236 /* colorize default images */
7237 if (turner && (tt.red || tt.green || tt.blue)) {
7238 for (i = 0; i < GRAPHICS; i++) if (defaultimage[i] != NULL) {
7239 ted = gdImageColorExact(defaultimage[i], 0, 0, 0);
7240
7241 if (ted < 0)
7242 ted = gdImageColorClosest(defaultimage[i], 0, 0, 0);
7243
7244 if ((ted >= 0) && (ted != gdImageGetTransparent(defaultimage[i]))) {
7245 defaultimage[i]->red[ted] = tt.red;
7246 defaultimage[i]->green[ted] = tt.green;
7247 defaultimage[i]->blue[ted] = tt.blue;
7248 }
7249 }
7250 }
7251 }
7252
openpicture(int inumber)7253 static void openpicture(int inumber) {
7254 if (picture[inumber].isarray) {
7255 picture[inumber].iscreated = 1;
7256 gcldebug("Using array image for %s", picname[inumber]);
7257 }
7258 else {
7259 if ((picture[inumber].graphic == NULL) && (picturedirectory.graphic != NULL)) {
7260 sprintf(pathbuffer, "%s%s%s.%s",
7261 picturedirectory.graphic,
7262 "/" + slashnotneeded,
7263 defaultpicturename[inumber],
7264 graphictypes[picturedirectory.gtype]);
7265 if (access(pathbuffer, F_OK) == 0) {
7266 picture[inumber].graphic = strdup(pathbuffer);
7267 picture[inumber].gtype = picturedirectory.gtype;
7268 }
7269 }
7270
7271 createimage(inumber);
7272 if ((picture[inumber].image == NULL) && (defaultimage[inumber] != NULL) && (nodefaultpicture[inumber] == 0)) {
7273 gcldebug("Using default %s image", picname[inumber]);
7274 picture[inumber].image = defaultimage[inumber];
7275 }
7276
7277 if (picture[inumber].image) {
7278 picture[inumber].iscreated = 1;
7279 picture[inumber].x = picture[inumber].y = 0;
7280 picture[inumber].dx = gdImageSX(picture[inumber].image);
7281 picture[inumber].dy = gdImageSY(picture[inumber].image);
7282 }
7283 }
7284 }
7285
getrandomnumber(int s)7286 static counter_t getrandomnumber(int s) {
7287 /*
7288 * This is not a very good generator. I am open to suggestions...
7289 */
7290 randomnumber = randomnumber * GCLRNDMUL + GCLRNDADD;
7291 if (s == 0) randomnumber &= ((counter_t)(-1) >> 1);
7292 return randomnumber;
7293 }
7294
setincrementrange(scounter_t a,scounter_t b)7295 static void setincrementrange(scounter_t a, scounter_t b) {
7296 register scounter_t temp;
7297
7298 if (a <= b) {
7299 incrementrange[0] = a;
7300 incrementrange[1] = b;
7301 }
7302 else {
7303 incrementrange[0] = b;
7304 incrementrange[1] = a;
7305 }
7306 if (incrementrange[0] == incrementrange[1])
7307 increment = incrementrange[0];
7308 else {
7309 temp = incrementrange[1] - incrementrange[0] + 1;
7310 increment = getrandomnumber(1);
7311 if (temp) {
7312 increment %= (counter_t)temp;
7313 increment += incrementrange[0];
7314 }
7315 }
7316 issigma = 0;
7317 }
7318
7319