|
|
1.1 root 1: /* Copyright (c) 1979 Regents of the University of California */
2: #include "ex.h"
3: #include "ex_argv.h"
4: #include "ex_temp.h"
5: #include "ex_tty.h"
6:
7: #ifdef TRACE
8: char tttrace[] = { '/','d','e','v','/','t','t','y','x','x',0 };
9: #endif
10:
11: /*
12: * The code for ex is divided as follows:
13: *
14: * ex.c Entry point and routines handling interrupt, hangup
15: * signals; initialization code.
16: *
17: * ex_addr.c Address parsing routines for command mode decoding.
18: * Routines to set and check address ranges on commands.
19: *
20: * ex_cmds.c Command mode command decoding.
21: *
22: * ex_cmds2.c Subroutines for command decoding and processing of
23: * file names in the argument list. Routines to print
24: * messages and reset state when errors occur.
25: *
26: * ex_cmdsub.c Subroutines which implement command mode functions
27: * such as append, delete, join.
28: *
29: * ex_data.c Initialization of options.
30: *
31: * ex_get.c Command mode input routines.
32: *
33: * ex_io.c General input/output processing: file i/o, unix
34: * escapes, filtering, source commands, preserving
35: * and recovering.
36: *
37: * ex_put.c Terminal driving and optimizing routines for low-level
38: * output (cursor-positioning); output line formatting
39: * routines.
40: *
41: * ex_re.c Global commands, substitute, regular expression
42: * compilation and execution.
43: *
44: * ex_set.c The set command.
45: *
46: * ex_subr.c Loads of miscellaneous subroutines.
47: *
48: * ex_temp.c Editor buffer routines for main buffer and also
49: * for named buffers (Q registers if you will.)
50: *
51: * ex_tty.c Terminal dependent initializations from termcap
52: * data base, grabbing of tty modes (at beginning
53: * and after escapes).
54: *
55: * ex_v*.c Visual/open mode routines... see ex_v.c for a
56: * guide to the overall organization.
57: */
58:
59: /*
60: * Main procedure. Process arguments and then
61: * transfer control to the main command processing loop
62: * in the routine commands. We are entered as either "ex", "edit" or "vi"
63: * and the distinction is made here. Actually, we are "vi" if
64: * there is a 'v' in our name, and "edit" if there is a 'd' in our
65: * name. For edit we just diddle options; for vi we actually
66: * force an early visual command, setting the external initev so
67: * the q command in visual doesn't give command mode.
68: */
69: main(ac, av)
70: register int ac;
71: register char *av[];
72: {
73: #ifndef VMUNIX
74: char *erpath = EXSTRINGS;
75: #endif
76: register char *cp;
77: register int c;
78: bool recov = 0;
79: bool ivis;
80: bool itag = 0;
81: bool fast = 0;
82: #ifdef TRACE
83: register char *tracef;
84: #endif
85:
86: /*
87: * Immediately grab the tty modes so that we wont
88: * get messed up if an interrupt comes in quickly.
89: */
90: gTTY(1);
91: normf = tty.sg_flags;
92: ppid = getpid();
93: /*
94: * Defend against d's, v's, and a's in directories of
95: * path leading to our true name.
96: */
97: av[0] = tailpath(av[0]);
98: ivis = any('v', av[0]);
99:
100: /*
101: * For debugging take files out of . if name is a.out.
102: * If a 'd' in our name, then set options for edit.
103: */
104: #ifndef VMUNIX
105: if (av[0][0] == 'a')
106: erpath = tailpath(erpath);
107: #endif
108: if (ivis) {
109: #ifdef notdef
110: options[BEAUTIFY].odefault = value(BEAUTIFY) = 1;
111: #endif
112: } else if (any('d', av[0])) {
113: value(OPEN) = 0;
114: value(REPORT) = 1;
115: value(MAGIC) = 0;
116: }
117:
118: /*
119: * Open the error message file.
120: */
121: draino();
122: #ifndef VMUNIX
123: erfile = open(erpath+4, 0);
124: if (erfile < 0) {
125: erfile = open(erpath, 0);
126: }
127: #endif
128: pstop();
129:
130: /*
131: * Initialize interrupt handling.
132: */
133: oldhup = signal(SIGHUP, SIG_IGN);
134: if (oldhup == SIG_DFL)
135: signal(SIGHUP, onhup);
136: oldquit = signal(SIGQUIT, SIG_IGN);
137: ruptible = signal(SIGINT, SIG_IGN) == SIG_DFL;
138: if (signal(SIGTERM, SIG_IGN) == SIG_DFL)
139: signal(SIGTERM, onhup);
140:
141: /*
142: * Initialize end of core pointers.
143: * Normally we avoid breaking back to fendcore after each
144: * file since this can be expensive (much core-core copying).
145: * If your system can scatter load processes you could do
146: * this as ed does, saving a little core, but it will probably
147: * not often make much difference.
148: */
149: fendcore = (line *) sbrk(0);
150: endcore = fendcore - 2;
151:
152: /*
153: * Process flag arguments.
154: */
155: ac--, av++;
156: while (ac && av[0][0] == '-') {
157: c = av[0][1];
158: if (c == 0) {
159: hush = 1;
160: value(AUTOPRINT) = 0;
161: fast++;
162: } else switch (c) {
163:
164: #ifdef TRACE
165: case 'T':
166: if (av[0][2] == 0)
167: tracef = "trace";
168: else {
169: tracef = tttrace;
170: tracef[8] = av[0][2];
171: if (tracef[8])
172: tracef[9] = av[0][3];
173: else
174: tracef[9] = 0;
175: }
176: trace = fopen(tracef, "w");
177: if (trace == NULL)
178: printf("Trace create error\n");
179: setbuf(trace, tracbuf);
180: break;
181:
182: #endif
183:
184: #ifdef LISPCODE
185: case 'l':
186: value(LISP) = 1;
187: value(SHOWMATCH) = 1;
188: break;
189: #endif
190:
191: case 'r':
192: recov++;
193: break;
194:
195: case 't':
196: if (ac > 1 && av[1][0] != '-') {
197: ac--, av++;
198: itag = 1;
199: /* BUG: should check for too long tag. */
200: CP(lasttag, av[0]);
201: }
202: break;
203:
204: case 'v':
205: ivis = 1;
206: break;
207:
208: case 'w':
209: defwind = 0;
210: if (av[0][2] == 0) defwind = 3;
211: else for (cp = &av[0][2]; isdigit(*cp); cp++)
212: defwind = 10*defwind + *cp - '0';
213: break;
214:
215: default:
216: smerror("Unknown option %s\n", av[0]);
217: break;
218: }
219: ac--, av++;
220: }
221: if (ac && av[0][0] == '+') {
222: firstpat = &av[0][1];
223: ac--, av++;
224: }
225:
226: /*
227: * If we are doing a recover and no filename
228: * was given, then execute an exrecover command with
229: * the -r option to type out the list of saved file names.
230: * Otherwise set the remembered file name to the first argument
231: * file name so the "recover" initial command will find it.
232: */
233: if (recov) {
234: if (ac == 0) {
235: ppid = 0;
236: setrupt();
237: execl(EXRECOVER, "exrecover", "-r", 0);
238: filioerr(EXRECOVER);
239: exit(1);
240: }
241: CP(savedfile, *av++), ac--;
242: }
243:
244: /*
245: * Initialize the argument list.
246: */
247: argv0 = av;
248: argc0 = ac;
249: args0 = av[0];
250: erewind();
251:
252: /*
253: * Initialize a temporary file (buffer) and
254: * set up terminal environment. Read user startup commands.
255: */
256: init();
257: if (setexit() == 0) {
258: setrupt();
259: intty = isatty(0);
260: value(PROMPT) = intty;
261: if (fast || !intty)
262: setterm("dumb");
263: else {
264: gettmode();
265: if ((cp = getenv("TERM")) != 0)
266: setterm(cp);
267: }
268: }
269: if (setexit() == 0 && !fast && intty)
270: if (globp = getenv("EXINIT"))
271: commands(1,1);
272: else if ((cp = getenv("HOME")) != 0)
273: source(strcat(strcpy(genbuf, cp), "/.exrc"), 1);
274:
275: /*
276: * Initial processing. Handle tag, recover, and file argument
277: * implied next commands. If going in as 'vi', then don't do
278: * anything, just set initev so we will do it later (from within
279: * visual).
280: */
281: if (setexit() == 0) {
282: if (recov)
283: globp = "recover";
284: else if (itag)
285: globp = ivis ? "tag" : "tag|p";
286: else if (argc)
287: globp = "next";
288: if (ivis)
289: initev = globp;
290: else if (globp) {
291: inglobal = 1;
292: commands(1, 1);
293: inglobal = 0;
294: }
295: }
296:
297: /*
298: * Vi command... go into visual.
299: * Strange... everything in vi usually happens
300: * before we ever "start".
301: */
302: if (ivis) {
303: /*
304: * Don't have to be upward compatible with stupidity
305: * of starting editing at line $.
306: */
307: if (dol > zero)
308: dot = one;
309: globp = "visual";
310: if (setexit() == 0)
311: commands(1, 1);
312: }
313:
314: /*
315: * Clear out trash in state accumulated by startup,
316: * and then do the main command loop for a normal edit.
317: * If you quit out of a 'vi' command by doing Q or ^\,
318: * you also fall through to here.
319: */
320: ungetchar(0);
321: globp = 0;
322: initev = 0;
323: setlastchar('\n');
324: setexit();
325: commands(0, 0);
326: cleanup(1);
327: exit(0);
328: }
329:
330: /*
331: * Initialization, before editing a new file.
332: * Main thing here is to get a new buffer (in fileinit),
333: * rest is peripheral state resetting.
334: */
335: init()
336: {
337: register int i;
338:
339: fileinit();
340: dot = zero = truedol = unddol = dol = fendcore;
341: one = zero+1;
342: undkind = UNDNONE;
343: chng = 0;
344: edited = 0;
345: for (i = 0; i <= 'z'-'a'+1; i++)
346: names[i] = 1;
347: anymarks = 0;
348: }
349:
350: /*
351: * When a hangup occurs our actions are similar to a preserve
352: * command. If the buffer has not been [Modified], then we do
353: * nothing but remove the temporary files and exit.
354: * Otherwise, we sync the temp file and then attempt a preserve.
355: * If the preserve succeeds, we unlink our temp files.
356: * If the preserve fails, we leave the temp files as they are
357: * as they are a backup even without preservation if they
358: * are not removed.
359: */
360: onhup()
361: {
362:
363: if (chng == 0) {
364: cleanup(1);
365: exit(0);
366: }
367: if (setexit() == 0) {
368: if (preserve()) {
369: cleanup(1);
370: exit(0);
371: }
372: }
373: exit(1);
374: }
375:
376: /*
377: * An interrupt occurred. Drain any output which
378: * is still in the output buffering pipeline.
379: * Catch interrupts again. Unless we are in visual
380: * reset the output state (out of -nl mode, e.g).
381: * Then like a normal error (with the \n before Interrupt
382: * suppressed in visual mode).
383: */
384: onintr()
385: {
386:
387: #ifndef CBREAK
388: signal(SIGINT, onintr);
389: #else
390: signal(SIGINT, inopen ? vintr : onintr);
391: #endif
392: draino();
393: if (!inopen) {
394: pstop();
395: setlastchar('\n');
396: #ifdef CBREAK
397: }
398: #else
399: } else
400: vraw();
401: #endif
402: error("\nInterrupt" + inopen);
403: }
404:
405: /*
406: * If we are interruptible, enable interrupts again.
407: * In some critical sections we turn interrupts off,
408: * but not very often.
409: */
410: setrupt()
411: {
412:
413: if (ruptible)
414: #ifndef CBREAK
415: signal(SIGINT, onintr);
416: #else
417: signal(SIGINT, inopen ? vintr : onintr);
418: #endif
419: }
420:
421: preserve()
422: {
423:
424: synctmp();
425: pid = fork();
426: if (pid < 0)
427: return (0);
428: if (pid == 0) {
429: close(0);
430: dup(tfile);
431: execl(EXPRESERVE, "expreserve", (char *) 0);
432: exit(1);
433: }
434: waitfor();
435: if (rpid == pid && status == 0)
436: return (1);
437: return (0);
438: }
439:
440: #ifndef V6
441: exit(i)
442: int i;
443: {
444:
445: _exit(i);
446: }
447: #endif
448:
449: /*
450: * Return last component of unix path name p.
451: */
452: char *
453: tailpath(p)
454: register char *p;
455: {
456: register char *r;
457:
458: for (r=p; *p; p++)
459: if (*p == '/')
460: r = p+1;
461: return(r);
462: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.