Subversion Repositories planix.SVN

Rev

Rev 115 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

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