Subversion Repositories planix.SVN

Rev

Rev 106 | Rev 113 | 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
static char *sccsid = "@(#)ex_io.c	7.11.1.1 (Berkeley) 8/12/86";
9
#endif
10
 
11
#include "ex.h"
12
#include "ex_argv.h"
13
#include "ex_temp.h"
14
#include "ex_tty.h"
15
#include "ex_vis.h"
109 7u83 16
void
17
checkmodeline(char * li_ne);
18
void
19
putfile(int isfilter);
105 7u83 20
 
21
/*
22
 * File input/output, source, preserve and recover
23
 */
24
 
25
/*
26
 * Following remember where . was in the previous file for return
27
 * on file switching.
28
 */
29
int	altdot;
30
int	oldadot;
31
bool	wasalt;
32
short	isalt;
33
 
34
long	cntch;			/* Count of characters on unit io */
35
#ifndef VMUNIX
36
short	cntln;			/* Count of lines " */
37
#else
38
int	cntln;
39
#endif
40
long	cntnull;		/* Count of nulls " */
41
long	cntodd;			/* Count of non-ascii characters " */
42
 
43
/*
44
 * Parse file name for command encoded by comm.
45
 * If comm is E then command is doomed and we are
46
 * parsing just so user won't have to retype the name.
47
 */
109 7u83 48
void
105 7u83 49
filename(comm)
50
	int comm;
51
{
52
	register int c = comm, d;
53
	register int i;
54
 
55
	d = getchar();
56
	if (endcmd(d)) {
57
		if (savedfile[0] == 0 && comm != 'f')
58
			error("No file|No current filename");
59
		CP(file, savedfile);
60
		wasalt = (isalt > 0) ? isalt-1 : 0;
61
		isalt = 0;
62
		oldadot = altdot;
63
		if (c == 'e' || c == 'E')
64
			altdot = lineDOT();
65
		if (d == EOF)
66
			ungetchar(d);
67
	} else {
68
		ungetchar(d);
69
		getone();
70
		eol();
71
		if (savedfile[0] == 0 && c != 'E' && c != 'e') {
72
			c = 'e';
73
			edited = 0;
74
		}
75
		wasalt = strcmp(file, altfile) == 0;
76
		oldadot = altdot;
77
		switch (c) {
78
 
79
		case 'f':
80
			edited = 0;
81
			/* fall into ... */
82
 
83
		case 'e':
84
			if (savedfile[0]) {
85
				altdot = lineDOT();
86
				CP(altfile, savedfile);
87
			}
88
			CP(savedfile, file);
89
			break;
90
 
91
		default:
92
			if (file[0]) {
93
				if (c != 'E')
94
					altdot = lineDOT();
95
				CP(altfile, file);
96
			}
97
			break;
98
		}
99
	}
100
	if (hush && comm != 'f' || comm == 'E')
101
		return;
102
	if (file[0] != 0) {
103
		lprintf("\"%s\"", file);
104
		if (comm == 'f') {
105
			if (value(READONLY))
106
				printf(" [Read only]");
107
			if (!edited)
108
				printf(" [Not edited]");
109
			if (tchng)
110
				printf(" [Modified]");
111
		}
112
		flush();
113
	} else
114
		printf("No file ");
115
	if (comm == 'f') {
116
		if (!(i = lineDOL()))
117
			i++;
118
		printf(" line %d of %d --%ld%%--", lineDOT(), lineDOL(),
119
		    (long) 100 * lineDOT() / i);
120
	}
121
}
122
 
123
/*
124
 * Get the argument words for a command into genbuf
125
 * expanding # and %.
126
 */
