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