|
|
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 "fp.h"
10: #include "termcap.h"
11: #include "ctype.h"
12: #include "chars.h"
13: #include "disp.h"
14: #include "re.h"
15:
16: #if defined(JOB_CONTROL) || defined(IPROCS)
17: # include <signal.h>
18: #endif
19:
20: #ifdef MAC
21: # include "mac.h"
22: #else
23: # ifdef STDARGS
24: # include <stdarg.h>
25: # else
26: # include <varargs.h>
27: # endif
28: #endif
29:
30: #ifdef MSDOS
31: # include <process.h>
32: #endif
33:
34: private void
35: DefAutoExec proto((struct data_obj *(*proc)()));
36:
37: private int
38: match proto((char **, char *));
39:
40: int InJoverc = 0;
41:
42: /* Auto execute code */
43:
44: #define NEXECS 20
45:
46: private struct {
47: char *a_pattern;
48: data_obj *a_cmd;
49: } AutoExecs[NEXECS]; /* must be initialized by system to 0 */
50:
51: private int ExecIndex = 0;
52:
53: /* Command auto-execute. */
54:
55: void
56: CAutoExec()
57: {
58: DefAutoExec(findcom);
59: }
60:
61: /* Macro auto-execute. */
62:
63: void
64: MAutoExec()
65: {
66: DefAutoExec(findmac);
67: }
68:
69: private void
70: DefAutoExec(proc)
71: #if defined(MAC) || defined(IBMPC)
72: data_obj *(*proc)();
73: #else
74: data_obj *(*proc) proto((char *));
75: #endif
76: {
77: data_obj *d;
78: char *pattern;
79: int i;
80:
81: if (ExecIndex >= NEXECS)
82: complain("Too many auto-executes, max %d.", NEXECS);
83: if ((d = (*proc)(ProcFmt)) == 0)
84: return;
85: pattern = do_ask("\r\n", (int (*) proto((int))) 0, (char *) 0, ": %f %s ",
86: d->Name);
87: for (i = 0; i < ExecIndex; i++) {
88: if (AutoExecs[i].a_cmd == d) {
89: char *ipat = AutoExecs[i].a_pattern;
90:
91: if ((pattern == NULL || ipat == NULL)?
92: (pattern == ipat) : (strcmp(pattern, ipat) == 0))
93: return; /* eliminate duplicates */
94: }
95: }
96: AutoExecs[ExecIndex].a_pattern = copystr(pattern);
97: AutoExecs[ExecIndex].a_cmd = d;
98: ExecIndex += 1;
99: }
100:
101: /* DoAutoExec: NEW and OLD are file names, and if NEW and OLD aren't the
102: same kind of file (i.e., match the same pattern) or OLD is 0 and it
103: matches, OR if the pattern is 0 (none was specified) then, we execute
104: the command associated with that kind of file. */
105:
106: void
107: DoAutoExec(new, old)
108: register char *new,
109: *old;
110: {
111: register int i;
112:
113: set_arg_value(1);
114: for (i = 0; i < ExecIndex; i++)
115: if ((AutoExecs[i].a_pattern == 0) ||
116: ((new != 0 && LookingAt(AutoExecs[i].a_pattern, new, 0)) &&
117: (old == 0 || !LookingAt(AutoExecs[i].a_pattern, old, 0))))
118: ExecCmd(AutoExecs[i].a_cmd);
119: }
120:
121: int
122: addgetc()
123: {
124: int c;
125:
126: if (!InJoverc) {
127: Asking = strlen(mesgbuf);
128: c = getch();
129: Asking = 0;
130: add_mess("%p ", c);
131: } else {
132: c = getch();
133: if (c == '\n')
134: return EOF; /* this isn't part of the sequence */
135: else if (c == '\\') {
136: if ((c = getch()) == LF)
137: complain("[Premature end of line]");
138: } else if (c == '^') {
139: if ((c = getch()) == '?')
140: c = RUBOUT;
141: else if (isalpha(c) || strchr("@[\\]^_", c))
142: c = CTL(c);
143: else
144: complain("[Unknown control character]");
145: }
146: }
147: return c;
148: }
149:
150: void
151: Extend()
152: {
153: data_obj *d;
154:
155: if ((d = findcom(": ")) != NULL)
156: ExecCmd(d);
157: }
158:
159: /* Read a positive integer from CP. It must be in base BASE, and
160: complains if it isn't. If allints is nonzero, all the characters
161: in the string must be integers or we return -1; otherwise we stop
162: reading at the first nondigit. */
163:
164: int
165: chr_to_int(cp, base, allints, result)
166: register char *cp;
167: int base,
168: allints;
169: register int *result;
170: {
171: register int c;
172: int value = 0,
173: sign;
174:
175: if ((c = *cp) == '-') {
176: sign = -1;
177: cp += 1;
178: } else
179: sign = 1;
180: while ((c = *cp++) != '\0') {
181: if (!isdigit(c)) {
182: if (allints == YES)
183: return INT_BAD;
184: break;
185: }
186: c = c - '0';
187: if (c >= base)
188: complain("You must specify in base %d.", base);
189: value = value * base + c;
190: }
191: *result = value * sign;
192: return INT_OKAY;
193: }
194:
195: int
196: ask_int(prompt, base)
197: char *prompt;
198: int base;
199: {
200: char *val = ask((char *) 0, prompt);
201: int value;
202:
203: if (chr_to_int(val, base, YES, &value) == INT_BAD)
204: complain("That's not a number!");
205: return value;
206: }
207:
208: void
209: vpr_aux(vp, buf)
210: register const struct variable *vp;
211: char *buf;
212: {
213: switch (vp->v_flags & V_TYPEMASK) {
214: case V_BASE10:
215: swritef(buf, "%d", *((int *) vp->v_value));
216: break;
217:
218: case V_BASE8:
219: swritef(buf, "%o", *((int *) vp->v_value));
220: break;
221:
222: case V_BOOL:
223: swritef(buf, (*((int *) vp->v_value)) ? "on" : "off");
224: break;
225:
226: case V_STRING:
227: case V_FILENAME:
228: swritef(buf, "%s", vp->v_value);
229: break;
230:
231: case V_CHAR:
232: swritef(buf, "%p", *((int *) vp->v_value));
233: break;
234: }
235: }
236:
237: void
238: PrVar()
239: {
240: struct variable *vp;
241: char prbuf[256];
242:
243: if ((vp = (struct variable *) findvar(ProcFmt)) == 0)
244: return;
245: vpr_aux(vp, prbuf);
246: s_mess(": %f %s => %s", vp->Name, prbuf);
247: }
248:
249: void
250: SetVar()
251: {
252: struct variable *vp;
253: char *prompt;
254:
255: if ((vp = (struct variable *) findvar(ProcFmt)) == 0)
256: return;
257: prompt = sprint(": %f %s ", vp->Name);
258:
259: switch (vp->v_flags & V_TYPEMASK) {
260: case V_BASE10:
261: case V_BASE8:
262: {
263: int value;
264:
265: value = ask_int(prompt, ((vp->v_flags & V_TYPEMASK) == V_BASE10)
266: ? 10 : 8);
267: *((int *) vp->v_value) = value;
268: break;
269: }
270:
271: case V_BOOL:
272: {
273: char *def = *((int *) vp->v_value) ? "off" : "on",
274: *on_off;
275: int value;
276:
277: on_off = ask(def, prompt);
278: if (casecmp(on_off, "on") == 0)
279: value = ON;
280: else if (casecmp(on_off, "off") == 0)
281: value = OFF;
282: else
283: complain("Boolean variables must be ON or OFF.");
284: *((int *) vp->v_value) = value;
285: #ifdef MAC
286: MarkVar(vp,-1,0); /* mark the menu item */
287: #endif
288: s_mess("%s%s", prompt, value ? "on" : "off");
289: break;
290: }
291:
292: case V_FILENAME:
293: {
294: char fbuf[FILESIZE];
295:
296: (void) ask_file(prompt, (char *) vp->v_value, fbuf);
297: strcpy((char *) vp->v_value, fbuf);
298: break;
299: }
300:
301: case V_STRING:
302: {
303: char *str;
304:
305: /* Do_ask() so you can set string to "" if you so desire. */
306: str = do_ask("\r\n", (int (*) proto((int))) 0, (char *) vp->v_value,
307: prompt);
308: if (str == 0)
309: str = NullStr;
310: strcpy(vp->v_value, str);
311: /* ... and hope there is enough room. */
312: break;
313: }
314: case V_CHAR:
315: f_mess(prompt);
316: *((int *) vp->v_value) = addgetc();
317: break;
318:
319: }
320: if (vp->v_flags & V_MODELINE)
321: UpdModLine = YES;
322: if (vp->v_flags & V_CLRSCREEN) {
323: #ifdef IBMPC
324: setcolor(Fgcolor, Bgcolor);
325: #endif /* IBMPC */
326: ClAndRedraw();
327: }
328: if (vp->v_flags & V_TTY_RESET)
329: tty_reset();
330: }
331:
332: /* Command completion - possible is an array of strings, prompt is
333: the prompt to use, and flags are ... well read jove.h.
334:
335: If flags are RET_STATE, and the user hits <return> what they typed
336: so far is in the Minibuf string. */
337:
338: private char **Possible;
339: private int comp_value,
340: comp_flags;
341:
342: int
343: aux_complete(c)
344: int c;
345: {
346: int command,
347: i;
348:
349: if (comp_flags & CASEIND) {
350: char *lp;
351:
352: for (lp = linebuf; *lp != '\0'; lp++)
353: #if (defined(IBMPC) || defined(MAC))
354: lower(lp);
355: #else
356: if (isupper(*lp))
357: *lp = tolower(*lp);
358: #endif
359: }
360: switch (c) {
361: case EOF:
362: comp_value = -1;
363: return 0;
364:
365: case '\r':
366: case '\n':
367: command = match(Possible, linebuf);
368: if (command >= 0) {
369: comp_value = command;
370: return 0; /* tells ask to stop */
371: }
372: if (eolp() && bolp()) {
373: comp_value = NULLSTRING;
374: return 0;
375: }
376: if (comp_flags & RET_STATE) {
377: comp_value = command;
378: return 0;
379: }
380: if (InJoverc)
381: complain("[\"%s\" unknown]", linebuf);
382: rbell();
383: break;
384:
385: case '\t':
386: case ' ':
387: {
388: int minmatch = 1000,
389: maxmatch = 0,
390: numfound = 0,
391: lastmatch = -1,
392: len = strlen(linebuf);
393:
394: for (i = 0; Possible[i] != 0; i++) {
395: int this_len;
396:
397: this_len = numcomp(Possible[i], linebuf);
398: maxmatch = max(maxmatch, this_len);
399: if (this_len >= len) {
400: if (numfound)
401: minmatch = min(minmatch, numcomp(Possible[lastmatch], Possible[i]));
402: else
403: minmatch = strlen(Possible[i]);
404: numfound += 1;
405: lastmatch = i;
406: if (strcmp(linebuf, Possible[i]) == 0)
407: break;
408: }
409: }
410:
411: if (numfound == 0) {
412: rbell();
413: if (InJoverc)
414: complain("[\"%s\" unknown]", linebuf);
415: /* If we're not in the .joverc then
416: let's do something helpful for the
417: user. */
418: if (maxmatch < len) {
419: char *cp;
420:
421: cp = linebuf + maxmatch;
422: *cp = 0;
423: Eol();
424: }
425: break;
426: }
427: if (c != '\t' && numfound == 1) {
428: comp_value = lastmatch;
429: return 0;
430: }
431: null_ncpy(linebuf, Possible[lastmatch], (size_t) minmatch);
432: Eol();
433: if (minmatch == len) /* No difference */
434: rbell();
435: break;
436: }
437:
438: case '?':
439: {
440: int len;
441:
442: if (InJoverc)
443: complain((char *) 0);
444: /* kludge: in case we're using UseBuffers, in which case
445: linebuf gets written all over */
446: strcpy(Minibuf, linebuf);
447: len = strlen(Minibuf);
448: TOstart("Completion", TRUE); /* for now ... */
449: for (i = 0; Possible[i]; i++)
450: if (numcomp(Possible[i], Minibuf) >= len) {
451: Typeout(Possible[i]);
452: if (TOabort != 0)
453: break;
454: }
455:
456: TOstop();
457: }
458: break;
459: }
460: return !FALSE;
461: }
462:
463: int
464: complete(possible, prompt, flags)
465: register char *possible[];
466: char *prompt;
467: int flags;
468: {
469: /* protect static "Possible" from being overwritten due to recursion */
470: if (InRealAsk)
471: complain((char *) NULL);
472:
473: Possible = possible;
474: comp_flags = flags;
475: (void) do_ask("\r\n \t?", aux_complete, NullStr, prompt);
476: return comp_value;
477: }
478:
479: private int
480: match(choices, what)
481: register char **choices,
482: *what;
483: {
484: register size_t len;
485: int i,
486: found = 0,
487: save,
488: exactmatch = -1;
489:
490: len = strlen(what);
491: if (len == 0)
492: return NULLSTRING;
493: for (i = 0; choices[i]; i++) {
494: if (strncmp(what, choices[i], len) == 0) {
495: if (strcmp(what, choices[i]) == 0)
496: exactmatch = i;
497: save = i;
498: found += 1; /* found one */
499: }
500: }
501:
502: if (found == 0)
503: save = ORIGINAL;
504: else if (found > 1) {
505: if (exactmatch != -1)
506: save = exactmatch;
507: else
508: save = AMBIGUOUS;
509: }
510:
511: return save;
512: }
513:
514: void
515: Source()
516: {
517: extern char *getenv();
518: char *com,
519: buf[FILESIZE];
520:
521: #ifndef MSDOS
522: swritef(buf, "%s/.joverc", HomeDir);
523: #else /* MSDOS */
524: if (com = getenv("JOVERC"))
525: strcpy(buf, com);
526: else
527: strcpy(buf, Joverc);
528: #endif /* MSDOS */
529: com = ask_file((char *) 0, buf, buf);
530: if (joverc(buf) == 0)
531: complain(IOerr("read", com));
532: }
533:
534: void
535: BufPos()
536: {
537: register Line *lp = curbuf->b_first;
538: register int i,
539: dotline;
540: long dotchar,
541: nchars;
542:
543: for (i = nchars = 0; lp != 0; i++, lp = lp->l_next) {
544: if (lp == curline) {
545: dotchar = nchars + curchar;
546: dotline = i + 1;
547: }
548: nchars += length(lp) + (lp->l_next != 0); /* include the NL */
549: }
550:
551: s_mess("[\"%s\" line %d/%d, char %D/%D (%d%%), cursor = %d/%d]",
552: filename(curbuf), dotline, i, dotchar, nchars,
553: (nchars == 0) ? 100 : (int) (((long) dotchar * 100) / nchars),
554: calc_pos(linebuf, curchar),
555: calc_pos(linebuf, (int)strlen(linebuf)));
556: }
557:
558: #define IF_UNBOUND (-1)
559: #define IF_TRUE 1
560: #define IF_FALSE (!IF_TRUE)
561:
562: #ifndef MAC
563: private int
564: do_if(cmd)
565: char *cmd;
566: {
567: #ifdef MSDOS
568: int status;
569: #else
570: int pid,
571: status;
572: #endif /* MSDOS */
573: #ifndef MSDOS
574:
575: switch (pid = fork()) {
576: case -1:
577: complain("[Fork failed: if]");
578: /*NOTREACHED*/
579:
580: case 0:
581: {
582: #endif /* MSDOS */
583: char *args[12],
584: *cp = cmd,
585: **ap = args;
586:
587: *ap++ = cmd;
588: for (;;) {
589: if ((cp = strchr(cp, ' ')) == 0)
590: break;
591: *cp++ = '\0';
592: *ap++ = cp;
593: }
594: *ap = 0;
595:
596: #ifndef MSDOS
597: close(0); /* we want reads to fail */
598: /* close(1); but not writes or ioctl's
599: close(2); */
600: #else /* MSDOS */
601: if ((status = spawnvp(0, args[0], args)) < 0)
602: complain("[Spawn failed: if]");
603: #endif /* MSDOS */
604:
605: #ifndef MSDOS
606: (void) execvp(args[0], (const char **)args);
607: _exit(-10); /* signals exec error (see below) */
608: }
609: }
610: #ifdef IPROCS
611: SigHold(SIGCHLD);
612: #endif
613: dowait(pid, &status);
614: #ifdef IPROCS
615: SigRelse(SIGCHLD);
616: #endif
617: if (status == -10)
618: complain("[Exec failed]");
619: if (status < 0)
620: complain("[Exit %d]", status);
621: #endif /* MSDOS */
622: return (status == 0); /* 0 means successful */
623: }
624: #endif /* MAC */
625:
626: int
627: joverc(file)
628: char *file;
629: {
630: char buf[LBSIZE],
631: lbuf[LBSIZE];
632: int lnum = 0,
633: eof = FALSE;
634: jmp_buf savejmp;
635: int IfStatus = IF_UNBOUND;
636: File *fp;
637:
638: fp = open_file(file, buf, F_READ, NO, YES);
639: if (fp == NIL)
640: return NO; /* joverc returns an integer */
641:
642: /* Catch any errors, here, and do the right thing with them,
643: and then restore the error handle to whoever did a setjmp
644: last. */
645:
646: InJoverc += 1;
647: push_env(savejmp);
648: if (setjmp(mainjmp)) {
649: Buffer *savebuf = curbuf;
650:
651: SetBuf(do_select((Window *) 0, "RC errors"));
652: ins_str(sprint("%s:%d:%s\t%s\n", pr_name(file, YES), lnum, lbuf, mesgbuf), NO);
653: unmodify();
654: SetBuf(savebuf);
655: Asking = 0;
656: }
657: if (!eof) do {
658: eof = (f_gets(fp, lbuf, sizeof lbuf) == EOF);
659: lnum += 1;
660: if (lbuf[0] == '#') /* a comment */
661: continue;
662: #ifndef MAC
663: if (casencmp(lbuf, "if", (size_t)2) == 0) {
664: char cmd[128];
665:
666: if (IfStatus != IF_UNBOUND)
667: complain("[Cannot have nested if's]");
668: if (LookingAt("if[ \t]*\\(.*\\)$", lbuf, 0) == 0)
669: complain("[If syntax error]");
670: putmatch(1, cmd, sizeof cmd);
671: IfStatus = do_if(cmd) ? IF_TRUE : IF_FALSE;
672: continue;
673: } else if (casencmp(lbuf, "else", (size_t)4) == 0) {
674: if (IfStatus == IF_UNBOUND)
675: complain("[Unexpected `else']");
676: IfStatus = !IfStatus;
677: continue;
678: } else if (casencmp(lbuf, "endif", (size_t)5) == 0) {
679: if (IfStatus == IF_UNBOUND)
680: complain("[Unexpected `endif']");
681: IfStatus = IF_UNBOUND;
682: continue;
683: }
684: #endif
685: if (IfStatus == IF_FALSE)
686: continue;
687: (void) strcat(lbuf, "\n");
688: Inputp = lbuf;
689: while (*Inputp == ' ' || *Inputp == '\t')
690: Inputp += 1; /* skip white space */
691: Extend();
692: } while (!eof);
693:
694: f_close(fp);
695: pop_env(savejmp);
696: Inputp = 0;
697: Asking = 0;
698: InJoverc -= 1;
699: if (IfStatus != IF_UNBOUND)
700: complain("[Missing endif]");
701: return 1;
702: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.