127
getargs()
128
{
129
	register int c;
130
	register char *cp, *fp;
131
	static char fpatbuf[32];	/* hence limit on :next +/pat */
132
 
133
	pastwh();
134
	if (peekchar() == '+') {
135
		for (cp = fpatbuf;;) {
136
			c = *cp++ = getchar();
137
			if (cp >= &fpatbuf[sizeof(fpatbuf)])
138
				error("Pattern too long");
139
			if (c == '\\' && isspace(peekchar()))
140
				c = getchar();
141
			if (c == EOF || isspace(c)) {
142
				ungetchar(c);
143
				*--cp = 0;
144
				firstpat = &fpatbuf[1];
145
				break;
146
			}
147
		}
148
	}
149
	if (skipend())
150
		return (0);
151
	CP(genbuf, "echo "); cp = &genbuf[5];
152
	for (;;) {
153
		c = getchar();
154
		if (endcmd(c)) {
155
			ungetchar(c);
156
			break;
157
		}
158
		switch (c) {
159
 
160
		case '\\':
161
			if (any(peekchar(), "#%|"))
162
				c = getchar();
163
			/* fall into... */
164
 
165
		default:
166
			if (cp > &genbuf[LBSIZE - 2])
167
flong:
168
				error("Argument buffer overflow");
169
			*cp++ = c;
170
			break;
171
 
172
		case '#':
173
			fp = altfile;
174
			if (*fp == 0)
175
				error("No alternate filename@to substitute for #");
176
			goto filexp;
177
 
178
		case '%':
179
			fp = savedfile;
180
			if (*fp == 0)
181
				error("No current filename@to substitute for %%");
182
filexp:
183
			while (*fp) {
184
				if (cp > &genbuf[LBSIZE - 2])
185
					goto flong;
186
				*cp++ = *fp++;
187
			}
188
			break;
189
		}
190
	}
191
	*cp = 0;
192
	return (1);
193
}
194
 
195
/*
196
 * Glob the argument words in genbuf, or if no globbing
197
 * is implied, just split them up directly.
198
 */
109 7u83 199
void
105 7u83 200
glob(gp)
201
	struct glob *gp;
202
{
203
	int pvec[2];
204
	register char **argv = gp->argv;
205
	register char *cp = gp->argspac;
206
	register int c;
207
	char ch;
208
	int nleft = NCARGS;
209
 
210
	gp->argc0 = 0;
211
	if (gscan() == 0) {
212
		register char *v = genbuf + 5;		/* strlen("echo ") */
213
 
214
		for (;;) {
215
			while (isspace(*v))
216
				v++;
217
			if (!*v)
218
				break;
219
			*argv++ = cp;
220
			while (*v && !isspace(*v))
221
				*cp++ = *v++;
222
			*cp++ = 0;
223
			gp->argc0++;
224
		}
225
		*argv = 0;
226
		return;
227
	}
228
	if (pipe(pvec) < 0)
229
		error("Can't make pipe to glob");
230
	pid = fork();
231
	io = pvec[0];
232
	if (pid < 0) {
233
		close(pvec[1]);
234
		error("Can't fork to do glob");
235
	}
236
	if (pid == 0) {
237
		int oerrno;
238
 
239
		close(1);
240
		dup(pvec[1]);
241
		close(pvec[0]);
242
		close(2);	/* so errors don't mess up the screen */
243
		open("/dev/null", 1);
244
		execl(svalue(SHELL), "sh", "-c", genbuf, 0);
245
		oerrno = errno; close(1); dup(2); errno = oerrno;
246
		filioerr(svalue(SHELL));
247
	}
248
	close(pvec[1]);
249
	do {
250
		*argv = cp;
251
		for (;;) {
252
			if (read(io, &ch, 1) != 1) {
253
				close(io);
254
				c = -1;
255
			} else
256
#ifndef	ISO
257
				c = ch & TRIM;
258
#else
259
			{
260
				if (niso(ch))
261
					c = ch & TRIM;
262
				else
263
					c = ch;
264
			}
265
#endif
266
			if (c <= 0 || isspace(c))
267
				break;
268
			*cp++ = c;
269
			if (--nleft <= 0)
270
				error("Arg list too long");
271
		}
272
		if (cp != *argv) {
273
			--nleft;
274
			*cp++ = 0;
275
			gp->argc0++;
276
			if (gp->argc0 >= NARGS)
277
				error("Arg list too long");
278
			argv++;
279
		}
280
	} while (c >= 0);
281
	waitfor();
282
	if (gp->argc0 == 0)
283
		error("No match");
284
}
285
 
286
/*
287
 * Scan genbuf for shell metacharacters.
288
 * Set is union of v7 shell and csh metas.
289
 */
290
gscan()
291
{
292
	register char *cp;
293
 
294
	for (cp = genbuf; *cp; cp++)
295
		if (any(*cp, "~{[*?$`'\"\\"))
296
			return (1);
297
	return (0);
298
}
299
 
300
/*
301
 * Parse one filename into file.
302
 */
303
struct glob G;
304
getone()
305
{
306
	register char *str;
307
 
308
	if (getargs() == 0)
309
		error("Missing filename");
310
	glob(&G);
311
	if (G.argc0 > 1)
312
		error("Ambiguous|Too many file names");
313
	str = G.argv[G.argc0 - 1];
314
	if (strlen(str) > FNSIZE - 4)
315
		error("Filename too long");
316
samef:
317
	CP(file, str);
318
}
319
 
