1 /*
2  * @(#)startup.c	1.1	10/21/84
3  *
4  * Startup file processing for the SUN Gremlin picture editor.
5  *
6  * Mark Opperman (opcode@monet.BERKELEY)
7  *
8  */
9 
10 #include "gremlin.h"
11 #include <vfont.h>
12 #include <sys/types.h>
13 #include <sys/stat.h>
14 #include <ctype.h>
15 
16 /* imports from C */
17 
18 extern char *malloc();
19 extern FILE *fopen();
20 
21 /* imports from path.c */
22 
23 extern PSetPath();
24 
25 /* imports from graphics files */
26 
27 extern char *font_types[];		/* normally "R", "I", "B", "S" */
28 extern font_sizes[];			/* normally 7, 10, 14, 24 */
29 extern char fontdir[];			/* font directory */
30 extern char stippledir[];		/* stipple directory */
31 extern char stippletype[];		/* stipple font type ("ug" or "cf") */
32 extern stipple_index[];			/* stipple font numbers */
33 
34 /* imports from main.c */
35 
36 extern Artmode;				/* point display size */
37 extern CBRUSH;				/* current brush */
38 extern CFONT;				/* current font */
39 extern CJUST;				/* current text justification */
40 extern CSIZE;				/* current size */
41 extern CSTIPPLE;			/* current stipple pattern */
42 extern Alignment;			/* point alignment indicator */
43 extern Adjustment;			/* point adjustment mode */
44 extern GravityOn;			/* gravity mode flag */
45 extern Gridon;				/* grid mode indicator */
46 extern SymbolicLines;			/* pr_vector OK for all lines */
47 extern long timeon_s, timeon_ms;	/* current set flash on rate */
48 extern long timeoff_s, timeoff_ms;	/* current set flash off rate */
49 
50 /* locally defined variables */
51 
52 #define STon(s)  (strncmp(s, "on", 2) == 0)
53 
54 int STERROR = FALSE;			/* indicates error on startup */
55 
56 static char *lines[] = { "broken", "dashed", "dotted",
57 			 "medium", "narrow", "thick", NULL };
58 static lnum[] = { 2, 4, 1, 6, 5, 3 };
59 
60 static char *textpos[JUSTMODES] = { "tl", "tc", "tr",
61 				    "cl", "cc", "cr",
62 				    "bl", "bc", "br",
63 				    "lt", "ct", "rt",
64 				    "lc",       "rc",
65 				    "lb", "cb", "rb"  };
66 static textmode[JUSTMODES] = { TOPLEFT,  TOPCENT,  TOPRIGHT,
67 			       CENTLEFT, CENTCENT, CENTRIGHT,
68 			       BOTLEFT,  BOTCENT,  BOTRIGHT,
69 			       TOPLEFT,  TOPCENT,  TOPRIGHT,
70 			       CENTLEFT,           CENTRIGHT,
71 			       BOTLEFT,  BOTCENT,  BOTRIGHT  };
72 
73 static char *fonts[] = { "bold", "italics", "roman", "special", NULL };
74 static fnum[] = { 3, 2, 1, 4 };
75 
76 /* The following are defined to allow creation of the command lookup table. */
77 
78 extern ST1(), ST2(), ST3(), ST4(), STB(), STI(), STR(), STS(),
79     STalign(), STbrush(), STflashoff(), STflashon(), STfont(), STfontdir(),
80     STgravity(), STgrid(), SThadjust(), STjustify(), STlittlepoint(),
81     STmadjust(), STpath(), STsize(), STstipple(),
82     STstipple1(), STstipple2(), STstipple3(), STstipple4(),
83     STstipple5(), STstipple6(), STstipple7(), STstipple8(),
84     STstippledir(), STstippletype(), STsymboliclines(), STvadjust();
85 
86 /* The following two arrays define the startup commands and the routines
87    that process them. */
88 
89 static char *startupcmds[] = {
90     "1",
91     "2",
92     "3",
93     "4",
94     "B",
95     "I",
96     "R",
97     "S",
98     "align",
99     "brush",
100     "flashoff",
101     "flashon",
102     "font",
103     "fontdir",
104     "gravity",
105     "grid",
106     "hadjust",
107     "justify",
108     "l1",
109     "l2",
110     "l3",
111     "l4",
112     "l5",
113     "l6",
114     "l7",
115     "l8",
116     "littlepoint",
117     "madjust",
118     "path",
119     "size",
120     "stipple",
121     "stipple1",
122     "stipple2",
123     "stipple3",
124     "stipple4",
125     "stipple5",
126     "stipple6",
127     "stipple7",
128     "stipple8",
129     "stippledir",
130     "stippletype",
131     "symboliclines",
132     "vadjust",
133     NULL
134 };
135 
136 static (*(strtns[]))() = {
137     ST1,			/* set size 1 point size */
138     ST2,			/* set size 2 point size */
139     ST3,			/* set size 3 point size */
140     ST4,			/* set size 4 point size */
141     STB,			/* set B font type */
142     STI,			/* set I font type */
143     STR,			/* set R font type */
144     STS,			/* set S font type */
145     STalign,			/* set point alignment */
146     STbrush,			/* set brush */
147     STflashoff,			/* set current set flash off time */
148     STflashon,			/* set current set flash on time */
149     STfont,			/* set font */
150     STfontdir,			/* font directory */
151     STgravity,			/* toggle gravity */
152     STgrid,			/* toggle grid display */
153     SThadjust,			/* horizontal adjust */
154     STjustify,			/* text justification */
155     STstipple1,			/* set stipple #1 index equivalent */
156     STstipple2,			/* set stipple #2 index equivalent */
157     STstipple3,			/* set stipple #3 index equivalent */
158     STstipple4,			/* set stipple #4 index equivalent */
159     STstipple5,			/* set stipple #5 index equivalent */
160     STstipple6,			/* set stipple #6 index equivalent */
161     STstipple7,			/* set stipple #7 index equivalent */
162     STstipple8,			/* set stipple #8 index equivalent */
163     STlittlepoint,		/* point size */
164     STmadjust,			/* manhattan adjust */
165     STpath,			/* set path or toggle search mode */
166     STsize,			/* character size */
167     STstipple,			/* set stipple pattern */
168     STstipple1,			/* set stipple #1 index */
169     STstipple2,			/* set stipple #2 index */
170     STstipple3,			/* set stipple #3 index */
171     STstipple4,			/* set stipple #4 index */
172     STstipple5,			/* set stipple #5 index */
173     STstipple6,			/* set stipple #6 index */
174     STstipple7,			/* set stipple #7 index */
175     STstipple8,			/* set stipple #8 index */
176     STstippledir,		/* stipple directory */
177     STstippletype,		/* stipple font file name */
178     STsymboliclines,		/* toggle symbolic lines */
179     STvadjust			/* vertical adjust */
180 };
181 
182 
183 /*
184  *  Check for .gremlinrc file(s) and process if found.
185  *  The only globally accessible routine in this file.
186  */
187 STgremlinrc(altfile)
188 char *altfile;			/* alternate startup file */
189 {
190     FILE *fp;
191     struct stat buf;
192     ino_t home_inode, cwd_inode;
193     char home[128];
194 
195     /* look in home directory */
196     sprintf(home, "%s/.gremlinrc", getenv("HOME"));
197     fp = fopen(home, "r");
198     if (fp != NULL) {
199 	fstat(fileno(fp), &buf);
200 	home_inode = buf.st_ino;
201 	STstartup(fp);
202 	fclose(fp);
203     }
204     else
205 	home_inode = 0;
206 
207     /* look in current directory */
208     fp = fopen(".gremlinrc", "r");
209     if (fp != NULL) {
210 	fstat(fileno(fp), &buf);
211 	cwd_inode = buf.st_ino;
212 	if (cwd_inode != home_inode)        /* not in home directory */
213 	    STstartup(fp);
214 	fclose(fp);
215     }
216 
217     /* check for alternate startup file */
218     if (*altfile != '\0') {
219 	fp = fopen(altfile, "r");
220 	if (fp != NULL) {
221 	    fstat(fileno(fp), &buf);
222 	    if ((buf.st_ino != home_inode) && (buf.st_ino != cwd_inode))
223 		STstartup(fp);
224 	    fclose(fp);
225 	}
226     }
227 }  /* end STgremlinrc */
228 
229 
230 static
231 STerror(s)
232 register char *s;
233 {
234     char msg[256];
235 
236     STERROR = 1;
237     sprintf(msg, "startup: %s", s);
238     TxPutMsg(msg);
239 }  /* end STerror */
240 
241 
242 /*
243  *  Do startup processing on open file referenced by fp.
244  */
245 static
246 STstartup(fp)
247 register FILE *fp;
248 {
249     register char *s;
250     register i;
251     char buf[256];
252 
253     s = fgets(buf, 256, fp);
254     while (s != NULL) {
255 	for (i=0; (buf[i] != '\n'); ++i)
256 	    if (i > 255)
257 		break;
258 	buf[i] = '\0';
259 	STcommand(buf);
260 	s = fgets(buf, 400, fp);
261     }
262 }  /* end STstartup */
263 
264 
265 /*
266  *  Make a string lower case.
267  */
268 STtolower(s)
269 register char *s;
270 {
271     register c;
272 
273     while ((c = (int) *s) != 0) {
274 	if (isupper(c))
275 	    *s = tolower(c);
276 	s++;
277     }
278 }
279 
280 
281 /*
282  *  STlookup searches a table of strings to find one that matches a
283  *  given string.
284  *
285  *  If str is an unambiguous abbreviation for one of the entries
286  *  in table, then the index of the matching entry is returned.
287  *  If str is an abbreviation for more than one entry in table,
288  *  then -1 is returned.  If str doesn't match any entry, then
289  *  -2 is returned.
290  *
291  *  The search is carried out by using two pointers, one which moves
292  *  forward through table from its start, and one which moves backward
293  *  through table from its end.  The two pointers mark the range of
294  *  strings that match the portion of str that we have scanned.  When
295  *  all of the characters of str have been scanned, then the two
296  *  pointers better be identical.
297  */
298 static
299 STlookup(str, table, next)
300 char str[];			/* Pointer to a string to be looked up */
301 char *(table[]);		/* Pointer to an array of string pointers
302 				   which are the valid commands.  The strings
303 				   must be ordered monotonically (i.e. all
304 				   strings whose first characters are identical
305 				   must be adjacent in the table). */
306 int *next;			/* Index to delimiter after search */
307 {
308     char **bot, **top;
309     int match, index;
310 
311     match = 0;
312     bot = table;
313     for (top = table; *top != NULL; top++)
314 	;
315     if (top == bot)
316 	return(-2);
317     top--;
318 
319     for (index=0; ; index++) {
320         *next = index;
321 
322 	/* Check for the end of string */
323 	if (Delimiter(str[index]))
324 	    return(((bot == top) || Delimiter((*bot)[index])) ? match : -1);
325 
326 	/*
327 	 * Move bot up until the string it points to matches str
328 	 * in the index'th position.
329 	 * Make match refer to the index of bot in table.
330 	 */
331 
332 	while ((*bot)[index] != str[index]) {
333 	    if (bot == top)
334 		return(-2);
335 	    bot++;
336 	    match++;
337 	}
338 
339 	/* Move top down until it matches */
340 
341 	while ((*top)[index] != str[index]) {
342 	    if (bot == top)
343 		return(-2);
344 	    top--;
345 	}
346     }
347 }  /* end STlookup */
348 
349 
350 /*
351  *  This routine looks up and executes a startup command.
352  */
353 static
354 STcommand(line)
355 register char *line;
356 {
357     register index;
358     register char *save;
359     char buf[256];
360     int next;
361 
362     if ((*line == '\0') || (*line == '#'))
363         return;
364 
365     index = STlookup(save = line, startupcmds, &next);
366 
367     if (index >= 0) {
368 	line = line + next;
369 
370 	/* skip to first non-blank */
371 	while ((*line == '\t') || (*line == ' '))
372 	    line++;
373 
374 	(*(strtns[index]))(line);
375     }
376     else if (index == -1) {
377 	sprintf(buf, "ambigous command: %s", save);
378 	STerror(buf);
379     }
380     else if (index == -2) {
381 	sprintf(buf, "unknown command: %s", save);
382 	STerror(buf);
383     }
384 }  /* end STcommand */
385 
386 
387 /*
388  * This routine interprets the string starting at line
389  * as a positive integral numeric parameter.  The function
390  * returns the numeric equivalent or -1 it there is some
391  * error in interpreting the string.
392  * NOTE: expects line with at least one non-space character.
393  */
394 static
395 STgetnum(line)
396 register char *line;
397 {
398     register i;
399     char num[128];
400     int result;
401 
402     for (i=0; !Delimiter(*line); ++i) {
403 	num[i] = *line++;
404 	if (!isdigit(num[i]))
405 	    return(-1);
406     }
407 
408     num[i] = '\0';
409     (void) sscanf(num, "%d", &result);
410     return(result);
411 }  /* end STgetnum */
412 
413 
414 static
415 ST1(line)
416 register char *line;
417 {
418     register size;
419 
420     if (*line == '\0')
421 	return;
422 
423     size = STgetnum(line);
424     if (size != -1)
425 	font_sizes[0] = size;
426     else
427 	STerror("bad size 1");
428 }
429 
430 
431 static
432 ST2(line)
433 register char *line;
434 {
435     register size;
436 
437     if (*line == '\0')
438 	return;
439 
440     size = STgetnum(line);
441     if (size != -1)
442 	font_sizes[1] = size;
443     else
444 	STerror("bad size 2");
445 }
446 
447 
448 static
449 ST3(line)
450 register char *line;
451 {
452     register size;
453 
454     if (*line == '\0')
455 	return;
456 
457     size = STgetnum(line);
458     if (size != -1)
459 	font_sizes[2] = size;
460     else
461 	STerror("bad size 3");
462 }
463 
464 
465 static
466 ST4(line)
467 register char *line;
468 {
469     register size;
470 
471     if (*line == '\0')
472 	return;
473 
474     size = STgetnum(line);
475     if (size != -1)
476 	font_sizes[3] = size;
477     else
478 	STerror("bad size 4");
479 }
480 
481 
482 static
483 STB(line)
484 register char *line;
485 {
486     register char *f;
487     register i = 0;
488 
489     if (*line == '\0')
490 	return;
491 
492     f = line;
493     while (!Delimiter(*f))
494 	f++, i++;
495 
496     f = malloc((unsigned) i+1);
497     strncpy(f, line, i+1);
498     font_types[BFONT] = f;
499 }
500 
501 
502 static
503 STI(line)
504 register char *line;
505 {
506     register char *f;
507     register i = 0;
508 
509     if (*line == '\0')
510 	return;
511 
512     f = line;
513     while (!Delimiter(*f))
514 	f++, i++;
515 
516     f = malloc((unsigned) i+1);
517     strncpy(f, line, i+1);
518     font_types[IFONT] = f;
519 }
520 
521 
522 static
523 STR(line)
524 register char *line;
525 {
526     register char *f;
527     register i = 0;
528 
529     if (*line == '\0')
530 	return;
531 
532     f = line;
533     while (!Delimiter(*f))
534 	f++, i++;
535 
536     f = malloc((unsigned) i+1);
537     strncpy(f, line, i+1);
538     font_types[RFONT] = f;
539 }
540 
541 
542 static
543 STS(line)
544 register char *line;
545 {
546     register char *f;
547     register i = 0;
548 
549     if (*line == '\0')
550 	return;
551 
552     f = line;
553     while (!Delimiter(*f))
554 	f++, i++;
555 
556     f = malloc((unsigned) i+1);
557     strncpy(f, line, i+1);
558     font_types[SFONT] = f;
559 }
560 
561 
562 static
563 STalign(line)
564 register char *line;
565 {
566     register a;
567     register align = 1;
568 
569     if (*line == '\0')
570 	return;
571 
572     a = STgetnum(line);
573     if (a <= 0)
574 	STerror("bad alignment");
575     else {
576 	a >>= 1;
577 	while (a != 0) {
578 	    align <<= 1;
579 	    a >>= 1;
580 	}
581 	Alignment = (align > 512) ? 512 : align;
582     }
583 }
584 
585 
586 static
587 STbrush(line)
588 register char *line;
589 {
590     register newbrush;
591     int index = 0;
592 
593     if (*line == '\0')
594 	return;
595 
596     STtolower(line);		/* force argument to lower case */
597 
598     if ((newbrush = STlookup(line, lines, &index)) >= 0)
599 	CBRUSH = lnum[newbrush];
600     else
601 	STerror("bad brush name");
602 }
603 
604 
605 static
606 STflashoff(line)
607 register char *line;
608 {
609     register flashoff;
610     int index = 0;
611 
612     if (*line == '\0')
613 	return;
614 
615     flashoff = STgetnum(line);
616     if (flashoff == -1)
617 	STerror("bad flash off time");
618     else {
619 	timeoff_s = flashoff / 1000;
620 	timeoff_ms = flashoff % 1000;
621     }
622 }
623 
624 
625 static
626 STflashon(line)
627 register char *line;
628 {
629     register flashon;
630     int index = 0;
631 
632     if (*line == '\0')
633 	return;
634 
635     flashon = STgetnum(line);
636     if (flashon == -1)
637 	STerror("bad flash on time");
638     else {
639 	timeon_s = flashon / 1000;
640 	timeon_ms = flashon % 1000;
641     }
642 }
643 
644 
645 static
646 STfont(line)
647 register char *line;
648 {
649     int font;
650     int index = 0;
651 
652     if (*line == '\0')
653 	return;
654 
655     STtolower(line);		/* force argument to lower case */
656 
657     if ((font = STlookup(line, fonts, &index)) >= 0)
658 	CFONT = fnum[font];
659     else
660         STerror("bad font number");
661 }
662 
663 
664 static
665 STfontdir(line)
666 register char *line;
667 {
668     register i = 0;
669 
670     if (*line == '\0')
671 	return;
672 
673     while (!Delimiter(*line))
674 	fontdir[i++] = *line++;
675 
676     if (fontdir[--i] != '/')
677 	fontdir[++i] = '/';
678 
679     fontdir[++i] = '\0';
680 }
681 
682 
683 static
684 STgravity(line)
685 register char *line;
686 {
687     STtolower(line);
688     GravityOn = STon(line);
689 }
690 
691 
692 static
693 STgrid(line)
694 register char *line;
695 {
696     STtolower(line);
697     Gridon = STon(line);
698 }
699 
700 
701 static
702 SThadjust(line)
703 register char *line;
704 {
705     STtolower(line);
706 
707     if (STon(line))
708 	Adjustment = HORZ;
709     else if (Adjustment == HORZ)
710 	Adjustment = NOADJ;
711     /*
712     Adjustment = (Adjustment == HORZ) ? NOADJ : HORZ;
713     */
714 }
715 
716 
717 static
718 STjustify(line)
719 register char *line;
720 {
721     int new;
722     int index = 0;
723 
724     if (*line == '\0')
725 	return;
726 
727     STtolower(line);		/* force argument to lower case */
728 
729     for (new = 0; (strcmp(line, textpos[new]) != 0); ++new) {
730 	if (new >= JUSTMODES) {
731 	   STerror("bad justification mode");
732 	   return;
733 	}
734     }
735 
736     CJUST = textmode[new];
737 }
738 
739 
740 static
741 STlittlepoint(line)
742 register char *line;
743 {
744     /*
745     Artmode = !Artmode;
746     */
747     STtolower(line);
748     Artmode = STon(line);
749 }
750 
751 
752 static
753 STmadjust(line)
754 register char *line;
755 {
756     STtolower(line);		/* force argument to lower case */
757 
758     if (STon(line))
759 	Adjustment = MAN;
760     else if (Adjustment == MAN)
761 	Adjustment = NOADJ;
762     /*
763     Adjustment = (Adjustment == MAN) ? NOADJ : MAN;
764     */
765 }
766 
767 
768 static
769 STpath(line)
770 register char *line;
771 {
772     if (*line == '\0')
773 	return;
774 
775     PSetPath(line);
776 }
777 
778 
779 static
780 STsize(line)
781 register char *line;
782 {
783     int new;
784 
785     if (*line == '\0')
786 	return;
787 
788     new = STgetnum(line);
789 
790     if ((new == -1) || (new > NSIZES))
791         STerror("bad font size");
792     else
793         CSIZE = new;
794 }
795 
796 
797 static
798 STstipple(line)
799 register char *line;
800 {
801     int newstipple;
802 
803     if (*line == '\0')
804 	return;
805 
806     newstipple = STgetnum(line);
807 
808     if ((newstipple == -1) || (newstipple > NSTIPPLES))
809         STerror("bad stipple number");
810     else
811 	CSTIPPLE = newstipple;
812 }
813 
814 
815 static
816 STstipplenum(line, num)
817 register char *line;
818 register num;
819 {
820     register index;
821 
822     if (*line == '\0')
823 	return;
824 
825     index = STgetnum(line);
826 
827     if ((index == -1) || (index >= NUM_DISPATCH))
828         STerror("bad stipple font index");
829     else
830 	stipple_index[num-1] = index;
831 }
832 
833 
834 static
835 STstipple1(line)
836 register char *line;
837 {
838     STstipplenum(line, 1);
839 }
840 
841 
842 static
843 STstipple2(line)
844 register char *line;
845 {
846     STstipplenum(line, 2);
847 }
848 
849 
850 static
851 STstipple3(line)
852 register char *line;
853 {
854     STstipplenum(line, 3);
855 }
856 
857 
858 static
859 STstipple4(line)
860 register char *line;
861 {
862     STstipplenum(line, 4);
863 }
864 
865 
866 static
867 STstipple5(line)
868 register char *line;
869 {
870     STstipplenum(line, 5);
871 }
872 
873 
874 static
875 STstipple6(line)
876 register char *line;
877 {
878     STstipplenum(line, 6);
879 }
880 
881 
882 static
883 STstipple7(line)
884 register char *line;
885 {
886     STstipplenum(line, 7);
887 }
888 
889 
890 static
891 STstipple8(line)
892 register char *line;
893 {
894     STstipplenum(line, 8);
895 }
896 
897 
898 static
899 STstippledir(line)
900 register char *line;
901 {
902     register i = 0;
903 
904     if (*line == '\0')
905 	return;
906 
907     while (!Delimiter(*line))
908 	stippledir[i++] = *line++;
909 
910     if (stippledir[--i] != '/')
911 	stippledir[++i] = '/';
912 
913     stippledir[++i] = '\0';
914 }
915 
916 
917 static
918 STstippletype(line)
919 register char *line;
920 {
921     register i = 0;
922 
923     if (*line == '\0')
924 	return;
925 
926     while (!Delimiter(*line))
927 	stippletype[i++] = *line++;
928 
929     stippletype[i] = '\0';
930 }
931 
932 
933 static
934 STsymboliclines(line)
935 register char *line;
936 {
937     /*
938     SymbolicLines = !SymbolicLines;
939     */
940     STtolower(line);
941     SymbolicLines = STon(line);
942 }
943 
944 
945 static
946 STvadjust(line)
947 register char *line;
948 {
949     STtolower(line);
950 
951     if (STon(line))
952 	Adjustment = VERT;
953     else if (Adjustment == VERT)
954 	Adjustment = NOADJ;
955     /*
956     Adjustment = (Adjustment == VERT) ? NOADJ : VERT;
957     */
958 }
959