|
|
1.1 root 1: /* opts.c */
2:
3: /* Author:
4: * Steve Kirkendall
5: * 16820 SW Tallac Way
6: * Beaverton, OR 97006
7: * [email protected], or ...uunet!tektronix!psueea!jove!kirkenda
8: */
9:
10:
11: /* This file contains the code that manages the run-time options -- The
12: * values that can be modified via the "set" command.
13: */
14:
15: #include "config.h"
16: #include "vi.h"
17: #ifndef NULL
18: #define NULL (char *)0
19: #endif
20: extern char *getenv();
21:
22: /* maximum width to permit for strings, including ="" */
23: #define MAXWIDTH 20
24:
25: /* These are the default values of all options */
26: char o_autoindent[1] = {FALSE};
27: char o_autoprint[1] = {TRUE};
28: char o_autowrite[1] = {FALSE};
29: #ifndef NO_ERRLIST
30: char o_cc[30] = {CC_COMMAND};
31: #endif
32: #ifndef NO_CHARATTR
33: char o_charattr[1] = {FALSE};
34: #endif
35: char o_columns[3] = {80, 32, 255};
36: #ifndef NO_DIGRAPH
37: char o_digraph[1] = {FALSE};
38: #endif
39: char o_directory[30] = TMPDIR;
40: char o_edcompatible[1] = {FALSE};
41: char o_errorbells[1] = {TRUE};
42: char o_exrefresh[1] = {TRUE};
43: #ifndef NO_DIGRAPH
44: char o_flipcase[80]
45: # if CS_IBMPC
46: = {"\207\200\201\232\202\220\204\216\206\217\221\222\224\231\244\245"}
47: # endif
48: # if CS_LATIN1
49: /* initialized by initopts() */
50: # endif
51: ;
52: #endif
53: #ifndef NO_SENTENCE
54: char o_hideformat[1] = {FALSE};
55: #endif
56: char o_ignorecase[1] = {FALSE};
57: #ifndef NO_EXTENSIONS
58: char o_inputmode[1] = {FALSE};
59: #endif
60: char o_keytime[3] = {2, 0, 5};
61: char o_keywordprg[80] = {KEYWORDPRG};
62: char o_lines[3] = {25, 2, 50}; /* More lines? Enlarge kbuf */
63: char o_list[1] = {FALSE};
64: #ifndef NO_MAGIC
65: char o_magic[1] = {TRUE};
66: #endif
67: #ifndef NO_ERRLIST
68: char o_make[30] = {MAKE_COMMAND};
69: #endif
70: #ifndef NO_MODELINE
71: char o_modeline[1] = {FALSE};
72: #endif
73: #ifndef NO_SENTENCE
74: char o_paragraphs[30] = "PPppIPLPQP";
75: #endif
76: #if MSDOS
77: char o_pcbios[1] = {TRUE};
78: #endif
79: char o_readonly[1] = {FALSE};
80: char o_report[3] = {5, 1, 127};
81: char o_scroll[3] = {12, 1, 127};
82: #ifndef NO_SENTENCE
83: char o_sections[30] = "NHSHSSSEse";
84: #endif
85: char o_shell[60] = SHELL;
86: char o_shiftwidth[3] = {8, 1, 255};
87: #ifndef NO_SHOWMATCH
88: char o_showmatch[1] = {FALSE};
89: #endif
90: #ifndef NO_SHOWMODE
91: char o_smd[1] = {FALSE};
92: #endif
93: char o_sidescroll[3] = {8, 1, 40};
94: char o_sync[1] = {NEEDSYNC};
95: char o_tabstop[3] = {8, 1, 40};
96: char o_term[30] = "?";
97: char o_vbell[1] = {TRUE};
98: char o_warn[1] = {TRUE};
99: char o_wrapmargin[3] = {0, 0, 255};
100: char o_wrapscan[1] = {TRUE};
101:
102:
103: /* The following describes the names & types of all options */
104: #define BOOL 0
105: #define NUM 1
106: #define STR 2
107: #define SET 0x01 /* this option has had its value altered */
108: #define CANSET 0x02 /* this option can be set at any time */
109: #define RCSET 0x06 /* this option can be set in a .exrc file only */
110: #define MR 0x40 /* does this option affect the way text is displayed? */
111: struct
112: {
113: char *name; /* name of an option */
114: char *nm; /* short name of an option */
115: char type; /* type of an option */
116: char flags; /* boolean: has this option been set? */
117: char *value; /* value */
118: }
119: opts[] =
120: {
121: /* name type flags redraw value */
122: { "autoindent", "ai", BOOL, CANSET , o_autoindent },
123: { "autoprint", "ap", BOOL, CANSET , o_autoprint },
124: { "autowrite", "aw", BOOL, CANSET , o_autowrite },
125: #ifndef NO_ERRLIST
126: { "cc", "cc", STR, CANSET , o_cc },
127: #endif
128: #ifndef NO_CHARATTR
129: { "charattr", "ca", BOOL, CANSET | MR, o_charattr },
130: #endif
131: { "columns", "co", NUM, SET , o_columns },
132: #ifndef NO_DIGRAPH
133: { "digraph", "dig", BOOL, CANSET , o_digraph },
134: #endif
135: { "directory", "dir", STR, RCSET , o_directory },
136: { "edcompatible","ed", BOOL, CANSET , o_edcompatible },
137: { "errorbells", "eb", BOOL, CANSET , o_errorbells },
138: { "exrefresh", "er", BOOL, CANSET , o_exrefresh },
139: #ifndef NO_DIGRAPH
140: { "flipcase", "fc", STR, CANSET , o_flipcase },
141: #endif
142: #ifndef NO_SENTENCE
143: { "hideformat", "hf", BOOL, CANSET | MR, o_hideformat },
144: #endif
145: { "ignorecase", "ic", BOOL, CANSET , o_ignorecase },
146: #ifndef NO_EXTENSIONS
147: { "inputmode", "im", BOOL, CANSET , o_inputmode },
148: #endif
149: { "keytime", "kt", NUM, CANSET , o_keytime },
150: { "keywordprg", "kp", STR, CANSET , o_keywordprg },
151: { "lines", "ls", NUM, SET , o_lines },
152: { "list", "li", BOOL, CANSET | MR, o_list },
153: #ifndef NO_MAGIC
154: { "magic", "ma", BOOL, CANSET , o_magic },
155: #endif
156: #ifndef NO_ERRLIST
157: { "make", "mk", STR, CANSET , o_make },
158: #endif
159: #ifndef NO_MODELINE
160: { "modeline", "ml", BOOL, CANSET , o_modeline },
161: #endif
162: #ifndef NO_SENTENCE
163: { "paragraphs", "pa", STR, CANSET , o_paragraphs },
164: #endif
165: #if MSDOS
166: { "pcbios", "pc", BOOL, SET , o_pcbios },
167: #endif
168: { "readonly", "ro", BOOL, CANSET , o_readonly },
169: { "report", "re", NUM, CANSET , o_report },
170: { "scroll", "sc", NUM, CANSET , o_scroll },
171: #ifndef NO_SENTENCE
172: { "sections", "se", STR, CANSET , o_sections },
173: #endif
174: { "shell", "sh", STR, CANSET , o_shell },
175: #ifndef NO_SHOWMATCH
176: { "showmatch", "sm", BOOL, CANSET , o_showmatch },
177: #endif
178: #ifndef NO_SHOWMODE
179: { "showmode", "smd", BOOL, CANSET , o_smd },
180: #endif
181: { "shiftwidth", "sw", NUM, CANSET , o_shiftwidth },
182: { "sidescroll", "ss", NUM, CANSET , o_sidescroll },
183: { "sync", "sy", BOOL, CANSET , o_sync },
184: { "tabstop", "ts", NUM, CANSET | MR, o_tabstop },
185: { "term", "te", STR, SET , o_term },
186: { "vbell", "vb", BOOL, CANSET , o_vbell },
187: { "warn", "wa", BOOL, CANSET , o_warn },
188: { "wrapmargin", "wm", NUM, CANSET , o_wrapmargin },
189: { "wrapscan", "ws", BOOL, CANSET , o_wrapscan },
190: { NULL, NULL, 0, CANSET, NULL }
191: };
192:
193:
194: /* This function initializes certain options from environment variables, etc. */
195: void initopts()
196: {
197: char *val;
198: int i;
199:
200: /* set some stuff from environment variables */
201: #if MSDOS
202: if (val = getenv("COMSPEC")) /* yes, ASSIGNMENT! */
203: #else
204: if (val = getenv("SHELL")) /* yes, ASSIGNMENT! */
205: #endif
206: {
207: strcpy(o_shell, val);
208: }
209:
210: #if ANY_UNIX
211: if (val = getenv("TERM")) /* yes, ASSIGNMENT! */
212: {
213: strcpy(o_term, val);
214: }
215: #endif
216: #if TOS
217: val = "vt52";
218: strcpy(o_term, val);
219: #endif
220: #if MSDOS
221: if ((val = getenv("TERM")) /* yes, ASSIGNMENT! */
222: && strcmp(val, "pcbios"))
223: {
224: strcpy(o_term, val);
225: o_pcbios[0] = 0;
226: }
227: else
228: {
229: strcpy(o_term, "pcbios");
230: o_pcbios[0] = 1;
231: }
232: #endif
233: #if MSDOS || TOS
234: if ((val = getenv("TMP")) /* yes, ASSIGNMENT! */
235: || (val = getenv("TEMP")))
236: strcpy(o_directory, val);
237: #endif
238:
239: *o_scroll = LINES / 2 - 1;
240:
241: /* disable the vbell option if we don't know how to do a vbell */
242: if (!has_VB)
243: {
244: for (i = 0; opts[i].value != o_vbell; i++)
245: {
246: }
247: opts[i].flags &= ~CANSET;
248: *o_vbell = FALSE;
249: }
250:
251: #ifndef NO_DIGRAPH
252: # ifdef CS_LATIN1
253: for (i = 0, val = o_flipcase; i < 32; i++)
254: {
255: /* leave out the multiply/divide symbols */
256: if (i == 23)
257: continue;
258:
259: /* add upper/lowercase pair */
260: *val++ = i + 0xc0;
261: *val++ = i + 0xe0;
262: }
263: *val = '\0';
264: # endif /* CS_LATIN1 */
265: #endif /* not NO_DIGRAPH */
266: }
267:
268: /* This function lists the current values of all options */
269: void dumpopts(all)
270: int all; /* boolean: dump all options, or just set ones? */
271: {
272: #ifndef NO_OPTCOLS
273: int i, j, k;
274: char nbuf[4]; /* used for converting numbers to ASCII */
275: int widths[5]; /* width of each column, including gap */
276: int ncols; /* number of columns */
277: int nrows; /* number of options per column */
278: int nset; /* number of options to be output */
279: int width; /* width of a particular option */
280: int todump[50]; /* indicies of options to be dumped */
281:
282: /* step 1: count the number of set options */
283: for (nset = i = 0; opts[i].name; i++)
284: {
285: if (all || (opts[i].flags & SET))
286: {
287: todump[nset++] = i;
288: }
289: }
290:
291: /* step two: try to use as many columns as possible */
292: for (ncols = (nset > 5 ? 5 : nset); ncols > 1; ncols--)
293: {
294: /* how many would go in this column? */
295: nrows = (nset + ncols - 1) / ncols;
296:
297: /* figure out the width of each column */
298: for (i = 0; i < ncols; i++)
299: {
300: widths[i] = 0;
301: for (j = 0, k = nrows * i; j < nrows && k < nset; j++, k++)
302: {
303: /* figure out the width of a particular option */
304: switch (opts[todump[k]].type)
305: {
306: case BOOL:
307: if (!*opts[todump[k]].value)
308: width = 2;
309: else
310: width = 0;
311: break;
312:
313: case STR:
314: width = 3 + strlen(opts[todump[k]].value);
315: if (width > MAXWIDTH)
316: width = MAXWIDTH;
317: break;
318:
319: case NUM:
320: width = 4;
321: break;
322: }
323: width += strlen(opts[todump[k]].name);
324:
325: /* if this is the widest so far, widen col */
326: if (width > widths[i])
327: {
328: widths[i] = width;
329: }
330: }
331:
332: }
333:
334: /* if the total width is narrow enough, then use it */
335: for (width = -2, i = 0; i < ncols; i++)
336: {
337: width += widths[i] + 2;
338: }
339: if (width < COLS - 1)
340: {
341: break;
342: }
343: }
344:
345: /* step 3: output the columns */
346: nrows = (nset + ncols - 1) / ncols;
347: for (i = 0; i < nrows; i++)
348: {
349: for (j = 0; j < ncols; j++)
350: {
351: /* if we hit the end of the options, quit */
352: k = i + j * nrows;
353: if (k >= nset)
354: {
355: break;
356: }
357:
358: /* output this option's value */
359: width = 0;
360: switch (opts[todump[k]].type)
361: {
362: case BOOL:
363: if (!*opts[todump[k]].value)
364: {
365: qaddch('n');
366: qaddch('o');
367: width = 2;
368: }
369: qaddstr(opts[todump[k]].name);
370: width += strlen(opts[todump[k]].name);
371: break;
372:
373: case NUM:
374: sprintf(nbuf, "%-3d", UCHAR(*opts[todump[k]].value));
375: qaddstr(opts[todump[k]].name);
376: qaddch('=');
377: qaddstr(nbuf);
378: width = 4 + strlen(opts[todump[k]].name);
379: break;
380:
381: case STR:
382: qaddstr(opts[todump[k]].name);
383: qaddch('=');
384: qaddch('"');
385: strcpy(tmpblk.c, opts[todump[k]].value);
386: width = 3 + strlen(tmpblk.c);
387: if (width > MAXWIDTH)
388: {
389: width = MAXWIDTH;
390: strcpy(tmpblk.c + MAXWIDTH - 6, "...");
391: }
392: qaddstr(tmpblk.c);
393: qaddch('"');
394: width += strlen(opts[todump[k]].name);
395: break;
396: }
397:
398: /* pad the field to the correct size */
399: if (k + nrows <= nset)
400: {
401: while (width < widths[j] + 2)
402: {
403: qaddch(' ');
404: width++;
405: }
406: }
407: }
408: addch('\n');
409: exrefresh();
410: }
411: #else
412: int i;
413: int col;
414: char nbuf[4];
415:
416: for (i = col = 0; opts[i].name; i++)
417: {
418: /* if not set and not all, ignore this option */
419: if (!all && !(opts[i].flags & SET))
420: {
421: continue;
422: }
423:
424: /* align this option in one of the columns */
425: if (col > 52)
426: {
427: addch('\n');
428: col = 0;
429: }
430: else if (col > 26)
431: {
432: while (col < 52)
433: {
434: qaddch(' ');
435: col++;
436: }
437: }
438: else if (col > 0)
439: {
440: while (col < 26)
441: {
442: qaddch(' ');
443: col++;
444: }
445: }
446:
447: switch (opts[i].type)
448: {
449: case BOOL:
450: if (!*opts[i].value)
451: {
452: qaddch('n');
453: qaddch('o');
454: col += 2;
455: }
456: qaddstr(opts[i].name);
457: col += strlen(opts[i].name);
458: break;
459:
460: case NUM:
461: sprintf(nbuf, "%-3d", UCHAR(*opts[i].value));
462: qaddstr(opts[i].name);
463: qaddch('=');
464: qaddstr(nbuf);
465: col += 4 + strlen(opts[i].name);
466: break;
467:
468: case STR:
469: qaddstr(opts[i].name);
470: qaddch('=');
471: qaddch('"');
472: qaddstr(opts[i].value);
473: qaddch('"');
474: col += 3 + strlen(opts[i].name) + strlen(opts[i].value);
475: break;
476: }
477: exrefresh();
478: }
479: if (col > 0)
480: {
481: addch('\n');
482: exrefresh();
483: }
484: #endif
485: }
486:
487: #ifndef NO_MKEXRC
488: /* This function saves the current configuarion of options to a file */
489: void saveopts(fd)
490: int fd; /* file descriptor to write to */
491: {
492: int i;
493: char buf[256], *pos;
494:
495: /* write each set options */
496: for (i = 0; opts[i].name; i++)
497: {
498: /* if unset or unsettable, ignore this option */
499: if (!(opts[i].flags & SET) || !(opts[i].flags & CANSET))
500: {
501: continue;
502: }
503:
504: strcpy(buf, "set ");
505: pos = &buf[4];
506: switch (opts[i].type)
507: {
508: case BOOL:
509: if (!*opts[i].value)
510: {
511: *pos++='n';
512: *pos++='o';
513: }
514: strcpy(pos, opts[i].name);
515: strcat(pos, "\n");
516: break;
517:
518: case NUM:
519: sprintf(pos, "%s=%-3d\n", opts[i].name, *opts[i].value & 0xff);
520: break;
521:
522: case STR:
523: sprintf(pos, "%s=\"%s\"\n", opts[i].name, opts[i].value);
524: break;
525: }
526: twrite(fd, buf, strlen(buf));
527: }
528: }
529: #endif
530:
531:
532: /* This function changes the values of one or more options. */
533: void setopts(assignments)
534: char *assignments; /* a string containing option assignments */
535: {
536: char *name; /* name of variable in assignments */
537: char *value; /* value of the variable */
538: char *scan; /* used for moving through strings */
539: int i, j;
540:
541: /* for each assignment... */
542: for (name = assignments; *name; )
543: {
544: /* skip whitespace */
545: if (*name == ' ' || *name == '\t')
546: {
547: name++;
548: continue;
549: }
550:
551: /* find the value, if any */
552: for (scan = name; *scan >= 'a' && *scan <= 'z'; scan++)
553: {
554: }
555: if (*scan == '=')
556: {
557: *scan++ = '\0';
558: if (*scan == '"')
559: {
560: value = ++scan;
561: while (*scan && *scan != '"')
562: {
563: scan++;
564: }
565: if (*scan)
566: {
567: *scan++ = '\0';
568: }
569: }
570: else
571: {
572: value = scan;
573: while (*scan && *scan != ' ' && *scan != '\t')
574: {
575: scan++;
576: }
577: if (*scan)
578: {
579: *scan++ = '\0';
580: }
581: }
582: }
583: else
584: {
585: if (*scan)
586: {
587: *scan++ = '\0';
588: }
589: value = NULL;
590: if (name[0] == 'n' && name[1] == 'o')
591: {
592: name += 2;
593: }
594: }
595:
596: /* find the variable */
597: for (i = 0;
598: opts[i].name && strcmp(opts[i].name, name) && strcmp(opts[i].nm, name);
599: i++)
600: {
601: }
602:
603: /* change the variable */
604: if (!opts[i].name)
605: {
606: msg("invalid option name \"%s\"", name);
607: }
608: else if ((opts[i].flags & CANSET) != CANSET)
609: {
610: msg("option \"%s\" can't be altered", name);
611: }
612: else if ((opts[i].flags & RCSET) != CANSET && nlines >= 1L)
613: {
614: msg("option \"%s\" can only be set in a %s file", name, EXRC);
615: }
616: else if (value)
617: {
618: switch (opts[i].type)
619: {
620: case BOOL:
621: msg("option \"[no]%s\" is boolean", name);
622: break;
623:
624: case NUM:
625: j = atoi(value);
626: if (j == 0 && *value != '0')
627: {
628: msg("option \"%s\" must have a numeric value", name);
629: }
630: else if (j < opts[i].value[1] || j > (opts[i].value[2] & 0xff))
631: {
632: msg("option \"%s\" must have a value between %d and %d",
633: name, opts[i].value[1], opts[i].value[2] & 0xff);
634: }
635: else
636: {
637: *opts[i].value = atoi(value);
638: opts[i].flags |= SET;
639: }
640: break;
641:
642: case STR:
643: strcpy(opts[i].value, value);
644: opts[i].flags |= SET;
645: break;
646: }
647: if (opts[i].flags & MR)
648: {
649: mustredraw = TRUE;
650: }
651: }
652: else /* valid option, no value */
653: {
654: if (opts[i].type == BOOL)
655: {
656: *opts[i].value = (name[-1] != 'o');
657: opts[i].flags |= SET;
658: if (opts[i].flags & MR)
659: {
660: mustredraw = TRUE;
661: }
662: }
663: else
664: {
665: msg("option \"%s\" must be given a value", name);
666: }
667: }
668:
669: /* move on to the next option */
670: name = scan;
671: }
672:
673: /* special processing ... */
674:
675: /* if "readonly" then set the READONLY flag for this file */
676: if (*o_readonly)
677: {
678: setflag(file, READONLY);
679: }
680: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.