320
/*
321
 * Read a file from the world.
322
 * C is command, 'e' if this really an edit (or a recover).
323
 */
109 7u83 324
void
105 7u83 325
rop(c)
326
	int c;
327
{
328
	register int i;
329
	struct stat stbuf;
330
	short magic;
331
	static int ovro;	/* old value(READONLY) */
332
	static int denied;	/* 1 if READONLY was set due to file permissions */
333
 
334
	io = open(file, 0);
335
	if (io < 0) {
336
		if (c == 'e' && errno == ENOENT) {
337
			edited++;
338
			/*
339
			 * If the user just did "ex foo" he is probably
340
			 * creating a new file.  Don't be an error, since
341
			 * this is ugly, and it screws up the + option.
342
			 */
343
			if (!seenprompt) {
344
				printf(" [New file]");
345
				noonl();
346
				return;
347
			}
348
		}
349
		syserror();
350
	}
351
	if (fstat(io, &stbuf))
352
		syserror();
353
	switch (stbuf.st_mode & S_IFMT) {
354
 
355
	case S_IFBLK:
356
		error(" Block special file");
357
 
358
	case S_IFCHR:
359
		if (isatty(io))
360
			error(" Teletype");
361
		if (samei(&stbuf, "/dev/null"))
362
			break;
363
		error(" Character special file");
364
 
365
	case S_IFDIR:
366
		error(" Directory");
367
 
368
	case S_IFREG:
369
		i = read(io, (char *) &magic, sizeof(magic));
370
		lseek(io, 0l, 0);
371
		if (i != sizeof(magic))
372
			break;
373
#if !defined (BIT8) && !defined(ISO)
374
		switch (magic) {
375
 
376
		case 0405:	/* data overlay on exec */
377
		case 0407:	/* unshared */
378
		case 0410:	/* shared text */
379
		case 0411:	/* separate I/D */
380
		case 0413:	/* VM/Unix demand paged */
381
		case 0430:	/* PDP-11 Overlay shared */
382
		case 0431:	/* PDP-11 Overlay sep I/D */
383
			error(" Executable");
384
 
385
		/*
386
		 * We do not forbid the editing of portable archives
387
		 * because it is reasonable to edit them, especially
388
		 * if they are archives of text files.  This is
389
		 * especially useful if you archive source files together
390
		 * and copy them to another system with ~%take, since
391
		 * the files sometimes show up munged and must be fixed.
392
		 */
393
		case 0177545:
394
		case 0177555:
395
			error(" Archive");
396
 
397
		default:
398
#ifdef mbb
399
			/* C/70 has a 10 bit byte */
400
			if (magic & 03401600)
401
#else
402
			/* Everybody else has an 8 bit byte */
403
			if (magic & 0100200)
404
#endif
405
				error(" Non-ascii file");
406
			break;
407
		}
408
#endif /* !BIT8 */
409
	}
410
	if (c != 'r') {
411
		if (value(READONLY) && denied) {
412
			value(READONLY) = ovro;
413
			denied = 0;
414
		}
415
		if ((stbuf.st_mode & 0222) == 0 || access(file, 2) < 0) {
416
			ovro = value(READONLY);
417
			denied = 1;
418
			value(READONLY) = 1;
419
		}
420
	}
421
	if (value(READONLY)) {
422
		printf(" [Read only]");
423
		flush();
424
	}
425
	if (c == 'r')
426
		setdot();
427
	else
428
		setall();
429
	if (FIXUNDO && inopen && c == 'r')
430
		undap1 = undap2 = dot + 1;
431
	rop2();
432
	rop3(c);
433
}
434
 
435
rop2()
436
{
437
	line *first, *last, *a;
438
	struct stat statb;
439
 
440
	deletenone();
441
	clrstats();
442
	first = addr2 + 1;
106 7u83 443
 
444
/*	if (fstat(io, &statb) < 0)
105 7u83 445
		bsize = LBSIZE;
446
	else {
447
		bsize = statb.st_blksize;
448
		if (bsize <= 0)
449
			bsize = LBSIZE;
450
	}
106 7u83 451
*/
452
	bsize=LBSIZE;	
453
 
105 7u83 454
	ignore(append(getfile, addr2));
455
	last = dot;
456
	/*
457
	 *	if the modeline variable is set,
458
	 *	check the first and last five lines of the file
459
	 *	for a mode line.
460
	 */
461
	if (value(MODELINE)) {
462
		for (a=first; a<=last; a++) {
463
			if (a==first+5 && last-first > 10)
464
				a = last - 4;
465
			getline(*a);
466
			checkmodeline(linebuf);
467
		}
468
	}
469
}
470
 
