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("&nbsp;");
6956 				break;
6957 			case '<':
6958 				printf("&lt;");
6959 				break;
6960 			case '>':
6961 				printf("&gt;");
6962 				break;
6963 			case '&':
6964 				printf("&amp;");
6965 				break;
6966 			case '"':
6967 				printf("&quot;");
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