mgp_1.06a.19991206.orig.tar.gz
[alioth/magicpoint.git] / parse.c
1 /*
2  * Copyright (C) 1997 and 1998 WIDE Project.  All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  * 3. Neither the name of the project nor the names of its contributors
13  *    may be used to endorse or promote products derived from this software
14  *    without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  */
28 /*
29  * $Id: parse.c,v 1.81 1999/12/05 17:28:44 nishida Exp $
30  */
31
32 #include "mgp.h"
33 #ifdef HAVE_FCNTL_H
34 # include <fcntl.h>
35 #endif
36
37 static struct ctrl *parse_text __P((char *, u_int));
38 static void read_rc __P((FILE *, char *));
39 static void read_file __P((FILE *, char *, u_int *, u_int *, int));
40 static void secondpass __P((void));
41 static void thirdpass __P((void));
42 static void debug __P((void));
43 static int define_font __P((struct ctrl *));
44 static struct ctrl *find_font __P((char *));
45
46 /*image*/
47 extern int findImage __P((char *, char *));
48
49 /* lex/yacc variables */
50 extern int n_errors;
51 extern struct ctrl *root;
52 extern char *yyfilename;
53 extern int yylineno;
54 /* Prevent warning if -Wall.  */
55 #ifdef __GNUC__
56 extern void lex_init(u_char *);
57 extern int yyparse (void);
58 #endif
59
60 static int filterval = 0;
61
62 void
63 load_file(filename)
64         char *filename;
65 {
66         FILE *fp;
67         u_int page;
68         u_int line;
69         char rc[MAXPATHLEN];
70         char *dir;
71
72         page = 1;
73         line = 0;
74
75         dir = getenv("HOME");
76         if (dir) {
77                 snprintf(rc, sizeof(rc), "%s/%s", dir, RCFILE);
78                 fp = fopen(rc, "r");
79                 if (fp) {
80                         read_rc(fp, rc);
81                         fclose(fp);
82                 }
83         }
84
85         if ((fp = fopen(filename, "r")) == NULL) {
86                 fprintf(stderr, "can't open %s\n", filename);
87                 exit(-1);
88         }
89         read_file(fp, filename, &page, &line, 1);
90         fclose(fp);
91         secondpass();
92         thirdpass();
93         if (parse_debug)
94                 debug();
95 }
96
97 void
98 cleanup_file()
99 {
100         u_int line;
101         u_int page;
102
103         for (line = 0; line < MAXLINE; line ++) {
104                 if (default_control[line]) {
105                         ctlfree(default_control[line]);
106                         default_control[line] = NULL;
107                 }
108                 if (init_control[line]) {
109                         ctlfree(init_control[line]);
110                         init_control[line] = NULL;
111                 }
112         }
113         for (page = 0; page < MAXPAGE; page ++) {
114                 for (line = 0; line < MAXLINE; line ++) {
115                         if (!page_control[page][line])
116                                 continue;
117                         ctlfree(page_control[page][line]);
118                         page_control[page][line] = NULL;
119                 }
120                 memset(&page_attribute[page], 0, sizeof(page_attribute[page]));
121         }
122         for (line = 0; line < MAXTAB + MAXSTYLE; line++) {
123                 if (!tab_control[line])
124                         continue;
125                 ctlfree(tab_control[line]);
126                 tab_control[line] = NULL;
127         }
128         for (line = 0; line < MAXFONTDEF; line++) {
129                 if (!fontdef_control[line])
130                         continue;
131                 ctlfree(fontdef_control[line]);
132                 fontdef_control[line] = NULL;
133         }
134 }
135
136 static struct ctrl *
137 parse_text(p, page)
138         char *p;
139         u_int page;
140 {
141         struct ctrl sentinel;
142         struct ctrl *cp;
143
144         assert(p);
145
146         cp = &sentinel;
147
148         cp->ct_next = ctlalloc1(CTL_TEXT);
149         if (!cp->ct_next) {
150                 ctlfree(cp);
151                 return NULL;
152         }
153         cp = cp->ct_next;
154         cp->ct_page = page;
155         cp->ctc_value = strdup(p);
156
157         return sentinel.ct_next;
158 }
159
160 /*
161  * read ~/.mgprc: there's no percentage sign
162  */
163 static void
164 read_rc(fp, filename)
165         FILE *fp;
166         char *filename;
167 {
168         char buf[BUFSIZ];
169 #if 0
170         struct ctrl *cp;
171 #endif
172         int lineno;
173
174         if (2 <= parse_debug)
175                 fprintf(stderr, "read_rc(%s):\n", filename);
176
177         lineno = 0;
178         while (fgets(buf, sizeof(buf), fp) != NULL) {
179                 lineno++;
180                 if (buf[strlen(buf) - 1] == '\n')
181                         buf[strlen(buf) - 1] = '\0';
182                 if (buf[0] == '#' || !buf[0])
183                         continue;
184
185                 yyfilename = filename;
186                 yylineno = lineno;
187
188                 lex_init(buf);
189                 if (yyparse() || n_errors) {
190                         fprintf(stderr, "%s:%d: fatal syntax error detected\n",
191                                 filename, lineno);
192                         exit(-1);
193                 }
194
195                 if (!root) {
196                         fprintf(stderr, "%s:%d: something bad happened\n",
197                                 filename, lineno);
198                         exit(-1);
199                 }
200                 if (2 <= parse_debug) {
201                         fprintf(stderr, "%s:%d: %s\n", filename, lineno, buf);
202                         debug1(root);
203                 }
204
205                 switch (root->ct_op) {
206 #if 0
207                 case CTL_DEFFONT:
208                         /* safety check */
209                         for (cp = root; cp; cp = cp->ct_next) {
210                                 if (cp->ct_op == CTL_FONT) {
211                                         fprintf(stderr,
212 "%s:%d: %%font used in %%deffont, which is disallowed\n",
213                                                 filename, lineno);
214                                         exit(-1);
215                                 }
216                         }
217
218                         if (define_font(root) < 0) {
219                                 fprintf(stderr, "%s:%d: could not define "
220                                         "font \"%s\"\n", filename, lineno,
221                                         root->ctc_value);
222                                 exit(-1);
223                         }
224                         break;
225 #endif
226 #ifdef VFLIB
227                 case CTL_VFCAP:
228                         vfcap_name = root->ctc_value;
229                         break;
230 #endif
231 #ifdef FREETYPE
232                 case CTL_TFDIR:
233                         freetypefontdir = root->ctc_value;
234                         break;
235                 case CTL_TFONT0:
236                         freetypefont0 = root->ctc_value;
237                         break;
238                 case CTL_TMFONT0:
239                         freetypemfont0 = root->ctc_value;
240                         break;
241 #endif
242                 case CTL_NOOP:
243                         /* done in grammar.y */
244                         break;
245                 default:
246                         fprintf(stderr, "%s:%d: operator disallowed:\n\t",
247                                 filename, lineno);
248                         debug0(root);
249                         exit(-1);
250                 }
251         }
252 }
253
254 static void
255 read_file(fp, filename, page, line, preamble)
256         FILE *fp;
257         char *filename;
258         u_int *page;
259         u_int *line;
260         int preamble;
261 {
262         char buf[BUFSIZ];
263         char buf2[BUFSIZ];
264         struct ctrl **ch;
265         struct ctrl *cp;
266         struct ctrl *p;
267         int line_cont;
268         char *infilename;
269         struct ctrl *filtermode;
270         int filterfd = -1;
271         char filtername[MAXPATHLEN];
272         pid_t filterpid = -1;
273         void (*filtersig)() = (void (*)())NULL;
274         int lineno;
275         static char *searchpath[] = {
276                 "",     /*mgp_fname*/
277 #ifdef MGPLIBDIR
278                 MGPLIBDIR "/",
279 #endif
280                 NULL,
281         };
282
283         if (2 <= parse_debug)
284                 fprintf(stderr, "read_file(%s):\n", filename);
285
286         filtername[0] = '\0';
287         lineno = 0;
288
289         if (!preamble)
290                 goto page;
291
292         /*
293          * default analysis in preamble
294          */
295         while (fgets(buf, sizeof(buf), fp) != NULL) {
296                 lineno++;
297                 if (buf[strlen(buf) - 1] == '\n')
298                         buf[strlen(buf) - 1] = '\0';
299
300                 if (buf[0] == '#')
301                         continue;
302                 if (buf[0] != '%') {
303                         fprintf(stderr, "%s:%d: no text allowed in preamble; "
304                                 "ignored\n", filename, lineno);
305                         continue;
306                 }
307                 if (buf[1] == '%')
308                         continue;
309
310                 yyfilename = filename;
311                 yylineno = lineno;
312                 lex_init(buf + 1);
313                 if (yyparse() || n_errors) {
314                         fprintf(stderr, "%s:%d: fatal syntax error detected\n",
315                                 filename, lineno);
316                         exit(-1);
317                 }
318                 if (!root) {
319                         fprintf(stderr, "%s:%d: something bad happened\n",
320                                 filename, lineno);
321                         exit(-1);
322                 }
323                 if (2 <= parse_debug)
324                         debug1(root);
325
326                 switch (root->ct_op) {
327                 case CTL_PAGE:
328                         goto page;
329
330                 case CTL_INCLUDE:
331                     {
332                         FILE *infp;
333
334                         infilename = root->ctc_value;
335                         searchpath[0] = mgp_fname;
336                         infp = fsearchopen(infilename, "r", searchpath);
337                         if (infp == NULL) {
338                                 fprintf(stderr, "%s:%d: can't open "
339                                         "include file \"%s\"\n",
340                                         filename, lineno, infilename);
341                                 exit(-1);
342                         }
343                         read_file(infp, infilename, page, line, 1);
344                         fclose(infp);
345                         continue;
346                     }
347
348                 case CTL_DEFAULT:
349                         ch = &default_control[root->cti_value - 1];
350                         if (*ch)
351                                 ctlappend(*ch, root->ct_next);
352                         else
353                                 *ch = root->ct_next;
354                         break;
355
356                 case CTL_TAB:
357                     {
358                         int i = root->cti_value - 1;
359                         if (i < 0) {
360                                 fprintf(stderr, "%s:%d: "
361                                         "invalid tab index %d\n",
362                                         filename, lineno, root->cti_value);
363                                 exit(-1);
364                         }
365                         if (i >= MAXTAB) {      /*XXX*/
366                                 /* must be a string */
367                                 /* find a free entry */
368                                 for (i = MAXTAB ; i < MAXTAB + MAXSTYLE ; i++) {
369                                         if (!tab_control[i])
370                                                 continue;
371                                         if (strcmp(tab_control[i]->ctc_value,
372                                                     root->ctc_value) == 0) {
373                                                 ctlfree(tab_control[i]);
374                                                 tab_control[i] = NULL;
375                                                 break;
376                                         }
377                                 }
378
379                                 for (i = MAXTAB ; i < MAXTAB + MAXSTYLE ; i++) {
380                                         if (!tab_control[i])
381                                                 break;
382                                 }
383                                 if (i == MAXTAB + MAXSTYLE) {
384                                         fprintf(stderr, "%s:%d: "
385                                                 "too many styles\n",
386                                                 filename, lineno);
387                                         exit(-1);
388                                 }
389                         }
390                         ch = &tab_control[i];
391                         if (*ch)
392                                 ctlappend(*ch, root->ct_next);
393                         else if (i < MAXTAB)
394                                 *ch = root->ct_next;
395                         else
396                                 *ch = root; /* keep name as well */
397                     }
398                         break;
399
400                 case CTL_DEFFONT:
401                         /* safety check */
402                         for (cp = root; cp; cp = cp->ct_next) {
403                                 if (cp->ct_op == CTL_FONT) {
404                                         fprintf(stderr,
405 "%s:%d: %%font used in %%deffont, which is disallowed\n",
406                                                 filename, lineno);
407                                         exit(-1);
408                                 }
409                         }
410
411                         if (define_font(root) < 0) {
412                                 fprintf(stderr, "%s:%d: could not define "
413                                         "font \"%s\"\n", filename, lineno,
414                                         root->ctc_value);
415                                 exit(-1);
416                         }
417                         break;
418
419                 default:
420                         fprintf(stderr, "%s:%d: invalid operator\n",
421                                 filename, lineno);
422                         exit(-1);
423                 }
424         }
425
426         /*
427          * page analysis
428          */
429 page:
430         line_cont = 0;
431         filtermode = NULL;
432 command:
433         while (fgets(buf, sizeof(buf), fp) != NULL) {
434                 lineno++;
435                 if (filtermode && strncmp(buf, "%endfilter", 10) != 0) {
436                         write(filterfd, buf, strlen(buf));
437                         continue;
438                 }
439             {
440                 char *p, *q;
441
442                 p = buf + strlen(buf);
443                 if (buf < p && p[-1] == '\n') {
444                         p--;
445                         *p = '\0'; 
446                 }
447                 while (buf < p && p - buf < sizeof(buf) && p[-1] == '\\') {
448                         p--;
449                         if (fgets(buf2, sizeof(buf) - (p - buf), fp) == NULL)
450                                 break;
451                         q = buf2;
452                         /* ignore blanks */
453                         while (*q && isspace(*q))
454                                 q++;
455                         strncpy(p, q, sizeof(buf) - (p - buf));
456                         p += strlen(p);
457                         if (buf < p && p[-1] == '\n') {
458                                 p--;
459                                 *p = '\0'; 
460                         }
461                 }
462             }
463
464                 if (buf[0] == '#')
465                         continue;
466                 if (buf[0] == '%') {
467                         /* this is directive */
468                         int pb;
469                         int ct;
470                         int prevfiltermode;
471
472                         if (buf[1] == '%')
473                                 continue;
474
475                         prevfiltermode = filtermode ? 1 : 0;
476
477                         yyfilename = filename;
478                         yylineno = lineno;
479                         lex_init(buf + 1);
480                         if (yyparse() || n_errors) {
481                                 fprintf(stderr,
482                                         "%s:%d: fatal syntax error detected\n",
483                                         filename, lineno);
484                                 exit(-1);
485                         }
486                         if (!root) {
487                                 fprintf(stderr,
488                                         "%s:%d: something bad happened\n",
489                                         filename, lineno);
490                                 exit(-1);
491                         }
492                         if (2 <= parse_debug)
493                                 debug1(root);
494
495                         cp = root;
496
497                         pb = ct = 0;
498                         for (p = cp; p; p = p->ct_next) {
499                                 switch (p->ct_op) {
500                                 case CTL_PAGE:
501                                         pb++;
502                                         break;
503                                 case CTL_NODEF:
504                                         page_attribute[*page].pg_flag
505                                                 |= PGFLAG_NODEF;
506                                         break;
507                                 case CTL_CONT:
508                                         ct++;
509                                         break;
510                                 case CTL_FILTER:
511                                         filtermode = p;
512                                         break;
513                                 case CTL_ENDFILTER:
514                                         filtermode = NULL;
515                                         break;
516                                 case CTL_EMBED:
517                                         embed_file(fp, p, &lineno);
518                                         goto command;
519                                 }
520                         }
521
522                         /* filter */
523                         if (!prevfiltermode && filtermode) {
524                                 int filtertmp;
525                                 int pipefd[2];
526
527                                 if (mgp_flag & FL_NOFORK) {
528                                         int i;
529                                         if (mgp_flag & FL_VERBOSE) {
530                                             fprintf(stderr, "%s:%d: %%filter ",
531                                                 filename, lineno);
532                                             for (i = 0; i < cp->cta_argc; i++) {
533                                                 fprintf(stderr, "%c%s",
534                                                     (i == 0) ? '"' : ' ',
535                                                     cp->cta_argv[i]);
536                                                 }
537                                                 fprintf(stderr, "\": "
538                                                     "directive skipped\n");
539                                         }
540                                         filterfd = open("/dev/null", O_WRONLY);
541                                         strcpy(filtername, "/dev/null");
542                                         continue;
543                                 }
544
545                                 sprintf(filtername, "/tmp/%d.%ld.%d",
546                                         getpid(), (long)time(NULL),
547                                         filterval++);
548                                 filtertmp = open(filtername, O_CREAT|O_WRONLY,
549                                         0644);
550                                 if (filtertmp < 0) {
551                                         fprintf(stderr,
552                                             "%s:%d: cannot open file tmp file "
553                                             "for filter\n", filename, lineno);
554                                         exit(-1);
555                                 }
556                                 if (pipe(pipefd) < 0) {
557                                         fprintf(stderr,
558                                             "%s:%d: cannot open pipe for "
559                                             "filter\n", filename, lineno);
560                                         exit(-1);
561                                 }
562
563                                 filterpid = fork();
564                                 if (filterpid < 0) {
565                                         perror("fork");
566                                         exit(1);
567                                 } else if (filterpid == 0) {
568                                         close(pipefd[1]);
569                                         close(STDIN_FILENO);
570                                         dup2(pipefd[0], STDIN_FILENO);
571                                         close(pipefd[0]);
572                                         close(STDOUT_FILENO);
573                                         dup2(filtertmp, STDOUT_FILENO);
574                                         close(STDERR_FILENO);
575                                         dup2(filtertmp, STDERR_FILENO);
576                                         close(filtertmp);
577                                         execvp(filtermode->cta_argv[0],
578                                                 (char **)filtermode->cta_argv);
579                                 } else {
580                                         close(filtertmp);
581                                         close(pipefd[0]);
582                                         filterfd = pipefd[1];
583                                         filtersig = signal(SIGCHLD, SIG_DFL);
584                                 }
585                                 continue;
586                         } else if (prevfiltermode && !filtermode
587                          && filtername[0]) {
588                                 FILE *filterfp;
589                                 int estat;
590
591                                 if (mgp_flag & FL_NOFORK) {
592                                         close(filterfd);
593                                         filtername[0] = '\0';
594                                         continue;
595                                 }
596
597                                 close(filterfd);
598                                 waitpid(filterpid, &estat, 0);
599                                 signal(SIGCHLD, filtersig);
600                                 filterfp = fopen(filtername, "r");
601                                 if (filterfp == NULL) {
602                                         fprintf(stderr, "%s:%d: cant read "
603                                                 "filter output\n",
604                                                 filename, lineno);
605                                         exit(-1);
606                                 }
607                                 read_file(filterfp, filtername, page, line, 0);
608                                 fclose(filterfp);
609                                 unlink(filtername);
610                                 filtername[0] = '\0';
611                                 continue;
612                         }
613
614                         if (pb) {
615                                 /* Seen pagebreak. */
616                                 page_attribute[*page].pg_linenum = *line;
617                                 *page = *page + 1;
618                                 *line = 0;
619                                 continue;
620                         }
621                         if (ct)
622                                 line_cont = 1;
623
624                         if (cp) {
625                                 /*
626                                  * append to the currently existing
627                                  * page struct.
628                                  */
629                                 ch = &page_control[*page][*line];
630
631 #if 0
632                                 if (!line_cont &&
633                                     (/* cp->ct_op == CTL_IMAGE || */
634                                      cp->ct_op == CTL_BAR)) {
635                                         struct ctrl *cp1;
636                                         cp1 = ctlalloc1(CTL_LINESTART);
637                                         if (cp1) {
638                                                 if (!*ch)
639                                                         *ch = cp1;
640                                                 else
641                                                         ctlappend(*ch, cp1);
642                                         }
643                                 }
644 #endif
645
646                                 if (!*ch)
647                                         *ch = cp;
648                                 else
649                                         ctlappend(*ch, cp);
650
651                                 /*
652                                  * special case: %image and %line has to be
653                                  * treated as independent item
654                                  */
655                                 if (cp->ct_op == CTL_IMAGE
656                                  || cp->ct_op == CTL_BAR) {
657                                         line_cont = 0;
658                                         *line = *line + 1;
659                                 }
660                         }
661                 } else {
662                         /* this is data */
663                         cp = parse_text(buf, *page);
664                         if (cp) {
665                                 ch = &page_control[*page][*line];
666                                 if (!*ch)
667                                         *ch = cp;
668                                 else
669                                         ctlappend(*ch, cp);
670                         }
671                         line_cont = 0;
672
673                         *line = *line + 1;
674                 }
675         }
676
677         /* Treat as we've seen pagebreak.  See the above comment for detail. */
678         page_attribute[*page].pg_linenum = *line;
679 #if 0
680         *page = *page + 1;
681         *line = 0;
682 #endif
683
684         maxpage = *page;
685 }
686
687 /*
688  * rather simple rewrites.
689  */
690 static void
691 secondpass()
692 {
693         u_int page;
694         u_int l;
695         struct ctrl **ch;
696         struct ctrl *cp;
697         struct ctrl *cp1;
698
699         /*
700          * add CTL_PAUSE to the last line of a page.
701          * we don't add one at the last page, intentionally.
702          */
703         for (page = 1; page < maxpage; page++) {
704                 l = page_attribute[page].pg_linenum;
705
706                 ch = &page_control[page][l + 1];
707                 cp = ctlalloc1(CTL_PAUSE);
708                 if (cp) {
709                         cp->cti_value = 1;      /* 1 indicates page end */
710                         if (!*ch)
711                                 *ch = cp;
712                         else
713                                 ctlappend(*ch, cp);
714                 }
715                 page_attribute[page].pg_linenum++;
716         }
717
718         /*
719          * split GAP into VGAP and HGAP.
720          */
721         for (page = 1; page <= maxpage; page++) {
722                 for (l = 0; l <= page_attribute[page].pg_linenum; l++) {
723                         for (cp = page_control[page][l];
724                              cp;
725                              cp = cp->ct_next) {
726                                 if (cp->ct_op == CTL_GAP) {
727                                         cp->ct_op = CTL_VGAP;
728                                         cp1 = ctlalloc1(CTL_HGAP);
729                                         cp1->cti_value = cp->cti_value;
730                                         cp1->ct_next = cp->ct_next;
731                                         cp->ct_next = cp1->ct_next;
732                                 }
733                         }
734                 }
735         }
736
737         /* CTL_PREFIX in tab_control should be CTL_TABPREFIX. */
738         for (l = 0; l < MAXTAB + MAXSTYLE; l++) {
739                 for (cp = tab_control[l]; cp; cp = cp->ct_next) {
740                         if (cp->ct_op == CTL_PREFIX)
741                                 cp->ct_op = CTL_TABPREFIX;
742                 }
743         }
744 }
745
746 /*
747  * rather complex rewrites.  ordering is VERY important.
748  */
749 static void
750 thirdpass()
751 {
752         u_int page;
753         u_int line;
754         u_int l;
755         struct ctrl **ch;
756         struct ctrl *cp;
757         struct ctrl *cp1;
758         struct ctrl *cp2;
759         char *p;
760         struct ctrl *carryover[MAXPAGE];
761
762     {
763         /*
764          * there are several control items that are to be carried
765          * over to the next line.  make them explicit so that there'll
766          * be no bogus control items to be used when we go back a page.
767          */
768         struct ctrl *tmpstr[10];
769         struct ctrl *tmpint[10];
770         struct ctrl *tmplong[10];
771         struct ctrl *tmpvoid[10];
772         struct ctrl sentinel;
773         int i;
774
775         memset(carryover, 0, sizeof(carryover));
776         memset(tmpstr, 0, sizeof(tmpstr));
777         memset(tmpint, 0, sizeof(tmpint));
778         memset(tmplong, 0, sizeof(tmplong));
779         memset(tmpvoid, 0, sizeof(tmpvoid));
780
781         /* default value for page 1 */
782         tmpstr[0] = ctlalloc1(CTL_PREFIX);
783         tmpstr[0]->ctc_value = strdup("");
784 #if defined(VFLIB) && defined(VFONT)
785         tmpstr[1] = ctlalloc1(CTL_VFONT);
786         tmpstr[1]->ctc_value = strdup(VFONT);           /*XXX*/
787 #else
788         tmpstr[1] = ctlalloc1(CTL_NOOP);
789         tmpstr[1]->ctc_value = strdup("");
790 #endif
791         tmpstr[2] = ctlalloc1(CTL_XFONT2);
792         tmpstr[2]->ctc2_value1 = strdup(DEFAULT_X_FONT);
793         tmpstr[2]->ctc2_value2 = strdup("iso8859-1");
794 #ifdef FREETYPE
795         tmpstr[3] = ctlalloc1(CTL_TFONT);
796         tmpstr[3]->ctc_value = strdup(freetypefont0 ? freetypefont0 : "arial.ttf");
797 #else
798         tmpstr[3] = ctlalloc1(CTL_NOOP);        /* CTL_TFONT */
799         tmpstr[3]->ctc_value = strdup("");
800 #endif
801 #ifdef FREETYPE_CHARSET16
802         tmpstr[4] = ctlalloc1(CTL_TMFONT);      /* CTL_TMFONT */
803         tmpstr[4]->ctc_value = strdup("wadalab-gothic.ttf");
804 #else
805         tmpstr[4] = ctlalloc1(CTL_NOOP);        /* CTL_TMFONT */
806         tmpstr[4]->ctc_value = strdup("");
807 #endif
808         tmpstr[5] = ctlalloc1(CTL_XFONT2);
809         tmpstr[5]->ctc2_value1 = strdup("k14");
810         tmpstr[5]->ctc2_value2 = strdup("jisx0208.1983-*");
811         tmplong[0] = ctlalloc1(CTL_FORE);
812         get_color(DEFAULT_FORE, &tmplong[0]->ctl_value);
813         tmplong[1] = ctlalloc1(CTL_BACK);
814         get_color(DEFAULT_BACK, &tmplong[1]->ctl_value);
815         tmplong[2] = ctlalloc1(CTL_CCOLOR);
816         get_color(DEFAULT_FORE, &tmplong[2]->ctl_value);
817         tmpint[0] = ctlalloc1(CTL_SIZE);
818         tmpint[0]->ctf_value = DEFAULT_CHARSIZE;
819         tmpint[1] = ctlalloc1(CTL_HGAP);
820         tmpint[1]->cti_value = DEFAULT_HGAP;
821         tmpint[2] = ctlalloc1(CTL_VGAP);
822         tmpint[2]->cti_value = DEFAULT_VGAP;
823         tmpint[3] = ctlalloc1(CTL_QUALITY);
824         tmpint[3]->cti_value = DEFAULT_BQUALITY;
825         tmpvoid[0] = ctlalloc1(CTL_LEFT);
826
827         /* for page 1 */
828         cp = &sentinel;
829         for (i = 0; i < 10; i++) {
830                 if (!tmpstr[i])
831                         continue;
832                 cp->ct_next = ctlalloc1(tmpstr[i]->ct_op);
833                 if (ctl_words[tmpstr[i]->ct_op].ctl_vtype == T_STR2) {
834                         if (tmpstr[i]->ctc2_value1) {
835                                 cp->ct_next->ctc2_value1 =
836                                         strdup(tmpstr[i]->ctc2_value1);
837                         } else
838                                 cp->ct_next->ctc2_value1 = NULL;
839                         if (tmpstr[i]->ctc2_value2) {
840                                 cp->ct_next->ctc2_value2 =
841                                         strdup(tmpstr[i]->ctc2_value2);
842                         } else
843                                 cp->ct_next->ctc2_value2 = NULL;
844                 } else {
845                         if (tmpstr[i]->ctc_value) {
846                                 cp->ct_next->ctc_value =
847                                         strdup(tmpstr[i]->ctc_value);
848                         } else
849                                 cp->ct_next->ctc_value = NULL;
850                 }
851                 cp = cp->ct_next;
852         }
853         for (i = 0; i < 10; i++) {
854                 if (!tmplong[i])
855                         continue;
856                 cp->ct_next = ctlalloc1(tmplong[i]->ct_op);
857                 cp->ct_next->ctl_value = tmplong[i]->ctl_value;
858                 cp = cp->ct_next;
859         }
860         for (i = 0; i < 10; i++) {
861                 if (!tmpint[i])
862                         continue;
863                 cp->ct_next = ctlalloc1(tmpint[i]->ct_op);
864                 cp->ct_next->ct_val = tmpint[i]->ct_val;
865                 cp = cp->ct_next;
866         }
867         for (i = 0; i < 10; i++) {
868                 if (!tmpvoid[i])
869                         continue;
870                 cp->ct_next = ctlalloc1(tmpvoid[i]->ct_op);
871                 cp = cp->ct_next;
872         }
873         carryover[0] = sentinel.ct_next;
874
875         /*
876          * parse through the pages, remember what kind of directives are there.
877          */
878         for (page = 1; page <= maxpage; page++) {
879                 for (l = 0; l <= page_attribute[page].pg_linenum; l++) {
880                         for (cp = page_control[page][l];
881                              cp;
882                              cp = cp->ct_next) {
883                                 switch (cp->ct_op) {
884                                 case CTL_PREFIX: tmpstr[0] = cp; break;
885                                 case CTL_VFONT: tmpstr[1] = cp; break;
886                                 case CTL_TFONT: tmpstr[3] = cp; break;
887 #ifdef FREETYPE_CHARSET16
888                                 case CTL_TMFONT: tmpstr[4] = cp; break;
889 #endif
890                                 case CTL_XFONT2:
891                                         if (strcmp(cp->ctc2_value2,
892                                                         "iso8859-1") == 0) {
893                                                 tmpstr[2] = cp;
894                                                 break;
895                                         }
896                                     {
897                                         struct ctrl **cpe;      /*empty cp*/
898                                         cpe = (struct ctrl **)NULL;
899                                         for (i = 5; i < 10; i++) {
900                                             if (!tmpstr[i]) {
901                                                 if (!cpe)
902                                                     cpe = &tmpstr[i];
903                                                 continue;
904                                             }
905                                             if (strcmp(cp->ctc2_value2,
906                                                 tmpstr[i]->ctc2_value2) == 0) {
907                                                     tmpstr[i] = cp;
908                                                     goto xfont_ok;
909                                             }
910                                         }
911                                         if (cpe)
912                                             *cpe = cp;
913                                     xfont_ok:
914                                         break;
915                                     }
916
917                                 case CTL_FORE: tmplong[0] = cp; break;
918                                 case CTL_BACK: tmplong[1] = cp; break;
919                                 case CTL_CCOLOR: tmpint[2] = cp; break;
920
921                                 case CTL_SIZE: tmpint[0] = cp; break;
922                                 case CTL_HGAP: tmpint[1] = cp; break;
923                                 case CTL_VGAP: tmpint[2] = cp; break;
924                                 case CTL_QUALITY: tmpint[3] = cp; break;
925
926                                 case CTL_LEFT: tmpvoid[0] = cp; break;
927                                 case CTL_RIGHT: tmpvoid[0] = cp; break;
928                                 case CTL_CENTER: tmpvoid[0] = cp; break;
929                                 case CTL_LEFTFILL: tmpvoid[0] = cp; break;
930                                 }
931                         }
932                 }
933
934                 cp = &sentinel;
935                 for (i = 0; i < 10; i++) {
936                         if (!tmpstr[i])
937                                 continue;
938                         cp->ct_next = ctlalloc1(tmpstr[i]->ct_op);
939                         if (ctl_words[tmpstr[i]->ct_op].ctl_vtype == T_STR2) {
940                                 if (tmpstr[i]->ctc2_value1) {
941                                         cp->ct_next->ctc2_value1 =
942                                                 strdup(tmpstr[i]->ctc2_value1);
943                                 } else
944                                         cp->ct_next->ctc2_value1 = NULL;
945                                 if (tmpstr[i]->ctc2_value2) {
946                                         cp->ct_next->ctc2_value2 =
947                                                 strdup(tmpstr[i]->ctc2_value2);
948                                 } else
949                                         cp->ct_next->ctc2_value2 = NULL;
950                         } else {
951                                 if (tmpstr[i]->ctc_value) {
952                                         cp->ct_next->ctc_value =
953                                                 strdup(tmpstr[i]->ctc_value);
954                                 } else
955                                         cp->ct_next->ctc_value = NULL;
956                         }
957                         cp = cp->ct_next;
958                 }
959                 for (i = 0; i < 10; i++) {
960                         if (!tmplong[i])
961                                 continue;
962                         cp->ct_next = ctlalloc1(tmplong[i]->ct_op);
963                         cp->ct_next->ctl_value = tmplong[i]->ctl_value;
964                         cp = cp->ct_next;
965                 }
966                 for (i = 0; i < 10; i++) {
967                         if (!tmpint[i])
968                                 continue;
969                         cp->ct_next = ctlalloc1(tmpint[i]->ct_op);
970                         cp->ct_next->ct_val = tmpint[i]->ct_val;
971                         cp = cp->ct_next;
972                 }
973                 for (i = 0; i < 10; i++) {
974                         if (!tmpvoid[i])
975                                 continue;
976                         cp->ct_next = ctlalloc1(tmpvoid[i]->ct_op);
977                         cp = cp->ct_next;
978                 }
979
980                 carryover[page] = sentinel.ct_next;
981         }
982     }
983
984         /* add default directives to each line */
985         for (page = 1; page <= maxpage; page++) {
986                 if (page_attribute[page].pg_flag & PGFLAG_NODEF)
987                         continue;
988                 line = page_attribute[page].pg_linenum;
989                 for (l = 0; l <= line; l++) {
990                         ch = &page_control[page][l];
991                         if (default_control[l]) {
992                                 ctlinsert(ch, ctlcopy(default_control[l]));
993                         }
994                 }
995         }
996
997         /*
998          * add carryover directives to each page.
999          * default directive has priority over the carryover items,
1000          * so carryover items should appear earlier than default directive.
1001          */
1002         for (page = 1; page <= maxpage; page++) {
1003                 ch = &page_control[page][0];
1004                 if (carryover[page - 1])
1005                         ctlinsert(ch, carryover[page - 1]);
1006         }
1007
1008         /*
1009          * add CTL_LINEEND and CTL_LINESTART to each lines that contain
1010          * CTL_TEXT/CTL_IMAGE/CTL_BAR/CTL_ICON.
1011          * note that we must carefully handle CTL_CONT.
1012          */
1013     {
1014         int textseen;
1015         int contseen;
1016         for (page = 1; page <= maxpage; page++) {
1017                 line = page_attribute[page].pg_linenum;
1018                 for (l = 0; l <= line; l++) {
1019                         textseen = 0;
1020                         for (cp = page_control[page][l];
1021                              cp;
1022                              cp = cp->ct_next) {
1023                                 if (cp->ct_op == CTL_TEXT
1024                                  || cp->ct_op == CTL_IMAGE
1025                                  || cp->ct_op == CTL_BAR
1026                                  || cp->ct_op == CTL_ICON) {
1027                                         textseen++;
1028                                         break;
1029                                 }
1030                         }
1031
1032                         if (!textseen)
1033                                 continue;
1034
1035                         /*
1036                          * check if the line #l includes CONT directive.
1037                          * if it has, don't add LINESTART to the line #l.
1038                          */
1039                         contseen = 0;
1040                         for (cp = page_control[page][l];
1041                              cp;
1042                              cp = cp->ct_next) {
1043                                 if (cp->ct_op == CTL_CONT) {
1044                                         contseen++;
1045                                         break;
1046                                 }
1047                         }
1048                         if (!contseen) {
1049                                 cp = ctlalloc1(CTL_LINESTART);
1050                                 if (cp) {
1051                                     for (ch = &page_control[page][l];
1052                                          ch && *ch;
1053                                          ch = &((*ch)->ct_next)) {
1054                                         if ((*ch)->ct_op == CTL_TEXT
1055                                          || (*ch)->ct_op == CTL_IMAGE
1056                                          || (*ch)->ct_op == CTL_BAR
1057                                          || (*ch)->ct_op == CTL_ICON) {
1058                                             break;
1059                                         }
1060                                     }
1061                                     ctlinsert(ch,  cp);
1062                                 }
1063                         }
1064
1065                         /*
1066                          * check if the line #(l+1) includes CONT directive.
1067                          * if it has, don't add LINEEND to the line #l.
1068                          */
1069                         contseen = 0;
1070                         if (l + 1 <= line) {
1071                                 for (cp = page_control[page][l + 1];
1072                                      cp;
1073                                      cp = cp->ct_next) {
1074                                         if (cp->ct_op == CTL_CONT) {
1075                                                 contseen++;
1076                                                 break;
1077                                         }
1078                                 }
1079                         }
1080                         if (!contseen) {
1081                                 cp2 = NULL;
1082                                 for (cp1 = page_control[page][l];
1083                                      cp1;
1084                                      cp1 = cp1->ct_next) {
1085                                         if (cp1->ct_op == CTL_TEXT
1086                                          || cp1->ct_op == CTL_IMAGE
1087                                          || cp1->ct_op == CTL_BAR
1088                                          || cp1->ct_op == CTL_ICON) {
1089                                             cp2 = cp1;
1090                                         }
1091                                 }
1092                                 /* cp2 has the last TEXT/IMAGE/whatever */
1093                                 if (cp2) {
1094                                         cp = ctlalloc1(CTL_LINEEND);
1095                                         if (cp)
1096                                                 ctlinsert(&(cp2->ct_next),  cp);
1097                                 }
1098                         }
1099                 }
1100         }
1101     }
1102
1103         /* insert CTL_TAB items into CTL_LINESTART */
1104         for (page = 1; page <= maxpage; page++) {
1105                 line = page_attribute[page].pg_linenum;
1106                 for (l = 0; l <= line; l++) {
1107                         /*
1108                          * if we don't have CTL_LINESTART, we don't add
1109                          * directives here.
1110                          */
1111                         cp = page_control[page][l];
1112                         while (cp && cp->ct_op != CTL_LINESTART)
1113                                 cp = cp->ct_next;
1114                         if (!cp)
1115                                 continue;
1116
1117                         /* cp2: CTL_LINESTART */
1118                         cp2 = cp1 = cp;
1119                         while (cp && cp->ct_op != CTL_TEXT) {
1120                                 cp1 = cp;
1121                                 cp = cp->ct_next;
1122                         }
1123                         if (!cp)
1124                                 continue;
1125                         if (cp1->ct_next != cp)
1126                                 continue;
1127                         p = cp->ctc_value;
1128                         if (p && *p == '\t') {
1129                                 int tab_depth;
1130
1131                                 tab_depth = 0;
1132                                 p++;
1133                                 while (*p == '\t') {
1134                                         tab_depth++;
1135                                         p++;
1136                                 }
1137                                 if (p) {
1138                                         char *tmp;
1139
1140                                         tmp = cp->ctc_value;
1141                                         p = cp->ctc_value = strdup(p);
1142                                         free(tmp);
1143                                 }
1144
1145                                 if (tab_control[tab_depth]) {
1146                                         ctlinsert(&cp1->ct_next,
1147                                             ctlcopy(tab_control[tab_depth]));
1148                                 }
1149                         }
1150                         /* special: style escape */
1151                         if (p && *p == '&') {
1152                                 char *p0;
1153                                 char *tmp;
1154                                 int i;
1155
1156                                 p0 = p;
1157                                 while (*p && !isspace(*p))
1158                                         p++;
1159
1160                                 tmp = cp->ctc_value;
1161                                 if (!*p)
1162                                         cp->ctc_value = strdup(p);
1163                                 else {
1164                                         *p++ = '\0';
1165                                         while (*p && isspace(*p))
1166                                                 p++;
1167                                         cp->ctc_value = strdup(p);
1168                                 }
1169
1170                                 for (i = MAXTAB; i < MAXTAB + MAXSTYLE ; i++) {
1171                                         if (tab_control[i]
1172                                          && strcmp(p0 + 1, tab_control[i]->ctc_value) == 0)
1173                                                 break;
1174                                 }
1175                                 if (i == MAXTAB + MAXSTYLE) {
1176                                         fprintf(stderr, "style %s not found\n",
1177                                                 p0 + 1);
1178                                 } else {
1179                                         ctlinsert(&cp1->ct_next,
1180                                             ctlcopy(tab_control[i]->ct_next));
1181                                 }
1182                                 free(tmp);
1183                         }
1184                 }
1185         }
1186
1187         /* find where to put PREFIX. */
1188         for (page = 1; page <= maxpage; page++) {
1189                 line = page_attribute[page].pg_linenum;
1190                 for (l = 0; l <= line; l++) {
1191                         for (cp = page_control[page][l]; cp; cp = cp->ct_next) {
1192                                 if (cp->ct_op == CTL_LINESTART)
1193                                         break;
1194                         }
1195                         if (!cp)
1196                                 continue;
1197                         cp1 = cp;       /* cp1: CTL_LINESTART */
1198
1199                         for (cp = cp1; cp->ct_next; cp = cp->ct_next) {
1200                                 if (cp->ct_next->ct_op == CTL_TEXT
1201                                  || cp->ct_next->ct_op == CTL_IMAGE
1202                                  || cp->ct_next->ct_op == CTL_ICON) {
1203                                         break;
1204                                 }
1205                         }
1206                         if (!cp)
1207                                 continue;
1208
1209                         cp2 = ctlalloc1(CTL_PREFIXPOS);
1210                         if (!cp2)
1211                                 continue;
1212
1213                         cp2->ct_next = cp->ct_next;
1214                         cp->ct_next = cp2;
1215                 }
1216         }
1217
1218         /*
1219          * CTL_FONT must be replaced with appropriate font def defined by
1220          * CTL_DEFFONT.
1221          */
1222         for (page = 1; page <= maxpage; page++) {
1223                 for (l = 0; l <= page_attribute[page].pg_linenum; l++) {
1224                         for (cp = page_control[page][l];
1225                              cp;
1226                              cp = cp->ct_next) {
1227                                 if (cp->ct_op == CTL_FONT) {
1228                                         cp->ct_op = CTL_NOOP;
1229                                         cp1 = find_font(cp->ctc_value);
1230                                         if (!cp1) {
1231                                                 fprintf(stderr,
1232 "page %d line %d: font def for \"%s\" not found: ignored\n",
1233                                                         page, l, cp->ctc_value);
1234                                                 continue;
1235                                         }
1236                                         ctlinsert(&cp->ct_next,
1237                                                 ctlcopy(cp1->ct_next));
1238                                 }
1239                         }
1240                 }
1241         }
1242
1243         /*
1244          * CTL_XFONT is now obsolete, use CTL_XFONT2.
1245          */
1246         for (page = 1; page <= maxpage; page++) {
1247                 for (l = 0; l <= page_attribute[page].pg_linenum; l++) {
1248                         for (cp = page_control[page][l];
1249                              cp;
1250                              cp = cp->ct_next) {
1251                                 if (cp->ct_op == CTL_XFONT) {
1252                                         p = cp->ctc_value;
1253                                         cp->ct_op = CTL_XFONT2;
1254                                         cp->ctc2_value1 = p;
1255                                         cp->ctc2_value2 = strdup("iso8859-1");
1256                                 }
1257                         }
1258                 }
1259         }
1260 }
1261
1262 void
1263 debug0(p)
1264         struct ctrl *p;
1265 {
1266         int i;
1267
1268         fprintf(stderr, "%p: ", p);
1269         fprintf(stderr, " %s ", ctl_words[p->ct_op].ctl_string);
1270
1271         switch (ctl_words[p->ct_op].ctl_vtype) {
1272         case T_STR:
1273                 fprintf(stderr, "\"%s\"", p->ctc_value);
1274                 break;
1275         case T_STR2:
1276                 fprintf(stderr, "\"%s\" \"%s\"",
1277                         p->ctc2_value1, p->ctc2_value2);
1278                 break;
1279         case T_INT:
1280                 fprintf(stderr, "%d", p->cti_value);
1281                 break;
1282         case T_LONG:
1283                 fprintf(stderr, "#%lx", p->ctl_value);
1284                 break;
1285         case T_DOUBLE:
1286                 fprintf(stderr, "#%g", p->ctf_value);
1287                 break;
1288         case T_VOID:
1289                 break;
1290         case T_SP:
1291                 break;
1292         default:
1293                 fprintf(stderr, "(UNDEFINED TYPE)");
1294         }
1295
1296         if (ctl_words[p->ct_op].ctl_vtype != T_SP)
1297                 goto done;
1298
1299         switch (p->ct_op) {
1300         case CTL_PAUSE:
1301                 fprintf(stderr, "(%s)",
1302                         p->cti_value ? "page end" : "normal");
1303                 break;
1304         case CTL_TAB:
1305                 if (p->cti_value > MAXTAB)
1306                         fprintf(stderr, "\"%s\"", p->ctc_value);
1307                 else
1308                         fprintf(stderr, "%d", p->cti_value);
1309                 break;
1310         case CTL_SYSTEM:
1311         case CTL_XSYSTEM:
1312         case CTL_FILTER:
1313                 fprintf(stderr, "argc=%d term=%s flag=%d",
1314                         p->cta_argc,
1315                         p->cta_argv[p->cta_argc] ? "bad" : "good",
1316                         p->cta_flag);
1317                 for (i = 0; i < p->cta_argc; i++)
1318                         fprintf(stderr, "%s ", p->cta_argv[i]);
1319                 break;
1320         case CTL_BAR:
1321                 fprintf(stderr, "color=#%lx width=%d start=%d length=%d",
1322                         p->ctb_color, p->ctb_width,
1323                         p->ctb_start, p->ctb_length);
1324                 break;
1325         case CTL_BIMAGE:
1326         case CTL_IMAGE:
1327                 fprintf(stderr, "file=%s colors=%d x=%d y=%d zoom=%d",
1328                         p->ctm_fname, p->ctm_numcolor,
1329                         p->ctm_ximagesize, p->ctm_yimagesize,
1330                         p->ctm_zoomflag);
1331                 break;
1332         case CTL_BGRAD:
1333                 fprintf(stderr, "w=%d h=%d nc=%d dir=%d zoom=%d colors=%d",
1334                         p->ctd_width, p->ctd_height,
1335                         p->ctd_numcolor, p->ctd_dir,
1336                         p->ctd_zoomflag, p->ctd_g_colors);
1337                 break;
1338         case CTL_ICON:
1339                 fprintf(stderr, "type=%s color=%x siz=%d",
1340                         p->ctic_value, (int)p->ctic_color, (int) p->ctic_size);
1341                 break;
1342         default:
1343                 fprintf(stderr, "???");
1344         }
1345
1346 done:
1347         fprintf(stderr, "\n");
1348 }
1349
1350 void
1351 debug1(p)
1352         struct ctrl *p;
1353 {
1354         while (p) {
1355                 fprintf(stderr, "\t");
1356                 debug0(p);
1357                 p = p->ct_next;
1358         }
1359 }
1360
1361 static void
1362 debug()
1363 {
1364         int page, line;
1365
1366         for (line = 0; line < MAXLINE; line ++) {
1367                 if (!default_control[line])
1368                         continue;
1369                 fprintf(stderr, "def line %d:\n", line);
1370                 debug1(default_control[line]);
1371         }
1372         for (page = 0; page < MAXPAGE; page ++) {
1373                 for (line = 0; line < MAXLINE; line ++) {
1374                         if (!page_control[page][line])
1375                                 continue;
1376                         fprintf(stderr, "page %d line %d:\n", page, line);
1377                         debug1(page_control[page][line]);
1378                 }
1379         }
1380 }
1381
1382 int
1383 chkfile(p)
1384         char *p;
1385 {
1386         char buf[BUFSIZ];
1387
1388         buf[0] = '\0';
1389         if (findImage(p, buf) >= 0) {
1390                 if (parse_debug)
1391                         fprintf(stderr, "File %s found\n", p);
1392                 return 0;
1393         }
1394         fprintf(stderr, "File %s can not found\n", p);
1395         parse_error++;
1396         return -1;
1397 }
1398
1399 /*------------------------------------------------------------*/
1400
1401 struct ctrl *
1402 ctllastitem(this)
1403         struct ctrl *this;
1404 {
1405         struct ctrl *p;
1406
1407         assert(this);
1408         p = this;
1409         while (p && p->ct_next)
1410                 p = p->ct_next;
1411
1412         return p;
1413 }
1414
1415 void
1416 ctlappend(to, this)
1417         struct ctrl *to;
1418         struct ctrl *this;
1419 {
1420         struct ctrl *p;
1421
1422         assert(to);
1423         assert(this);
1424         p = ctllastitem(to);
1425         p->ct_next = this;
1426 }
1427
1428 void
1429 ctlinsert(here, this)
1430         struct ctrl **here;
1431         struct ctrl *this;
1432 {
1433         struct ctrl *p;
1434         struct ctrl *q;
1435
1436         assert(here); assert(this);
1437         p = *here;
1438         *here = this;
1439         q = ctllastitem(this);
1440         q->ct_next = p;
1441 }
1442
1443 struct ctrl *
1444 ctlalloc1(op)
1445         u_int op;
1446 {
1447         struct ctrl *p;
1448
1449         p = (struct ctrl *)malloc(sizeof(struct ctrl));
1450         if (!p) {
1451                 perror("malloc");
1452                 exit(-1);
1453         }
1454         memset(p, 0, sizeof(struct ctrl));
1455         p->ct_op = op;
1456         p->ct_next = NULL;      /*just to make sure*/
1457         return p;
1458 }
1459
1460 void
1461 ctlfree(this)
1462         struct ctrl *this;
1463 {
1464         struct ctrl *p;
1465         struct ctrl *q;
1466
1467         assert(this);
1468         p = this;
1469         do {
1470                 q = p->ct_next;
1471                 free(p);
1472                 p = q;
1473         } while (p);
1474 }
1475
1476 struct ctrl *
1477 ctlcopy(this)
1478         struct ctrl *this;
1479 {
1480         struct ctrl *dst0;
1481         struct ctrl *dst;
1482         struct ctrl *src;
1483
1484         src = this;
1485         if (!src)
1486                 return NULL;
1487         dst = dst0 = ctlalloc1(0);
1488         memcpy(dst, src, sizeof(struct ctrl));
1489         src = src->ct_next;
1490         while (src) {
1491                 dst->ct_next = ctlalloc1(0);
1492                 dst = dst->ct_next;
1493                 memcpy(dst, src, sizeof(struct ctrl));
1494                 src = src->ct_next;
1495         }
1496
1497         return dst0;
1498 }
1499
1500 int
1501 ctlcmp(a, b)
1502         struct ctrl *a;
1503         struct ctrl *b;
1504 {
1505         int i;
1506
1507         assert(a);
1508         assert(b);
1509
1510         if (a->ct_op != b->ct_op)
1511                 return 1;
1512         if (a->ct_flag != b->ct_flag)
1513                 return 1;
1514
1515         switch (ctl_words[a->ct_op].ctl_vtype) {
1516         case T_STR:
1517                 return strcmp(a->ctc_value, b->ctc_value);
1518         case T_STR2:
1519                 if (strcmp(a->ctc2_value1, b->ctc2_value1) == 0
1520                  && strcmp(a->ctc2_value2, b->ctc2_value2) == 0) {
1521                         return 0;
1522                 } else
1523                         return 1;
1524         case T_INT:
1525                 return (a->cti_value == b->cti_value) ? 0 : 1;
1526         case T_LONG:
1527                 return (a->ctl_value == b->ctl_value) ? 0 : 1;
1528         case T_DOUBLE:
1529                 return (a->ctf_value == b->ctf_value) ? 0 : 1;
1530         case T_VOID:
1531                 return 0;
1532         case T_SP:
1533                 break;
1534         default:
1535                 fprintf(stderr, "UNDEFINED TYPE in ctlcmp()\n");
1536                 return 1;
1537         }
1538
1539         switch (a->ct_op) {
1540         case CTL_TAB:
1541         case CTL_PAUSE:
1542                 return (a->cti_value == b->cti_value) ? 0 : 1;
1543         case CTL_SYSTEM:
1544         case CTL_XSYSTEM:
1545         case CTL_FILTER:
1546                 return 1;
1547         case CTL_IMAGE:
1548         case CTL_BIMAGE:
1549                 if (a->ctm_numcolor == b->ctm_numcolor
1550                  && a->ctm_ximagesize == b->ctm_ximagesize
1551                  && a->ctm_yimagesize == b->ctm_yimagesize
1552                  && a->ctm_zoomflag == b->ctm_zoomflag)
1553                         return strcmp(a->ctm_fname, b->ctm_fname);
1554                 else
1555                         return 1;
1556         case CTL_BGRAD:
1557                 if (a->ctd_g_colors == b->ctd_g_colors
1558                  && a->ctd_numcolor == b->ctd_numcolor
1559                  && a->ctd_dir == b->ctd_dir
1560                  && a->ctd_width == b->ctd_width
1561                  && a->ctd_height == b->ctd_height
1562                  && a->ctd_zoomflag == b->ctd_zoomflag) {
1563                         for (i = 0; i < a->ctd_g_colors; i++) {
1564                                 if (memcmp(a->ctd_colors[0], b->ctd_colors[0],
1565                                                 sizeof(struct g_color)) != 0)
1566                                         return 1;
1567                         }
1568                         return 0;
1569                 } else
1570                         return 1;
1571         case CTL_BAR:
1572                 if (a->ctb_color == b->ctb_color
1573                  && a->ctb_width == b->ctb_width
1574                  && a->ctb_start == b->ctb_start
1575                  && a->ctb_length == b->ctb_length)
1576                         return 0;
1577                 else
1578                         return 1;
1579         case CTL_ICON:
1580                 if (strcmp(a->ctic_value, b->ctic_value) == 0
1581                  && a->ctic_color == b->ctic_color
1582                  && a->ctic_size == b->ctic_size)
1583                         return 0;
1584                 else
1585                         return 1;
1586         default:
1587                 assert(0);
1588         }
1589 }
1590
1591 FILE *
1592 fsearchopen(fname, mode, path)
1593         char *fname;
1594         char *mode;
1595         char **path;
1596 {
1597         FILE *fp;
1598         char buf[MAXPATHLEN];
1599         char *p;
1600         int i;
1601
1602         i = -1;
1603         fp = NULL;
1604         while (1) {
1605                 p = (i == -1) ? "" : path[i];
1606                 if (!p)
1607                         break;
1608                 strcpy(buf, p);
1609                 if ((p = strrchr(buf, '/'))) {
1610                         p[1] = '\0';
1611                 }
1612                 strcat(buf, fname);
1613                 fp = fopen(buf, mode);
1614                 if (fp)
1615                         break;
1616                 i++;
1617         }
1618         return fp;
1619 }
1620
1621 static int
1622 define_font(cp)
1623         struct ctrl *cp;
1624 {
1625         int i;
1626
1627         /* find duplicated def */
1628         for (i = 0; i < MAXFONTDEF; i++) {
1629                 if (!fontdef_control[i])
1630                         continue;
1631                 if (strcmp(fontdef_control[i]->ctc_value,
1632                                 cp->ctc_value) == 0) {
1633                         ctlfree(fontdef_control[i]);
1634                         fontdef_control[i] = NULL;
1635                         goto defineit;
1636                 }
1637         }
1638
1639         /* find empty def */
1640         for (i = 0; i < MAXFONTDEF; i++) {
1641                 if (!fontdef_control[i])
1642                         break;
1643         }
1644         if (i == MAXFONTDEF) {
1645                 return -1;
1646         }
1647
1648 defineit:
1649         /* define it */
1650         fontdef_control[i] = cp;
1651         return 0;
1652 }
1653
1654 static struct ctrl *
1655 find_font(font)
1656         char *font;
1657 {
1658         int i;
1659
1660         /* find duplicated def */
1661         for (i = 0; i < MAXFONTDEF; i++) {
1662                 if (!fontdef_control[i])
1663                         continue;
1664                 if (strcmp(fontdef_control[i]->ctc_value, font) == 0)
1665                         return fontdef_control[i];
1666         }
1667         return NULL;
1668 }