471
rop3(c)
472
	int c;
473
{
474
 
475
	if (iostats() == 0 && c == 'e')
476
		edited++;
477
	if (c == 'e') {
478
		if (wasalt || firstpat) {
479
			register line *addr = zero + oldadot;
480
 
481
			if (addr > dol)
482
				addr = dol;
483
			if (firstpat) {
484
				globp = (*firstpat) ? firstpat : "$";
485
				commands(1,1);
486
				firstpat = 0;
487
			} else if (addr >= one) {
488
				if (inopen)
489
					dot = addr;
490
				markpr(addr);
491
			} else
492
				goto other;
493
		} else
494
other:
495
			if (dol > zero) {
496
				if (inopen)
497
					dot = one;
498
				markpr(one);
499
			}
500
		if(FIXUNDO)
501
			undkind = UNDNONE;
502
		if (inopen) {
503
			vcline = 0;
504
			vreplace(0, LINES, lineDOL());
505
		}
506
	}
507
}
508
 
509
/*
510
 * Are these two really the same inode?
511
 */
512
samei(sp, cp)
513
	struct stat *sp;
514
	char *cp;
515
{
516
	struct stat stb;
517
 
518
	if (stat(cp, &stb) < 0 || sp->st_dev != stb.st_dev)
519
		return (0);
520
	return (sp->st_ino == stb.st_ino);
521
}
522
 
523
/* Returns from edited() */
524
#define	EDF	0		/* Edited file */
525
#define	NOTEDF	-1		/* Not edited file */
526
#define	PARTBUF	1		/* Write of partial buffer to Edited file */
527
 
528
/*
529
 * Write a file.
530
 */
531
wop(dofname)
532
bool dofname;	/* if 1 call filename, else use savedfile */
533
{
534
	register int c, exclam, nonexist;
535
	line *saddr1, *saddr2;
536
	struct stat stbuf;
537
 
538
	c = 0;
539
	exclam = 0;
540
	if (dofname) {
541
		if (peekchar() == '!')
542
			exclam++, ignchar();
543
		ignore(skipwh());
544
		while (peekchar() == '>')
545
			ignchar(), c++, ignore(skipwh());
546
		if (c != 0 && c != 2)
547
			error("Write forms are 'w' and 'w>>'");
548
		filename('w');
549
	} else {
550
		if (savedfile[0] == 0)
551
			error("No file|No current filename");
552
		saddr1=addr1;
553
		saddr2=addr2;
554
		addr1=one;
555
		addr2=dol;
556
		CP(file, savedfile);
557
		if (inopen) {
558
			vclrech(0);
559
			splitw++;
560
		}
561
		lprintf("\"%s\"", file);
562
	}
563
	nonexist = stat(file, &stbuf);
564
	switch (c) {
565
 
566
	case 0:
567
		if (!exclam && (!value(WRITEANY) || value(READONLY)))
568
		switch (edfile()) {
569
 
570
		case NOTEDF:
571
			if (nonexist)
572
				break;
573
			if ((stbuf.st_mode & S_IFMT) == S_IFCHR) {
574
				if (samei(&stbuf, "/dev/null"))
575
					break;
576
				if (samei(&stbuf, "/dev/tty"))
577
					break;
578
			}
579
			io = open(file, 1);
580
			if (io < 0)
581
				syserror();
582
			if (!isatty(io))
583
				serror(" File exists| File exists - use \"w! %s\" to overwrite", file);
584
			close(io);
585
			break;
586
 
587
		case EDF:
588
			if (value(READONLY))
589
				error(" File is read only");
590
			break;
591
 
592
		case PARTBUF:
593
			if (value(READONLY))
594
				error(" File is read only");
595
			error(" Use \"w!\" to write partial buffer");
596
		}
597
cre:
598
/*
599
		synctmp();
600
*/
601
#ifdef V6
602
		io = creat(file, 0644);
603
#else
604
		io = creat(file, 0666);
605
#endif
606
		if (io < 0)
607
			syserror();
608
		writing = 1;
609
		if (hush == 0)
610
			if (nonexist)
611
				printf(" [New file]");
612
			else if (value(WRITEANY) && edfile() != EDF)
613
				printf(" [Existing file]");
614
		break;
615
 
616
	case 2:
617
		io = open(file, 1);
618
		if (io < 0) {
619
			if (exclam || value(WRITEANY))
620
				goto cre;
621
			syserror();
622
		}
623
		lseek(io, 0l, 2);
624
		break;
625
	}
626
	putfile(0);
627
	ignore(iostats());
628
	if (c != 2 && addr1 == one && addr2 == dol) {
629
		if (eq(file, savedfile))
630
			edited = 1;
631
		sync();
632
	}
633
	if (!dofname) {
634
		addr1 = saddr1;
635
		addr2 = saddr2;
636
	}
637
	writing = 0;
638
}
639
 
