|
|
1.1 root 1: /* cmd1.c */
2:
3: /* Author:
4: * Steve Kirkendall
5: * 14407 SW Teal Blvd. #C
6: * Beaverton, OR 97005
7: * [email protected]
8: */
9:
10:
11: /* This file contains some of the EX commands - mostly ones that deal with
12: * files, options, etc. -- anything except text.
13: */
14:
15: #include "config.h"
16: #include "ctype.h"
17: #include "vi.h"
18: #include "regexp.h"
19:
20: #ifdef DEBUG
21: /* print the selected lines with info on the blocks */
22: /*ARGSUSED*/
23: void cmd_debug(frommark, tomark, cmd, bang, extra)
24: MARK frommark;
25: MARK tomark;
26: CMD cmd;
27: int bang;
28: char *extra;
29: {
30: REG char *scan;
31: REG long l;
32: REG int i;
33: int len;
34:
35: /* scan lnum[] to determine which block its in */
36: l = markline(frommark);
37: for (i = 1; l > lnum[i]; i++)
38: {
39: }
40:
41: do
42: {
43: /* fetch text of the block containing that line */
44: scan = blkget(i)->c;
45:
46: /* calculate its length */
47: if (scan[BLKSIZE - 1])
48: {
49: len = BLKSIZE;
50: }
51: else
52: {
53: len = strlen(scan);
54: }
55:
56: /* print block stats */
57: msg("##### hdr[%d]=%d, lnum[%d-1]=%ld, lnum[%d]=%ld (%ld lines)",
58: i, hdr.n[i], i, lnum[i-1], i, lnum[i], lnum[i] - lnum[i - 1]);
59: msg("##### len=%d, buf=0x%lx, %sdirty",
60: len, scan, ((int *)scan)[MAXBLKS + 1] ? "" : "not ");
61: if (bang)
62: {
63: while (--len >= 0)
64: {
65: addch(*scan);
66: scan++;
67: }
68: }
69: exrefresh();
70:
71: /* next block */
72: i++;
73: } while (i < MAXBLKS && lnum[i] && lnum[i - 1] < markline(tomark));
74: }
75:
76:
77: /* This function checks a lot of conditions to make sure they aren't screwy */
78: /*ARGSUSED*/
79: void cmd_validate(frommark, tomark, cmd, bang, extra)
80: MARK frommark;
81: MARK tomark;
82: CMD cmd;
83: int bang;
84: char *extra;
85: {
86: char *scan;
87: int i;
88: int nlcnt; /* used to count newlines */
89: int len; /* counts non-NUL characters */
90:
91: /* check lnum[0] */
92: if (lnum[0] != 0L)
93: {
94: msg("lnum[0] = %ld", lnum[0]);
95: }
96:
97: /* check each block */
98: for (i = 1; lnum[i] <= nlines; i++)
99: {
100: scan = blkget(i)->c;
101: if (scan[BLKSIZE - 1])
102: {
103: msg("block %d has no NUL at the end", i);
104: }
105: else
106: {
107: for (nlcnt = len = 0; *scan; scan++, len++)
108: {
109: if (*scan == '\n')
110: {
111: nlcnt++;
112: }
113: }
114: if (scan[-1] != '\n')
115: {
116: msg("block %d doesn't end with '\\n' (length %d)", i, len);
117: }
118: if (bang || nlcnt != lnum[i] - lnum[i - 1])
119: {
120: msg("block %d (line %ld?) has %d lines, but should have %ld",
121: i, lnum[i - 1] + 1L, nlcnt, lnum[i] - lnum[i - 1]);
122: }
123: }
124: exrefresh();
125: }
126:
127: /* check lnum again */
128: if (lnum[i] != INFINITY)
129: {
130: msg("hdr.n[%d] = %d, but lnum[%d] = %ld",
131: i, hdr.n[i], i, lnum[i]);
132: }
133:
134: msg("# = \"%s\", %% = \"%s\"", prevorig, origname);
135: msg("V_from=%ld.%d, cursor=%ld.%d", markline(V_from), markidx(V_from), markline(cursor), markidx(cursor));
136: }
137: #endif /* DEBUG */
138:
139:
140: /*ARGSUSED*/
141: void cmd_mark(frommark, tomark, cmd, bang, extra)
142: MARK frommark;
143: MARK tomark;
144: CMD cmd;
145: int bang;
146: char *extra;
147: {
148: /* validate the name of the mark */
149: if (*extra == '"')
150: {
151: extra++;
152: }
153: /* valid mark names are lowercase ascii characters */
154: if (!isascii(*extra) || !islower(*extra) || extra[1])
155: {
156: msg("Invalid mark name");
157: return;
158: }
159:
160: mark[*extra - 'a'] = tomark;
161: }
162:
163: /*ARGSUSED*/
164: void cmd_write(frommark, tomark, cmd, bang, extra)
165: MARK frommark;
166: MARK tomark;
167: CMD cmd;
168: int bang;
169: char *extra;
170: {
171: int fd;
172: int append; /* boolean: write in "append" mode? */
173: REG long l;
174: REG char *scan;
175: REG int i;
176:
177: /* if writing to a filter, then let filter() handle it */
178: if (*extra == '!')
179: {
180: filter(frommark, tomark, extra + 1, FALSE);
181: return;
182: }
183:
184: /* if all lines are to be written, use tmpsave() */
185: if (frommark == MARK_FIRST && tomark == MARK_LAST && cmd == CMD_WRITE)
186: {
187: tmpsave(extra, bang);
188: return;
189: }
190:
191: /* see if we're going to do this in append mode or not */
192: append = FALSE;
193: if (extra[0] == '>' && extra[1] == '>')
194: {
195: extra += 2;
196: append = TRUE;
197: }
198:
199: /* either the file must not exist, or we must have a ! or be appending */
200: if (access(extra, 0) == 0 && !bang && !append)
201: {
202: msg("File already exists - Use :w! to overwrite");
203: return;
204: }
205:
206: /* else do it line-by-line, like cmd_print() */
207: if (append)
208: {
209: #ifdef O_APPEND
210: fd = open(extra, O_WRONLY|O_APPEND);
211: #else
212: fd = open(extra, O_WRONLY);
213: if (fd >= 0)
214: {
215: lseek(fd, 0L, 2);
216: }
217: #endif
218: }
219: else
220: {
221: fd = -1; /* so we know the file isn't open yet */
222: }
223:
224: if (fd < 0)
225: {
226: fd = creat(extra, FILEPERMS);
227: if (fd < 0)
228: {
229: msg("Can't write to \"%s\"", extra);
230: return;
231: }
232: }
233: for (l = markline(frommark); l <= markline(tomark); l++)
234: {
235: /* get the next line */
236: scan = fetchline(l);
237: i = strlen(scan);
238: scan[i++] = '\n';
239:
240: /* print the line */
241: if (twrite(fd, scan, i) < i)
242: {
243: msg("Write failed");
244: break;
245: }
246: }
247: rptlines = markline(tomark) - markline(frommark) + 1;
248: rptlabel = "written";
249: close(fd);
250: }
251:
252:
253: /*ARGSUSED*/
254: void cmd_shell(frommark, tomark, cmd, bang, extra)
255: MARK frommark, tomark;
256: CMD cmd;
257: int bang;
258: char *extra;
259: {
260: static char prevextra[80];
261:
262: /* special case: ":sh" means ":!sh" */
263: if (cmd == CMD_SHELL)
264: {
265: extra = o_shell;
266: frommark = tomark = 0L;
267: }
268:
269: /* if extra is "!", substitute previous command */
270: if (*extra == '!')
271: {
272: if (!*prevextra)
273: {
274: msg("No previous shell command to substitute for '!'");
275: return;
276: }
277: extra = prevextra;
278: }
279: else if (cmd == CMD_BANG && strlen(extra) < sizeof(prevextra) - 1)
280: {
281: strcpy(prevextra, extra);
282: }
283:
284: /* warn the user if the file hasn't been saved yet */
285: if (*o_warn && tstflag(file, MODIFIED))
286: {
287: if (mode == MODE_VI)
288: {
289: mode = MODE_COLON;
290: }
291: msg("Warning: \"%s\" has been modified but not yet saved", origname);
292: }
293:
294: /* if no lines were specified, just run the command */
295: suspend_curses();
296: if (frommark == 0L)
297: {
298: system(extra);
299: }
300: else /* pipe lines from the file through the command */
301: {
302: filter(frommark, tomark, extra, TRUE);
303: }
304:
305: /* resume curses quietly for MODE_EX, but noisily otherwise */
306: resume_curses(mode == MODE_EX);
307: }
308:
309:
310: /*ARGSUSED*/
311: void cmd_global(frommark, tomark, cmd, bang, extra)
312: MARK frommark, tomark;
313: CMD cmd;
314: int bang;
315: char *extra; /* rest of the command line */
316: {
317: char *cmdptr; /* the command from the command line */
318: char cmdln[100]; /* copy of the command from the command line */
319: char *line; /* a line from the file */
320: long l; /* used as a counter to move through lines */
321: long lqty; /* quantity of lines to be scanned */
322: long nchanged; /* number of lines changed */
323: regexp *re; /* the compiled search expression */
324:
325: /* can't nest global commands */
326: if (doingglobal)
327: {
328: msg("Can't nest global commands.");
329: rptlines = -1L;
330: return;
331: }
332:
333: /* ":g! ..." is the same as ":v ..." */
334: if (bang)
335: {
336: cmd = CMD_VGLOBAL;
337: }
338:
339: /* make sure we got a search pattern */
340: if (*extra != '/' && *extra != '?')
341: {
342: msg("Usage: %c /regular expression/ command", cmd == CMD_GLOBAL ? 'g' : 'v');
343: return;
344: }
345:
346: /* parse & compile the search pattern */
347: cmdptr = parseptrn(extra);
348: if (!extra[1])
349: {
350: msg("Can't use empty regular expression with '%c' command", cmd == CMD_GLOBAL ? 'g' : 'v');
351: return;
352: }
353: re = regcomp(extra + 1);
354: if (!re)
355: {
356: /* regcomp found & described an error */
357: return;
358: }
359:
360: /* for each line in the range */
361: doingglobal = TRUE;
362: ChangeText
363: {
364: /* NOTE: we have to go through the lines in a forward order,
365: * otherwise "g/re/p" would look funny. *BUT* for "g/re/d"
366: * to work, simply adding 1 to the line# on each loop won't
367: * work. The solution: count lines relative to the end of
368: * the file. Think about it.
369: */
370: for (l = nlines - markline(frommark),
371: lqty = markline(tomark) - markline(frommark) + 1L,
372: nchanged = 0L;
373: lqty > 0 && nlines - l >= 0 && nchanged >= 0L;
374: l--, lqty--)
375: {
376: /* fetch the line */
377: line = fetchline(nlines - l);
378:
379: /* if it contains the search pattern... */
380: if ((!regexec(re, line, 1)) == (cmd != CMD_GLOBAL))
381: {
382: /* move the cursor to that line */
383: cursor = MARK_AT_LINE(nlines - l);
384:
385: /* do the ex command (without mucking up
386: * the original copy of the command line)
387: */
388: strcpy(cmdln, cmdptr);
389: rptlines = 0L;
390: doexcmd(cmdln);
391: nchanged += rptlines;
392: }
393: }
394: }
395: doingglobal = FALSE;
396:
397: /* free the regexp */
398: _free_(re);
399:
400: /* Reporting...*/
401: rptlines = nchanged;
402: }
403:
404:
405: /*ARGSUSED*/
406: void cmd_file(frommark, tomark, cmd, bang, extra)
407: MARK frommark, tomark;
408: CMD cmd;
409: int bang;
410: char *extra;
411: {
412: #ifndef CRUNCH
413: /* if we're given a new filename, use it as this file's name */
414: if (extra && *extra)
415: {
416: strcpy(origname, extra);
417: storename(origname);
418: setflag(file, NOTEDITED);
419: }
420: #endif
421: if (cmd == CMD_FILE)
422: {
423: #ifndef CRUNCH
424: msg("\"%s\" %s%s%s %ld lines, line %ld [%ld%%]",
425: #else
426: msg("\"%s\" %s%s %ld lines, line %ld [%ld%%]",
427: #endif
428: *origname ? origname : "[NO FILE]",
429: tstflag(file, MODIFIED) ? "[MODIFIED]" : "",
430: #ifndef CRUNCH
431: tstflag(file, NOTEDITED) ?"[NOT EDITED]":"",
432: #endif
433: tstflag(file, READONLY) ? "[READONLY]" : "",
434: nlines,
435: markline(frommark),
436: markline(frommark) * 100 / nlines);
437: }
438: #ifndef CRUNCH
439: else if (markline(frommark) != markline(tomark))
440: {
441: msg("range \"%ld,%ld\" contains %ld lines",
442: markline(frommark),
443: markline(tomark),
444: markline(tomark) - markline(frommark) + 1L);
445: }
446: #endif
447: else
448: {
449: msg("%ld", markline(frommark));
450: }
451: }
452:
453:
454: /*ARGSUSED*/
455: void cmd_edit(frommark, tomark, cmd, bang, extra)
456: MARK frommark, tomark;
457: CMD cmd;
458: int bang;
459: char *extra;
460: {
461: long line = 1L; /* might be set to prevline */
462: #ifndef CRUNCH
463: char *init = (char *)0;
464: #endif
465:
466:
467: /* if ":vi", then switch to visual mode, and if no file is named
468: * then don't switch files.
469: */
470: if (cmd == CMD_VISUAL)
471: {
472: mode = MODE_VI;
473: msg("");
474: if (!*extra)
475: {
476: return;
477: }
478: }
479:
480: /* Editing previous file? Then start at previous line */
481: if (!strcmp(extra, prevorig))
482: {
483: line = prevline;
484: }
485:
486: #ifndef CRUNCH
487: /* if we were given an explicit starting line, then start there */
488: if (*extra == '+')
489: {
490: for (init = ++extra; !isspace(*extra); extra++)
491: {
492: }
493: while (isspace(*extra))
494: {
495: *extra++ = '\0';
496: }
497: if (!*init)
498: {
499: init = "$";
500: }
501: if (!extra)
502: {
503: extra = origname;
504: }
505: }
506: #endif /* not CRUNCH */
507:
508: /* switch files */
509: if (tmpabort(bang))
510: {
511: tmpstart(extra);
512: if (line <= nlines && line >= 1L)
513: {
514: cursor = MARK_AT_LINE(line);
515: }
516: #ifndef CRUNCH
517: if (init)
518: {
519: doexcmd(init);
520: }
521: #endif
522: }
523: else
524: {
525: msg("Use edit! to abort changes, or w to save changes");
526:
527: /* so we can say ":e!#" next time... */
528: strcpy(prevorig, extra);
529: prevline = 1L;
530: }
531: }
532:
533: /* This code is also used for rewind -- GB */
534:
535: /*ARGSUSED*/
536: void cmd_next(frommark, tomark, cmd, bang, extra)
537: MARK frommark, tomark;
538: CMD cmd;
539: int bang;
540: char *extra;
541: {
542: int i, j;
543: char *scan;
544:
545: /* if extra stuff given, use ":args" to define a new args list */
546: if (cmd == CMD_NEXT && extra && *extra)
547: {
548: cmd_args(frommark, tomark, cmd, bang, extra);
549: }
550:
551: /* move to the next arg */
552: if (cmd == CMD_NEXT)
553: {
554: i = argno + 1;
555: }
556: else if (cmd == CMD_PREVIOUS)
557: {
558: i = argno - 1;
559: }
560: else /* cmd == CMD_REWIND */
561: {
562: i = 0;
563: }
564: if (i < 0 || i >= nargs)
565: {
566: msg("No %sfiles to edit", cmd == CMD_REWIND ? "" : "more ");
567: return;
568: }
569:
570: /* find & isolate the name of the file to edit */
571: for (j = i, scan = args; j > 0; j--)
572: {
573: while(*scan++)
574: {
575: }
576: }
577:
578: /* switch to the next file */
579: if (tmpabort(bang))
580: {
581: tmpstart(scan);
582: argno = i;
583: }
584: else
585: {
586: msg("Use :%s! to abort changes, or w to save changes",
587: cmd == CMD_NEXT ? "next" :
588: cmd == CMD_PREVIOUS ? "previous" :
589: "rewind");
590: }
591: }
592:
593: /* also called from :wq -- always writes back in this case */
594:
595: /*ARGSUSED*/
596: void cmd_xit(frommark, tomark, cmd, bang, extra)
597: MARK frommark, tomark;
598: CMD cmd;
599: int bang;
600: char *extra;
601: {
602: static long whenwarned; /* when the user was last warned of extra files */
603: int oldflag;
604:
605: /* if there are more files to edit, then warn user */
606: if (argno >= 0 && argno + 1 < nargs && whenwarned != changes && (!bang || cmd != CMD_QUIT))
607: {
608: msg("More files to edit -- Use \":n\" to go to next file");
609: whenwarned = changes;
610: return;
611: }
612:
613: if (cmd == CMD_QUIT)
614: {
615: oldflag = *o_autowrite;
616: *o_autowrite = FALSE;
617: if (tmpabort(bang))
618: {
619: mode = MODE_QUIT;
620: }
621: else
622: {
623: msg("Use q! to abort changes, or wq to save changes");
624: }
625: *o_autowrite = oldflag;
626: }
627: else
628: {
629: /* else try to save this file */
630: oldflag = tstflag(file, MODIFIED);
631: if (cmd == CMD_WQUIT)
632: setflag(file, MODIFIED);
633: if (tmpend(bang))
634: {
635: mode = MODE_QUIT;
636: }
637: else
638: {
639: msg("Could not save file -- use quit! to abort changes, or w filename");
640: }
641: if (!oldflag)
642: clrflag(file, MODIFIED);
643: }
644: }
645:
646:
647: /*ARGSUSED*/
648: void cmd_args(frommark, tomark, cmd, bang, extra)
649: MARK frommark, tomark;
650: CMD cmd;
651: int bang;
652: char *extra;
653: {
654: char *scan;
655: int col;
656: int arg;
657: int scrolled = FALSE;
658: int width;
659:
660: /* if no extra names given, or just current name, then report the args
661: * we have now.
662: */
663: if (!extra || !*extra)
664: {
665: /* empty args list? */
666: if (nargs == 1 && !*args)
667: {
668: return;
669: }
670:
671: /* list the arguments */
672: for (scan = args, col = arg = 0;
673: arg < nargs;
674: scan += width + 1, col += width, arg++)
675: {
676: width = strlen(scan);
677: if (col + width >= COLS - 4)
678: {
679: addch('\n');
680: col = 0;
681: scrolled = TRUE;
682: }
683: else if (col > 0)
684: {
685: addch(' ');
686: col++;
687: }
688: if (arg == argno)
689: {
690: addch('[');
691: addstr(scan);
692: addch(']');
693: col += 2;
694: }
695: else
696: {
697: addstr(scan);
698: }
699: }
700:
701: /* write a trailing newline */
702: if ((mode == MODE_EX || mode == MODE_COLON || scrolled) && col)
703: {
704: addch('\n');
705: }
706: exrefresh();
707: }
708: else /* new args list given */
709: {
710: for (scan = args, nargs = 1; *extra; )
711: {
712: if (isspace(*extra))
713: {
714: *scan++ = '\0';
715: while (isspace(*extra))
716: {
717: extra++;
718: }
719: if (*extra)
720: {
721: nargs++;
722: }
723: }
724: else
725: {
726: *scan++ = *extra++;
727: }
728: }
729: *scan = '\0';
730:
731: /* reset argno to before the first, so :next will go to first */
732: argno = -1;
733:
734: if (nargs != 1)
735: {
736: msg("%d files to edit", nargs);
737: }
738: }
739: }
740:
741:
742: /*ARGSUSED*/
743: void cmd_cd(frommark, tomark, cmd, bang, extra)
744: MARK frommark, tomark;
745: CMD cmd;
746: int bang;
747: char *extra;
748: {
749: char *getenv();
750:
751: #ifndef CRUNCH
752: /* if current file is modified, and no '!' was given, then error */
753: if (tstflag(file, MODIFIED) && !bang)
754: {
755: msg("File modified; use \"cd! %s\" to switch anyway", extra);
756: }
757: #endif
758:
759: /* default directory name is $HOME */
760: if (!*extra)
761: {
762: extra = getenv("HOME");
763: if (!extra)
764: {
765: msg("environment variable $HOME not set");
766: return;
767: }
768: }
769:
770: /* go to the directory */
771: if (chdir(extra) < 0)
772: {
773: perror(extra);
774: }
775: }
776:
777:
778: /*ARGSUSED*/
779: void cmd_map(frommark, tomark, cmd, bang, extra)
780: MARK frommark, tomark;
781: CMD cmd;
782: int bang;
783: char *extra;
784: {
785: char *mapto;
786: char *build, *scan;
787: #ifndef NO_FKEY
788: static char *fnames[NFKEYS] =
789: {
790: "#10", "#1", "#2", "#3", "#4",
791: "#5", "#6", "#7", "#8", "#9",
792: # ifndef NO_SHIFT_FKEY
793: "#10s", "#1s", "#2s", "#3s", "#4s",
794: "#5s", "#6s", "#7s", "#8s", "#9s",
795: # ifndef NO_CTRL_FKEY
796: "#10c", "#1c", "#2c", "#3c", "#4c",
797: "#5c", "#6c", "#7c", "#8c", "#9c",
798: # ifndef NO_ALT_FKEY
799: "#10a", "#1a", "#2a", "#3a", "#4a",
800: "#5a", "#6a", "#7a", "#8a", "#9a",
801: # endif
802: # endif
803: # endif
804: };
805: int key;
806: #endif
807:
808: /* "map" with no extra will dump the map table contents */
809: if (!*extra)
810: {
811: #ifndef NO_ABBR
812: if (cmd == CMD_ABBR)
813: {
814: dumpkey(bang ? WHEN_EX|WHEN_VIINP|WHEN_VIREP : WHEN_VIINP|WHEN_VIREP, TRUE);
815: }
816: else
817: #endif
818: {
819: dumpkey(bang ? WHEN_VIINP|WHEN_VIREP : WHEN_VICMD, FALSE);
820: }
821: }
822: else
823: {
824: /* "extra" is key to map, followed by what it maps to */
825:
826: /* handle quoting inside the "raw" string */
827: for (build = mapto = extra;
828: *mapto && (*mapto != ' ' && *mapto != '\t');
829: *build++ = *mapto++)
830: {
831: if (*mapto == ctrl('V') && mapto[1])
832: {
833: mapto++;
834: }
835: }
836:
837: /* skip whitespace, and mark the end of the "raw" string */
838: while ((*mapto == ' ' || *mapto == '\t'))
839: {
840: *mapto++ = '\0';
841: }
842: *build = '\0';
843:
844: /* strip ^Vs from the "cooked" string */
845: for (scan = build = mapto; *scan; *build++ = *scan++)
846: {
847: if (*scan == ctrl('V') && scan[1])
848: {
849: scan++;
850: }
851: }
852: *build = '\0';
853:
854: #ifndef NO_FKEY
855: /* if the mapped string is '#' and a number, then assume
856: * the user wanted that function key
857: */
858: if (extra[0] == '#' && isdigit(extra[1]))
859: {
860: key = atoi(extra + 1) % 10;
861: # ifndef NO_SHIFT_FKEY
862: build = extra + strlen(extra) - 1;
863: if (*build == 's')
864: key += 10;
865: # ifndef NO_CTRL_FKEY
866: else if (*build == 'c')
867: key += 20;
868: # ifndef NO_ALT_FKEY
869: else if (*build == 'a')
870: key += 30;
871: # endif
872: # endif
873: # endif
874: if (FKEY[key])
875: mapkey(FKEY[key], mapto, bang ? WHEN_VIINP|WHEN_VIREP : WHEN_VICMD, fnames[key]);
876: #if !COHERENT
877: else
878: msg("This terminal has no %s key", fnames[key]);
879: #endif
880: }
881: else
882: #endif
883: #ifndef NO_ABBR
884: if (cmd == CMD_ABBR || cmd == CMD_UNABBR)
885: {
886: mapkey(extra, mapto, bang ? WHEN_EX|WHEN_VIINP|WHEN_VIREP : WHEN_VIINP|WHEN_VIREP, "abbr");
887: }
888: else
889: #endif
890: {
891: mapkey(extra, mapto, bang ? WHEN_VIINP|WHEN_VIREP : WHEN_VICMD, (char *)0);
892: }
893: }
894: }
895:
896:
897: /*ARGSUSED*/
898: void cmd_set(frommark, tomark, cmd, bang, extra)
899: MARK frommark, tomark;
900: CMD cmd;
901: int bang;
902: char *extra;
903: {
904: if (!*extra)
905: {
906: dumpopts(FALSE);/* "FALSE" means "don't dump all" - only set */
907: }
908: else if (!strcmp(extra, "all"))
909: {
910: dumpopts(TRUE); /* "TRUE" means "dump all" - even unset vars */
911: }
912: else
913: {
914: setopts(extra);
915:
916: /* That option may have affected the appearence of text */
917: changes++;
918: }
919: }
920:
921: /*ARGSUSED*/
922: void cmd_tag(frommark, tomark, cmd, bang, extra)
923: MARK frommark, tomark;
924: CMD cmd;
925: int bang;
926: char *extra;
927: {
928: int fd; /* file descriptor used to read the file */
929: char *scan; /* used to scan through the tmpblk.c */
930: #ifdef INTERNAL_TAGS
931: char *cmp; /* char of tag name we're comparing, or NULL */
932: char *end; /* marks the end of chars in tmpblk.c */
933: #else
934: int i;
935: #endif
936: #ifndef NO_MAGIC
937: char wasmagic; /* preserves the original state of o_magic */
938: #endif
939: static char prevtag[30];
940:
941: /* if no tag is given, use the previous tag */
942: if (!extra || !*extra)
943: {
944: if (!*prevtag)
945: {
946: msg("No previous tag");
947: return;
948: }
949: extra = prevtag;
950: }
951: else
952: {
953: strncpy(prevtag, extra, sizeof prevtag);
954: prevtag[sizeof prevtag - 1] = '\0';
955: }
956:
957: #ifndef INTERNAL_TAGS
958: /* use "ref" to look up the tag info for this tag */
959: sprintf(tmpblk.c, "ref -t %s%s %s", (*origname ? "-f" : ""),origname, prevtag);
960: fd = rpipe(tmpblk.c, 0);
961: if (fd < 0)
962: {
963: msg("Can't run \"%s\"", tmpblk.c);
964: return;
965: }
966:
967: /* try to read the tag info */
968: for (scan = tmpblk.c;
969: (i = tread(fd, scan, scan - tmpblk.c + BLKSIZE)) > 0;
970: scan += i)
971: {
972: }
973: *scan = '\0';
974:
975: /* close the pipe. abort if error */
976: if (rpclose(fd) != 0 || scan < tmpblk.c + 3)
977: {
978: msg("tag \"%s\" not found", extra);
979: return;
980: }
981:
982: #else /* use internal code to look up the tag */
983: /* open the tags file */
984: fd = open(TAGS, O_RDONLY);
985: if (fd < 0)
986: {
987: msg("No tags file");
988: return;
989: }
990:
991: /* Hmmm... this would have been a lot easier with <stdio.h> */
992:
993: /* find the line with our tag in it */
994: for(scan = end = tmpblk.c, cmp = extra; ; scan++)
995: {
996: /* read a block, if necessary */
997: if (scan >= end)
998: {
999: end = tmpblk.c + tread(fd, tmpblk.c, BLKSIZE);
1000: scan = tmpblk.c;
1001: if (scan >= end)
1002: {
1003: msg("tag \"%s\" not found", extra);
1004: close(fd);
1005: return;
1006: }
1007: }
1008:
1009: /* if we're comparing, compare... */
1010: if (cmp)
1011: {
1012: /* matched??? wow! */
1013: if (!*cmp && *scan == '\t')
1014: {
1015: break;
1016: }
1017: if (*cmp++ != *scan)
1018: {
1019: /* failed! skip to newline */
1020: cmp = (char *)0;
1021: }
1022: }
1023:
1024: /* if we're skipping to newline, do it fast! */
1025: if (!cmp)
1026: {
1027: while (scan < end && *scan != '\n')
1028: {
1029: scan++;
1030: }
1031: if (scan < end)
1032: {
1033: cmp = extra;
1034: }
1035: }
1036: }
1037:
1038: /* found it! get the rest of the line into memory */
1039: for (cmp = tmpblk.c, scan++; scan < end && *scan != '\n'; )
1040: {
1041: *cmp++ = *scan++;
1042: }
1043: if (scan == end)
1044: {
1045: tread(fd, cmp, BLKSIZE - (int)(cmp - tmpblk.c));
1046: }
1047: else
1048: *cmp = *scan;
1049:
1050: /* we can close the tags file now */
1051: close(fd);
1052: #endif /* INTERNAL_TAGS */
1053:
1054: /* extract the filename from the line, and edit the file */
1055: for (scan = tmpblk.c; *scan != '\t'; scan++)
1056: {
1057: }
1058: *scan++ = '\0';
1059: if (strcmp(origname, tmpblk.c) != 0)
1060: {
1061: if (!tmpabort(bang))
1062: {
1063: msg("Use :tag! to abort changes, or :w to save changes");
1064: return;
1065: }
1066: tmpstart(tmpblk.c);
1067: }
1068:
1069: /* move to the desired line (or to line 1 if that fails) */
1070: #ifndef NO_MAGIC
1071: wasmagic = *o_magic;
1072: *o_magic = FALSE;
1073: #endif
1074: cursor = MARK_FIRST;
1075: linespec(scan, &cursor);
1076: if (cursor == MARK_UNSET)
1077: {
1078: cursor = MARK_FIRST;
1079: msg("Tag's address is out of date");
1080: }
1081: #ifndef NO_MAGIC
1082: *o_magic = wasmagic;
1083: #endif
1084: }
1085:
1086:
1087:
1088:
1089:
1090: /* describe this version of the program */
1091: /*ARGSUSED*/
1092: void cmd_version(frommark, tomark, cmd, bang, extra)
1093: MARK frommark;
1094: MARK tomark;
1095: CMD cmd;
1096: int bang;
1097: char *extra;
1098: {
1099: msg("%s", VERSION);
1100: #ifdef CREDIT
1101: msg("%s", CREDIT);
1102: #endif
1103: #ifdef CREDIT2
1104: msg("%s", CREDIT2);
1105: #endif
1106: #ifdef COMPILED_BY
1107: msg("Compiled by %s", COMPILED_BY);
1108: #endif
1109: #ifdef COPYING
1110: msg("%s", COPYING);
1111: #endif
1112: }
1113:
1114:
1115: #ifndef NO_MKEXRC
1116: /* make a .exrc file which describes the current configuration */
1117: /*ARGSUSED*/
1118: void cmd_mkexrc(frommark, tomark, cmd, bang, extra)
1119: MARK frommark;
1120: MARK tomark;
1121: CMD cmd;
1122: int bang;
1123: char *extra;
1124: {
1125: int fd;
1126:
1127: /* the default name for the .exrc file EXRC */
1128: if (!*extra)
1129: {
1130: extra = EXRC;
1131: }
1132:
1133: /* create the .exrc file */
1134: fd = creat(extra, FILEPERMS);
1135: if (fd < 0)
1136: {
1137: msg("Couldn't create a new \"%s\" file", extra);
1138: return;
1139: }
1140:
1141: /* save stuff */
1142: saveopts(fd);
1143: savemaps(fd, FALSE);
1144: #ifndef NO_ABBR
1145: savemaps(fd, TRUE);
1146: #endif
1147: #ifndef NO_DIGRAPH
1148: savedigs(fd);
1149: #endif
1150: #ifndef NO_COLOR
1151: savecolor(fd);
1152: #endif
1153:
1154: /* close the file */
1155: close(fd);
1156: msg("Configuration saved");
1157: }
1158: #endif
1159:
1160: #ifndef NO_DIGRAPH
1161: /*ARGSUSED*/
1162: void cmd_digraph(frommark, tomark, cmd, bang, extra)
1163: MARK frommark;
1164: MARK tomark;
1165: CMD cmd;
1166: int bang;
1167: char *extra;
1168: {
1169: do_digraph(bang, extra);
1170: }
1171: #endif
1172:
1173:
1174: #ifndef NO_ERRLIST
1175: static char errfile[256]; /* the name of a file containing an error */
1176: static long errline; /* the line number for an error */
1177: static int errfd = -2; /* fd of the errlist file */
1178:
1179: /* This static function tries to parse an error message.
1180: *
1181: * For most compilers, the first word is taken to be the name of the erroneous
1182: * file, and the first number after that is taken to be the line number where
1183: * the error was detected. The description of the error follows, possibly
1184: * preceded by an "error ... :" or "warning ... :" label which is skipped.
1185: *
1186: * For Coherent, error messages look like "line#: filename: message".
1187: *
1188: * For non-error lines, or unparsable error lines, this function returns NULL.
1189: * Normally, though, it alters errfile and errline, and returns a pointer to
1190: * the description.
1191: */
1192: static char *parse_errmsg(text)
1193: REG char *text;
1194: {
1195: REG char *cpy;
1196: long atol();
1197: # if COHERENT || TOS /* any Mark Williams compiler */
1198: /* Get the line number. If no line number, then ignore this line. */
1199: errline = atol(text);
1200: if (errline == 0L)
1201: return (char *)0;
1202:
1203: /* Skip to the start of the filename */
1204: while (*text && *text++ != ':')
1205: {
1206: }
1207: if (!*text++)
1208: return (char *)0;
1209:
1210: /* copy the filename to errfile */
1211: for (cpy = errfile; *text && (*cpy++ = *text++) != ':'; )
1212: {
1213: }
1214: if (!*text++)
1215: return (char *)0;
1216: cpy[-1] = '\0';
1217:
1218: return text;
1219: # else /* not a Mark Williams compiler */
1220: char *errmsg;
1221:
1222: /* the error message is the whole line, by default */
1223: errmsg = text;
1224:
1225: /* skip leading garbage */
1226: while (*text && !isalnum(*text))
1227: {
1228: text++;
1229: }
1230:
1231: /* copy over the filename */
1232: cpy = errfile;
1233: while(isalnum(*text) || *text == '.')
1234: {
1235: *cpy++ = *text++;
1236: }
1237: *cpy = '\0';
1238:
1239: /* ignore the name "Error" and filenames that contain a '/' */
1240: if (*text == '/' || !*errfile || !strcmp(errfile + 1, "rror") || access(errfile, 0) < 0)
1241: {
1242: return (char *)0;
1243: }
1244:
1245: /* skip garbage between filename and line number */
1246: while (*text && !isdigit(*text))
1247: {
1248: text++;
1249: }
1250:
1251: /* if the number is part of a larger word, then ignore this line */
1252: if (*text && isalpha(text[-1]))
1253: {
1254: return (char *)0;
1255: }
1256:
1257: /* get the error line */
1258: errline = 0L;
1259: while (isdigit(*text))
1260: {
1261: errline *= 10;
1262: errline += (*text - '0');
1263: text++;
1264: }
1265:
1266: /* any line which lacks a filename or line number should be ignored */
1267: if (!errfile[0] || !errline)
1268: {
1269: return (char *)0;
1270: }
1271:
1272: /* locate the beginning of the error description */
1273: while (*text && !isspace(*text))
1274: {
1275: text++;
1276: }
1277: while (*text)
1278: {
1279: # ifndef CRUNCH
1280: /* skip "error #:" and "warning #:" clauses */
1281: if (!strncmp(text + 1, "rror ", 5)
1282: || !strncmp(text + 1, "arning ", 7)
1283: || !strncmp(text + 1, "atal error", 10))
1284: {
1285: do
1286: {
1287: text++;
1288: } while (*text && *text != ':');
1289: continue;
1290: }
1291: # endif
1292:
1293: /* anything other than whitespace or a colon is important */
1294: if (!isspace(*text) && *text != ':')
1295: {
1296: errmsg = text;
1297: break;
1298: }
1299:
1300: /* else keep looking... */
1301: text++;
1302: }
1303:
1304: return errmsg;
1305: # endif /* not COHERENT */
1306: }
1307:
1308: /*ARGSUSED*/
1309: void cmd_errlist(frommark, tomark, cmd, bang, extra)
1310: MARK frommark, tomark;
1311: CMD cmd;
1312: int bang;
1313: char *extra;
1314: {
1315: static long endline;/* original number of lines in this file */
1316: static long offset; /* offset of the next line in the errlist file */
1317: int i;
1318: char *errmsg;
1319:
1320: /* if a new errlist file is named, open it */
1321: if (extra && extra[0])
1322: {
1323: /* close the old one */
1324: if (errfd >= 0)
1325: {
1326: close(errfd);
1327: }
1328:
1329: /* open the new one */
1330: errfd = open(extra, O_RDONLY);
1331: offset = 0L;
1332: endline = nlines;
1333: }
1334: else if (errfd < 0)
1335: {
1336: /* open the default file */
1337: errfd = open(ERRLIST, O_RDONLY);
1338: offset = 0L;
1339: endline = nlines;
1340: }
1341:
1342: /* do we have an errlist file now? */
1343: if (errfd < 0)
1344: {
1345: msg("There is no errlist file");
1346: beep();
1347: return;
1348: }
1349:
1350: /* find the next error message in the file */
1351: do
1352: {
1353: /* read the next line from the errlist */
1354: lseek(errfd, offset, 0);
1355: if (tread(errfd, tmpblk.c, (unsigned)BLKSIZE) <= 0)
1356: {
1357: msg("No more errors");
1358: beep();
1359: close(errfd);
1360: errfd = -2;
1361: return;
1362: }
1363: for (i = 0; tmpblk.c[i] != '\n'; i++)
1364: {
1365: }
1366: tmpblk.c[i++] = 0;
1367:
1368: /* look for an error message in the line */
1369: errmsg = parse_errmsg(tmpblk.c);
1370: if (!errmsg)
1371: {
1372: offset += i;
1373: }
1374:
1375: } while (!errmsg);
1376:
1377: /* switch to the file containing the error, if this isn't it */
1378: if (strcmp(origname, errfile))
1379: {
1380: if (!tmpabort(bang))
1381: {
1382: msg("Use :er! to abort changes, or :w to save changes");
1383: beep();
1384: return;
1385: }
1386: tmpstart(errfile);
1387: endline = nlines;
1388: }
1389: else if (endline == 0L)
1390: {
1391: endline = nlines;
1392: }
1393:
1394: /* go to the line where the error was detected */
1395: cursor = MARK_AT_LINE(errline + (nlines - endline));
1396: if (cursor > MARK_LAST)
1397: {
1398: cursor = MARK_LAST;
1399: }
1400: if (mode == MODE_VI)
1401: {
1402: redraw(cursor, FALSE);
1403: }
1404:
1405: /* display the error message */
1406: #ifdef CRUNCH
1407: msg("%.70s", errmsg);
1408: #else
1409: if (nlines > endline)
1410: {
1411: msg("line %ld(+%ld): %.60s", errline, nlines - endline, errmsg);
1412: }
1413: else if (nlines < endline)
1414: {
1415: msg("line %ld(-%ld): %.60s", errline, endline - nlines, errmsg);
1416: }
1417: else
1418: {
1419: msg("line %ld: %.65s", errline, errmsg);
1420: }
1421: #endif
1422:
1423: /* remember where the NEXT error line will start */
1424: offset += i;
1425: }
1426:
1427:
1428: /*ARGSUSED*/
1429: void cmd_make(frommark, tomark, cmd, bang, extra)
1430: MARK frommark, tomark;
1431: CMD cmd;
1432: int bang;
1433: char *extra;
1434: {
1435: BLK buf;
1436:
1437: /* if the file hasn't been saved, then complain unless ! */
1438: if (tstflag(file, MODIFIED) && !bang)
1439: {
1440: msg("\"%s\" not saved yet", origname);
1441: return;
1442: }
1443:
1444: /* build the command */
1445: sprintf(buf.c, "%s %s %s%s", (cmd == CMD_CC ? o_cc : o_make), extra, REDIRECT, ERRLIST);
1446: qaddstr(buf.c);
1447: addch('\n');
1448:
1449: /* close the old errlist file, if any */
1450: if (errfd >= 0)
1451: {
1452: close(errfd);
1453: errfd = -3;
1454: }
1455:
1456: /* run the command, with curses temporarily disabled */
1457: suspend_curses();
1458: system(buf.c);
1459: resume_curses(mode == MODE_EX);
1460: if (mode == MODE_COLON)
1461: mode = MODE_VI;
1462:
1463: /* run the "errlist" command */
1464: cmd_errlist(MARK_UNSET, MARK_UNSET, cmd, bang, ERRLIST);
1465: }
1466: #endif
1467:
1468:
1469:
1470: #ifndef NO_COLOR
1471:
1472: /* figure out the number of text colors we use with this configuration */
1473: # ifndef NO_POPUP
1474: # ifndef NO_VISIBLE
1475: # define NCOLORS 7
1476: # else
1477: # define NCOLORS 6
1478: # endif
1479: # else
1480: # ifndef NO_VISIBLE
1481: # define NCOLORS 6
1482: # else
1483: # define NCOLORS 5
1484: # endif
1485: # endif
1486:
1487: /* the attribute bytes used in each of "when"s */
1488: static char bytes[NCOLORS];
1489:
1490: static struct
1491: {
1492: char *word; /* a legal word */
1493: int type; /* what type of word this is */
1494: int val; /* some other value */
1495: }
1496: words[] =
1497: {
1498: {"normal", 1, A_NORMAL}, /* all "when" names must come */
1499: {"standout", 1, A_STANDOUT}, /* at the top of the list. */
1500: {"bold", 1, A_BOLD}, /* The first 3 must be normal,*/
1501: {"underlined", 1, A_UNDERLINE}, /* standout, and bold; the */
1502: {"italics", 1, A_ALTCHARSET}, /* remaining names follow. */
1503: #ifndef NO_POPUP
1504: {"popup", 1, A_POPUP},
1505: #endif
1506: #ifndef NO_VISIBLE
1507: {"visible", 1, A_VISIBLE},
1508: #endif
1509:
1510: {"black", 3, 0x00}, /* The color names start right*/
1511: {"blue", 3, 0x01}, /* after the "when" names. */
1512: {"green", 3, 0x02},
1513: {"cyan", 3, 0x03},
1514: {"red", 3, 0x04},
1515: {"magenta", 3, 0x05},
1516: {"brown", 3, 0x06},
1517: {"white", 3, 0x07},
1518: {"yellow", 3, 0x0E}, /* bright brown */
1519: {"gray", 3, 0x08}, /* bright black? of course! */
1520: {"grey", 3, 0x08},
1521:
1522: {"bright", 2, 0x08},
1523: {"light", 2, 0x08},
1524: {"blinking", 2, 0x80},
1525: {"on", 0, 0},
1526: {"n", 1, A_NORMAL},
1527: {"s", 1, A_STANDOUT},
1528: {"b", 1, A_BOLD},
1529: {"u", 1, A_UNDERLINE},
1530: {"i", 1, A_ALTCHARSET},
1531: #ifndef NO_POPUP
1532: {"p", 1, A_POPUP},
1533: {"menu", 1, A_POPUP},
1534: #endif
1535: #ifndef NO_VISIBLE
1536: {"v", 1, A_VISIBLE},
1537: #endif
1538: {(char *)0, 0, 0}
1539: };
1540:
1541: /*ARGSUSED*/
1542: void cmd_color(frommark, tomark, cmd, bang, extra)
1543: MARK frommark, tomark;
1544: CMD cmd;
1545: int bang;
1546: char *extra;
1547: {
1548: int attrbyte;
1549: int cmode;
1550: int nowbg; /* BOOLEAN: is the next color background? */
1551:
1552: REG char *scan;
1553: REG i;
1554:
1555:
1556: #ifndef CRUNCH
1557: /* if no args are given, then report the current colors */
1558: if (!*extra)
1559: {
1560: /* if no colors are set, then say so */
1561: if (!bytes[0])
1562: {
1563: msg("no colors have been set");
1564: return;
1565: }
1566:
1567: /* report all five color combinations */
1568: for (i = 0; i < NCOLORS; i++)
1569: {
1570: qaddstr("color ");
1571: qaddstr(words[i].word);
1572: qaddch(' ');
1573: if (bytes[i] & 0x80)
1574: qaddstr("blinking ");
1575: switch (bytes[i] & 0xf)
1576: {
1577: case 0x08: qaddstr("gray"); break;
1578: case 0x0e: qaddstr("yellow"); break;
1579: case 0x0f: qaddstr("bright white");break;
1580: default:
1581: if (bytes[i] & 0x08)
1582: qaddstr("light ");
1583: qaddstr(words[(bytes[i] & 0x07) + NCOLORS].word);
1584: }
1585: qaddstr(" on ");
1586: qaddstr(words[((bytes[i] >> 4) & 0x07) + NCOLORS].word);
1587: addch('\n');
1588: exrefresh();
1589: }
1590: return;
1591: }
1592: #endif
1593:
1594: /* The default background color is the same as "normal" chars.
1595: * There is no default foreground color.
1596: */
1597: cmode = A_NORMAL;
1598: attrbyte = bytes[0] & 0x70;
1599: nowbg = FALSE;
1600:
1601: /* parse each word in the "extra" text */
1602: for (scan = extra; *extra; extra = scan)
1603: {
1604: /* locate the end of the word */
1605: while (*scan && *scan != ' ')
1606: {
1607: scan++;
1608: }
1609:
1610: /* skip whitespace at the end of the word */
1611: while(*scan == ' ')
1612: {
1613: *scan++ = '\0';
1614: }
1615:
1616: /* lookup the word */
1617: for (i = 0; words[i].word && strcmp(words[i].word, extra); i++)
1618: {
1619: }
1620:
1621: /* if not a word, then complain */
1622: if (!words[i].word)
1623: {
1624: msg("Invalid color name: %s", extra);
1625: return;
1626: }
1627:
1628: /* process the word */
1629: switch (words[i].type)
1630: {
1631: case 1:
1632: cmode = words[i].val;
1633: break;
1634:
1635: case 2:
1636: attrbyte |= words[i].val;
1637: break;
1638:
1639: case 3:
1640: if (nowbg)
1641: attrbyte = ((attrbyte & ~0x70) | ((words[i].val & 0x07) << 4));
1642: else
1643: attrbyte |= words[i].val;
1644: nowbg = TRUE;
1645: break;
1646: }
1647: }
1648:
1649: /* if nowbg isn't set now, then we were never given a foreground color */
1650: if (!nowbg)
1651: {
1652: msg("usage: color [when] [\"bright\"] [\"blinking\"] foreground [background]");
1653: return;
1654: }
1655:
1656: /* the first ":color" command MUST define the "normal" colors */
1657: if (!bytes[0])
1658: cmode = A_NORMAL;
1659:
1660: /* we should now have a cmode and an attribute byte... */
1661:
1662: /* set the color */
1663: setcolor(cmode, attrbyte);
1664:
1665: /* remember what we just did */
1666: bytes[cmode] = attrbyte;
1667:
1668: /* if the other colors haven't been set yet, then set them to defaults */
1669: if (!bytes[1])
1670: {
1671: /* standout is the opposite of normal */
1672: bytes[1] = ((attrbyte << 4) & 0x70 | (attrbyte >> 4) & 0x07);
1673: setcolor(A_STANDOUT, bytes[1]);
1674:
1675: /* if "normal" isn't bright, then bold defaults to normal+bright
1676: * else bold defaults to bright white.
1677: */
1678: bytes[2] = attrbyte | ((attrbyte & 0x08) ? 0x0f : 0x08);
1679: setcolor(A_BOLD, bytes[2]);
1680:
1681: /* all others default to the "standout" colors, without blinking */
1682: for (i = 3; i < NCOLORS; i++)
1683: {
1684: bytes[i] = (bytes[1] & 0x7f);
1685: setcolor(words[i].val, bytes[i]);
1686: }
1687: }
1688:
1689: /* force a redraw, so we see the new colors */
1690: redraw(MARK_UNSET, FALSE);
1691: }
1692:
1693:
1694:
1695: void savecolor(fd)
1696: int fd; /* file descriptor to write colors to */
1697: {
1698: int i;
1699: char buf[80];
1700:
1701: /* if no colors are set, then return */
1702: if (!bytes[0])
1703: {
1704: return;
1705: }
1706:
1707: /* save all five color combinations */
1708: for (i = 0; i < NCOLORS; i++)
1709: {
1710: strcpy(buf, "color ");
1711: strcat(buf, words[i].word);
1712: strcat(buf, " ");
1713: if (bytes[i] & 0x80)
1714: strcat(buf, "blinking ");
1715: switch (bytes[i] & 0xf)
1716: {
1717: case 0x08: strcat(buf, "gray"); break;
1718: case 0x0e: strcat(buf, "yellow"); break;
1719: case 0x0f: strcat(buf, "bright white");break;
1720: default:
1721: if (bytes[i] & 0x08)
1722: strcat(buf, "light ");
1723: strcat(buf, words[(bytes[i] & 0x07) + NCOLORS].word);
1724: }
1725: strcat(buf, " on ");
1726: strcat(buf, words[((bytes[i] >> 4) & 0x07) + NCOLORS].word);
1727: strcat(buf, "\n");
1728: twrite(fd, buf, (unsigned)strlen(buf));
1729: }
1730: }
1731: #endif
1732:
1733: #ifdef SIGTSTP
1734: /* temporarily suspend elvis */
1735: /*ARGSUSED*/
1736: void cmd_suspend(frommark, tomark, cmd, bang, extra)
1737: MARK frommark;
1738: MARK tomark;
1739: CMD cmd;
1740: int bang;
1741: char *extra;
1742: {
1743: void (*func)(); /* stores the previous setting of SIGTSTP */
1744:
1745: #if ANY_UNIX
1746: /* the Bourne shell can't handle ^Z */
1747: if (!strcmp(o_shell, "/bin/sh"))
1748: {
1749: msg("The /bin/sh shell doesn't support ^Z");
1750: return;
1751: }
1752: #endif
1753:
1754: move(LINES - 1, 0);
1755: if (tstflag(file, MODIFIED))
1756: {
1757: addstr("Warning: \"");
1758: addstr(origname);
1759: addstr("\" modified but not yet saved");
1760: clrtoeol();
1761: }
1762: refresh();
1763: suspend_curses();
1764: func = signal(SIGTSTP, SIG_DFL);
1765: kill (0, SIGTSTP);
1766:
1767: /* the process stops and resumes here */
1768:
1769: signal(SIGTSTP, func);
1770: resume_curses(TRUE);
1771: if (mode == MODE_VI || mode == MODE_COLON)
1772: redraw(MARK_UNSET, FALSE);
1773: else
1774: refresh ();
1775: }
1776: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.