Subversion Repositories planix.SVN

Rev

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