Print this page
12306 XPG4v2 slave pty behaviour should generally be disabled
Reviewed by: Robert Mustacchi <rm@fingolfin.org>
Change-ID: I7ccd399c22866f34dd20c6bb9d28e77ba4e24c67
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/cmd/ed/ed.c
+++ new/usr/src/cmd/ed/ed.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21
22 22 /*
23 23 * Copyright (c) 1988, 2010, Oracle and/or its affiliates. All rights reserved.
24 24 */
25 25
26 26 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
27 27 /* All Rights Reserved */
28 28
29 29 /*
30 30 * Editor
31 31 */
32 32
33 33 #include <crypt.h>
34 34 #include <libgen.h>
35 35 #include <wait.h>
36 36 #include <string.h>
37 37 #include <sys/types.h>
38 38 #include <locale.h>
39 39 #include <regexpr.h>
40 40 #include <regex.h>
41 41 #include <errno.h>
42 42 #include <paths.h>
43 43
44 44 static const char *msgtab[] =
45 45 {
46 46 "write or open on pipe failed", /* 0 */
47 47 "warning: expecting `w'", /* 1 */
48 48 "mark not lower case ascii", /* 2 */
49 49 "Cannot open input file", /* 3 */
50 50 "PWB spec problem", /* 4 */
51 51 "nothing to undo", /* 5 */
52 52 "restricted shell", /* 6 */
53 53 "cannot create output file", /* 7 */
54 54 "filesystem out of space!", /* 8 */
55 55 "cannot open file", /* 9 */
56 56 "cannot link", /* 10 */
57 57 "Range endpoint too large", /* 11 */
58 58 "unknown command", /* 12 */
59 59 "search string not found", /* 13 */
60 60 "-", /* 14 */
61 61 "line out of range", /* 15 */
62 62 "bad number", /* 16 */
63 63 "bad range", /* 17 */
64 64 "Illegal address count", /* 18 */
65 65 "incomplete global expression", /* 19 */
66 66 "illegal suffix", /* 20 */
67 67 "illegal or missing filename", /* 21 */
68 68 "no space after command", /* 22 */
69 69 "fork failed - try again", /* 23 */
70 70 "maximum of 64 characters in file names", /* 24 */
71 71 "`\\digit' out of range", /* 25 */
72 72 "interrupt", /* 26 */
73 73 "line too long", /* 27 */
74 74 "illegal character in input file", /* 28 */
75 75 "write error", /* 29 */
76 76 "out of memory for append", /* 30 */
77 77 "temp file too big", /* 31 */
78 78 "I/O error on temp file", /* 32 */
79 79 "multiple globals not allowed", /* 33 */
80 80 "global too long", /* 34 */
81 81 "no match", /* 35 */
82 82 "illegal or missing delimiter", /* 36 */
83 83 "-", /* 37 */
84 84 "replacement string too long", /* 38 */
85 85 "illegal move destination", /* 39 */
86 86 "-", /* 40 */
87 87 "no remembered search string", /* 41 */
88 88 "'\\( \\)' imbalance", /* 42 */
89 89 "Too many `\\(' s", /* 43 */
90 90 "more than 2 numbers given", /* 44 */
91 91 "'\\}' expected", /* 45 */
92 92 "first number exceeds second", /* 46 */
93 93 "incomplete substitute", /* 47 */
94 94 "newline unexpected", /* 48 */
95 95 "'[ ]' imbalance", /* 49 */
96 96 "regular expression overflow", /* 50 */
97 97 "regular expression error", /* 51 */
98 98 "command expected", /* 52 */
99 99 "a, i, or c not allowed in G", /* 53 */
100 100 "end of line expected", /* 54 */
101 101 "no remembered replacement string", /* 55 */
102 102 "no remembered command", /* 56 */
103 103 "illegal redirection", /* 57 */
104 104 "possible concurrent update", /* 58 */
105 105 "-", /* 59 */
106 106 "the x command has become X (upper case)", /* 60 */
107 107 "Warning: 'w' may destroy input file "
108 108 "(due to `illegal char' read earlier)",
109 109 /* 61 */
110 110 "Caution: 'q' may lose data in buffer;"
111 111 " 'w' may destroy input file",
112 112 /* 62 */
113 113 "Encryption of string failed", /* 63 */
114 114 "Encryption facility not available", /* 64 */
115 115 "Cannot encrypt temporary file", /* 65 */
116 116 "Enter key:", /* 66 */
117 117 "Illegal byte sequence", /* 67 */
118 118 "File does not exist", /* 68 */
119 119 "tempnam failed", /* 69 */
120 120 "Cannot open temporary file", /* 70 */
121 121 0
122 122 };
123 123
124 124 #include <stdlib.h>
125 125 #include <limits.h>
126 126 #include <stdio.h>
127 127 #include <signal.h>
128 128 #include <sys/types.h>
129 129 #include <sys/stat.h>
130 130 #include <sys/statvfs.h>
131 131 #include <unistd.h>
132 132 #include <termio.h>
133 133 #include <ctype.h>
134 134 #include <setjmp.h>
135 135 #include <fcntl.h>
136 136 #include <wchar.h> /* I18N */
137 137 #include <wctype.h> /* I18N */
138 138 #include <widec.h> /* I18N */
139 139
140 140 #define FTYPE(A) (A.st_mode)
141 141 #define FMODE(A) (A.st_mode)
142 142 #define IDENTICAL(A, B) (A.st_dev == B.st_dev && A.st_ino == B.st_ino)
143 143 #define ISBLK(A) ((A.st_mode & S_IFMT) == S_IFBLK)
144 144 #define ISCHR(A) ((A.st_mode & S_IFMT) == S_IFCHR)
145 145 #define ISDIR(A) ((A.st_mode & S_IFMT) == S_IFDIR)
146 146 #define ISFIFO(A) ((A.st_mode & S_IFMT) == S_IFIFO)
147 147 #define ISREG(A) ((A.st_mode & S_IFMT) == S_IFREG)
148 148
149 149 #define PUTM() if (xcode >= 0) puts(gettext(msgtab[xcode]))
150 150 #define UNGETC(c) (peekc = c)
151 151 #define FNSIZE PATH_MAX
152 152 #define LBSIZE LINE_MAX
153 153
↓ open down ↓ |
153 lines elided |
↑ open up ↑ |
154 154 /* size of substitution replacement pattern buffer */
155 155 #define RHSIZE (LINE_MAX*2)
156 156
157 157 #define KSIZE 8
158 158
159 159 #define READ 0
160 160 #define WRITE 1
161 161
162 162 extern char *optarg; /* Value of argument */
163 163 extern int optind; /* Indicator of argument */
164 -extern int __xpg4; /* defined in xpg4.c; 0 if not xpg4-compiled program */
165 164
166 165 struct Fspec {
167 166 char Ftabs[22];
168 167 char Fdel;
169 168 unsigned char Flim;
170 169 char Fmov;
171 170 char Ffill;
172 171 };
173 172 static struct Fspec fss;
174 173
175 174 static char *fsp;
176 175 static int fsprtn;
177 176 static char line[70];
178 177 static char *linp = line;
179 178 static int sig;
180 179 static int Xqt = 0;
181 180 static int lastc;
182 181 static char savedfile[FNSIZE];
183 182 static char file[FNSIZE];
184 183 static char funny[FNSIZE];
185 184 static int funlink = 0;
186 185 static char linebuf[LBSIZE];
187 186 static char *tstring = linebuf;
188 187
189 188 static char *expbuf;
190 189
191 190 static char rhsbuf[RHSIZE];
192 191 struct lin {
193 192 long cur;
194 193 long sav;
195 194 };
196 195 typedef struct lin *LINE;
197 196 static LINE zero;
198 197 static LINE dot;
199 198 static LINE dol;
200 199 static LINE endcore;
201 200 static LINE fendcore;
202 201 static LINE addr1;
203 202 static LINE addr2;
204 203 static LINE savdol, savdot;
205 204 static int globflg;
206 205 static int initflg;
207 206 static char genbuf[LBSIZE];
208 207 static long count;
209 208 static int numpass; /* Number of passes thru dosub(). */
210 209 static int gsubf; /* Occurrence value. LBSIZE-1=all. */
211 210 static int ocerr1; /* Allows lines NOT changed by dosub() to NOT be put */
212 211 /* out. Retains last line changed as current line. */
213 212 static int ocerr2; /* Flags if ANY line changed by substitute(). 0=nc. */
214 213 static char *nextip;
215 214 static char *linebp;
216 215 static int ninbuf;
217 216 static int peekc;
218 217 static int io;
219 218 static void (*oldhup)(), (*oldintr)();
220 219 static void (*oldquit)(), (*oldpipe)();
221 220 static void quit(int) __NORETURN;
222 221 static int vflag = 1;
223 222 static int xflag;
224 223 static int xtflag;
225 224 static int kflag;
226 225 static int crflag;
227 226 /* Flag for determining if file being read is encrypted */
228 227 static int hflag;
229 228 static int xcode = -1;
230 229 static char crbuf[LBSIZE];
231 230 static int perm[2];
232 231 static int tperm[2];
233 232 static int permflag;
234 233 static int tpermflag;
235 234 static int col;
236 235 static char *globp;
237 236 static int tfile = -1;
238 237 static int tline;
239 238 static char *tfname;
240 239 extern char *locs;
241 240 static char ibuff[LBSIZE];
242 241 static int iblock = -1;
243 242 static char obuff[LBSIZE];
244 243 static int oblock = -1;
245 244 static int ichanged;
246 245 static int nleft;
247 246 static long savnames[26], names[26];
248 247 static int anymarks;
249 248 static long subnewa;
250 249 static int fchange;
251 250 static int nline;
252 251 static int fflg, shflg;
253 252 static char prompt[16] = "*";
254 253 static int rflg;
255 254 static int readflg;
256 255 static int eflg;
257 256 static int qflg = 0;
258 257 static int ncflg;
259 258 static int listn;
260 259 static int listf;
261 260 static int pflag;
262 261 static int flag28 = 0; /* Prevents write after a partial read */
263 262 static int save28 = 0; /* Flag whether buffer empty at start of read */
264 263 static long savtime;
265 264 static char *name = "SHELL";
266 265 static char *rshell = "/usr/lib/rsh";
267 266 static char *val;
268 267 static char *home;
269 268 static int nodelim;
270 269
271 270 int makekey(int *);
272 271 int _mbftowc(char *, wchar_t *, int (*)(), int *);
273 272 static int error(int code);
274 273 static void tlist(struct Fspec *);
275 274 static void tstd(struct Fspec *);
276 275 static void gdelete(void);
277 276 static void delete(void);
278 277 static void exfile(void);
279 278 static void filename(int comm);
280 279 static void newline(void);
281 280 static int gettty(void);
282 281 static void commands(void);
283 282 static void undo(void);
284 283 static void save(void);
285 284 static void strcopy(char *source, char *dest);
286 285 static int strequal(char **scan1, char *str);
287 286 static int stdtab(char *, char *);
288 287 static int lenchk(char *, struct Fspec *);
289 288 static void clear(struct Fspec *);
290 289 static int expnd(char *, char *, int *, struct Fspec *);
291 290 static void tincr(int, struct Fspec *);
292 291 static void targ(struct Fspec *);
293 292 static int numb(void);
294 293 static int fspec(char *, struct Fspec *, int);
295 294 static void red(char *);
296 295 static void newtime(void);
297 296 static void chktime(void);
298 297 static void getime(void);
299 298 static void mkfunny(void);
300 299 static int eopen(char *, int);
301 300 static void eclose(int f);
302 301 static void globaln(int);
303 302 static char *getkey(const char *);
304 303 static int execute(int, LINE);
305 304 static void error1(int);
306 305 static int getcopy(void);
307 306 static void move(int);
308 307 static void dosub(void);
309 308 static int getsub(void);
310 309 static int compsub(void);
311 310 static void substitute(int);
312 311 static void join(void);
313 312 static void global(int);
314 313 static void init(void);
315 314 static void rdelete(LINE, LINE);
316 315 static void append(int (*)(void), LINE);
317 316 static int getfile(void);
318 317 static void putfile(void);
319 318 static void onpipe(int);
320 319 static void onhup(int);
321 320 static void onintr(int);
322 321 static void setdot(void);
323 322 static void setall(void);
324 323 static void setnoaddr(void);
325 324 static void nonzero(void);
326 325 static void setzeroasone(void);
327 326 static long putline(void);
328 327 static LINE address(void);
329 328 static char *getaline(long);
330 329 static char *getblock(long, long);
331 330 static char *place(char *, char *, char *);
332 331 static void comple(wchar_t);
333 332 static void putchr(unsigned char);
334 333 static void putwchr(wchar_t);
335 334 static int getchr(void);
336 335 static void unixcom(void);
337 336 static void blkio(int, char *, ssize_t (*)());
338 337 static void reverse(LINE, LINE);
339 338 static void putd();
340 339 static wchar_t get_wchr(void);
341 340
342 341 static struct stat Fl, Tf;
343 342 #ifndef RESEARCH
344 343 static struct statvfs U;
345 344 static int Short = 0;
346 345 static mode_t oldmask; /* No umask while writing */
347 346 #endif
348 347 static jmp_buf savej;
349 348
350 349 #ifdef NULLS
351 350 int nulls; /* Null count */
352 351 #endif
353 352 static long ccount;
354 353
355 354 static int errcnt = 0;
356 355
357 356
358 357 static void
359 358 onpipe(int sig)
360 359 {
361 360 (int)error(0);
362 361 }
363 362
364 363 int
365 364 main(int argc, char **argv)
366 365 {
367 366 char *p1, *p2;
368 367 int c;
369 368
370 369 (void) setlocale(LC_ALL, "");
371 370 #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */
372 371 #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */
373 372 #endif
374 373 (void) textdomain(TEXT_DOMAIN);
375 374
376 375 oldquit = signal(SIGQUIT, SIG_IGN);
377 376 oldhup = signal(SIGHUP, SIG_IGN);
378 377 oldintr = signal(SIGINT, SIG_IGN);
379 378 oldpipe = signal(SIGPIPE, onpipe);
380 379 if (signal(SIGTERM, SIG_IGN) != SIG_IGN)
381 380 signal(SIGTERM, quit);
382 381 p1 = *argv;
383 382 while (*p1++)
384 383 ;
385 384 while (--p1 >= *argv)
386 385 if (*p1 == '/')
387 386 break;
388 387 *argv = p1 + 1;
389 388 /* if SHELL set in environment and is /usr/lib/rsh, set rflg */
390 389 if ((val = getenv(name)) != NULL)
391 390 if (strcmp(val, rshell) == 0)
392 391 rflg++;
393 392 if (**argv == 'r')
394 393 rflg++;
395 394 home = getenv("HOME");
396 395 while (1) {
397 396 while ((c = getopt(argc, argv, "sp:qxC")) != EOF) {
398 397 switch (c) {
399 398
400 399 case 's':
401 400 vflag = 0;
402 401 break;
403 402
404 403 case 'p':
405 404 strncpy(prompt, optarg, sizeof (prompt)-1);
406 405 shflg = 1;
407 406 break;
408 407
409 408 case 'q':
410 409 signal(SIGQUIT, SIG_DFL);
411 410 vflag = 1;
412 411 break;
413 412
414 413 case 'x':
415 414 crflag = -1;
416 415 xflag = 1;
417 416 break;
418 417
419 418 case 'C':
420 419 crflag = 1;
421 420 xflag = 1;
422 421 break;
423 422
424 423 case '?':
425 424 (void) fprintf(stderr, gettext(
426 425 "Usage: ed [- | -s] [-p string] [-x] [-C] [file]\n"
427 426 " red [- | -s] [-p string] [-x] [-C] [file]\n"));
428 427 exit(2);
429 428 }
430 429 }
431 430 if (argv[optind] && strcmp(argv[optind], "-") == 0 &&
432 431 strcmp(argv[optind-1], "--") != 0) {
433 432 vflag = 0;
434 433 optind++;
435 434 continue;
436 435 }
437 436 break;
438 437 }
439 438 argc = argc - optind;
440 439 argv = &argv[optind];
441 440
442 441 if (xflag) {
443 442 if (permflag)
444 443 crypt_close(perm);
445 444 permflag = 1;
446 445 kflag = run_setkey(&perm[0], getkey(msgtab[66]));
447 446 if (kflag == -1) {
448 447 puts(gettext(msgtab[64]));
449 448 xflag = 0;
450 449 kflag = 0;
451 450 }
452 451 if (kflag == 0)
453 452 crflag = 0;
454 453 }
455 454
456 455 if (argc > 0) {
457 456 p1 = *argv;
458 457 if (strlen(p1) >= (size_t)FNSIZE) {
459 458 puts(gettext("file name too long"));
460 459 if (kflag)
461 460 crypt_close(perm);
462 461 exit(2);
463 462 }
464 463 p2 = savedfile;
465 464 while (*p2++ = *p1++)
466 465 ;
467 466 globp = "e";
468 467 fflg++;
469 468 } else /* editing with no file so set savtime to 0 */
470 469 savtime = 0;
471 470 eflg++;
472 471 if ((tfname = tempnam("", "ea")) == NULL) {
473 472 puts(gettext(msgtab[69]));
474 473 exit(2);
475 474 }
476 475
477 476 fendcore = (LINE)sbrk(0);
478 477 init();
479 478 if (oldintr != SIG_IGN)
480 479 signal(SIGINT, onintr);
481 480 if (oldhup != SIG_IGN)
482 481 signal(SIGHUP, onhup);
483 482 setjmp(savej);
484 483 commands();
485 484 quit(sig);
486 485 return (0);
487 486 }
488 487
489 488 static void
490 489 commands(void)
491 490 {
492 491 LINE a1;
493 492 int c;
494 493 char *p1, *p2;
495 494 int fsave, m, n;
496 495
497 496 for (;;) {
498 497 nodelim = 0;
499 498 if (pflag) {
500 499 pflag = 0;
501 500 addr1 = addr2 = dot;
502 501 goto print;
503 502 }
504 503 if (shflg && globp == 0)
505 504 write(1, gettext(prompt), strlen(gettext(prompt)));
506 505 addr1 = 0;
507 506 addr2 = 0;
508 507 if ((c = getchr()) == ',') {
509 508 addr1 = zero + 1;
510 509 addr2 = dol;
511 510 #ifdef XPG6
512 511 /* XPG4 - it was an error if the second address was */
513 512 /* input and the first address was ommitted */
514 513 /* Parse second address */
515 514 if ((a1 = address()) != 0) {
516 515 addr2 = a1;
517 516 }
518 517 #endif
519 518 c = getchr();
520 519 goto swch;
521 520 } else if (c == ';') {
522 521 addr1 = dot;
523 522 addr2 = dol;
524 523 #ifdef XPG6
525 524 /* XPG4 - it was an error if the second address was */
526 525 /* input and the first address was ommitted */
527 526 /* Parse second address */
528 527 if ((a1 = address()) != 0) {
529 528 addr2 = a1;
530 529 }
531 530 #endif
532 531 c = getchr();
533 532 goto swch;
534 533 } else
535 534 peekc = c;
536 535 do {
537 536 addr1 = addr2;
538 537 if ((a1 = address()) == 0) {
539 538 c = getchr();
540 539 break;
541 540 }
542 541 addr2 = a1;
543 542 if ((c = getchr()) == ';') {
544 543 c = ',';
545 544 dot = a1;
546 545 }
547 546 } while (c == ',');
548 547 if (addr1 == 0)
549 548 addr1 = addr2;
550 549 swch:
551 550 switch (c) {
552 551
553 552 case 'a':
554 553 setdot();
555 554 newline();
556 555 if (!globflg) save();
557 556 append(gettty, addr2);
558 557 continue;
559 558
560 559 case 'c':
561 560 #ifdef XPG6
562 561 setzeroasone();
563 562 #endif
564 563 delete();
565 564 append(gettty, addr1-1);
566 565
567 566 /* XPG4 - If no new lines are inserted, then the current */
568 567 /* line becomes the line after the lines deleted. */
569 568
570 569 if (((linebuf[0] != '.') || (dot == (addr1-1))) &&
571 570 (addr2 <= dol))
572 571 dot = addr1;
573 572 continue;
574 573
575 574 case 'd':
576 575 delete();
577 576 continue;
578 577
579 578 case 'E':
580 579 fchange = 0;
581 580 c = 'e';
582 581 /* FALLTHROUGH */
583 582 case 'e':
584 583 fflg++;
585 584 setnoaddr();
586 585 if (vflag && fchange) {
587 586 fchange = 0;
588 587 (void) error(1);
589 588 }
590 589 filename(c);
591 590 eflg++;
592 591 init();
593 592 addr2 = zero;
594 593 goto caseread;
595 594
596 595 case 'f':
597 596 setnoaddr();
598 597 filename(c);
599 598 if (!ncflg) /* there is a filename */
600 599 getime();
601 600 else
602 601 ncflg--;
603 602 puts(savedfile);
604 603 continue;
605 604
606 605 case 'g':
607 606 global(1);
608 607 continue;
609 608 case 'G':
610 609 globaln(1);
611 610 continue;
612 611
613 612 case 'h':
614 613 newline();
615 614 setnoaddr();
616 615 PUTM();
617 616 continue;
618 617
619 618 case 'H':
620 619 newline();
621 620 setnoaddr();
622 621 if (!hflag) {
623 622 hflag = 1;
624 623 PUTM();
625 624 }
626 625 else
627 626 hflag = 0;
628 627 continue;
629 628
630 629 case 'i':
631 630 #ifdef XPG6
632 631 setzeroasone();
633 632 #endif
634 633 setdot();
635 634 nonzero();
636 635 newline();
637 636 if (!globflg) save();
638 637 append(gettty, addr2-1);
639 638 if (dot == addr2-1)
640 639 dot += 1;
641 640 continue;
642 641
643 642 case 'j':
644 643 if (addr2 == 0) {
645 644 addr1 = dot;
646 645 addr2 = dot+1;
647 646 }
648 647 setdot();
649 648 newline();
650 649 nonzero();
651 650 if (!globflg) save();
652 651 join();
653 652 continue;
654 653
655 654 case 'k':
656 655 if ((c = getchr()) < 'a' || c > 'z')
657 656 (void) error(2);
658 657 newline();
659 658 setdot();
660 659 nonzero();
661 660 names[c-'a'] = addr2->cur & ~01;
662 661 anymarks |= 01;
663 662 continue;
664 663
665 664 case 'm':
666 665 move(0);
667 666 continue;
668 667
669 668 case '\n':
670 669 if (addr2 == 0)
671 670 addr2 = dot+1;
672 671 addr1 = addr2;
673 672 goto print;
674 673
675 674 case 'n':
676 675 listn++;
677 676 newline();
678 677 goto print;
679 678
680 679 case 'l':
681 680 listf++;
682 681 /* FALLTHROUGH */
683 682 case 'p':
684 683 newline();
685 684 print:
686 685 setdot();
687 686 nonzero();
688 687 a1 = addr1;
689 688 do {
690 689 if (listn) {
691 690 count = a1 - zero;
692 691 putd();
693 692 putchr('\t');
694 693 }
695 694 puts(getaline((a1++)->cur));
696 695 } while (a1 <= addr2);
697 696 dot = addr2;
698 697 pflag = 0;
699 698 listn = 0;
700 699 listf = 0;
701 700 continue;
702 701
703 702 case 'Q':
704 703 fchange = 0;
705 704 /* FALLTHROUGH */
706 705 case 'q':
707 706 setnoaddr();
708 707 newline();
709 708 quit(sig);
710 709
711 710 case 'r':
712 711 filename(c);
713 712 caseread:
714 713 readflg = 1;
715 714 save28 = (dol != fendcore);
716 715 if (crflag == 2 || crflag == -2)
717 716 crflag = -1; /* restore crflag for next file */
718 717 errno = 0;
719 718 if ((io = eopen(file, O_RDONLY)) < 0) {
720 719 lastc = '\n';
721 720 /* if first entering editor and file does not exist */
722 721 /* set saved access time to 0 */
723 722 if (eflg) {
724 723 savtime = 0;
725 724 eflg = 0;
726 725 if (c == 'e' && vflag == 0)
727 726 qflg = 1;
728 727 }
729 728 if (errno == ENOENT) {
730 729 (void) error(68);
731 730 } else {
732 731 (void) error(3);
733 732 }
734 733 }
735 734 /* get last mod time of file */
736 735 /* eflg - entered editor with ed or e */
737 736 if (eflg) {
738 737 eflg = 0;
739 738 getime();
740 739 }
741 740 setall();
742 741 ninbuf = 0;
743 742 n = zero != dol;
744 743 #ifdef NULLS
745 744 nulls = 0;
746 745 #endif
747 746 if (!globflg && (c == 'r')) save();
748 747 append(getfile, addr2);
749 748 exfile();
750 749 readflg = 0;
751 750 fchange = n;
752 751 continue;
753 752
754 753 case 's':
755 754 setdot();
756 755 nonzero();
757 756 if (!globflg) save();
758 757 substitute(globp != 0);
759 758 continue;
760 759
761 760 case 't':
762 761 move(1);
763 762 continue;
764 763
765 764 case 'u':
766 765 setdot();
767 766 newline();
768 767 if (!initflg)
769 768 undo();
770 769 else
771 770 (void) error(5);
772 771 fchange = 1;
773 772 continue;
774 773
775 774 case 'v':
776 775 global(0);
777 776 continue;
778 777 case 'V':
779 778 globaln(0);
780 779 continue;
781 780
782 781 case 'W':
783 782 case 'w':
784 783 if (flag28) {
785 784 flag28 = 0;
786 785 fchange = 0;
787 786 (void) error(61);
788 787 }
789 788 setall();
790 789
791 790 /* on NULL-RE condition do not generate error */
792 791
793 792 if ((linebuf[0] != '.') && (zero != dol) &&
794 793 (addr1 <= zero || addr2 > dol))
795 794 (void) error(15);
796 795 filename(c);
797 796 if (Xqt) {
798 797 io = eopen(file, O_WRONLY);
799 798 n = 1; /* set n so newtime will not execute */
800 799 } else {
801 800 struct stat lFl;
802 801 fstat(tfile, &Tf);
803 802 if (stat(file, &Fl) < 0) {
804 803 if ((io = creat(file, S_IRUSR|S_IWUSR|S_IRGRP
805 804 |S_IWGRP|S_IROTH|S_IWOTH)) < 0)
806 805 (void) error(7);
807 806 fstat(io, &Fl);
808 807 Fl.st_mtime = 0;
809 808 lFl = Fl;
810 809 close(io);
811 810 } else {
812 811 #ifndef RESEARCH
813 812 oldmask = umask(0);
814 813 /*
815 814 * Must determine if file is
816 815 * a symbolic link
817 816 */
818 817 lstat(file, &lFl);
819 818 #endif
820 819 }
821 820 #ifndef RESEARCH
822 821 /*
823 822 * Determine if there are enough free blocks on system
824 823 */
825 824 if (!Short && statvfs(file, &U) == 0 &&
826 825 U.f_bfree < ((Tf.st_size/U.f_frsize) + 100)) {
827 826 Short = 1;
828 827 (void) error(8);
829 828 }
830 829 Short = 0;
831 830 #endif
832 831 p1 = savedfile; /* The current filename */
833 832 p2 = file;
834 833 m = strcmp(p1, p2);
835 834 if (c == 'w' && Fl.st_nlink == 1 && ISREG(lFl)) {
836 835 if (close(open(file, O_WRONLY)) < 0)
837 836 (void) error(9);
838 837 if (!(n = m))
839 838 chktime();
840 839 mkfunny();
841 840 /*
842 841 * If funlink equals one it means that
843 842 * funny points to a valid file which must
844 843 * be unlinked when interrupted.
845 844 */
846 845
847 846 funlink = 1;
848 847 if ((io = creat(funny, FMODE(Fl))) >= 0) {
849 848 chown(funny, Fl.st_uid, Fl.st_gid);
850 849 chmod(funny, FMODE(Fl));
851 850 putfile();
852 851 exfile();
853 852
854 853 if (rename(funny, file))
855 854 (void) error(10);
856 855 funlink = 0;
857 856 /* if filenames are the same */
858 857 if (!n)
859 858 newtime();
860 859 /* check if entire buffer was written */
861 860 fsave = fchange;
862 861 if (((addr1 == zero) ||
863 862 (addr1 == (zero + 1))) &&
864 863 (addr2 == dol))
865 864 fchange = 0;
866 865 else
867 866 fchange = 1;
868 867 if (fchange == 1 && m != 0)
869 868 fchange = fsave;
870 869 continue;
871 870 }
872 871 } else {
873 872 n = 1; /* set n so newtime will not execute */
874 873 }
875 874 if ((io = open(file,
876 875 (c == 'w') ? O_WRONLY|O_CREAT|O_TRUNC
877 876 : O_WRONLY|O_CREAT|O_APPEND, S_IRUSR|S_IWUSR
878 877 |S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)) < 0)
879 878 (void) error(7);
880 879 }
881 880 putfile();
882 881 exfile();
883 882 if (!n)
884 883 newtime();
885 884 fsave = fchange;
886 885 fchange = (((addr1 == zero) || (addr1 == (zero + 1))) &&
887 886 (addr2 == dol)) ? 0 : 1;
888 887 /* Leave fchange alone if partial write was to another file */
889 888 if (fchange == 1 && m != 0) fchange = fsave;
890 889 continue;
891 890
892 891 case 'C':
893 892 crflag = 1;
894 893 /*
895 894 * C is same as X, but always assume input files are
896 895 * ciphertext
897 896 */
898 897 goto encrypt;
899 898
900 899 case 'X':
901 900 crflag = -1;
902 901 encrypt:
903 902 setnoaddr();
904 903 newline();
905 904 xflag = 1;
906 905 if (permflag)
907 906 (void) crypt_close(perm);
908 907 permflag = 1;
909 908 if ((kflag = run_setkey(&perm[0], getkey(msgtab[66]))) == -1) {
910 909 xflag = 0;
911 910 kflag = 0;
912 911 crflag = 0;
913 912 (void) error(64);
914 913 }
915 914 if (kflag == 0)
916 915 crflag = 0;
917 916 continue;
918 917
919 918 case '=':
920 919 setall();
921 920 newline();
922 921 count = (addr2-zero)&077777;
923 922 putd();
924 923 putchr('\n');
925 924 continue;
926 925
927 926 case '!':
928 927 unixcom();
929 928 continue;
930 929
931 930 case EOF:
932 931 return;
933 932
934 933 case 'P':
935 934 setnoaddr();
936 935 newline();
937 936 if (shflg)
938 937 shflg = 0;
939 938 else
940 939 shflg++;
941 940 continue;
942 941 }
943 942 if (c == 'x')
944 943 (void) error(60);
945 944 else
946 945 (void) error(12);
947 946 }
948 947 }
949 948
950 949 LINE
951 950 address(void)
952 951 {
953 952 int minus, c;
954 953 LINE a1;
955 954 int n, relerr, retval;
956 955
957 956 minus = 0;
958 957 a1 = 0;
959 958 for (;;) {
960 959 c = getchr();
961 960 if ('0' <= c && c <= '9') {
962 961 n = 0;
963 962 do {
964 963 n *= 10;
965 964 n += c - '0';
966 965 } while ((c = getchr()) >= '0' && c <= '9');
967 966 peekc = c;
968 967 if (a1 == 0)
969 968 a1 = zero;
970 969 if (minus < 0)
971 970 n = -n;
972 971 a1 += n;
973 972 minus = 0;
974 973 continue;
975 974 }
976 975 relerr = 0;
977 976 if (a1 || minus)
978 977 relerr++;
979 978 switch (c) {
980 979 case ' ':
981 980 case '\t':
982 981 continue;
983 982
984 983 case '+':
985 984 minus++;
986 985 if (a1 == 0)
987 986 a1 = dot;
988 987 continue;
989 988
990 989 case '-':
991 990 case '^':
992 991 minus--;
993 992 if (a1 == 0)
994 993 a1 = dot;
995 994 continue;
996 995
997 996 case '?':
998 997 case '/':
999 998 comple(c);
1000 999 a1 = dot;
1001 1000 for (;;) {
1002 1001 if (c == '/') {
1003 1002 a1++;
1004 1003 if (a1 > dol)
1005 1004 a1 = zero;
1006 1005 } else {
1007 1006 a1--;
1008 1007 if (a1 < zero)
1009 1008 a1 = dol;
1010 1009 }
1011 1010
1012 1011 if (execute(0, a1))
1013 1012 break;
1014 1013 if (a1 == dot)
1015 1014 (void) error(13);
1016 1015 }
1017 1016 break;
1018 1017
1019 1018 case '$':
1020 1019 a1 = dol;
1021 1020 break;
1022 1021
1023 1022 case '.':
1024 1023 a1 = dot;
1025 1024 break;
1026 1025
1027 1026 case '\'':
1028 1027 if ((c = getchr()) < 'a' || c > 'z')
1029 1028 (void) error(2);
1030 1029 for (a1 = zero; a1 <= dol; a1++)
1031 1030 if (names[c-'a'] == (a1->cur & ~01))
1032 1031 break;
1033 1032 break;
1034 1033
1035 1034 default:
1036 1035 peekc = c;
1037 1036 if (a1 == 0)
1038 1037 return (0);
1039 1038 a1 += minus;
1040 1039
1041 1040 /* on NULL-RE condition do not generate error */
1042 1041
1043 1042 if ((linebuf[0] != '.') && (a1 < zero || a1 > dol))
1044 1043 (void) error(15);
1045 1044 return (a1);
1046 1045 }
1047 1046 if (relerr)
1048 1047 (void) error(16);
1049 1048 }
1050 1049 }
1051 1050
1052 1051 static void
1053 1052 setdot(void)
1054 1053 {
1055 1054 if (addr2 == 0)
1056 1055 addr1 = addr2 = dot;
1057 1056 if (addr1 > addr2)
1058 1057 (void) error(17);
1059 1058 }
1060 1059
1061 1060 static void
1062 1061 setall(void)
1063 1062 {
1064 1063 if (addr2 == 0) {
1065 1064 addr1 = zero+1;
1066 1065 addr2 = dol;
1067 1066 if (dol == zero)
1068 1067 addr1 = zero;
1069 1068 }
1070 1069 setdot();
1071 1070 }
1072 1071
1073 1072 static void
1074 1073 setnoaddr(void)
1075 1074 {
1076 1075 if (addr2)
1077 1076 (void) error(18);
1078 1077 }
1079 1078
1080 1079 static void
1081 1080 nonzero(void)
1082 1081 {
1083 1082 /* on NULL-RE condition do not generate error */
1084 1083
1085 1084 if ((linebuf[0] != '.') && (addr1 <= zero || addr2 > dol))
1086 1085 (void) error(15);
1087 1086 }
1088 1087
1089 1088 static void
1090 1089 setzeroasone(void)
1091 1090 {
1092 1091 /* for the c and i commands 0 equal to 1 address */
1093 1092 if (addr1 == zero) {
1094 1093 addr1 = zero+1;
1095 1094 }
1096 1095 if (addr2 == zero) {
1097 1096 addr2 = zero+1;
1098 1097 }
1099 1098 }
1100 1099
1101 1100
1102 1101 static void
1103 1102 newline(void)
1104 1103 {
1105 1104 int c;
1106 1105
1107 1106 if ((c = getchr()) == '\n')
1108 1107 return;
1109 1108 if (c == 'p' || c == 'l' || c == 'n') {
1110 1109 pflag++;
1111 1110 if (c == 'l') listf++;
1112 1111 if (c == 'n') listn++;
1113 1112 if ((c = getchr()) == '\n')
1114 1113 return;
1115 1114 }
1116 1115 (void) error(20);
1117 1116 }
1118 1117
1119 1118 static void
1120 1119 filename(int comm)
1121 1120 {
1122 1121 char *p1, *p2;
1123 1122 int c;
1124 1123 int i = 0;
1125 1124
1126 1125 count = 0;
1127 1126 c = getchr();
1128 1127 if (c == '\n' || c == EOF) {
1129 1128 p1 = savedfile;
1130 1129 if (*p1 == 0 && comm != 'f')
1131 1130 (void) error(21);
1132 1131 /* ncflg set means do not get mod time of file */
1133 1132 /* since no filename followed f */
1134 1133 if (comm == 'f')
1135 1134 ncflg++;
1136 1135 p2 = file;
1137 1136 while (*p2++ = *p1++)
1138 1137 ;
1139 1138 red(savedfile);
1140 1139 return;
1141 1140 }
1142 1141 if (c != ' ')
1143 1142 (void) error(22);
1144 1143 while ((c = getchr()) == ' ')
1145 1144 ;
1146 1145 if (c == '!')
1147 1146 ++Xqt, c = getchr();
1148 1147 if (c == '\n')
1149 1148 (void) error(21);
1150 1149 p1 = file;
1151 1150 do {
1152 1151 if (++i >= FNSIZE)
1153 1152 (void) error(24);
1154 1153 *p1++ = c;
1155 1154 if (c == EOF || (c == ' ' && !Xqt))
1156 1155 (void) error(21);
1157 1156 } while ((c = getchr()) != '\n');
1158 1157 *p1++ = 0;
1159 1158 if (Xqt)
1160 1159 if (comm == 'f') {
1161 1160 --Xqt;
1162 1161 (void) error(57);
1163 1162 }
1164 1163 else
1165 1164 return;
1166 1165 if (savedfile[0] == 0 || comm == 'e' || comm == 'f') {
1167 1166 p1 = savedfile;
1168 1167 p2 = file;
1169 1168 while (*p1++ = *p2++)
1170 1169 ;
1171 1170 }
1172 1171 red(file);
1173 1172 }
1174 1173
1175 1174
1176 1175 static void
1177 1176 exfile(void)
1178 1177 {
1179 1178 #ifdef NULLS
1180 1179 int c;
1181 1180 #endif
1182 1181
1183 1182 #ifndef RESEARCH
1184 1183 if (oldmask) {
1185 1184 umask(oldmask);
1186 1185 oldmask = 0;
1187 1186 }
1188 1187 #endif
1189 1188 eclose(io);
1190 1189 io = -1;
1191 1190 if (vflag) {
1192 1191 putd();
1193 1192 putchr('\n');
1194 1193 #ifdef NULLS
1195 1194 if (nulls) {
1196 1195 c = count;
1197 1196 count = nulls;
1198 1197 nulls = 0;
1199 1198 putd();
1200 1199 puts(gettext(" nulls replaced by '\\0'"));
1201 1200 count = c;
1202 1201 }
1203 1202 #endif
1204 1203 }
1205 1204 }
1206 1205
1207 1206 static void
1208 1207 onintr(int sig)
1209 1208 {
1210 1209 signal(SIGINT, onintr);
1211 1210 putchr('\n');
1212 1211 lastc = '\n';
1213 1212 globflg = 0;
1214 1213 if (funlink) unlink(funny); /* remove tmp file */
1215 1214 /* if interrupted a read, only part of file may be in buffer */
1216 1215 if (readflg) {
1217 1216 sprintf(tstring, "\007read may be incomplete - beware!\007");
1218 1217 puts(gettext(tstring));
1219 1218 fchange = 0;
1220 1219 }
1221 1220 (void) error(26);
1222 1221 }
1223 1222
1224 1223 static void
1225 1224 onhup(int sig)
1226 1225 {
1227 1226 signal(SIGINT, SIG_IGN);
1228 1227 signal(SIGHUP, SIG_IGN);
1229 1228 /*
1230 1229 * if there are lines in file and file was not written
1231 1230 * since last update, save in ed.hup, or $HOME/ed.hup
1232 1231 */
1233 1232 if (dol > zero && fchange == 1) {
1234 1233 addr1 = zero+1;
1235 1234 addr2 = dol;
1236 1235 io = creat("ed.hup",
1237 1236 S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH);
1238 1237 if (io < 0 && home) {
1239 1238 char *fn;
1240 1239
1241 1240 fn = (char *)calloc(strlen(home) + 8, sizeof (char));
1242 1241 if (fn) {
1243 1242 strcpy(fn, home);
1244 1243 strcat(fn, "/ed.hup");
1245 1244 io = creat(fn, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP
1246 1245 |S_IROTH|S_IWOTH);
1247 1246 free(fn);
1248 1247 }
1249 1248 }
1250 1249 if (io > 0)
1251 1250 putfile();
1252 1251 }
1253 1252 fchange = 0;
1254 1253 ++errcnt;
1255 1254 quit(sig);
1256 1255 }
1257 1256
1258 1257 static int
1259 1258 error(int code)
1260 1259 {
1261 1260 int c;
1262 1261
1263 1262 if (code == 28 && save28 == 0) {
1264 1263 fchange = 0;
1265 1264 flag28++;
1266 1265 }
1267 1266 readflg = 0;
1268 1267 ++errcnt;
1269 1268 listf = listn = 0;
1270 1269 pflag = 0;
1271 1270 #ifndef RESEARCH
1272 1271 if (oldmask) {
1273 1272 umask(oldmask);
1274 1273 oldmask = 0;
1275 1274 }
1276 1275 #endif
1277 1276 #ifdef NULLS /* Not really nulls, but close enough */
1278 1277 /* This is a bug because of buffering */
1279 1278 if (code == 28) /* illegal char. */
1280 1279 putd();
1281 1280 #endif
1282 1281 /* Cant open file or file does not exist */
1283 1282 if ((code == 3) || (code == 68)) {
1284 1283 if (qflg == 0) {
1285 1284 putchr('?');
1286 1285 puts(file);
1287 1286 }
1288 1287 else
1289 1288 qflg = 0;
1290 1289 }
1291 1290 else
1292 1291 {
1293 1292 putchr('?');
1294 1293 putchr('\n');
1295 1294 }
1296 1295 count = 0;
1297 1296 lseek(0, (long)0, 2);
1298 1297 if (globp)
1299 1298 lastc = '\n';
1300 1299 globp = 0;
1301 1300 peekc = lastc;
1302 1301 if (lastc)
1303 1302 while ((c = getchr()) != '\n' && c != EOF)
1304 1303 ;
1305 1304 if (io) {
1306 1305 eclose(io);
1307 1306 io = -1;
1308 1307 }
1309 1308 xcode = code;
1310 1309 if (hflag)
1311 1310 PUTM();
1312 1311 if (code == 4)
1313 1312 return (0); /* Non-fatal error. */
1314 1313 longjmp(savej, 1);
1315 1314 /* NOTREACHED */
1316 1315 }
1317 1316
1318 1317 static int
1319 1318 getchr(void)
1320 1319 {
1321 1320 char c;
1322 1321 if (lastc = peekc) {
1323 1322 peekc = 0;
1324 1323 return (lastc);
1325 1324 }
1326 1325 if (globp) {
1327 1326 if ((lastc = (unsigned char)*globp++) != 0)
1328 1327 return (lastc);
1329 1328 globp = 0;
1330 1329 return (EOF);
1331 1330 }
1332 1331 if (read(0, &c, 1) <= 0)
1333 1332 return (lastc = EOF);
1334 1333 lastc = (unsigned char)c;
1335 1334 return (lastc);
1336 1335 }
1337 1336
1338 1337 static int
1339 1338 gettty(void)
1340 1339 {
1341 1340 int c;
1342 1341 char *gf;
1343 1342 char *p;
1344 1343
1345 1344 p = linebuf;
1346 1345 gf = globp;
1347 1346 while ((c = getchr()) != '\n') {
1348 1347 if (c == EOF) {
1349 1348 if (gf)
1350 1349 peekc = c;
1351 1350 return (c);
1352 1351 }
1353 1352 if (c == 0)
1354 1353 continue;
1355 1354 *p++ = c;
1356 1355
1357 1356 if (p > &linebuf[LBSIZE-1])
1358 1357 (void) error(27);
1359 1358 }
1360 1359 *p++ = 0;
1361 1360 if (linebuf[0] == '.' && linebuf[1] == 0)
1362 1361 return (EOF);
1363 1362
1364 1363 /*
1365 1364 * POSIX.2/XPG4 explicitly says no to this:
1366 1365 *
1367 1366 * in Solaris backslash followed by special character "." is
1368 1367 * special character "." itself; (so terminating input mode can be
1369 1368 * "\.\n").
1370 1369 *
1371 1370 * however, POSIX2/XPG4 says, input mode is terminated by
1372 1371 * entering line consisting of only 2 characters: ".\n"
1373 1372 *
1374 1373 * if (linebuf[0]=='\\' && linebuf[1]=='.' && linebuf[2]==0) {
1375 1374 * linebuf[0] = '.';
1376 1375 * linebuf[1] = 0;
1377 1376 * }
1378 1377 */
1379 1378 return (0);
1380 1379 }
1381 1380
1382 1381 static int
1383 1382 getfile(void)
1384 1383 {
1385 1384 char c;
1386 1385 char *lp, *fp;
1387 1386
1388 1387 lp = linebuf;
1389 1388 fp = nextip;
1390 1389 do {
1391 1390 if (--ninbuf < 0) {
1392 1391 if ((ninbuf = read(io, genbuf, LBSIZE)-1) < 0)
1393 1392 if (lp > linebuf) {
1394 1393 puts(gettext("'\\n' appended"));
1395 1394 *genbuf = '\n';
1396 1395 }
1397 1396 else
1398 1397 return (EOF);
1399 1398 if (crflag == -1) {
1400 1399 if (isencrypt(genbuf, ninbuf + 1))
1401 1400 crflag = 2;
1402 1401 else
1403 1402 crflag = -2;
1404 1403 }
1405 1404 fp = genbuf;
1406 1405 if (crflag > 0)
1407 1406 if (run_crypt(count, genbuf, ninbuf+1, perm) == -1)
1408 1407 (void) error(63);
1409 1408 }
1410 1409 if (lp >= &linebuf[LBSIZE]) {
1411 1410 lastc = '\n';
1412 1411 (void) error(27);
1413 1412 }
1414 1413 if ((*lp++ = c = *fp++) == 0) {
1415 1414 #ifdef NULLS
1416 1415 lp[-1] = '\\';
1417 1416 *lp++ = '0';
1418 1417 nulls++;
1419 1418 #else
1420 1419 lp--;
1421 1420 continue;
1422 1421 #endif
1423 1422 }
1424 1423 count++;
1425 1424 } while (c != '\n');
1426 1425 *--lp = 0;
1427 1426 nextip = fp;
1428 1427 if (fss.Ffill && fss.Flim && lenchk(linebuf, &fss) < 0) {
1429 1428 write(1, gettext("line too long: lno = "),
1430 1429 strlen(gettext("line too long: lno = ")));
1431 1430 ccount = count;
1432 1431 count = (++dot-zero)&077777;
1433 1432 dot--;
1434 1433 putd();
1435 1434 count = ccount;
1436 1435 putchr('\n');
1437 1436 }
1438 1437 return (0);
1439 1438 }
1440 1439
1441 1440 static void
1442 1441 putfile(void)
1443 1442 {
1444 1443 int n;
1445 1444 LINE a1;
1446 1445 char *fp, *lp;
1447 1446 int nib;
1448 1447
1449 1448 nib = LBSIZE;
1450 1449 fp = genbuf;
1451 1450 a1 = addr1;
1452 1451 do {
1453 1452 lp = getaline(a1++->cur);
1454 1453 if (fss.Ffill && fss.Flim && lenchk(linebuf, &fss) < 0) {
1455 1454 write(1, gettext("line too long: lno = "),
1456 1455 strlen(gettext("line too long: lno = ")));
1457 1456 ccount = count;
1458 1457 count = (a1-zero-1)&077777;
1459 1458 putd();
1460 1459 count = ccount;
1461 1460 putchr('\n');
1462 1461 }
1463 1462 for (;;) {
1464 1463 if (--nib < 0) {
1465 1464 n = fp-genbuf;
1466 1465 if (kflag)
1467 1466 if (run_crypt(count-n, genbuf, n, perm) == -1)
1468 1467 (void) error(63);
1469 1468 if (write(io, genbuf, n) != n)
1470 1469 (void) error(29);
1471 1470 nib = LBSIZE - 1;
1472 1471 fp = genbuf;
1473 1472 }
1474 1473 if (dol->cur == 0L)break; /* Allow write of null file */
1475 1474 count++;
1476 1475 if ((*fp++ = *lp++) == 0) {
1477 1476 fp[-1] = '\n';
1478 1477 break;
1479 1478 }
1480 1479 }
1481 1480 } while (a1 <= addr2);
1482 1481 n = fp-genbuf;
1483 1482 if (kflag)
1484 1483 if (run_crypt(count-n, genbuf, n, perm) == -1)
1485 1484 (void) error(63);
1486 1485 if (write(io, genbuf, n) != n)
1487 1486 (void) error(29);
1488 1487 }
1489 1488
1490 1489 static void
1491 1490 append(int (*f)(void), LINE a)
1492 1491 {
1493 1492 LINE a1, a2, rdot;
1494 1493 long tl;
1495 1494
1496 1495 nline = 0;
1497 1496 dot = a;
1498 1497 while ((*f)() == 0) {
1499 1498 if (dol >= endcore) {
1500 1499 if ((int)sbrk(512 * sizeof (struct lin)) == -1) {
1501 1500 lastc = '\n';
1502 1501 (void) error(30);
1503 1502 }
1504 1503 endcore += 512;
1505 1504 }
1506 1505 tl = putline();
1507 1506 nline++;
1508 1507 a1 = ++dol;
1509 1508 a2 = a1+1;
1510 1509 rdot = ++dot;
1511 1510 while (a1 > rdot)
1512 1511 (--a2)->cur = (--a1)->cur;
1513 1512 rdot->cur = tl;
1514 1513 }
1515 1514 }
1516 1515
1517 1516 static void
1518 1517 unixcom(void)
1519 1518 {
1520 1519 void (*savint)();
1521 1520 pid_t pid, rpid;
1522 1521 int retcode;
1523 1522 static char savcmd[LBSIZE]; /* last command */
1524 1523 char curcmd[LBSIZE]; /* current command */
1525 1524 char *psavcmd, *pcurcmd, *psavedfile;
1526 1525 int endflg = 1, shflg = 0;
1527 1526 wchar_t c;
1528 1527 int len;
1529 1528
1530 1529 setnoaddr();
1531 1530 if (rflg)
1532 1531 (void) error(6);
1533 1532 pcurcmd = curcmd;
1534 1533 /* read command til end */
1535 1534
1536 1535 /*
1537 1536 * a '!' found in beginning of command is replaced with the saved
1538 1537 * command. a '%' found in command is replaced with the current
1539 1538 * filename
1540 1539 */
1541 1540
1542 1541 c = getchr();
1543 1542 if (c == '!') {
1544 1543 if (savcmd[0] == 0)
1545 1544 (void) error(56);
1546 1545 else {
1547 1546 psavcmd = savcmd;
1548 1547 while (*pcurcmd++ = *psavcmd++)
1549 1548 ;
1550 1549 --pcurcmd;
1551 1550 shflg = 1;
1552 1551 }
1553 1552 } else
1554 1553 UNGETC(c); /* put c back */
1555 1554 while (endflg == 1) {
1556 1555 while ((c = get_wchr()) != '\n' && c != '%' && c != '\\') {
1557 1556 if ((len = wctomb(pcurcmd, c)) <= 0) {
1558 1557 *pcurcmd = (unsigned char)c;
1559 1558 len = 1;
1560 1559 }
1561 1560 pcurcmd += len;
1562 1561 }
1563 1562
1564 1563 if (c == '%') {
1565 1564 if (savedfile[0] == 0)
1566 1565 (void) error(21);
1567 1566 else {
1568 1567 psavedfile = savedfile;
1569 1568 while (pcurcmd < curcmd + LBSIZE &&
1570 1569 (*pcurcmd++ = *psavedfile++))
1571 1570 ;
1572 1571 --pcurcmd;
1573 1572 shflg = 1;
1574 1573 }
1575 1574 } else if (c == '\\') {
1576 1575 c = get_wchr();
1577 1576 if (c != '%')
1578 1577 *pcurcmd++ = '\\';
1579 1578 if ((len = wctomb(pcurcmd, c)) <= 0) {
1580 1579 *pcurcmd = (unsigned char)c;
1581 1580 len = 1;
1582 1581 }
1583 1582 pcurcmd += len;
1584 1583 }
1585 1584 else
1586 1585 /* end of command hit */
1587 1586 endflg = 0;
1588 1587 }
1589 1588 *pcurcmd++ = 0;
1590 1589 if (shflg == 1)
1591 1590 puts(curcmd);
1592 1591 /* save command */
1593 1592 strcpy(savcmd, curcmd);
1594 1593
1595 1594 if ((pid = fork()) == 0) {
1596 1595 signal(SIGHUP, oldhup);
1597 1596 signal(SIGQUIT, oldquit);
1598 1597 close(tfile);
1599 1598 execlp(_PATH_BSHELL, "sh", "-c", curcmd, NULL);
1600 1599 exit(0100);
1601 1600 }
1602 1601 savint = signal(SIGINT, SIG_IGN);
1603 1602 while ((rpid = wait(&retcode)) != pid && rpid != (pid_t)-1)
1604 1603 ;
1605 1604 signal(SIGINT, savint);
1606 1605 if (vflag) puts("!");
1607 1606 }
1608 1607
1609 1608 static void
1610 1609 quit(int sig)
1611 1610 {
1612 1611 if (vflag && fchange) {
1613 1612 fchange = 0;
1614 1613 if (flag28) {
1615 1614 flag28 = 0;
1616 1615 (void) error(62);
1617 1616 }
1618 1617
1619 1618 /*
1620 1619 * For case where user reads in BOTH a good
1621 1620 * file & a bad file
1622 1621 */
1623 1622 (void) error(1);
1624 1623 }
1625 1624 unlink(tfname);
1626 1625 if (kflag)
1627 1626 crypt_close(perm);
1628 1627 if (xtflag)
1629 1628 crypt_close(tperm);
1630 1629 exit(errcnt? 2: 0);
1631 1630 }
1632 1631
1633 1632 static void
1634 1633 delete(void)
1635 1634 {
1636 1635 setdot();
1637 1636 newline();
1638 1637 nonzero();
1639 1638 if (!globflg)
1640 1639 save();
1641 1640 rdelete(addr1, addr2);
1642 1641 }
1643 1642
1644 1643 static void
1645 1644 rdelete(LINE ad1, LINE ad2)
1646 1645 {
1647 1646 LINE a1, a2, a3;
1648 1647
1649 1648 a1 = ad1;
1650 1649 a2 = ad2+1;
1651 1650 a3 = dol;
1652 1651 dol -= a2 - a1;
1653 1652 do {
1654 1653 (a1++)->cur = (a2++)->cur;
1655 1654 } while (a2 <= a3);
1656 1655 a1 = ad1;
1657 1656 if (a1 > dol)
1658 1657 a1 = dol;
1659 1658 dot = a1;
1660 1659 fchange = 1;
1661 1660 }
1662 1661
1663 1662 static void
1664 1663 gdelete(void)
1665 1664 {
1666 1665 LINE a1, a2, a3;
1667 1666
1668 1667 a3 = dol;
1669 1668 for (a1 = zero+1; (a1->cur&01) == 0; a1++)
1670 1669 if (a1 >= a3)
1671 1670 return;
1672 1671 for (a2 = a1 + 1; a2 <= a3; ) {
1673 1672 if (a2->cur & 01) {
1674 1673 a2++;
1675 1674 dot = a1;
1676 1675 } else
1677 1676 (a1++)->cur = (a2++)->cur;
1678 1677 }
1679 1678 dol = a1-1;
1680 1679 if (dot > dol)
1681 1680 dot = dol;
1682 1681 fchange = 1;
1683 1682 }
1684 1683
1685 1684 static char *
1686 1685 getaline(long tl)
1687 1686 {
1688 1687 char *bp, *lp;
1689 1688 int nl;
1690 1689
1691 1690 lp = linebuf;
1692 1691 bp = getblock(tl, READ);
1693 1692 nl = nleft;
1694 1693 tl &= ~0377;
1695 1694 while (*lp++ = *bp++)
1696 1695 if (--nl == 0) {
1697 1696 bp = getblock(tl += 0400, READ);
1698 1697 nl = nleft;
1699 1698 }
1700 1699 return (linebuf);
1701 1700 }
1702 1701
1703 1702 static long
1704 1703 putline(void)
1705 1704 {
1706 1705 char *bp, *lp;
1707 1706 int nl;
1708 1707 long tl;
1709 1708
1710 1709 fchange = 1;
1711 1710 lp = linebuf;
1712 1711 tl = tline;
1713 1712 bp = getblock(tl, WRITE);
1714 1713 nl = nleft;
1715 1714 tl &= ~0377;
1716 1715 while (*bp = *lp++) {
1717 1716 if (*bp++ == '\n') {
1718 1717 *--bp = 0;
1719 1718 linebp = lp;
1720 1719 break;
1721 1720 }
1722 1721 if (--nl == 0) {
1723 1722 bp = getblock(tl += 0400, WRITE);
1724 1723 nl = nleft;
1725 1724 }
1726 1725 }
1727 1726 nl = tline;
1728 1727 tline += (((lp-linebuf)+03)>>1)&077776;
1729 1728 return (nl);
1730 1729 }
1731 1730
1732 1731 static char *
1733 1732 getblock(long atl, long iof)
1734 1733 {
1735 1734 int bno, off;
1736 1735 char *p1, *p2;
1737 1736 int n;
1738 1737
1739 1738 bno = atl >> 8;
1740 1739 off = (atl<<1)&0774;
1741 1740
1742 1741 /* bno is limited to 16 bits */
1743 1742 if (bno >= 65535) {
1744 1743 lastc = '\n';
1745 1744 (void) error(31);
1746 1745 }
1747 1746 nleft = 512 - off;
1748 1747 if (bno == iblock) {
1749 1748 ichanged |= iof;
1750 1749 return (ibuff+off);
1751 1750 }
1752 1751 if (bno == oblock)
1753 1752 return (obuff+off);
1754 1753 if (iof == READ) {
1755 1754 if (ichanged) {
1756 1755 if (xtflag)
1757 1756 if (run_crypt(0L, ibuff, 512, tperm) == -1)
1758 1757 (void) error(63);
1759 1758 blkio(iblock, ibuff, write);
1760 1759 }
1761 1760 ichanged = 0;
1762 1761 iblock = bno;
1763 1762 blkio(bno, ibuff, read);
1764 1763 if (xtflag)
1765 1764 if (run_crypt(0L, ibuff, 512, tperm) == -1)
1766 1765 (void) error(63);
1767 1766 return (ibuff+off);
1768 1767 }
1769 1768 if (oblock >= 0) {
1770 1769 if (xtflag) {
1771 1770 p1 = obuff;
1772 1771 p2 = crbuf;
1773 1772 n = 512;
1774 1773 while (n--)
1775 1774 *p2++ = *p1++;
1776 1775 if (run_crypt(0L, crbuf, 512, tperm) == -1)
1777 1776 (void) error(63);
1778 1777 blkio(oblock, crbuf, write);
1779 1778 } else
1780 1779 blkio(oblock, obuff, write);
1781 1780 }
1782 1781 oblock = bno;
1783 1782 return (obuff+off);
1784 1783 }
1785 1784
1786 1785 static void
1787 1786 blkio(int b, char *buf, ssize_t (*iofcn)())
1788 1787 {
1789 1788 lseek(tfile, (long)b<<9, 0);
1790 1789 if ((*iofcn)(tfile, buf, 512) != 512) {
1791 1790 if (dol != zero)
1792 1791 (void) error(32); /* Bypass this if writing null file */
1793 1792 }
1794 1793 }
1795 1794
1796 1795 static void
1797 1796 init(void)
1798 1797 {
1799 1798 long *markp;
1800 1799 mode_t omask;
1801 1800
1802 1801 if (tfile != -1) {
1803 1802 (void) close(tfile);
1804 1803 (void) unlink(tfname);
1805 1804 }
1806 1805
1807 1806 tline = 2;
1808 1807 for (markp = names; markp < &names[26]; )
1809 1808 *markp++ = 0L;
1810 1809 subnewa = 0L;
1811 1810 anymarks = 0;
1812 1811 iblock = -1;
1813 1812 oblock = -1;
1814 1813 ichanged = 0;
1815 1814 initflg = 1;
1816 1815 omask = umask(0);
1817 1816
1818 1817 if ((tfile = open(tfname, O_CREAT|O_EXCL|O_RDWR,
1819 1818 S_IRUSR|S_IWUSR)) < 0) {
1820 1819 puts(gettext(msgtab[70]));
1821 1820 exit(2);
1822 1821 }
1823 1822
1824 1823 umask(omask);
1825 1824 if (xflag) {
1826 1825 xtflag = 1;
1827 1826 if (tpermflag)
1828 1827 (void) crypt_close(tperm);
1829 1828 tpermflag = 1;
1830 1829 if (makekey(tperm)) {
1831 1830 xtflag = 0;
1832 1831 puts(gettext(msgtab[65]));
1833 1832 }
1834 1833 }
1835 1834 brk((char *)fendcore);
1836 1835 dot = zero = dol = savdot = savdol = fendcore;
1837 1836 flag28 = save28 = 0;
1838 1837 endcore = fendcore - sizeof (struct lin);
1839 1838 }
1840 1839
1841 1840 static void
1842 1841 global(int k)
1843 1842 {
1844 1843 char *gp;
1845 1844 wchar_t l;
1846 1845 char multic[MB_LEN_MAX];
1847 1846 wchar_t c;
1848 1847 LINE a1;
1849 1848 char globuf[LBSIZE];
1850 1849 int n;
1851 1850 int len;
1852 1851
1853 1852 if (globp)
1854 1853 (void) error(33);
1855 1854 setall();
1856 1855 nonzero();
1857 1856 if ((n = _mbftowc(multic, &l, getchr, &peekc)) <= 0)
1858 1857 (void) error(67);
1859 1858 if (l == '\n')
1860 1859 (void) error(19);
1861 1860 save();
1862 1861 comple(l);
1863 1862 gp = globuf;
1864 1863 while ((c = get_wchr()) != '\n') {
1865 1864 if (c == EOF)
1866 1865 (void) error(19);
1867 1866
1868 1867 /* '\\' has special meaning only if preceding a '\n' */
1869 1868 if (c == '\\') {
1870 1869 c = get_wchr();
1871 1870 if (c != '\n')
1872 1871 *gp++ = '\\';
1873 1872 }
1874 1873 if ((gp + (unsigned int)MB_CUR_MAX) >= &globuf[LBSIZE-1])
1875 1874 (void) error(34);
1876 1875 if ((len = wctomb(gp, c)) <= 0) {
1877 1876 *gp = (unsigned char)c;
1878 1877 len = 1;
1879 1878 }
1880 1879 gp += len;
1881 1880 }
1882 1881 if (gp == globuf)
1883 1882 *gp++ = 'p';
1884 1883 *gp++ = '\n';
1885 1884 *gp++ = 0;
1886 1885 for (a1 = zero; a1 <= dol; a1++) {
1887 1886 a1->cur &= ~01;
1888 1887 if (a1 >= addr1 && a1 <= addr2 && execute(0, a1) == k)
1889 1888 a1->cur |= 01;
1890 1889 }
1891 1890 /*
1892 1891 * Special case: g/.../d (avoid n^2 algorithm)
1893 1892 */
1894 1893 if (globuf[0] == 'd' && globuf[1] == '\n' && globuf[2] == '\0') {
1895 1894 gdelete();
1896 1895 return;
1897 1896 }
1898 1897 for (a1 = zero; a1 <= dol; a1++) {
1899 1898 if (a1->cur & 01) {
1900 1899 a1->cur &= ~01;
1901 1900 dot = a1;
1902 1901 globp = globuf;
1903 1902 globflg = 1;
1904 1903 commands();
1905 1904 globflg = 0;
1906 1905 a1 = zero;
1907 1906 }
1908 1907 }
1909 1908 }
1910 1909
1911 1910 static void
1912 1911 join(void)
1913 1912 {
1914 1913 char *gp, *lp;
1915 1914 LINE a1;
1916 1915
1917 1916 if (addr1 == addr2)
1918 1917 return;
1919 1918 gp = genbuf;
1920 1919 for (a1 = addr1; a1 <= addr2; a1++) {
1921 1920 lp = getaline(a1->cur);
1922 1921 while (*gp = *lp++)
1923 1922 if (gp++ > &genbuf[LBSIZE-1])
1924 1923 (void) error(27);
1925 1924 }
1926 1925 lp = linebuf;
1927 1926 gp = genbuf;
1928 1927 while (*lp++ = *gp++)
1929 1928 ;
1930 1929 addr1->cur = putline();
1931 1930 if (addr1 < addr2)
1932 1931 rdelete(addr1+1, addr2);
1933 1932 dot = addr1;
1934 1933 }
1935 1934
1936 1935 static void
1937 1936 substitute(int inglob)
1938 1937 {
1939 1938 int nl;
1940 1939 LINE a1;
1941 1940 long *markp;
1942 1941 int ingsav; /* For saving arg. */
1943 1942
1944 1943 ingsav = inglob;
1945 1944 ocerr2 = 0;
1946 1945 gsubf = compsub();
1947 1946 for (a1 = addr1; a1 <= addr2; a1++) {
1948 1947 if (execute(0, a1) == 0)
1949 1948 continue;
1950 1949 numpass = 0;
1951 1950 ocerr1 = 0;
1952 1951 inglob |= 01;
1953 1952 dosub();
1954 1953 if (gsubf) {
1955 1954 while (*loc2) {
1956 1955 if (execute(1, (LINE)0) == 0)
1957 1956 break;
1958 1957 dosub();
1959 1958 }
1960 1959 }
1961 1960 if (ocerr1 == 0)continue; /* Don't put out-not changed. */
1962 1961 subnewa = putline();
1963 1962 a1->cur &= ~01;
1964 1963 if (anymarks) {
1965 1964 for (markp = names; markp < &names[26]; markp++)
1966 1965 if (*markp == a1->cur)
1967 1966 *markp = subnewa;
1968 1967 }
1969 1968 a1->cur = subnewa;
1970 1969 append(getsub, a1);
1971 1970 nl = nline;
1972 1971 a1 += nl;
1973 1972 addr2 += nl;
1974 1973 }
1975 1974 if (ingsav)
1976 1975 return; /* Was in global-no error msg allowed. */
1977 1976 if (inglob == 0)
1978 1977 (void) error(35); /* Not in global, but not found. */
1979 1978 if (ocerr2 == 0)
1980 1979 (void) error(35); /* RE found, but occurrence match failed. */
1981 1980 }
1982 1981
1983 1982 static int
1984 1983 compsub(void)
1985 1984 {
1986 1985 int c;
1987 1986 wchar_t seof;
1988 1987 char *p;
1989 1988 char multic[MB_LEN_MAX];
1990 1989 int n;
1991 1990 static char remem[RHSIZE];
1992 1991 static int remflg = -1;
1993 1992 int i;
1994 1993
1995 1994 if ((n = _mbftowc(multic, &seof, getchr, &peekc)) <= 0)
1996 1995 (void) error(67);
1997 1996 if (seof == '\n' || seof == ' ')
1998 1997 (void) error(36);
1999 1998 comple(seof);
2000 1999 p = rhsbuf;
2001 2000 for (;;) {
2002 2001 wchar_t cl;
2003 2002 if ((n = _mbftowc(multic, &cl, getchr, &peekc)) <= 0)
2004 2003 (void) error(67);
2005 2004 if (cl == '\\') {
2006 2005 *p++ = '\\';
2007 2006 if (p >= &rhsbuf[RHSIZE])
2008 2007 (void) error(38);
2009 2008 if ((n = _mbftowc(multic, &cl, getchr, &peekc)) <= 0)
2010 2009 (void) error(67);
2011 2010 } else if (cl == '\n') {
2012 2011 if (nodelim == 1) {
2013 2012 nodelim = 0;
2014 2013 (void) error(36);
2015 2014 }
2016 2015 if (!(globp && globp[0])) {
2017 2016 UNGETC('\n');
2018 2017 pflag++;
2019 2018 break;
2020 2019 }
2021 2020 } else if (cl == seof)
2022 2021 break;
2023 2022 if (p + n > &rhsbuf[RHSIZE])
2024 2023 (void) error(38);
2025 2024 (void) strncpy(p, multic, n);
2026 2025 p += n;
2027 2026 }
2028 2027 *p++ = 0;
2029 2028 if (rhsbuf[0] == '%' && rhsbuf[1] == 0)
2030 2029 /*
2031 2030 * If there isn't a remembered string, it is an error;
2032 2031 * otherwise the right hand side is the previous right
2033 2032 * hand side.
2034 2033 */
2035 2034
2036 2035 if (remflg == -1)
2037 2036 (void) error(55);
2038 2037 else
2039 2038 strcpy(rhsbuf, remem);
2040 2039 else {
2041 2040 strcpy(remem, rhsbuf);
2042 2041 remflg = 0;
2043 2042 }
2044 2043 c = 0;
2045 2044 peekc = getchr(); /* Gets char after third delimiter. */
2046 2045 if (peekc == 'g') {
2047 2046 c = LBSIZE; peekc = 0;
2048 2047 }
2049 2048 if (peekc >= '1' && peekc <= '9') {
2050 2049 c = peekc-'0';
2051 2050 peekc = 0; /* Allows getchr() to get next char. */
2052 2051 while (1) {
2053 2052 i = getchr();
2054 2053 if (i < '0' || i > '9')
2055 2054 break;
2056 2055 c = c*10 + i-'0';
2057 2056 if (c > LBSIZE-1)
2058 2057 (void) error(20); /* "Illegal suffix" */
2059 2058 }
2060 2059 peekc = i; /* Effectively an unget. */
2061 2060 }
2062 2061 newline();
2063 2062 return (c);
2064 2063
2065 2064 /*
2066 2065 * Returns occurrence value. 0 & 1 both do first occurrence
2067 2066 * only: c = 0 if ordinary substitute; c = 1
2068 2067 * if use 1 in global sub(s/a/b/1). 0 in global form is illegal.
2069 2068 */
2070 2069 }
2071 2070
2072 2071 static int
2073 2072 getsub(void)
2074 2073 {
2075 2074 char *p1, *p2;
2076 2075
2077 2076 p1 = linebuf;
2078 2077 if ((p2 = linebp) == 0)
2079 2078 return (EOF);
2080 2079 while (*p1++ = *p2++)
2081 2080 ;
2082 2081 linebp = 0;
2083 2082 return (0);
2084 2083 }
2085 2084
2086 2085 static void
2087 2086 dosub(void)
2088 2087 {
2089 2088 char *lp, *sp, *rp;
2090 2089 int c;
2091 2090
2092 2091 if (gsubf > 0 && gsubf < LBSIZE) {
2093 2092 numpass++;
2094 2093 if (gsubf != numpass)
2095 2094 return;
2096 2095 }
2097 2096 ocerr1++;
2098 2097 ocerr2++;
2099 2098 lp = linebuf;
2100 2099 sp = genbuf;
2101 2100 rp = rhsbuf;
2102 2101 while (lp < loc1)
2103 2102 *sp++ = *lp++;
2104 2103 while (c = *rp++) {
2105 2104 if (c == '&') {
2106 2105 sp = place(sp, loc1, loc2);
2107 2106 continue;
2108 2107 } else if (c == '\\') {
2109 2108 c = *rp++;
2110 2109 if (c >= '1' && c < nbra + '1') {
2111 2110 sp = place(sp, braslist[c-'1'],
2112 2111 braelist[c-'1']);
2113 2112 continue;
2114 2113 }
2115 2114 }
2116 2115 *sp++ = c;
2117 2116 if (sp >= &genbuf[LBSIZE])
2118 2117 (void) error(27);
2119 2118 }
2120 2119 lp = loc2;
2121 2120 loc2 = sp - genbuf + linebuf;
2122 2121 while (*sp++ = *lp++)
2123 2122 if (sp >= &genbuf[LBSIZE])
2124 2123 (void) error(27);
2125 2124 lp = linebuf;
2126 2125 sp = genbuf;
2127 2126 while (*lp++ = *sp++)
2128 2127 ;
2129 2128 }
2130 2129
2131 2130 static char *
2132 2131 place(char *sp, char *l1, char *l2)
2133 2132 {
2134 2133
2135 2134 while (l1 < l2) {
2136 2135 *sp++ = *l1++;
2137 2136 if (sp >= &genbuf[LBSIZE])
2138 2137 (void) error(27);
2139 2138 }
2140 2139 return (sp);
2141 2140 }
2142 2141
2143 2142 static void
2144 2143 comple(wchar_t seof)
2145 2144 {
2146 2145 int cclass = 0;
2147 2146 wchar_t c;
2148 2147 int n;
2149 2148 char *cp = genbuf;
2150 2149 char multic[MB_LEN_MAX];
2151 2150
2152 2151 while (1) {
2153 2152 if ((n = _mbftowc(multic, &c, getchr, &peekc)) < 0)
2154 2153 error1(67);
2155 2154 if (n == 0 || c == '\n') {
2156 2155 if (cclass)
2157 2156 error1(49);
2158 2157 else
2159 2158 break;
2160 2159 }
2161 2160 if (c == seof && !cclass)
2162 2161 break;
2163 2162 if (cclass && c == ']') {
2164 2163 cclass = 0;
2165 2164 if (cp > &genbuf[LBSIZE-1])
2166 2165 error1(50);
2167 2166 *cp++ = ']';
2168 2167 continue;
2169 2168 }
2170 2169 if (c == '[' && !cclass) {
2171 2170 cclass = 1;
2172 2171 if (cp > &genbuf[LBSIZE-1])
2173 2172 error1(50);
2174 2173 *cp++ = '[';
2175 2174 if ((n = _mbftowc(multic, &c, getchr, &peekc)) < 0)
2176 2175 error1(67);
2177 2176 if (n == 0 || c == '\n')
2178 2177 error1(49);
2179 2178 }
2180 2179 if (c == '\\' && !cclass) {
2181 2180 if (cp > &genbuf[LBSIZE-1])
2182 2181 error1(50);
2183 2182 *cp++ = '\\';
2184 2183 if ((n = _mbftowc(multic, &c, getchr, &peekc)) < 0)
2185 2184 error1(67);
2186 2185 if (n == 0 || c == '\n')
2187 2186 error1(36);
2188 2187 }
2189 2188 if (cp + n > &genbuf[LBSIZE-1])
2190 2189 error1(50);
2191 2190 (void) strncpy(cp, multic, n);
2192 2191 cp += n;
2193 2192 }
2194 2193 *cp = '\0';
2195 2194 if (n != 0 && c == '\n')
2196 2195 UNGETC('\n');
2197 2196 if (n == 0 || c == '\n')
2198 2197 nodelim = 1;
2199 2198
2200 2199 /*
2201 2200 * NULL RE: do not compile a null regular expression; but process
2202 2201 * input with last regular expression encountered
2203 2202 */
2204 2203
2205 2204 if (genbuf[0] != '\0') {
2206 2205 if (expbuf)
2207 2206 free(expbuf);
2208 2207 expbuf = compile(genbuf, (char *)0, (char *)0);
2209 2208 }
2210 2209 if (regerrno)
2211 2210 error1(regerrno);
2212 2211 }
2213 2212
2214 2213 static void
2215 2214 move(int cflag)
2216 2215 {
2217 2216 LINE adt, ad1, ad2;
2218 2217
2219 2218 setdot();
2220 2219 nonzero();
2221 2220 if ((adt = address()) == 0)
2222 2221 (void) error(39);
2223 2222 newline();
2224 2223 if (!globflg) save();
2225 2224 if (cflag) {
2226 2225 ad1 = dol;
2227 2226 append(getcopy, ad1++);
2228 2227 ad2 = dol;
2229 2228 } else {
2230 2229 ad2 = addr2;
2231 2230 for (ad1 = addr1; ad1 <= ad2; )
2232 2231 (ad1++)->cur &= ~01;
2233 2232 ad1 = addr1;
2234 2233 }
2235 2234 ad2++;
2236 2235 if (adt < ad1) {
2237 2236 dot = adt + (ad2-ad1);
2238 2237 if ((++adt) == ad1)
2239 2238 return;
2240 2239 reverse(adt, ad1);
2241 2240 reverse(ad1, ad2);
2242 2241 reverse(adt, ad2);
2243 2242 } else if (adt >= ad2) {
2244 2243 dot = adt++;
2245 2244 reverse(ad1, ad2);
2246 2245 reverse(ad2, adt);
2247 2246 reverse(ad1, adt);
2248 2247 } else
2249 2248 (void) error(39);
2250 2249 fchange = 1;
2251 2250 }
2252 2251
2253 2252 static void
2254 2253 reverse(LINE a1, LINE a2)
2255 2254 {
2256 2255 long t;
2257 2256
2258 2257 for (;;) {
2259 2258 t = (--a2)->cur;
2260 2259 if (a2 <= a1)
2261 2260 return;
2262 2261 a2->cur = a1->cur;
2263 2262 (a1++)->cur = t;
2264 2263 }
2265 2264 }
2266 2265
2267 2266 static int
2268 2267 getcopy(void)
2269 2268 {
2270 2269
2271 2270 if (addr1 > addr2)
2272 2271 return (EOF);
2273 2272 (void) getaline((addr1++)->cur);
2274 2273 return (0);
2275 2274 }
2276 2275
2277 2276
2278 2277 /*
2279 2278 * Handles error code returned from comple() routine: regular expression
2280 2279 * compile and match routines
2281 2280 */
2282 2281
2283 2282 static void
2284 2283 error1(int code)
2285 2284 {
2286 2285 nbra = 0;
2287 2286 (void) error(code);
2288 2287 }
2289 2288
2290 2289
2291 2290 static int
2292 2291 execute(int gf, LINE addr)
2293 2292 {
2294 2293 char *p1;
2295 2294 int c;
2296 2295
2297 2296 for (c = 0; c < nbra; c++) {
2298 2297 braslist[c] = 0;
2299 2298 braelist[c] = 0;
2300 2299 }
2301 2300 if (gf)
2302 2301 locs = p1 = loc2;
2303 2302 else {
2304 2303 if (addr == zero)
2305 2304 return (0);
2306 2305 p1 = getaline(addr->cur);
2307 2306 locs = 0;
2308 2307 }
2309 2308 return (step(p1, expbuf));
2310 2309 }
2311 2310
2312 2311
2313 2312 static void
2314 2313 putd()
2315 2314 {
2316 2315 int r;
2317 2316
2318 2317 r = (int)(count%10);
2319 2318 count /= 10;
2320 2319 if (count)
2321 2320 putd();
2322 2321 putchr(r + '0');
2323 2322 }
2324 2323
2325 2324
2326 2325 int
2327 2326 puts(const char *sp)
2328 2327 {
2329 2328 int n;
2330 2329 wchar_t c;
2331 2330 int sz, i;
2332 2331 if (fss.Ffill && (listf == 0)) {
2333 2332
2334 2333 /* deliberate attempt to remove constness of sp because */
2335 2334 /* it needs to be expanded */
2336 2335
2337 2336 if ((i = expnd((char *)sp, funny, &sz, &fss)) == -1) {
2338 2337 write(1, funny, fss.Flim & 0377);
2339 2338 putchr('\n');
2340 2339 write(1, gettext("too long"),
2341 2340 strlen(gettext("too long")));
2342 2341 }
2343 2342 else
2344 2343 write(1, funny, sz);
2345 2344 putchr('\n');
2346 2345 if (i == -2)
2347 2346 write(1, gettext("tab count\n"),
2348 2347 strlen(gettext("tab count\n")));
2349 2348 return (0);
2350 2349 }
2351 2350 col = 0;
2352 2351 while (*sp) {
2353 2352 n = mbtowc(&c, sp, MB_LEN_MAX);
2354 2353 if (listf) {
2355 2354 if (n < 1)
2356 2355 (void) error(28);
2357 2356 else if (n == 1)
2358 2357 putchr((unsigned char)*sp++);
2359 2358 else {
2360 2359 sp += n;
2361 2360 putwchr(c);
2362 2361 }
2363 2362 } else {
2364 2363 putchr((unsigned char)*sp++);
2365 2364 }
2366 2365 }
2367 2366 #ifndef XPG6
2368 2367 if (listf)
2369 2368 putchr('$'); /* end of line is marked with a $ */
2370 2369 #else
2371 2370 if (listf) {
2372 2371 /* xpg6 - ensure that the end of line $ is not preceeded with a "\" */
2373 2372 /* by doing a putchr() with listf=0, thereby avoiding the $ case */
2374 2373 /* statement in putchr() */
2375 2374 listf = 0;
2376 2375 putchr('$'); /* end of line is marked with a $ */
2377 2376 listf++;
2378 2377 }
2379 2378 #endif
2380 2379 putchr('\n');
2381 2380 return (1);
2382 2381 }
2383 2382
2384 2383
2385 2384 static void
2386 2385 putwchr(wchar_t ac)
2387 2386 {
2388 2387 char buf[MB_LEN_MAX], *p;
2389 2388 char *lp;
2390 2389 wchar_t c;
2391 2390 short len;
2392 2391
2393 2392 lp = linp;
2394 2393 c = ac;
2395 2394 if (listf) {
2396 2395 if (!iswprint(c)) {
2397 2396 p = &buf[0];
2398 2397 if ((len = wctomb(p, c)) <= 0) {
2399 2398 *p = (unsigned char)c;
2400 2399 len = 1;
2401 2400 };
2402 2401 while (len--) {
2403 2402 if (col + 4 >= 72) {
2404 2403 col = 0;
2405 2404 *lp++ = '\\';
2406 2405 *lp++ = '\n';
2407 2406 }
2408 2407 (void) sprintf(lp, "\\%03o",
2409 2408 *(unsigned char *)p++);
2410 2409 col += 4;
2411 2410 lp += 4;
2412 2411 }
2413 2412 } else {
2414 2413 if ((len = wcwidth(c)) <= 0)
2415 2414 len = 0;
2416 2415 if (col + len >= 72) {
2417 2416 col = 0;
2418 2417 *lp++ = '\\';
2419 2418 *lp++ = '\n';
2420 2419 }
2421 2420 col += len;
2422 2421 if ((len = wctomb(lp, c)) <= 0) {
2423 2422 *lp = (unsigned char)c;
2424 2423 len = 1;
2425 2424 }
2426 2425 lp += len;
2427 2426 }
2428 2427 } else {
2429 2428 if ((len = wctomb(lp, c)) <= 0) {
2430 2429 *lp = (unsigned char)c;
2431 2430 len = 1;
2432 2431 }
2433 2432 lp += len;
2434 2433 }
2435 2434 if (c == '\n' || lp >= &line[64]) {
2436 2435 linp = line;
2437 2436 len = lp - line;
2438 2437 write(1, line, len);
2439 2438 return;
2440 2439 }
2441 2440 linp = lp;
2442 2441 }
2443 2442
2444 2443
2445 2444 static void
2446 2445 putchr(unsigned char c)
2447 2446 {
2448 2447 char *lp;
2449 2448 int len;
2450 2449
2451 2450 lp = linp;
2452 2451 if (listf && c != '\n') {
2453 2452 switch (c) {
2454 2453 case '\\' :
2455 2454 *lp++ = '\\';
2456 2455 *lp++ = '\\';
2457 2456 col += 2;
2458 2457 break;
2459 2458 case '\007' :
2460 2459 *lp++ = '\\';
2461 2460 *lp++ = 'a';
2462 2461 col += 2;
2463 2462 break;
2464 2463 case '\b' :
2465 2464 *lp++ = '\\';
2466 2465 *lp++ = 'b';
2467 2466 col += 2;
2468 2467 break;
2469 2468 case '\f' :
2470 2469 *lp++ = '\\';
2471 2470 *lp++ = 'f';
2472 2471 col += 2;
2473 2472 break;
2474 2473 case '\r' :
2475 2474 *lp++ = '\\';
2476 2475 *lp++ = 'r';
2477 2476 col += 2;
2478 2477 break;
2479 2478 case '\t' :
2480 2479 *lp++ = '\\';
2481 2480 *lp++ = 't';
2482 2481 col += 2;
2483 2482 break;
2484 2483 case '\v' :
2485 2484 *lp++ = '\\';
2486 2485 *lp++ = 'v';
2487 2486 col += 2;
2488 2487 break;
2489 2488 #ifdef XPG6
2490 2489 /* if $ characters are within the line preceed with \ */
2491 2490 case '$' :
2492 2491 *lp++ = '\\';
2493 2492 *lp++ = '$';
2494 2493 col += 2;
2495 2494 break;
2496 2495 #endif
2497 2496 default:
2498 2497 if (isprint(c)) {
2499 2498 *lp++ = c;
2500 2499 col += 1;
2501 2500 } else {
2502 2501 (void) sprintf(lp, "\\%03o", c);
2503 2502 col += 4;
2504 2503 lp += 4;
2505 2504 }
2506 2505 break;
2507 2506 }
2508 2507
2509 2508 /*
2510 2509 * long lines are folded w/ pt of folding indicated by writing
2511 2510 * backslash/newline character
2512 2511 */
2513 2512
2514 2513 if (col + 1 >= 72) {
2515 2514 col = 0;
2516 2515 *lp++ = '\\';
2517 2516 *lp++ = '\n';
2518 2517 }
2519 2518 } else
2520 2519 *lp++ = c;
2521 2520 if (c == '\n' || lp >= &line[64]) {
2522 2521 linp = line;
2523 2522 len = lp - line;
2524 2523 (void) write(1, line, len);
2525 2524 return;
2526 2525 }
2527 2526 linp = lp;
2528 2527 }
2529 2528
2530 2529
2531 2530 static char *
2532 2531 getkey(const char *prompt)
2533 2532 {
2534 2533 struct termio b;
2535 2534 int save;
2536 2535 void (*sig)();
2537 2536 static char key[KSIZE+1];
2538 2537 char *p;
2539 2538 int c;
2540 2539
2541 2540 sig = signal(SIGINT, SIG_IGN);
2542 2541 ioctl(0, TCGETA, &b);
2543 2542 save = b.c_lflag;
2544 2543 b.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL);
2545 2544 ioctl(0, TCSETAW, &b);
2546 2545 write(1, gettext(prompt), strlen(gettext(prompt)));
2547 2546 p = key;
2548 2547 while (((c = getchr()) != EOF) && (c != '\n')) {
2549 2548 if (p < &key[KSIZE])
2550 2549 *p++ = c;
2551 2550 }
2552 2551 *p = 0;
2553 2552 write(1, "\n", 1);
2554 2553 b.c_lflag = save;
2555 2554 ioctl(0, TCSETAW, &b);
2556 2555 signal(SIGINT, sig);
2557 2556 return (key);
2558 2557 }
2559 2558
2560 2559
2561 2560 static void
2562 2561 globaln(int k)
2563 2562 {
2564 2563 char *gp;
2565 2564 int c;
2566 2565 int n;
2567 2566 wchar_t cl;
2568 2567 LINE a1;
2569 2568 int nfirst;
2570 2569 char globuf[LBSIZE];
2571 2570 char multic[MB_LEN_MAX];
2572 2571 int len;
2573 2572 int pflag_save = 0;
2574 2573 int listf_save = 0;
2575 2574 int listn_save = 0;
2576 2575
2577 2576 if (globp)
2578 2577 (void) error(33);
2579 2578 setall();
2580 2579 nonzero();
2581 2580 if ((n = _mbftowc(multic, &cl, getchr, &peekc)) <= 0)
2582 2581 (void) error(67);
2583 2582 if (cl == '\n')
2584 2583 (void) error(19);
2585 2584 save();
2586 2585 comple(cl);
2587 2586 for (a1 = zero; a1 <= dol; a1++) {
2588 2587 a1->cur &= ~01;
2589 2588 if (a1 >= addr1 && a1 <= addr2 && execute(0, a1) == k)
2590 2589 a1->cur |= 01;
2591 2590 }
2592 2591 nfirst = 0;
2593 2592 newline();
2594 2593 /*
2595 2594 * preserve the p, l, and n suffix commands of the G and V
2596 2595 * commands during the interactive section and restore
2597 2596 * on completion of the G and V command.
2598 2597 */
2599 2598 pflag_save = pflag;
2600 2599 listf_save = listf;
2601 2600 listn_save = listn;
2602 2601 pflag = 0;
2603 2602 listf = 0;
2604 2603 listn = 0;
2605 2604 for (a1 = zero; a1 <= dol; a1++) {
2606 2605 if (a1->cur & 01) {
2607 2606 a1->cur &= ~01;
2608 2607 dot = a1;
2609 2608 puts(getaline(a1->cur));
2610 2609 if ((c = get_wchr()) == EOF)
2611 2610 (void) error(52);
2612 2611 if (c == 'a' || c == 'i' || c == 'c')
2613 2612 (void) error(53);
2614 2613 if (c == '\n') {
2615 2614 a1 = zero;
2616 2615 continue;
2617 2616 }
2618 2617 if (c != '&') {
2619 2618 gp = globuf;
2620 2619 if ((len = wctomb(gp, c)) <= 0) {
2621 2620 *gp = (unsigned char)c;
2622 2621 len = 1;
2623 2622 }
2624 2623 gp += len;
2625 2624 while ((c = get_wchr()) != '\n') {
2626 2625
2627 2626 /* '\\' has special meaning only if preceding a '\n' */
2628 2627 if (c == '\\') {
2629 2628 c = get_wchr();
2630 2629 if (c != '\n')
2631 2630 *gp++ = '\\';
2632 2631 }
2633 2632 if ((gp + (unsigned int)MB_CUR_MAX) >=
2634 2633 &globuf[LBSIZE-1])
2635 2634 (void) error(34);
2636 2635
2637 2636 if ((len = wctomb(gp, c)) <= 0) {
2638 2637 *gp = (unsigned char)c;
2639 2638 len = 1;
2640 2639 }
2641 2640 gp += len;
2642 2641 }
2643 2642 *gp++ = '\n';
2644 2643 *gp++ = 0;
2645 2644 nfirst = 1;
2646 2645 } else if ((c = get_wchr()) != '\n')
2647 2646 (void) error(54);
2648 2647 globp = globuf;
2649 2648 if (nfirst) {
2650 2649 globflg = 1;
2651 2650 commands();
2652 2651 globflg = 0;
2653 2652 } else
2654 2653 (void) error(56);
2655 2654 globp = 0;
2656 2655 a1 = zero;
2657 2656 }
2658 2657 }
2659 2658 pflag = pflag_save;
2660 2659 listf = listf_save;
2661 2660 listn = listn_save;
2662 2661 }
2663 2662
2664 2663
2665 2664 static int
2666 2665 eopen(char *string, int rw)
2667 2666 {
2668 2667 #define w_or_r(a, b) (rw ? a : b)
2669 2668 int pf[2];
2670 2669 pid_t i;
2671 2670 int io;
2672 2671 int chcount; /* # of char read. */
2673 2672
2674 2673 if (rflg) { /* restricted shell */
2675 2674 if (Xqt) {
2676 2675 Xqt = 0;
2677 2676 (void) error(6);
2678 2677 }
2679 2678 }
2680 2679 if (!Xqt) {
2681 2680 if ((io = open(string, rw)) >= 0) {
2682 2681 if (fflg) {
2683 2682 chcount = read(io, crbuf, LBSIZE);
2684 2683 if (crflag == -1) {
2685 2684 if (isencrypt(crbuf, chcount))
2686 2685 crflag = 2;
2687 2686 else
2688 2687 crflag = -2;
2689 2688 }
2690 2689 if (crflag > 0)
2691 2690 if (run_crypt(0L, crbuf, chcount, perm) == -1)
2692 2691 (void) error(63);
2693 2692 if (fspec(crbuf, &fss, 0) < 0) {
2694 2693 fss.Ffill = 0;
2695 2694 fflg = 0;
2696 2695 (void) error(4);
2697 2696 }
2698 2697 lseek(io, 0L, 0);
2699 2698 }
2700 2699 }
2701 2700 fflg = 0;
2702 2701 return (io);
2703 2702 }
2704 2703 if (pipe(pf) < 0)
2705 2704 xerr: (void) error(0);
2706 2705 if ((i = fork()) == 0) {
2707 2706 signal(SIGHUP, oldhup);
2708 2707 signal(SIGQUIT, oldquit);
2709 2708 signal(SIGPIPE, oldpipe);
2710 2709 signal(SIGINT, (void (*)()) 0);
2711 2710 close(w_or_r(pf[1], pf[0]));
2712 2711 close(w_or_r(0, 1));
2713 2712 dup(w_or_r(pf[0], pf[1]));
2714 2713 close(w_or_r(pf[0], pf[1]));
2715 2714 execlp(_PATH_BSHELL, "sh", "-c", string, (char *)0);
2716 2715 exit(1);
2717 2716 }
2718 2717 if (i == (pid_t)-1)
2719 2718 goto xerr;
2720 2719 close(w_or_r(pf[0], pf[1]));
2721 2720 return (w_or_r(pf[1], pf[0]));
2722 2721 }
2723 2722
2724 2723
2725 2724 static void
2726 2725 eclose(int f)
2727 2726 {
2728 2727 close(f);
2729 2728 if (Xqt)
2730 2729 Xqt = 0, wait((int *)0);
2731 2730 }
2732 2731
2733 2732
2734 2733 static void
2735 2734 mkfunny(void)
2736 2735 {
2737 2736 char *p, *p1, *p2;
2738 2737
2739 2738 p2 = p1 = funny;
2740 2739 p = file;
2741 2740 /*
2742 2741 * Go to end of file name
2743 2742 */
2744 2743 while (*p)
2745 2744 p++;
2746 2745 while (*--p == '/') /* delete trailing slashes */
2747 2746 *p = '\0';
2748 2747 /*
2749 2748 * go back to beginning of file
2750 2749 */
2751 2750 p = file;
2752 2751 /*
2753 2752 * Copy file name to funny setting p2 at
2754 2753 * basename of file.
2755 2754 */
2756 2755 while (*p1++ = *p)
2757 2756 if (*p++ == '/')
2758 2757 p2 = p1;
2759 2758 /*
2760 2759 * Set p1 to point to basename of tfname.
2761 2760 */
2762 2761 p1 = strrchr(tfname, '/');
2763 2762 if (strlen(tfname) > (size_t)6)
2764 2763 p1 = &tfname[strlen(tfname)-6];
2765 2764 p1++;
2766 2765 *p2 = '\007'; /* add unprintable char for funny a unique name */
2767 2766 /*
2768 2767 * Copy tfname to file.
2769 2768 */
2770 2769 while (*++p2 = *p1++)
2771 2770 ;
2772 2771 }
2773 2772
2774 2773
2775 2774 static void
2776 2775 getime(void) /* get modified time of file and save */
2777 2776 {
2778 2777 if (stat(file, &Fl) < 0)
2779 2778 savtime = 0;
2780 2779 else
2781 2780 savtime = Fl.st_mtime;
2782 2781 }
2783 2782
2784 2783
2785 2784 static void
2786 2785 chktime(void) /* check saved mod time against current mod time */
2787 2786 {
2788 2787 if (savtime != 0 && Fl.st_mtime != 0) {
2789 2788 if (savtime != Fl.st_mtime)
2790 2789 (void) error(58);
2791 2790 }
2792 2791 }
2793 2792
2794 2793
2795 2794 static void
2796 2795 newtime(void) /* get new mod time and save */
2797 2796 {
2798 2797 stat(file, &Fl);
2799 2798 savtime = Fl.st_mtime;
2800 2799 }
2801 2800
2802 2801
2803 2802 /*
2804 2803 * restricted - check for '/' in name and delete trailing '/'
2805 2804 */
2806 2805 static void
2807 2806 red(char *op)
2808 2807 {
2809 2808 char *p;
2810 2809
2811 2810 p = op;
2812 2811 while (*p)
2813 2812 if (*p++ == '/'&& rflg) {
2814 2813 *op = 0;
2815 2814 (void) error(6);
2816 2815 }
2817 2816 /* delete trailing '/' */
2818 2817 while (p > op) {
2819 2818 if (*--p == '/')
2820 2819 *p = '\0';
2821 2820 else break;
2822 2821 }
2823 2822 }
2824 2823
2825 2824
2826 2825 /*
2827 2826 * Searches thru beginning of file looking for a string of the form
2828 2827 * <: values... :>
2829 2828 *
2830 2829 * where "values" are
2831 2830 *
2832 2831 * \b ignored
2833 2832 * s<num> sets the Flim to <num>
2834 2833 * t??? sets tab stop stuff
2835 2834 * d ignored
2836 2835 * m<num> ignored
2837 2836 * e ignored
2838 2837 */
2839 2838
2840 2839 static int
2841 2840 fspec(char line[], struct Fspec *f, int up)
2842 2841 {
2843 2842 struct termio arg;
2844 2843 int havespec, n;
2845 2844 int len;
2846 2845
2847 2846 if (!up) clear(f);
2848 2847
2849 2848 havespec = fsprtn = 0;
2850 2849 for (fsp = line; *fsp && *fsp != '\n'; fsp += len) {
2851 2850 if ((len = mblen(fsp, MB_CUR_MAX)) <= 0)
2852 2851 len = 1;
2853 2852 switch (*fsp) {
2854 2853
2855 2854 case '<': if (havespec)
2856 2855 return (-1);
2857 2856 if (*(fsp+1) == ':') {
2858 2857 havespec = 1;
2859 2858 clear(f);
2860 2859 if (!ioctl(1, TCGETA, &arg) &&
2861 2860 ((arg.c_oflag & TAB3) ==
2862 2861 TAB3))
2863 2862 f->Ffill = 1;
2864 2863 fsp++;
2865 2864 }
2866 2865 continue;
2867 2866
2868 2867 case ' ': continue;
2869 2868
2870 2869 case 's': if (havespec && (n = numb()) >= 0)
2871 2870 f->Flim = n;
2872 2871 continue;
2873 2872
2874 2873 case 't': if (havespec) targ(f);
2875 2874 continue;
2876 2875
2877 2876 case 'd': continue;
2878 2877
2879 2878 case 'm': if (havespec) n = numb();
2880 2879 continue;
2881 2880
2882 2881 case 'e': continue;
2883 2882 case ':': if (!havespec) continue;
2884 2883 if (*(fsp+1) != '>') fsprtn = -1;
2885 2884 return (fsprtn);
2886 2885
2887 2886 default: if (!havespec) continue;
2888 2887 return (-1);
2889 2888 }
2890 2889 }
2891 2890 return (1);
2892 2891 }
2893 2892
2894 2893
2895 2894 static int
2896 2895 numb(void)
2897 2896 {
2898 2897 int n;
2899 2898
2900 2899 n = 0;
2901 2900 while (*++fsp >= '0' && *fsp <= '9')
2902 2901 n = 10*n + *fsp-'0';
2903 2902 fsp--;
2904 2903 return (n);
2905 2904 }
2906 2905
2907 2906
2908 2907 static void
2909 2908 targ(struct Fspec *f)
2910 2909 {
2911 2910
2912 2911 if (*++fsp == '-') {
2913 2912 if (*(fsp + 1) >= '0' && *(fsp+1) <= '9') tincr(numb(), f);
2914 2913 else tstd(f);
2915 2914 return;
2916 2915 }
2917 2916 if (*fsp >= '0' && *fsp <= '9') {
2918 2917 tlist(f);
2919 2918 return;
2920 2919 }
2921 2920 fsprtn = -1;
2922 2921 fsp--;
2923 2922 }
2924 2923
2925 2924
2926 2925 static void
2927 2926 tincr(int n, struct Fspec *f)
2928 2927 {
2929 2928 int l, i;
2930 2929
2931 2930 l = 1;
2932 2931 for (i = 0; i < 20; i++)
2933 2932 f->Ftabs[i] = l += n;
2934 2933 f->Ftabs[i] = 0;
2935 2934 }
2936 2935
2937 2936
2938 2937 static void
2939 2938 tstd(struct Fspec *f)
2940 2939 {
2941 2940 char std[3];
2942 2941
2943 2942 std[0] = *++fsp;
2944 2943 if (*(fsp+1) >= '0' && *(fsp+1) <= '9') {
2945 2944 std[1] = *++fsp;
2946 2945 std[2] = '\0';
2947 2946 } else {
2948 2947 std[1] = '\0';
2949 2948 }
2950 2949 fsprtn = stdtab(std, f->Ftabs);
2951 2950 }
2952 2951
2953 2952
2954 2953 static void
2955 2954 tlist(struct Fspec *f)
2956 2955 {
2957 2956 int n, last, i;
2958 2957
2959 2958 fsp--;
2960 2959 last = i = 0;
2961 2960
2962 2961 do {
2963 2962 if ((n = numb()) <= last || i >= 20) {
2964 2963 fsprtn = -1;
2965 2964 return;
2966 2965 }
2967 2966 f->Ftabs[i++] = last = n;
2968 2967 } while (*++fsp == ',');
2969 2968
2970 2969 f->Ftabs[i] = 0;
2971 2970 fsp--;
2972 2971 }
2973 2972
2974 2973
2975 2974 static int
2976 2975 expnd(char line[], char buf[], int *sz, struct Fspec *f)
2977 2976 {
2978 2977 char *l, *t;
2979 2978 int b;
2980 2979
2981 2980 l = line - 1;
2982 2981 b = 1;
2983 2982 t = f->Ftabs;
2984 2983 fsprtn = 0;
2985 2984
2986 2985 while (*++l && *l != '\n' && b < 511) {
2987 2986 if (*l == '\t') {
2988 2987 while (*t && b >= *t)
2989 2988 t++;
2990 2989 if (*t == 0)
2991 2990 fsprtn = -2;
2992 2991 do {
2993 2992 buf[b-1] = ' ';
2994 2993 } while (++b < *t);
2995 2994 } else {
2996 2995 buf[b++ - 1] = *l;
2997 2996 }
2998 2997 }
2999 2998
3000 2999 buf[b] = '\0';
3001 3000 *sz = b;
3002 3001 if (*l != '\0' && *l != '\n') {
3003 3002 buf[b-1] = '\n';
3004 3003 return (-1);
3005 3004 }
3006 3005 buf[b-1] = *l;
3007 3006 if (f->Flim && (b-1 > (int)f->Flim))
3008 3007 return (-1);
3009 3008 return (fsprtn);
3010 3009 }
3011 3010
3012 3011
3013 3012 static void
3014 3013 clear(struct Fspec *f)
3015 3014 {
3016 3015 f->Ftabs[0] = f->Fdel = f->Fmov = f->Ffill = 0;
3017 3016 f->Flim = 0;
3018 3017 }
3019 3018
3020 3019
3021 3020 static int
3022 3021 lenchk(char line[], struct Fspec *f)
3023 3022 {
3024 3023 char *l, *t;
3025 3024 int b;
3026 3025
3027 3026 l = line - 1;
3028 3027 b = 1;
3029 3028 t = f->Ftabs;
3030 3029
3031 3030 while (*++l && *l != '\n' && b < 511) {
3032 3031 if (*l == '\t') {
3033 3032 while (*t && b >= *t)
3034 3033 t++;
3035 3034 while (++b < *t)
3036 3035 ;
3037 3036 } else {
3038 3037 b++;
3039 3038 }
3040 3039 }
3041 3040
3042 3041 if ((*l != '\0' && *l != '\n') || (f->Flim && (b-1 > (int)f->Flim)))
3043 3042 return (-1);
3044 3043 return (0);
3045 3044 }
3046 3045 #define NTABS 21
3047 3046
3048 3047
3049 3048 /*
3050 3049 * stdtabs: standard tabs table
3051 3050 * format: option code letter(s), null, tabs, null
3052 3051 */
3053 3052
3054 3053 static char stdtabs[] = {
3055 3054 'a', 0, 1, 10, 16, 36, 72, 0, /* IBM 370 Assembler */
3056 3055 'a', '2', 0, 1, 10, 16, 40, 72, 0, /* IBM Assembler alternative */
3057 3056 'c', 0, 1, 8, 12, 16, 20, 55, 0, /* COBOL, normal */
3058 3057 'c', '2', 0, 1, 6, 10, 14, 49, 0, /* COBOL, crunched */
3059 3058 'c', '3', 0, 1, 6, 10, 14, 18, 22, 26, 30, 34, 38, 42, 46, 50,
3060 3059 54, 58, 62, 67, 0,
3061 3060 'f', 0, 1, 7, 11, 15, 19, 23, 0, /* FORTRAN */
3062 3061 'p', 0, 1, 5, 9, 13, 17, 21, 25, 29, 33, 37, 41, 45, 49, 53, 57, 61, 0,
3063 3062 /* PL/I */
3064 3063 's', 0, 1, 10, 55, 0, /* SNOBOL */
3065 3064 'u', 0, 1, 12, 20, 44, 0, /* UNIVAC ASM */
3066 3065 0 };
3067 3066
3068 3067
3069 3068 /*
3070 3069 * stdtab: return tab list for any "canned" tab option.
3071 3070 * entry: option points to null-terminated option string
3072 3071 * tabvect points to vector to be filled in
3073 3072 * exit: return (0) if legal, tabvect filled, ending with zero
3074 3073 * return (-1) if unknown option
3075 3074 */
3076 3075
3077 3076
3078 3077 static int
3079 3078 stdtab(char option[], char tabvect[NTABS])
3080 3079 {
3081 3080 char *scan;
3082 3081 tabvect[0] = 0;
3083 3082 scan = stdtabs;
3084 3083 while (*scan) {
3085 3084 if (strequal(&scan, option)) {
3086 3085 strcopy(scan, tabvect);
3087 3086 break;
3088 3087 } else
3089 3088 while (*scan++) /* skip over tab specs */
3090 3089 ;
3091 3090 }
3092 3091
3093 3092 /* later: look up code in /etc/something */
3094 3093 return (tabvect[0] ? 0 : -1);
3095 3094 }
3096 3095
3097 3096
3098 3097 /*
3099 3098 * strequal: checks strings for equality
3100 3099 * entry: scan1 points to scan pointer, str points to string
3101 3100 * exit: return (1) if equal, return (0) if not
3102 3101 * *scan1 is advanced to next nonzero byte after null
3103 3102 */
3104 3103
3105 3104
3106 3105 static int
3107 3106 strequal(char **scan1, char *str)
3108 3107 {
3109 3108 char c, *scan;
3110 3109 scan = *scan1;
3111 3110 while ((c = *scan++) == *str && c)
3112 3111 str++;
3113 3112 *scan1 = scan;
3114 3113 if (c == 0 && *str == 0)
3115 3114 return (1);
3116 3115 if (c)
3117 3116 while (*scan++)
3118 3117 ;
3119 3118 *scan1 = scan;
3120 3119 return (0);
3121 3120 }
3122 3121
3123 3122
3124 3123 /* strcopy: copy source to destination */
3125 3124
3126 3125
3127 3126 static void
3128 3127 strcopy(char *source, char *dest)
3129 3128 {
3130 3129 while (*dest++ = *source++)
3131 3130 ;
3132 3131 }
3133 3132
3134 3133
3135 3134 /* This is called before a buffer modifying command so that the */
3136 3135 /* current array of line ptrs is saved in sav and dot and dol are saved */
3137 3136
3138 3137
3139 3138 static void
3140 3139 save(void)
3141 3140 {
3142 3141 LINE i;
3143 3142 int j;
3144 3143
3145 3144 savdot = dot;
3146 3145 savdol = dol;
3147 3146 for (j = 0; j <= 25; j++)
3148 3147 savnames[j] = names[j];
3149 3148
3150 3149 for (i = zero + 1; i <= dol; i++)
3151 3150 i->sav = i->cur;
3152 3151 initflg = 0;
3153 3152 }
3154 3153
3155 3154
3156 3155 /* The undo command calls this to restore the previous ptr array sav */
3157 3156 /* and swap with cur - dot and dol are swapped also. This allows user to */
3158 3157 /* undo an undo */
3159 3158
3160 3159
3161 3160 static void
3162 3161 undo(void)
3163 3162 {
3164 3163 int j;
3165 3164 long tmp;
3166 3165 LINE i, tmpdot, tmpdol;
3167 3166
3168 3167 tmpdot = dot; dot = savdot; savdot = tmpdot;
3169 3168 tmpdol = dol; dol = savdol; savdol = tmpdol;
3170 3169 /* swap arrays using the greater of dol or savdol as upper limit */
3171 3170 for (i = zero + 1; i <= ((dol > savdol) ? dol : savdol); i++) {
3172 3171 tmp = i->cur;
3173 3172 i->cur = i->sav;
3174 3173 i->sav = tmp;
3175 3174 }
3176 3175 /*
3177 3176 * If the current text lines are swapped with the
3178 3177 * text lines in the save buffer, then swap the current
3179 3178 * marks with those in the save area.
3180 3179 */
3181 3180
3182 3181 for (j = 0; j <= 25; j++) {
3183 3182 tmp = names[j];
3184 3183 names[j] = savnames[j];
3185 3184 savnames[j] = tmp;
3186 3185 }
3187 3186 }
3188 3187
3189 3188 static wchar_t
3190 3189 get_wchr(void)
3191 3190 {
3192 3191 wchar_t wc;
3193 3192 char multi[MB_LEN_MAX];
3194 3193
3195 3194 if (_mbftowc(multi, &wc, getchr, &peekc) <= 0)
3196 3195 wc = getchr();
3197 3196 return (wc);
3198 3197 }
↓ open down ↓ |
3024 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX