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