1 /* $Header: /home/yav/catty/fkiss/RCS/kisscnf.c,v 1.25 2000/09/28 07:52:48 yav Exp $
2  * KISS configration file (*.cnf) parse
3  * written by yav <yav@bigfoot.com>
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18  */
19 
20 char id_kisscnf[] = "$Id: kisscnf.c,v 1.25 2000/09/28 07:52:48 yav Exp $";
21 
22 #include <X11/Xlib.h>
23 #include <X11/Xos.h>
24 #include <stdio.h>
25 #include "config.h"
26 
27 #include "headers.h"
28 #include "fkiss.h"
29 #include "work.h"
30 #define PUBLIC_KISSCNF_C
31 #include "extern.h"
32 
33 #define OBJINCSTEP 64
34 #define CELINCSTEP 64
35 
36 #define MAXCNFCOMMENT 25
37 
38 static int celcnt_alloced;
39 static int objcnt_alloced;
40 
41 static int linecnt = 0;
42 static char **lineptr = NULL;
43 static int transparency_hint = 0;
44 static char *cel_comment = NULL;
45 
init_object_cell()46 void init_object_cell()
47 {
48   int i, n;
49 
50   objcnt = celcnt = 0;
51   n = OBJINCSTEP * sizeof(OBJECT);
52   object = (OBJECT *)ks_malloc(n);
53   bzero((char *)object, n);
54   n = sizeof(OBJPOS)*OBJINCSTEP;
55   for (i = 0; i < MAXSET; i++) {
56     kset[i].obj = (OBJPOS *)ks_malloc(n);
57     bzero((char *)kset[i].obj, n);
58   }
59   objcnt_alloced = OBJINCSTEP;
60   n = CELINCSTEP * sizeof(CELL);
61   cell = (CELL *)ks_malloc(n);
62   bzero((char *)cell, n);
63   celcnt_alloced = CELINCSTEP;
64 }
65 
change_celmax(n)66 int change_celmax(n)
67      int n;
68 {
69   int i;
70 
71   if (n < 0 || n >= MAXCEL) {
72     msg("W cell count %d range over (max %d).\n", n, MAXCEL);
73     return 1;
74   }
75   if (n >= celcnt_alloced) {
76     for (i = celcnt_alloced; i < n; i += CELINCSTEP)
77       ;
78     cell = (CELL *)ks_realloc(cell, sizeof(*cell)*i);
79     bzero((char *)(cell+celcnt_alloced), sizeof(*cell)*(i-celcnt_alloced));
80     celcnt_alloced = i;
81   }
82   return 0;
83 }
84 
change_objmax(n)85 int change_objmax(n)
86      int n;
87 {
88   int i, j;
89 
90   if (n < 0 || n >= MAXOBJ) {
91     msg("W object mark %d range over (max %d).\n", n, MAXOBJ);
92     return 1;
93   }
94   if (n >= objcnt_alloced) {
95     for (i = objcnt_alloced; i < n; i += OBJINCSTEP)
96       ;
97     object = (OBJECT *)ks_realloc(object, sizeof(OBJECT)*i);
98     bzero((char *)(object+objcnt_alloced), sizeof(OBJECT)*(i-objcnt_alloced));
99     for (j = 0; j < MAXSET; j++) {
100       kset[j].obj = (OBJPOS *)ks_realloc(kset[j].obj, sizeof(OBJPOS)*i);
101       bzero((char *)(kset[j].obj+objcnt_alloced), sizeof(OBJPOS)*(i-objcnt_alloced));
102     }
103     objcnt_alloced = i;
104   }
105   return 0;
106 }
107 
skip_space(p)108 void skip_space(p)
109      char **p;
110 {
111   while (**p == ' ' || **p == '\t')
112     ++*p;
113 }
114 
skip_notspace(p)115 void skip_notspace(p)
116      char **p;
117 {
118   while (**p && **p != ' ' && **p != '\t')
119     ++*p;
120 }
121 
cnf_cell(str,lcnt)122 int cnf_cell(str, lcnt)
123      char *str;
124      int lcnt;			/* cnf line number */
125 {
126   int i;
127   int mark;
128   char *p;
129   CELL *cp;
130   CELL work_cell;
131   LSTR namebuf;
132 
133   cp = &work_cell;
134   bzero((char *)cp, sizeof(CELL));
135   cp->line = lcnt;
136   cp->transparency = transparency_hint;
137   cp->comment = cel_comment;
138   cel_comment = NULL;
139   /* parse mark */
140   mark = strtol(str, &str, 10);
141   cp->obj = mark;
142   /* check fix value */
143   if (*str == '.') {
144     str++;
145     i = strtol(str, &str, 10);
146     if (i > max_fix)
147       max_fix = i;
148     cp->fix = i;
149   }
150   skip_space(&str);
151   lstr_init(&namebuf);
152   while (*str != '\0' && *str != '\t' && *str != ' ')
153     lstr_ch(&namebuf, *str++);
154   cp->filename = namebuf.buf;
155   skip_space(&str);
156   /* color */
157   cp->colfile = 0;		/* default color 0 */
158   if (*str == '*') {
159     str++;			/* skip '*' */
160     i = strtol(str, &str, 10);
161     if (i >= colorfilecnt) {
162       msgset("W color file #%d nothing! use #0.\n", i);
163       i = 0;
164     }
165     cp->colfile = i;
166     skip_space(&str);
167   }
168   /* set */
169   for (i = 0; i < MAXSET; i++)
170     cp->setflag[i] = 1;		/* default all set active */
171   if (*str == ':') {
172     str++;			/* skip ':' */
173     for (i = 0; i < MAXSET; i++)
174       cp->setflag[i] = 0;
175     while((i = strtol(p = str, &str, 10)), str != p)
176       cp->setflag[i] = 1;
177   }
178   for (i = 0; i < MAXSET; i++) {
179     if (active_set[i] && cp->setflag[i]) {
180       /* work_cell -> cell */
181       if (objcnt <= mark) {
182 	if (change_objmax(mark+1))
183 	  return 1;
184 	objcnt = mark+1;
185       }
186       if (change_celmax(celcnt+1))
187 	return 1;
188 #if 0	/* yav told me that mio.h told him that fix values add up */
189       /* when the cels which build an object have DIFFERENT fixing values,
190       ** we take the highest of all values.
191       */
192       if ( (object+mark)->fix < cp->fix )
193 	(object+mark)->fix = cp->fix;
194 #else
195       if ( (object+mark)->fix + cp->fix >= MAXSHORT )
196         msg("W cell fix value %d + old fix value %d >= %d, ignored.\n",
197 	    (object+mark)->fix, cp->fix, MAXSHORT);
198       else
199         (object+mark)->fix += cp->fix;	/* add up all fixing values */
200 #endif
201       bcopy((char *)&work_cell, (char *)(cell+celcnt), sizeof(CELL));
202       celcnt++;
203       break;
204     }
205   }
206   return 0;
207 }
208 
cnf_set(str)209 int cnf_set(str)
210      char *str;
211 {
212   int i, j;
213   int x, y;
214   SETINFO *p;
215   Bool finish;
216 
217   if (setcnt >= MAXSET)
218     return 1;
219   p = &kset[setcnt++];
220   p->pal = strtol(str, &str, 10);
221   finish = False;
222   for (i = 0; i < objcnt; i++) {
223     (p->obj+i)->x = (p->obj+i)->y = x = y = 0;
224     if (objpos_first_align) {
225       for (j = 0; j < setcnt-1; j++) {
226 	x = (kset[j].obj+i)->x;
227 	y = (kset[j].obj+i)->y;
228 	if (x||y)
229 	  break;
230       }
231     }
232     if (!finish) {
233       skip_space(&str);
234       if (!*str)
235 	finish = True;
236     }
237     if (!finish) {
238       if (*str == '*') {
239 	str++;
240       } else {
241 	x = strtol(str, &str, 10);
242 	skip_space(&str);
243 	if (*str == ',')
244 	  str++;
245 	y = strtol(str, &str, 10);
246       }
247     }
248     (p->obj+i)->x = x;
249     (p->obj+i)->y = y;
250   }
251   return 0;
252 }
253 
cnf_color(str)254 int cnf_color(str)
255      char *str;
256 {
257   COLOR *cp;
258   LSTR buf;
259 
260   lstr_init(&buf);
261   if (!colorfilecnt)
262     kcflist = (COLOR *)ks_malloc(sizeof(COLOR));
263   else
264     kcflist = (COLOR *)ks_realloc(kcflist, sizeof(COLOR)*(colorfilecnt+1));
265   cp = kcflist + colorfilecnt;
266   while (*str != '\0' && *str != ' ' && *str != '\t')
267     lstr_ch(&buf, *str++);
268   cp->filename = buf.buf;
269   colorfilecnt++;
270   return 0;
271 }
272 
cnf_size(str)273 int cnf_size(str)
274      char *str;
275 {
276   int w, h;
277 
278   w = strtol(str, &str, 10);
279   skip_space(&str);
280   if (*str && !is_digit(*str))
281     str++;
282   h = strtol(str, &str, 10);
283   debug_printf("set screen size %3dx%3d.\n", w, h);
284   if (w > 0)
285     imgw0 = w;
286   if (h > 0)
287     imgh0 = h;
288   if (w <= 0 || h <= 0)
289     msgset("W bad screen size %dx%d.\n", w, h);
290   return 0;
291 }
292 
cnf_border(str)293 int cnf_border(str)
294      char *str;
295 {
296   int i;
297   char *p;
298 
299   i = strtol(str, &p, 10);
300   if (str != p) {
301     debug_printf("set border %d.\n", i);
302     border_color = i;
303   }
304   return 0;
305 }
306 
cut_comment(p)307 char *cut_comment(p)
308      char *p;
309 {
310   p = index(p, ';');
311   if (p != NULL) {
312     *p++ = '\0';
313   }
314   return p;
315 }
316 
anal_comment(p)317 void anal_comment(p)
318      char *p;
319 {
320   int i;
321   char *p2;
322 
323   transparency_hint = 0;	/* reset transparency */
324   if (cel_comment != NULL) {
325     free(cel_comment);
326     cel_comment = NULL;
327   }
328   if (p == NULL)
329     return;
330   while (skip_space(&p), *p) {
331     switch(*p++) {
332     case '@':
333       skip_notspace(&p);
334       break;
335     case '%':
336       skip_space(&p);
337       switch(*p++) {
338       case '\0':
339 	--p;
340 	break;
341       case 't':
342       case 'T':
343 	i = strtol(p, &p, 10);
344 	if (i >= 0 && i <= 256) {
345 	  transparency_hint = i;
346 	  debug_printf("set transparency hint %d\n", i);
347 	}
348 	break;
349       default:
350 	skip_notspace(&p);
351 	break;
352       }
353       break;
354     default:
355       p--;			/* enable top letter */
356       skip_space(&p);
357       if (*p) {
358 	/* ToDo: must convert Shift-JIS!! */
359 	p2 = parse_string(&p, NULL);
360 	if (cel_comment == NULL) {
361 	  cel_comment = p2;	/* First comment is stored */
362 	} else {
363 	  free(p2);		/* Other comments are ignored */
364 	}
365       }
366       break;
367     }
368   }
369 }
370 
report_cnf_error(name,lptr,lcnt)371 void report_cnf_error(name, lptr, lcnt)
372      char *name;		/* filename */
373      char **lptr;		/* original config lines */
374      int lcnt;			/* line number */
375 {
376   msg("%s:%d:\n%s", name, lcnt, *(lptr+lcnt-1));
377 }
378 
parse_config(str,name,lptr,lcnt)379 int parse_config(str, name, lptr, lcnt)
380      char *str;
381      char *name;		/* filename */
382      char **lptr;		/* original config lines */
383      int lcnt;			/* line number */
384 {
385   char *p;
386 
387   p = str;
388   if (*p)
389     p++;
390   skip_space(&p);
391   switch(*str) {
392   case '\0':			/* Comment or blank line */
393     break;
394   case '=':			/* Memory size */
395     /* memory size hint for KISS version 1.0 */
396     break;
397   case '(':			/* Screen size */
398     cnf_size(p);
399     break;
400   case '%':			/* Palette file */
401     cnf_color(p);
402     break;
403   case '[':			/* Border color */
404     cnf_border(p);
405     break;
406   case '#':			/* Cel file */
407     cnf_cell(p, lcnt);
408     break;
409   case '$':			/* Set information */
410     cnf_set(p);
411     break;
412   case '@':
413     cnf_event(p, lcnt);
414     break;
415   default:			/* unknown function */
416     msgset("W unknown function.\n");
417     break;
418   }
419   if (msg_queued()) {
420     report_cnf_error(name, lptr, lcnt);
421     return 1;
422   }
423   return 0;
424 }
425 
fill_sets(n0,n)426 void fill_sets(n0, n)
427      int n0;			/* set info. specified set count */
428      int n;			/* need to display set count */
429 {
430   int s, s0;
431 
432   s0 = n0 ? (n0-1) : 0;
433   for (s = n0; s < n; s++)
434     bcopy(kset+s0, kset+s, sizeof(*kset));
435 }
436 
437 /* update
438  *  setcnt, cset, active_set[], kset[]
439  */
adjust_effective_setcnt()440 void adjust_effective_setcnt()
441 {
442   int i, j, n;
443   char buf[MAXSET];
444 
445   bzero(buf, sizeof(buf));
446   for (i = 0; i < MAXSET; i++) {
447     if (active_set[i]) {
448       for (j = 0; j < celcnt; j++) {
449 	if ((cell+j)->setflag[i])
450 	  buf[i] = 1;
451       }
452     }
453   }
454   n = 0;
455   for (i = 0; i < MAXSET; i++) {
456     if (buf[i])
457       n = i;
458     else
459       active_set[i] = 0;
460   }
461   n++;
462   fill_sets(setcnt, n);
463   for (i = 0; i < n; i++) {
464     if (active_set[i]) {
465       cset = i;
466       break;
467     }
468   }
469   setcnt = n;
470 }
471 
init_org_position()472 void init_org_position()
473 {
474   int i, j;
475   OBJPOS *p;
476 
477   for (i = 0; i < setcnt; i++) {
478     if (active_set[i]) {
479       for (p = kset[i].obj, j = 0; j < objcnt; p++, j++) {
480 	p->ox = p->x;
481 	p->oy = p->y;
482       }
483     }
484   }
485 }
486 
read_config(name)487 int read_config(name)
488      char *name;
489 {
490   char *p;
491   int i, r, linecount, lastlcnt;
492   FILE *fp;
493   Bool eof_detect, pre_comment;
494   int evidn;			/* evid compare length */
495   char *commentstr;
496   char buf[1024];
497   char setstr[256+(1+5+1+5)*MAXOBJ];
498 
499   debug_printf("read_config [%s]\n", name);
500   fp = fopen(name, "r");
501   if (fp == NULL) {
502     msg("E ``%s'' open error!\n", name);
503     return 1;
504   }
505   /* preload */
506   lineptr = (char **)ks_malloc(sizeof(char *));
507   while (fgets(buf, sizeof(buf), fp) != NULL) {
508     lineptr = (char **)ks_realloc(lineptr, sizeof(char *) * (linecnt + 1));
509     *(lineptr+linecnt) = ks_strdup(buf);
510     linecnt++;
511     if (coding_type == CODING_UNKNOWN)
512       coding_type = check_coding(buf);
513   }
514   fclose(fp);
515   debug_printf("cnf file coding: %s\n", coding_name(coding_type));
516   evidn = strlen(evid);
517   kcflist = NULL;
518   cnf_comment = (char **)ks_malloc(sizeof(char *) * MAXCNFCOMMENT);
519   evn = cnf_comment_cnt = setcnt = celcnt = colorfilecnt = linecount = 0;
520   setstr[0] = '\0';
521   event_detect = eof_detect = False;
522   pre_comment = True;
523   while (!eof_detect) {
524     convert_coding(buf, *(lineptr+linecount));
525     p = buf;
526     if ((p = index(buf, 032)) != NULL) { /* check ^Z (CP/M EOF) */
527       *p = '\0';
528       eof_detect = True;
529     }
530     if (++linecount >= linecnt)
531       eof_detect = True;
532     cut_crlf(buf);
533     if (!buf[0])
534       continue;
535     if (buf[0] != ';')
536       pre_comment = False;
537     if (pre_comment) {
538       if (cnf_comment_cnt < MAXCNFCOMMENT)
539 	cnf_comment[cnf_comment_cnt++] = ks_strdup(buf);
540       msg("V%s\n", buf);
541     }
542     p = buf;
543     /* check event extension */
544     if (event_mode && !event_detect && (strncmp(buf, evid, evidn) == 0))
545       event_detect = True;
546     else if (event_detect && (strncmp(p, ";@", 2) == 0))
547       p++;
548     commentstr = cut_comment(p);
549     if (*p != ' ') {
550       if (setstr[0])
551 	parse_config(setstr, name, lineptr, lastlcnt);
552       lastlcnt = linecount;
553       setstr[0] = '\0';
554     }
555     strcat(setstr, p);
556     anal_comment(commentstr);
557   }
558   if (setstr[0])
559     parse_config(setstr, name, lineptr, lastlcnt);
560   adjust_effective_setcnt();
561   init_org_position();
562   if (event_detect) {
563     for (i = 0; i < evn; i++) {
564       r = compile_event(i);
565       /* This was more misleading than useful, because it reports
566       ** the error at the last line of the event block, and that
567       ** is much too late (except the error is in that last line).
568       ** instead, the error is now reported from compile_event().
569       */
570     }
571     init_hitck();
572     debug_printf("event compiled.\n");
573     kissevent_initialize();
574   }
575   /* free config lines */
576   for (linecount = 0; linecount < linecnt; linecount++)
577     free(*(lineptr+linecount));
578   free(lineptr);
579   return 0;
580 }
581 
write_set(fp,set)582 int write_set(fp, set)
583      FILE *fp;
584      int set;
585 {
586   int i, len, saveobjcnt;
587   char *p, *lastpos;
588   char buf[1024];
589   char tmpbuf[32];
590 
591   if (set >= MAXSET)
592     return 0;
593   if (set >= setcnt) {
594     fputs("$0 *\n", fp);
595     return 0;
596   }
597   /* check object position is (0,0) */
598   i = objcnt;
599   while (--i) {
600     if ((kset[set].obj+i)->x || (kset[set].obj+i)->y)
601       break;
602   }
603   saveobjcnt = i + 1;
604   len = (oldcnf_comaptible && objcnt <= KISSGS1_MAXCEL) ? 255 : 78;
605   sprintf(buf, "$%d", kset[set].pal);
606   p = buf + strlen(buf);
607   for (i = 0; i < saveobjcnt; i++) {
608     lastpos = p;
609     *p++ = ' ';
610     if (!(kset[set].obj+i)->x && !(kset[set].obj+i)->y) {
611       *p++ = '*';
612     } else {
613       sprintf(p, "%d,%d", (kset[set].obj+i)->x, (kset[set].obj+i)->y);
614       p += strlen(p);
615     }
616     if (p >= buf+len) {
617       *p = '\0';
618       strcpy(tmpbuf, lastpos);	/* keep after lastpos */
619       strcpy(lastpos, "\n");	/* cut after lastpos */
620       fputs(buf, fp);
621       strcpy(buf, tmpbuf);
622       p = buf + strlen(buf);
623     }
624   }
625   /* flush holding string */
626   if (p != buf) {
627     strcpy(p, "\n");
628     fputs(buf, fp);
629   }
630   return 0;
631 }
632 
633 /* write_config - write KISS configuration file
634  * copy src file to dst file except set information.
635  * current set information is written.
636  */
write_config(src,dst)637 int write_config(src, dst)
638      FILE *src;			/* source cnf file */
639      FILE *dst;			/* destination cnf file */
640 {
641   int i;
642   int set, lastcmd;
643   Bool eof_detect;
644   char *p;
645   char buf[1024];
646   char buf2[1024];
647 
648   lastcmd = set = 0;
649   eof_detect = False;
650   buf2[0] = '\0';
651   while (!eof_detect) {
652     if (fgets(buf, sizeof(buf), src) == NULL)
653       break;
654     p = index(buf, 032);	/* check ^Z (CP/M EOF) */
655     if (p != NULL) {
656       strcpy(buf2, p);		/* keep after ^Z (CP/M EOF) data */
657       *p = '\0';
658       eof_detect = True;
659     }
660     if (buf[0] == '$')
661       write_set(dst, set++);	/* replace new set information */
662     if (buf[0] != ' ')
663       lastcmd = buf[0];
664     if (lastcmd != '$')
665       fputs(buf, dst);
666   }
667   while (set < setcnt)
668     write_set(dst, set++);
669   if (buf2[0] != '\0')
670     fputs(buf2, dst);
671   /* keep trailing garbage */
672   while ((i = fread(buf, 1, sizeof(buf), src)) != 0)
673     fwrite(buf, 1, i, dst);
674   return ferror(src)|ferror(dst);
675 }
676 
677 /* update set information in KISS configuration file */
save_config(name)678 int save_config(name)
679      char *name;
680 {
681   int i;
682   FILE *fp;
683   FILE *wfp;
684   char *newfile;
685   char *bakfile;
686 
687   debug_printf("write_config [%s]\n", name);
688   fp = fopen(name, "r");
689   if (fp == NULL) {
690     msg("W ``%s'' open error!\n", name);
691     return 1;
692   }
693   i = strlen(name) + 1 + 1;
694   bakfile = ks_malloc(i);
695   newfile = ks_malloc(i);
696   sprintf(bakfile, "%s~", name);
697   sprintf(newfile, "%s#", name);
698   wfp = fopen(newfile, "w");
699   if (wfp == NULL) {
700     msg("W ``%s'' open error!\n", newfile);
701     free(bakfile);
702     free(newfile);
703     return 1;
704   }
705   i = write_config(fp, wfp);
706   fclose(wfp);
707   fclose(fp);
708   if (i) {
709     msg("W ``%s'' write error!\n", newfile);
710     free(bakfile);
711     free(newfile);
712     return 1;
713   }
714   if (rename(name, bakfile)) {
715     msg("W rename ``%s'' -> ``%s'' failed!\n", name, bakfile);
716     free(bakfile);
717     free(newfile);
718     return 1;
719   }
720   if (rename(newfile, name)) {
721     msg("W rename ``%s'' -> ``%s'' failed!\n", newfile, name);
722     free(bakfile);
723     free(newfile);
724     return 1;
725   }
726   infostr0[0] = '\0';
727   sprintf(infostr, "Wrote ``%s''", name);
728   disp_info();
729   free(bakfile);
730   free(newfile);
731   return 0;
732 }
733 
734 /* End of file */
735