640
/*
641
 * Is file the edited file?
642
 * Work here is that it is not considered edited
643
 * if this is a partial buffer, and distinguish
644
 * all cases.
645
 */
646
edfile()
647
{
648
 
649
	if (!edited || !eq(file, savedfile))
650
		return (NOTEDF);
651
	return (addr1 == one && addr2 == dol ? EDF : PARTBUF);
652
}
653
 
654
/*
655
 * Extract the next line from the io stream.
656
 */
657
char *nextip;
658
 
659
getfile()
660
{
661
	register short c;
662
	register char *lp, *fp;
663
 
664
	lp = linebuf;
665
	fp = nextip;
666
	do {
667
		if (--ninbuf < 0) {
668
			ninbuf = read(io, genbuf, bsize) - 1;
669
			if (ninbuf < 0) {
670
				if (lp != linebuf) {
671
					lp++;
672
					printf(" [Incomplete last line]");
673
					break;
674
				}
675
				return (EOF);
676
			}
677
			fp = genbuf;
678
			cntch += ninbuf+1;
679
		}
680
		if (lp >= &linebuf[LBSIZE]) {
681
			error(" Line too long");
682
		}
683
		c = *fp++;
684
		if (c == 0) {
685
			cntnull++;
686
			continue;
687
		}
688
#ifndef	BIT8
689
#ifndef	ISO
690
		if (c & QUOTE) {
691
#else
692
		if (niso(c)) {
693
#endif
694
			cntodd++;
695
			c &= TRIM;
696
			if (c == 0)
697
				continue;
698
		}
699
#endif
700
		*lp++ = c;
701
	} while (c != '\n');
702
	*--lp = 0;
703
	nextip = fp;
704
	cntln++;
705
	return (0);
706
}
707
 
708
/*
709
 * Write a range onto the io stream.
710
 */
109 7u83 711
void
105 7u83 712
putfile(isfilter)
713
int isfilter;
714
{
715
	line *a1;
716
	register char *fp, *lp;
717
	register int nib;
718
	struct stat statb;
719
 
720
	a1 = addr1;
721
	clrstats();
722
	cntln = addr2 - a1 + 1;
723
	if (cntln == 0)
724
		return;
106 7u83 725
 
726
	bsize = LBSIZE;
727
 
728
/*	if (fstat(io, &statb) < 0)
105 7u83 729
		bsize = LBSIZE;
730
	else {
731
		bsize = statb.st_blksize;
732
		if (bsize <= 0)
733
			bsize = LBSIZE;
734
	}
106 7u83 735
	*/
736
 
105 7u83 737
	nib = bsize;
738
	fp = genbuf;
739
	do {
740
		getline(*a1++);
741
		lp = linebuf;
742
		for (;;) {
743
			if (--nib < 0) {
744
				nib = fp - genbuf;
745
				if (write(io, genbuf, nib) != nib) {
746
					wrerror();
747
				}
748
				cntch += nib;
749
				nib = bsize - 1;
750
				fp = genbuf;
751
			}
752
			if ((*fp++ = *lp++) == 0) {
753
				fp[-1] = '\n';
754
				break;
755
			}
756
		}
757
	} while (a1 <= addr2);
758
	nib = fp - genbuf;
759
	if (write(io, genbuf, nib) != nib) {
760
		wrerror();
761
	}
762
	cntch += nib;
763
}
764
 
765
/*
766
 * A write error has occurred;  if the file being written was
767
 * the edited file then we consider it to have changed since it is
768
 * now likely scrambled.
769
 */
770
wrerror()
771
{
772
 
773
	if (eq(file, savedfile) && edited)
774
		change();
775
	syserror();
776
}
777
 
778
/*
779
 * Source command, handles nested sources.
780
 * Traps errors since it mungs unit 0 during the source.
781
 */
782
short slevel;
783
short ttyindes;
784
 
109 7u83 785
void
105 7u83 786
source(fil, okfail)
787
	char *fil;
788
	bool okfail;
789
{
790
	jmp_buf osetexit;
791
	register int saveinp, ointty, oerrno;
792
	char *saveglobp;
793
	short savepeekc;
794
 
795
	signal(SIGINT, SIG_IGN);
796
	saveinp = dup(0);
797
	savepeekc = peekc;
798
	saveglobp = globp;
799
	peekc = 0; globp = 0;
800
	if (saveinp < 0)
801
		error("Too many nested sources");
802
	if (slevel <= 0)
803
		ttyindes = saveinp;
804
	close(0);
805
	if (open(fil, 0) < 0) {
806
		oerrno = errno;
807
		setrupt();
808
		dup(saveinp);
809
		close(saveinp);
810
		errno = oerrno;
811
		if (!okfail)
812
			filioerr(fil);
813
		return;
814
	}
815
	slevel++;
816
	ointty = intty;
817
	intty = isatty(0);
818
	oprompt = value(PROMPT);
819
	value(PROMPT) &= intty;
820
	getexit(osetexit);
821
	setrupt();
822
	if (setexit() == 0)
823
		commands(1, 1);
824
	else if (slevel > 1) {
825
		close(0);
826
		dup(saveinp);
827
		close(saveinp);
828
		slevel--;
829
		resexit(osetexit);
830
		reset();
831
	}
832
	intty = ointty;
833
	value(PROMPT) = oprompt;
834
	close(0);
835
	dup(saveinp);
836
	close(saveinp);
837
	globp = saveglobp;
838
	peekc = savepeekc;
839
	slevel--;
840
	resexit(osetexit);
841
}
842
 
843
/*
844
 * Clear io statistics before a read or write.
845
 */
846
clrstats()
847
{
848
 
849
	ninbuf = 0;
850
	cntch = 0;
851
	cntln = 0;
852
	cntnull = 0;
853
	cntodd = 0;
854
}
855
 
856
/*
857
 * Io is finished, close the unit and print statistics.
858
 */
859
iostats()
860
{
861
 
862
	(void) fsync(io);
863
	close(io);
864
	io = -1;
865
	if (hush == 0) {
866
		if (value(TERSE))
867
			printf(" %d/%D", cntln, cntch);
868
		else
869
			printf(" %d line%s, %D character%s", cntln, plural((long) cntln),
870
			    cntch, plural(cntch));
871
		if (cntnull || cntodd) {
872
			printf(" (");
873
			if (cntnull) {
874
				printf("%D null", cntnull);
875
				if (cntodd)
876
					printf(", ");
877
			}
878
			if (cntodd)
879
#ifndef	ISO
880
				printf("%D non-ASCII", cntodd);
881
#else
882
				printf("%D non-ISO", cntodd);
883
#endif
884
			putchar(')');
885
		}
886
		noonl();
887
		flush();
888
	}
889
	return (cntnull != 0 || cntodd != 0);
890
}
891
 
892
#if USG | USG3TTY
893
/* It's so wonderful how we all speak the same language... */
894
# define index strchr
895
# define rindex strrchr
896
#endif
897
 
109 7u83 898
void
105 7u83 899
checkmodeline(li_ne)
900
char *li_ne;
901
{
902
	char *beg, *end;
903
	char cmdbuf[1024];
904
	char *index(), *rindex();
905
 
906
	beg = index(li_ne, ':');
907
	if (beg == NULL)
908
		return;
909
	if (&beg[-3] < li_ne)
910
		return;
911
	if (!(  ( (beg[-3] == ' ' || beg[-3] == '\t')
912
	        && beg[-2] == 'e'
913
		&& beg[-1] == 'x')
914
	     || ( (beg[-3] == ' ' || beg[-3] == '\t')
915
	        && beg[-2] == 'v'
916
		&& beg[-1] == 'i'))) return;
917
	strncpy(cmdbuf, beg+1, sizeof cmdbuf);
918
	end = rindex(cmdbuf, ':');
919
	if (end == NULL)
920
		return;
921
	*end = 0;
922
	globp = cmdbuf;
923
	commands(1, 1);
924
}