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

Defined functions

checkmodeline defined in line 883; used 1 times
clrstats defined in line 835; used 2 times
edfile defined in line 628; used 2 times
filename defined in line 44; used 7 times
getargs defined in line 122; used 2 times
getfile defined in line 641; used 3 times
getone defined in line 289; used 3 times
glob defined in line 194; used 2 times
gscan defined in line 275; used 1 times
iostats defined in line 848; used 2 times
putfile defined in line 699; used 1 times
rop defined in line 309; used 2 times
rop2 defined in line 421; used 2 times
rop3 defined in line 453; used 2 times
samei defined in line 494; used 3 times
source defined in line 775; used 3 times
wop defined in line 513; used 2 times
wrerror defined in line 760; used 2 times

Defined variables

G defined in line 288; used 4 times
altdot defined in line 25; used 5 times
cntch defined in line 30; used 10 times
cntln defined in line 34; used 7 times
cntnull defined in line 36; used 6 times
cntodd defined in line 37; used 7 times
isalt defined in line 28; used 3 times
nextip defined in line 639; used 2 times
oldadot defined in line 26; used 3 times
sccsid defined in line 8; never used
slevel defined in line 772; used 5 times
ttyindes defined in line 773; used 1 times
wasalt defined in line 27; used 3 times

Defined macros

EDF defined in line 506; used 2 times
NOTEDF defined in line 507; used 1 times
PARTBUF defined in line 508; used 1 times
index defined in line 879; used 2 times
rindex defined in line 880; used 2 times
Last modified: 1985-06-08
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 3450
Valid CSS Valid XHTML 1.0 Strict