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

Defined functions

checkmodeline defined in line 856; used 1 times
clrstats defined in line 809; used 2 times
edfile defined in line 612; used 2 times
filename defined in line 36; used 7 times
getargs defined in line 114; used 2 times
getfile defined in line 625; used 3 times
getone defined in line 281; used 3 times
glob defined in line 186; used 2 times
gscan defined in line 267; used 1 times
iostats defined in line 822; used 2 times
putfile defined in line 682; used 1 times
rop defined in line 301; used 2 times
rop2 defined in line 413; used 2 times
rop3 defined in line 430; used 2 times
samei defined in line 478; used 3 times
source defined in line 750; used 3 times
wop defined in line 497; used 2 times
wrerror defined in line 735; used 2 times

Defined variables

G defined in line 280; used 4 times
altdot defined in line 17; used 5 times
cntch defined in line 22; used 10 times
cntln defined in line 26; used 7 times
cntnull defined in line 28; used 6 times
cntodd defined in line 29; used 7 times
isalt defined in line 20; used 3 times
nextip defined in line 623; used 2 times
oldadot defined in line 18; used 3 times
sccsid defined in line 2; never used
slevel defined in line 747; used 5 times
ttyindes defined in line 748; used 1 times
wasalt defined in line 19; used 3 times

Defined macros

EDF defined in line 490; used 2 times
NOTEDF defined in line 491; used 1 times
PARTBUF defined in line 492; used 1 times
index defined in line 852; used 2 times
rindex defined in line 853; used 2 times
Last modified: 1981-09-03
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 2287
Valid CSS Valid XHTML 1.0 Strict