|
|
1.1 root 1: /***************************************************************************
2: * This program is Copyright (C) 1986, 1987, 1988 by Jonathan Payne. JOVE *
3: * is provided to you without charge, and with no warranty. You may give *
4: * away copies of JOVE, including sources, provided that this notice is *
5: * included in all the files. *
6: ***************************************************************************/
7:
8: #include "jove.h"
9: #include "io.h"
10: #include "termcap.h"
11: #include "ctype.h"
12: #ifdef JOB_CONTROL
13: # include <signal.h>
14: #endif
15:
16: #ifdef MAC
17: # include "mac.h"
18: #else
19: # include <varargs.h>
20: #endif
21:
22: #ifdef MSDOS
23: #include <process.h>
24: #endif
25:
26: #ifdef MAC
27: # undef private
28: # define private
29: #endif
30:
31: #ifdef LINT_ARGS
32: private void
33: fb_aux(data_obj *, data_obj **, char *, char *),
34: find_binds(data_obj *, char *),
35: vpr_aux(struct variable *, char *);
36: #else
37: private void
38: fb_aux(),
39: find_binds(),
40: vpr_aux();
41: #endif /* LINT_ARGS */
42:
43: #ifdef MAC
44: # undef private
45: # define private static
46: #endif
47:
48:
49: int InJoverc = 0;
50:
51: extern int getch(),
52: getchar();
53:
54: /* Auto execute code */
55:
56: #define NEXECS 20
57:
58: private struct {
59: char *a_pattern;
60: data_obj *a_cmd;
61: } AutoExecs[NEXECS] = {0};
62:
63: private int ExecIndex = 0;
64:
65: /* Command auto-execute. */
66:
67: void
68: CAutoExec()
69: {
70: DefAutoExec(findcom);
71: }
72:
73: /* Macro auto-execute. */
74:
75: void
76: MAutoExec()
77: {
78: DefAutoExec(findmac);
79: }
80:
81: /* VARARGS0 */
82:
83: void
84: DefAutoExec(proc)
85: #ifdef LINT_ARGS
86: data_obj *(*proc)(char *);
87: #else
88: data_obj *(*proc)();
89: #endif
90: {
91: data_obj *d;
92: char *pattern;
93: int i;
94:
95: if (ExecIndex >= NEXECS)
96: complain("Too many auto-executes, max %d.", NEXECS);
97: if ((d = (*proc)(ProcFmt)) == 0)
98: return;
99: pattern = do_ask("\r\n", (int (*)()) 0, (char *) 0, ": %f %s ", d->Name);
100: if (pattern != 0)
101: for (i = 0; i < ExecIndex; i++)
102: if ((AutoExecs[i].a_cmd == d) &&
103: (strcmp(pattern, AutoExecs[i].a_pattern) == 0))
104: return; /* eliminate duplicates */
105: AutoExecs[ExecIndex].a_pattern = copystr(pattern);
106: AutoExecs[ExecIndex].a_cmd = d;
107: ExecIndex += 1;
108: }
109:
110: /* DoAutoExec: NEW and OLD are file names, and if NEW and OLD aren't the
111: same kind of file (i.e., match the same pattern) or OLD is 0 and it
112: matches, OR if the pattern is 0 (none was specified) then, we execute
113: the command associated with that kind of file. */
114:
115: void
116: DoAutoExec(new, old)
117: register char *new,
118: *old;
119: {
120: register int i;
121:
122: set_arg_value(1);
123: for (i = 0; i < ExecIndex; i++)
124: if ((AutoExecs[i].a_pattern == 0) ||
125: ((new != 0 && LookingAt(AutoExecs[i].a_pattern, new, 0)) &&
126: (old == 0 || !LookingAt(AutoExecs[i].a_pattern, old, 0))))
127: ExecCmd(AutoExecs[i].a_cmd);
128: }
129:
130: void
131: BindAKey()
132: {
133: BindSomething(findcom);
134: }
135:
136: void
137: BindMac()
138: {
139: BindSomething(findmac);
140: }
141:
142: extern void EscPrefix(),
143: CtlxPrefix(),
144: MiscPrefix();
145:
146: data_obj **
147: IsPrefix(cp)
148: data_obj *cp;
149: {
150: #ifdef MAC
151: void (*proc)();
152: #else
153: int (*proc)();
154: #endif
155:
156: if (cp == 0 || (cp->Type & TYPEMASK) != FUNCTION)
157: return 0;
158: proc = ((struct cmd *) cp)->c_proc;
159: if (proc == EscPrefix)
160: return pref1map;
161: if (proc == CtlxPrefix)
162: return pref2map;
163: if (proc == MiscPrefix)
164: return miscmap;
165: return 0;
166: }
167:
168: void
169: UnbindC()
170: {
171: char *keys;
172: data_obj **map = mainmap;
173:
174: keys = ask((char *) 0, ProcFmt);
175: for (;;) {
176: if (keys[1] == '\0')
177: break;
178: if ((map = IsPrefix(map[*keys])) == 0)
179: break;
180: keys += 1;
181: }
182: if (keys[1] != 0)
183: complain("That's not a legitimate key sequence.");
184: map[keys[0]] = 0;
185: }
186:
187: int
188: addgetc()
189: {
190: int c;
191:
192: if (!InJoverc) {
193: Asking = strlen(mesgbuf);
194: c = getch();
195: Asking = 0;
196: add_mess("%p ", c);
197: } else {
198: c = getch();
199: if (c == '\n')
200: return EOF; /* this isn't part of the sequence */
201: else if (c == '\\') {
202: if ((c = getch()) == LF)
203: complain("[Premature end of line]");
204: } else if (c == '^') {
205: if ((c = getch()) == '?')
206: c = RUBOUT;
207: else if (isalpha(c) || index("@[\\]^_", c))
208: c = CTL(c);
209: else
210: complain("[Unknown control character]");
211: }
212: }
213: return c;
214: }
215:
216: void
217: BindWMap(map, lastkey, cmd)
218: data_obj **map,
219: *cmd;
220: {
221: data_obj **nextmap;
222: int c;
223:
224: c = addgetc();
225: if (c == EOF) {
226: if (lastkey == EOF)
227: complain("[Empty key sequence]");
228: complain("[Premature end of key sequence]");
229: } else {
230: if (nextmap = IsPrefix(map[c]))
231: BindWMap(nextmap, c, cmd);
232: else {
233: map[c] = cmd;
234: #ifdef MAC
235: ((struct cmd *) cmd)->c_key = c; /* see about_j() in mac.c */
236: if(map == mainmap) ((struct cmd *) cmd)->c_map = F_MAINMAP;
237: else if(map == pref1map) ((struct cmd *) cmd)->c_map = F_PREF1MAP;
238: else if(map == pref2map) ((struct cmd *) cmd)->c_map = F_PREF2MAP;
239: #endif
240: }
241: }
242: }
243:
244: /* VARARGS0 */
245:
246: void
247: BindSomething(proc)
248: #ifdef LINT_ARGS
249: data_obj *(*proc)(char *);
250: #else
251: data_obj *(*proc)();
252: #endif
253: {
254: data_obj *d;
255:
256: if ((d = (*proc)(ProcFmt)) == 0)
257: return;
258: s_mess(": %f %s ", d->Name);
259: BindWMap(mainmap, EOF, d);
260: }
261:
262: /* Describe key */
263:
264: void
265: DescWMap(map, key)
266: data_obj **map;
267: {
268: data_obj *cp = map[key],
269: **prefp;
270:
271: if (cp == 0)
272: add_mess("is unbound.");
273: else if (prefp = IsPrefix(cp))
274: DescWMap(prefp, addgetc());
275: else
276: add_mess("is bound to %s.", cp->Name);
277: }
278:
279: void
280: KeyDesc()
281: {
282: s_mess(ProcFmt);
283: DescWMap(mainmap, addgetc());
284: }
285:
286: void
287: DescCom()
288: {
289: data_obj *dp;
290: char pattern[100],
291: doc_type[40],
292: *the_type,
293: *file = CmdDb;
294: File *fp;
295: int is_var;
296:
297: if (!strcmp(LastCmd->Name, "describe-variable")) {
298: dp = (data_obj *) findvar(ProcFmt);
299: the_type = "Variable";
300: is_var = YES;
301: } else {
302: dp = (data_obj *) findcom(ProcFmt);
303: the_type = "Command";
304: is_var = NO;
305: }
306: if (dp == 0)
307: return;
308: fp = open_file(file, iobuff, F_READ, COMPLAIN, QUIET);
309: Placur(ILI, 0);
310: flusho();
311: sprintf(pattern, "^:entry \"%s\" \"\\([^\"]*\\)\"", dp->Name);
312: TOstart("Help", TRUE);
313: for (;;) {
314: if (f_gets(fp, genbuf, LBSIZE) == EOF) {
315: Typeout("There is no documentation for \"%s\".", dp->Name);
316: goto outahere;
317: }
318: if ((strncmp(genbuf, ":entry", 6) == 0) &&
319: (LookingAt(pattern, genbuf, 0))) {
320: char type[64];
321:
322: putmatch(1, type, sizeof type);
323: if (strcmp(type, the_type) == 0)
324: break;
325: }
326: }
327: /* found it ... let's print it */
328: putmatch(1, doc_type, sizeof doc_type);
329: if (is_var == YES)
330: Typeout(dp->Name);
331: else {
332: char binding[128];
333:
334: find_binds(dp, binding);
335: if (blnkp(binding))
336: Typeout("To invoke %s, type \"ESC X %s<cr>\".",
337: dp->Name,
338: dp->Name);
339: else
340: Typeout("Type \"%s\" to invoke %s.", binding, dp->Name);
341: }
342: Typeout("");
343: while (f_gets(fp, genbuf, LBSIZE) != EOF)
344: if (strncmp(genbuf, ":entry", 6) == 0)
345: goto outahere;
346: else
347: Typeout("%s", genbuf);
348: outahere:
349: f_close(fp);
350: TOstop();
351: }
352:
353: void
354: DescBindings()
355: {
356: extern void Typeout();
357:
358: TOstart("Key Bindings", TRUE);
359: DescMap(mainmap, NullStr);
360: TOstop();
361: }
362:
363: extern int specialmap;
364:
365: void
366: DescMap(map, pref)
367: data_obj **map;
368: char *pref;
369: {
370: int c1,
371: c2 = 0,
372: numbetween;
373: char keydescbuf[40];
374: data_obj **prefp;
375:
376: #ifdef IBMPC
377: specialmap = (map == miscmap);
378: #endif
379:
380: for (c1 = 0; c1 < NCHARS && c2 < NCHARS; c1 = c2 + 1) {
381: c2 = c1;
382: if (map[c1] == 0)
383: continue;
384: while (++c2 < NCHARS && map[c1] == map[c2])
385: ;
386: c2 -= 1;
387: numbetween = c2 - c1;
388: if (numbetween == 1)
389: sprintf(keydescbuf, "%s {%p,%p}", pref, c1, c2);
390: else if (numbetween == 0)
391: sprintf(keydescbuf, "%s %p", pref, c1);
392: else
393: sprintf(keydescbuf, "%s [%p-%p]", pref, c1, c2);
394: if ((prefp = IsPrefix(map[c1])) && (prefp != map))
395: DescMap(prefp, keydescbuf);
396: else
397: Typeout("%-18s%s", keydescbuf, map[c1]->Name);
398: }
399: }
400:
401: private void
402: find_binds(dp, buf)
403: data_obj *dp;
404: char *buf;
405: {
406: char *endp;
407:
408: buf[0] = '\0';
409: fb_aux(dp, mainmap, (char *) 0, buf);
410: endp = buf + strlen(buf) - 2;
411: if ((endp > buf) && (strcmp(endp, ", ") == 0))
412: *endp = '\0';
413: }
414:
415: private void
416: fb_aux(cp, map, prefix, buf)
417: register data_obj *cp,
418: **map;
419: char *buf,
420: *prefix;
421: {
422: int c1,
423: c2;
424: char *bufp = buf + strlen(buf),
425: prefbuf[20];
426: data_obj **prefp;
427:
428: #ifdef IBMPC
429: specialmap = (map == miscmap);
430: #endif
431:
432: for (c1 = c2 = 0; c1 < NCHARS && c2 < NCHARS; c1 = c2 + 1) {
433: c2 = c1;
434: if (map[c1] == cp) {
435: while (++c2 < NCHARS && map[c1] == map[c2])
436: ;
437: c2 -= 1;
438: if (prefix)
439: sprintf(bufp, "%s ", prefix);
440: bufp += strlen(bufp);
441: switch (c2 - c1) {
442: case 0:
443: sprintf(bufp, "%p, ", c1);
444: break;
445:
446: case 1:
447: sprintf(bufp, "{%p,%p}, ", c1, c2);
448: break;
449:
450: default:
451: sprintf(bufp, "[%p-%p], ", c1, c2);
452: break;
453: }
454: }
455: if ((prefp = IsPrefix(map[c1])) && (prefp != map)) {
456: sprintf(prefbuf, "%p", c1);
457: fb_aux(cp, prefp, prefbuf, bufp);
458: }
459: bufp += strlen(bufp);
460: }
461: }
462:
463: void
464: Apropos()
465: {
466: register struct cmd *cp;
467: register struct macro *m;
468: register struct variable *v;
469: char *ans;
470: int anyfs = NO,
471: anyvs = NO,
472: anyms = NO;
473: char buf[256];
474:
475: ans = ask((char *) 0, ": %f (keyword) ");
476: TOstart("Help", TRUE);
477: for (cp = commands; cp->Name != 0; cp++)
478: if (sindex(ans, cp->Name)) {
479: if (anyfs == 0) {
480: Typeout("Commands");
481: Typeout("--------");
482: }
483: find_binds((data_obj *) cp, buf);
484: if (buf[0])
485: Typeout(": %-35s(%s)", cp->Name, buf);
486: else
487: Typeout(": %s", cp->Name);
488: anyfs = YES;
489: }
490: if (anyfs)
491: Typeout(NullStr);
492: for (v = variables; v->Name != 0; v++)
493: if (sindex(ans, v->Name)) {
494: if (anyvs == 0) {
495: Typeout("Variables");
496: Typeout("---------");
497: }
498: anyvs = YES;
499: vpr_aux(v, buf);
500: Typeout(": set %-26s%s", v->Name, buf);
501: }
502: if (anyvs)
503: Typeout(NullStr);
504: for (m = macros; m != 0; m = m->m_nextm)
505: if (sindex(ans, m->Name)) {
506: if (anyms == 0) {
507: Typeout("Macros");
508: Typeout("------");
509: }
510: anyms = YES;
511: find_binds((data_obj *) m, buf);
512: if (buf[0])
513: Typeout(": %-35s(%s)", m->Name, buf);
514: else
515: Typeout(": %-35s%s", "execute-macro", m->Name);
516: }
517: TOstop();
518: }
519:
520: void
521: Extend()
522: {
523: data_obj *d;
524:
525: if (d = findcom(": "))
526: ExecCmd(d);
527: }
528:
529: /* Read a positive integer from CP. It must be in base BASE, and
530: complains if it isn't. If allints is nonzero, all the characters
531: in the string must be integers or we return -1; otherwise we stop
532: reading at the first nondigit. */
533:
534: int
535: chr_to_int(cp, base, allints, result)
536: register char *cp;
537: register int *result;
538: {
539: register int c;
540: int value = 0,
541: sign;
542:
543: if ((c = *cp) == '-') {
544: sign = -1;
545: cp += 1;
546: } else
547: sign = 1;
548: while (c = *cp++) {
549: if (!isdigit(c)) {
550: if (allints == YES)
551: return INT_BAD;
552: break;
553: }
554: c = c - '0';
555: if (c >= base)
556: complain("You must specify in base %d.", base);
557: value = value * base + c;
558: }
559: *result = value * sign;
560: return INT_OKAY;
561: }
562:
563: int
564: ask_int(prompt, base)
565: char *prompt;
566: int base;
567: {
568: char *val = ask((char *) 0, prompt);
569: int value;
570:
571: if (chr_to_int(val, base, YES, &value) == INT_BAD)
572: complain("That's not a number!");
573: return value;
574: }
575:
576: private void
577: vpr_aux(vp, buf)
578: register struct variable *vp;
579: char *buf;
580: {
581: switch (vp->v_flags & V_TYPEMASK) {
582: case V_BASE10:
583: sprintf(buf, "%d", *(vp->v_value));
584: break;
585:
586: case V_BASE8:
587: sprintf(buf, "%o", *(vp->v_value));
588: break;
589:
590: case V_BOOL:
591: sprintf(buf, (*(vp->v_value)) ? "on" : "off");
592: break;
593:
594: case V_STRING:
595: case V_FILENAME:
596: sprintf(buf, "%s", (char *) vp->v_value);
597: break;
598:
599: case V_CHAR:
600: sprintf(buf, "%p", *(vp->v_value));
601: break;
602: }
603: }
604:
605: void
606: PrVar()
607: {
608: struct variable *vp;
609: char prbuf[256];
610:
611: if ((vp = (struct variable *) findvar(ProcFmt)) == 0)
612: return;
613: vpr_aux(vp, prbuf);
614: s_mess(": %f %s => %s", vp->Name, prbuf);
615: }
616:
617: void
618: SetVar()
619: {
620: struct variable *vp;
621: char *prompt;
622:
623: if ((vp = (struct variable *) findvar(ProcFmt)) == 0)
624: return;
625: prompt = sprint(": %f %s ", vp->Name);
626:
627: switch (vp->v_flags & V_TYPEMASK) {
628: case V_BASE10:
629: case V_BASE8:
630: {
631: int value;
632:
633: value = ask_int(prompt, ((vp->v_flags & V_TYPEMASK) == V_BASE10)
634: ? 10 : 8);
635: *(vp->v_value) = value;
636: break;
637: }
638:
639: case V_BOOL:
640: {
641: char *def = *(vp->v_value) ? "off" : "on",
642: *on_off;
643: int value;
644:
645: on_off = ask(def, prompt);
646: if (casecmp(on_off, "on") == 0)
647: value = ON;
648: else if (casecmp(on_off, "off") == 0)
649: value = OFF;
650: else
651: complain("Boolean variables must be ON or OFF.");
652: *(vp->v_value) = value;
653: #ifdef MAC
654: MarkVar(vp,-1,0); /* mark the menu item */
655: #endif
656: s_mess("%s%s", prompt, value ? "on" : "off");
657: break;
658: }
659:
660: case V_FILENAME:
661: {
662: char fbuf[FILESIZE];
663:
664: sprintf(&prompt[strlen(prompt)], "(default %s) ", vp->v_value);
665: (void) ask_file(prompt, (char *) vp->v_value, fbuf);
666: strcpy((char *) vp->v_value, fbuf);
667: break;
668: }
669:
670: case V_STRING:
671: {
672: char *str;
673:
674: /* Do_ask() so you can set string to "" if you so desire. */
675: str = do_ask("\r\n", (int (*)()) 0, (char *) vp->v_value, prompt);
676: if (str == 0)
677: str = NullStr;
678: strcpy((char *) vp->v_value, str);
679: /* ... and hope there is enough room. */
680: break;
681: }
682: case V_CHAR:
683: f_mess(prompt);
684: *(vp->v_value) = addgetc();
685: break;
686:
687: }
688: if (vp->v_flags & V_MODELINE)
689: UpdModLine = YES;
690: if (vp->v_flags & V_CLRSCREEN) {
691: #ifdef IBMPC
692: setcolor(Fgcolor, Bgcolor);
693: #endif /* IBMPC */
694: ClAndRedraw();
695: }
696: if (vp->v_flags & V_TTY_RESET)
697: tty_reset();
698: }
699:
700: /* Command completion - possible is an array of strings, prompt is
701: the prompt to use, and flags are ... well read jove.h.
702:
703: If flags are RET_STATE, and the user hits <return> what they typed
704: so far is in the Minibuf string. */
705:
706: private char **Possible;
707: private int comp_value,
708: comp_flags;
709:
710: int
711: aux_complete(c)
712: {
713: int command,
714: length,
715: i;
716:
717: if (comp_flags & CASEIND) {
718: char *lp;
719:
720: for (lp = linebuf; *lp != '\0'; lp++)
721: #if (defined(IBMPC) || defined(MAC))
722: lower(lp);
723: #else
724: if (isupper(*lp))
725: *lp = tolower(*lp);
726: #endif
727: }
728: switch (c) {
729: case EOF:
730: comp_value = -1;
731: return 0;
732:
733: case '\r':
734: case '\n':
735: command = match(Possible, linebuf);
736: if (command >= 0) {
737: comp_value = command;
738: return 0; /* tells ask to stop */
739: }
740: if (eolp() && bolp()) {
741: comp_value = NULLSTRING;
742: return 0;
743: }
744: if (comp_flags & RET_STATE) {
745: comp_value = command;
746: return 0;
747: }
748: if (InJoverc)
749: complain("[\"%s\" unknown]", linebuf);
750: rbell();
751: break;
752:
753: case '\t':
754: case ' ':
755: {
756: int minmatch = 1000,
757: maxmatch = 0,
758: numfound = 0,
759: lastmatch = -1,
760: length = strlen(linebuf);
761:
762: for (i = 0; Possible[i] != 0; i++) {
763: int this_len;
764:
765: this_len = numcomp(Possible[i], linebuf);
766: maxmatch = max(maxmatch, this_len);
767: if (this_len >= length) {
768: if (numfound)
769: minmatch = min(minmatch, numcomp(Possible[lastmatch], Possible[i]));
770: else
771: minmatch = strlen(Possible[i]);
772: numfound += 1;
773: lastmatch = i;
774: if (strcmp(linebuf, Possible[i]) == 0)
775: break;
776: }
777: }
778:
779: if (numfound == 0) {
780: rbell();
781: if (InJoverc)
782: complain("[\"%s\" unknown]", linebuf);
783: /* If we're not in the .joverc then
784: let's do something helpful for the
785: user. */
786: if (maxmatch < length) {
787: char *cp;
788:
789: cp = linebuf + maxmatch;
790: *cp = 0;
791: Eol();
792: }
793: break;
794: }
795: if (c != '\t' && numfound == 1) {
796: comp_value = lastmatch;
797: return 0;
798: }
799: null_ncpy(linebuf, Possible[lastmatch], minmatch);
800: Eol();
801: if (minmatch == length) /* No difference */
802: rbell();
803: break;
804: }
805:
806: case '?':
807: if (InJoverc)
808: complain((char *) 0);
809: /* kludge: in case we're using UseBuffers, in which case
810: linebuf gets written all over */
811: strcpy(Minibuf, linebuf);
812: length = strlen(Minibuf);
813: TOstart("Completion", TRUE); /* for now ... */
814: for (i = 0; Possible[i]; i++)
815: if (numcomp(Possible[i], Minibuf) >= length) {
816: Typeout(Possible[i]);
817: if (TOabort != 0)
818: break;
819: }
820:
821: TOstop();
822: break;
823: }
824: return !FALSE;
825: }
826:
827: int
828: complete(possible, prompt, flags)
829: register char *possible[];
830: char *prompt;
831: {
832: Possible = possible;
833: comp_flags = flags;
834: (void) do_ask("\r\n \t?", aux_complete, NullStr, prompt);
835: return comp_value;
836: }
837:
838: int
839: match(choices, what)
840: register char **choices,
841: *what;
842: {
843: register int len;
844: int i,
845: found = 0,
846: save,
847: exactmatch = -1;
848:
849: len = strlen(what);
850: if (len == 0)
851: return NULLSTRING;
852: for (i = 0; choices[i]; i++) {
853: if (strncmp(what, choices[i], len) == 0) {
854: if (strcmp(what, choices[i]) == 0)
855: exactmatch = i;
856: save = i;
857: found += 1; /* found one */
858: }
859: }
860:
861: if (found == 0)
862: save = ORIGINAL;
863: else if (found > 1) {
864: if (exactmatch != -1)
865: save = exactmatch;
866: else
867: save = AMBIGUOUS;
868: }
869:
870: return save;
871: }
872:
873: void
874: Source()
875: {
876: char *com, *getenv(),
877: buf[FILESIZE];
878:
879: #ifndef MSDOS
880: sprintf(buf, "%s/.joverc", getenv("HOME"));
881: #else /* MSDOS */
882: if (com = getenv("JOVERC"))
883: strcpy(buf, com);
884: else
885: strcpy(buf, Joverc);
886: #endif /* MSDOS */
887: com = ask_file((char *) 0, buf, buf);
888: if (joverc(buf) == 0)
889: complain(IOerr("read", com));
890: }
891:
892: void
893: BufPos()
894: {
895: register Line *lp = curbuf->b_first;
896: register int i,
897: dotline;
898: long dotchar,
899: nchars;
900:
901: for (i = nchars = 0; lp != 0; i++, lp = lp->l_next) {
902: if (lp == curline) {
903: dotchar = nchars + curchar;
904: dotline = i + 1;
905: }
906: nchars += length(lp) + (lp->l_next != 0); /* include the NL */
907: }
908:
909: s_mess("[\"%s\" line %d/%d, char %D/%D (%d%%), cursor = %d/%d]",
910: filename(curbuf), dotline, i, dotchar, nchars,
911: (nchars == 0) ? 100 : (int) (((long) dotchar * 100) / nchars),
912: calc_pos(linebuf, curchar),
913: calc_pos(linebuf, strlen(linebuf)));
914: }
915:
916: #define IF_UNBOUND -1
917: #define IF_TRUE 1
918: #define IF_FALSE !IF_TRUE
919:
920: #ifndef MAC
921: int
922: do_if(cmd)
923: char *cmd;
924: {
925: #ifdef MSDOS
926: int status;
927: #else
928: int pid,
929: status;
930: #endif /* MSDOS */
931: #ifndef MSDOS
932:
933: switch (pid = fork()) {
934: case -1:
935: complain("[Fork failed: if]");
936:
937: case 0:
938: {
939: #endif /* MSDOS */
940: char *args[12],
941: *cp = cmd,
942: **ap = args;
943:
944: *ap++ = cmd;
945: for (;;) {
946: if ((cp = index(cp, ' ')) == 0)
947: break;
948: *cp++ = '\0';
949: *ap++ = cp;
950: }
951: *ap = 0;
952:
953: #ifndef MSDOS
954: close(0); /* we want reads to fail */
955: /* close(1); but not writes or ioctl's
956: close(2); */
957: #else /* MSDOS */
958: if ((status = spawnvp(0, args[0], args)) < 0)
959: complain("[Spawn failed: if]");
960: #endif /* MSDOS */
961:
962: #ifndef MSDOS
963: (void) execvp(args[0], args);
964: _exit(-10); /* signals exec error (see below) */
965: }
966: }
967: #ifdef IPROCS
968: sighold(SIGCHLD);
969: #endif
970: dowait(pid, &status);
971: #ifdef IPROCS
972: sigrelse(SIGCHLD);
973: #endif
974: if (status == -10)
975: complain("[Exec failed]");
976: if (status < 0)
977: complain("[Exit %d]", status);
978: #endif /* MSDOS */
979: return (status == 0); /* 0 means successful */
980: }
981: #endif /* MAC */
982:
983: int
984: joverc(file)
985: char *file;
986: {
987: char buf[LBSIZE],
988: lbuf[LBSIZE];
989: int lnum = 0,
990: eof = FALSE;
991: jmp_buf savejmp;
992: int IfStatus = IF_UNBOUND;
993: File *fp;
994:
995: fp = open_file(file, buf, F_READ, !COMPLAIN, QUIET);
996: if (fp == NIL)
997: return NO; /* joverc returns an integer */
998:
999: /* Catch any errors, here, and do the right thing with them,
1000: and then restore the error handle to whoever did a setjmp
1001: last. */
1002:
1003: InJoverc += 1;
1004: push_env(savejmp);
1005: if (setjmp(mainjmp)) {
1006: Buffer *savebuf = curbuf;
1007:
1008: SetBuf(do_select((Window *) 0, "RC errors"));
1009: ins_str(sprint("%s:%d:%s\t%s\n", pr_name(file, YES), lnum, lbuf, mesgbuf), NO);
1010: unmodify();
1011: SetBuf(savebuf);
1012: Asking = 0;
1013: }
1014: if (!eof) do {
1015: eof = (f_gets(fp, lbuf, sizeof lbuf) == EOF);
1016: lnum += 1;
1017: if (lbuf[0] == '#') /* a comment */
1018: continue;
1019: #ifndef MAC
1020: if (casencmp(lbuf, "if", 2) == 0) {
1021: char cmd[128];
1022:
1023: if (IfStatus != IF_UNBOUND)
1024: complain("[Cannot have nested if's]");
1025: if (LookingAt("if[ \t]*\\(.*\\)$", lbuf, 0) == 0)
1026: complain("[If syntax error]");
1027: putmatch(1, cmd, sizeof cmd);
1028: IfStatus = do_if(cmd) ? IF_TRUE : IF_FALSE;
1029: continue;
1030: } else if (casencmp(lbuf, "else", 4) == 0) {
1031: if (IfStatus == IF_UNBOUND)
1032: complain("[Unexpected `else']");
1033: IfStatus = !IfStatus;
1034: continue;
1035: } else if (casencmp(lbuf, "endif", 5) == 0) {
1036: if (IfStatus == IF_UNBOUND)
1037: complain("[Unexpected `endif']");
1038: IfStatus = IF_UNBOUND;
1039: continue;
1040: }
1041: #endif
1042: if (IfStatus == IF_FALSE)
1043: continue;
1044: (void) strcat(lbuf, "\n");
1045: Inputp = lbuf;
1046: while (*Inputp == ' ' || *Inputp == '\t')
1047: Inputp += 1; /* skip white space */
1048: Extend();
1049: } while (!eof);
1050:
1051: f_close(fp);
1052: pop_env(savejmp);
1053: Inputp = 0;
1054: Asking = 0;
1055: InJoverc -= 1;
1056: if (IfStatus != IF_UNBOUND)
1057: complain("[Missing endif]");
1058: return 1;
1059: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.