1: #define UCB /* Controls output format for -F */ 2: #define UCB_PWHASH /* If have hashed password file */ 3: 4: static char *sccsid "@(#)ls.c 2.5"; 5: 6: /* 7: * ls - list file or directory 8: * 9: * Modified by Bill Joy UCB May/August 1977 10: * Modified by Dave Presotto BTL Feb/80 11: * Modified by Bill Joy and Mark Horton Summer 1980 12: * 13: * this version of ls is designed for graphic terminals and to 14: * list directories with lots of files in them compactly. 15: * It supports three variants for listings: 16: * 17: * 1) Columnar output. 18: * 2) Stream output. 19: * 3) Old one per line format. 20: * 21: * Columnar output is the default. 22: * If, however, the standard output is not a teletype, the default 23: * is one-per-line. 24: * 25: * With columnar output, the items are sorted down the columns. 26: * We use columns only for a directory we are interpreting. 27: * Thus, in particular, we do not use columns for 28: * 29: * ls /usr/bin/p* 30: * 31: * This version of ls also prints non-printing characters as '?' if 32: * the standard output is a teletype. 33: * 34: * Flags relating to these and other new features are: 35: * 36: * -m force stream output. 37: * 38: * -1 force one entry per line, e.g. to a teletype 39: * 40: * -q force non-printings to be '?'s, e.g. to a file 41: * 42: * -C force columnar output, e.g. into a file 43: * 44: * -n like -l, but user/group id's in decimal rather than 45: * looking in /etc/passwd to save time 46: * 47: * -F turns on the "flagging" of executables and directories 48: * 49: * -R causes ls to recurse through the branches of the subtree 50: * ala find 51: */ 52: 53: #include <sys/param.h> 54: #include <sys/stat.h> 55: #include <sys/dir.h> 56: #include <stdio.h> 57: #include <ctype.h> 58: #include <pwd.h> 59: #include <grp.h> 60: #include <utmp.h> 61: 62: struct utmp utmp; 63: #define NMAX (sizeof utmp.ut_name) 64: 65: #define MAXFILEWIDTH 14 66: #define NFILES 1024 67: FILE *pwdf, *dirf; 68: 69: struct lbuf { 70: union { 71: char lname[15]; 72: char *namep; 73: } ln; 74: char ltype; 75: ino_t lnum; 76: short lflags; 77: short lnl; 78: short luid; 79: short lgid; 80: long lsize; 81: long lmtime; 82: }; 83: 84: struct dchain { 85: char *dc_name; /* the path name */ 86: struct dchain *dc_next; /* the next directory on the chain */ 87: }; 88: 89: struct dchain *dfirst; /* the start of the directory chain */ 90: struct dchain *cdfirst; /* the start of the current directory chain */ 91: struct dchain *dtemp; /* temporary used when linking */ 92: char *curdir; /* the current directory */ 93: 94: int aflg, bflg, dflg, lflg, sflg, tflg, uflg, iflg, fflg, gflg, cflg; 95: int Aflg, nflg, qflg, Fflg, Rflg, across, Cflg; 96: int nopad; 97: int tabflg; 98: int rflg = 1; 99: long year; 100: int flags; 101: long tblocks; 102: int statreq; 103: int xtraent; /* for those switches which print out a total */ 104: struct lbuf *flist[NFILES]; 105: struct lbuf **lastp = flist; 106: struct lbuf **firstp = flist; 107: char *dotp = "."; 108: 109: char *makename(); 110: struct lbuf *gstat(); 111: char *ctime(); 112: long nblock(); 113: char *getname(); 114: 115: #define ISARG 0100000 116: int colwidth; 117: int filewidth; 118: int fixedwidth; 119: int outcol; 120: 121: char obuf[BUFSIZ]; 122: 123: main(argc, argv) 124: int argc; 125: char *argv[]; 126: { 127: #include <sgtty.h> 128: 129: int i, width; 130: register struct lbuf *ep; 131: register struct lbuf **slastp; 132: struct lbuf **epp; 133: struct lbuf lb; 134: char *t; 135: char *cp; 136: int compar(); 137: struct sgttyb sgbuf; 138: 139: Fflg = 0; 140: tabflg = 0; 141: Aflg = getuid() == 0; 142: setbuf(stdout, obuf); 143: lb.lmtime = time((long *) 0); 144: year = lb.lmtime - 6L*30L*24L*60L*60L; /* 6 months ago */ 145: qflg = gtty(1, &sgbuf) == 0; 146: 147: /* guarantee at least on column width */ 148: fixedwidth = 2; 149: 150: /* 151: * If the standard output is not a teletype, 152: * then we default to one-per-line format 153: * otherwise decide between stream and 154: * columnar based on our name. 155: */ 156: if (qflg) { 157: Cflg = 1; 158: if ((sgbuf.sg_flags & XTABS) == 0) 159: tabflg++; 160: for (cp = argv[0]; cp[0] && cp[1]; cp++) 161: continue; 162: /* 163: * Certain kinds of links (l, ll, lr, lf, lx) cause some 164: * various options to be turned on. 165: */ 166: switch (cp[0]) { 167: case 'l': 168: if (cp[-1] == 'l') { 169: /* ll => -l */ 170: lflg = 1; 171: statreq++; 172: xtraent++; 173: } else { 174: /* l => -m */ 175: nopad = 1; 176: Cflg = 0; 177: } 178: break; 179: case 'x': /* lx => -x */ 180: across = 1; 181: break; 182: case 'f': /* lf => -F */ 183: Fflg = 1; 184: break; 185: case 'r': /* lr => -R */ 186: Rflg = 1; 187: break; 188: } 189: } else { 190: tabflg++; 191: } 192: 193: while (--argc > 0 && *argv[1] == '-') { 194: argv++; 195: while (*++*argv) switch (**argv) { 196: /* 197: * C - force columnar output 198: */ 199: case 'C': 200: Cflg = 1; 201: nopad = 0; 202: continue; 203: /* 204: * m - force stream output 205: */ 206: case 'm': 207: Cflg = 0; 208: nopad = 1; 209: continue; 210: /* 211: * x - force sort across 212: */ 213: case 'x': 214: across = 1; 215: nopad = 0; 216: Cflg = 1; 217: continue; 218: /* 219: * q - force ?'s in output 220: */ 221: case 'q': 222: qflg = 1; 223: bflg = 0; 224: continue; 225: /* 226: * b - force octal value in output 227: */ 228: case 'b': 229: bflg = 1; 230: qflg = 0; 231: continue; 232: /* 233: * 1 - force 1/line in output 234: */ 235: case '1': 236: Cflg = 0; 237: nopad = 0; 238: continue; 239: /* STANDARD FLAGS */ 240: case 'a': 241: aflg++; 242: continue; 243: 244: case 'A': 245: Aflg = !Aflg; 246: continue; 247: 248: case 'c': 249: cflg++; 250: continue; 251: 252: case 's': 253: fixedwidth += 5; 254: sflg++; 255: statreq++; 256: xtraent++; 257: continue; 258: 259: case 'd': 260: dflg++; 261: continue; 262: 263: /* 264: * n - don't look in password file 265: */ 266: case 'n': 267: nflg++; 268: case 'l': 269: lflg++; 270: statreq++; 271: xtraent++; 272: continue; 273: 274: case 'r': 275: rflg = -1; 276: continue; 277: 278: case 't': 279: tflg++; 280: statreq++; 281: continue; 282: 283: case 'u': 284: uflg++; 285: continue; 286: 287: case 'i': 288: fixedwidth += 5; 289: iflg++; 290: continue; 291: 292: case 'f': 293: fflg++; 294: continue; 295: 296: case 'g': 297: gflg++; 298: continue; 299: 300: case 'F': 301: Fflg++; 302: continue; 303: 304: case 'R': 305: Rflg++; 306: continue; 307: 308: default: 309: fprintf (stderr, "usage: ls [-1ACFRabcdfgilmnqrstux] [files]\n"); 310: exit(1); 311: } 312: } 313: if (Fflg) 314: #ifdef UCB 315: fixedwidth++; 316: #else 317: fixedwidth += 2; 318: #endif 319: if (fflg) { 320: aflg++; 321: lflg = 0; 322: sflg = 0; 323: tflg = 0; 324: statreq = 0; 325: xtraent = 0; 326: } 327: if(lflg) { 328: Cflg = 0; 329: t = "/etc/passwd"; 330: if (gflg) 331: t = "/etc/group"; 332: nopad = 0; 333: fixedwidth = 70; 334: pwdf = fopen(t, "r"); 335: } 336: if (argc==0) { 337: argc++; 338: argv = &dotp - 1; 339: } 340: for (i=0; i < argc; i++) { 341: argv++; 342: if (Cflg) { 343: width = strlen (*argv); 344: if (width > filewidth) 345: filewidth = width; 346: } 347: if ((ep = gstat(*argv, 1))==NULL) 348: continue; 349: ep->ln.namep = *argv; 350: ep->lflags |= ISARG; 351: } 352: if (!Cflg) 353: filewidth = MAXFILEWIDTH; 354: else 355: colwidth = fixedwidth + filewidth; 356: qsort(firstp, lastp - firstp, sizeof *lastp, compar); 357: slastp = lastp; 358: /* For each argument user typed */ 359: for (epp=firstp; epp<slastp; epp++) { 360: ep = *epp; 361: if (ep->ltype=='d' && dflg==0 || fflg) 362: pdirectory(ep->ln.namep, (argc>1), slastp); 363: else 364: pentry(ep); 365: 366: /* -R: print subdirectories found */ 367: while (dfirst || cdfirst) { 368: /* Place direct subdirs on front in right order */ 369: while (cdfirst) { 370: /* reverse cdfirst onto front of dfirst */ 371: dtemp = cdfirst; 372: cdfirst = cdfirst -> dc_next; 373: dtemp -> dc_next = dfirst; 374: dfirst = dtemp; 375: } 376: /* take off first dir on dfirst & print it */ 377: dtemp = dfirst; 378: dfirst = dfirst->dc_next; 379: pdirectory (dtemp->dc_name, 1, firstp); 380: cfree (dtemp->dc_name); 381: cfree (dtemp); 382: } 383: } 384: if (outcol) 385: putc('\n', stdout); 386: fflush(stdout); 387: } 388: 389: /* 390: * pdirectory: print the directory name, labelling it if title is 391: * nonzero, using lp as the place to start reading in the dir. 392: */ 393: pdirectory (name, title, lp) 394: char *name; 395: int title; 396: struct lbuf **lp; 397: { 398: register struct dchain *dp; 399: register struct lbuf *ap; 400: register char *pname; 401: struct lbuf **app; 402: 403: filewidth = 0; 404: curdir = name; 405: if (title) 406: printf("\n%s:\n", name); 407: lastp = lp; 408: readdir(name); 409: if (!Cflg) 410: filewidth = MAXFILEWIDTH; 411: colwidth = fixedwidth + filewidth; 412: #ifdef notdef 413: /* Taken out because it appears this is done below in pem. */ 414: if (tabflg) { 415: if (colwidth <= 8) 416: colwidth = 8; 417: else 418: if (colwidth <= 16) 419: colwidth = 16; 420: } 421: #endif 422: if (fflg==0) 423: qsort(lp,lastp - lp,sizeof *lastp,compar); 424: if (Rflg) for (app=lastp-1; app>=lp; app--) { 425: ap = *app; 426: if (ap->ltype == 'd' && strcmp(ap->ln.lname, ".") && 427: strcmp(ap->ln.lname, "..")) { 428: dp = (struct dchain *) calloc(1, sizeof(struct dchain)); 429: pname = makename (curdir, ap->ln.lname); 430: dp->dc_name = (char *) calloc(1, strlen(pname)+1); 431: strcpy(dp->dc_name, pname); 432: dp -> dc_next = dfirst; 433: dfirst = dp; 434: } 435: } 436: if (lflg || sflg) 437: printf("total %D", tblocks); 438: pem(lp, lastp); 439: newline(); 440: } 441: 442: /* 443: * pem: print 'em. Print a list of files (e.g. a directory) bounded 444: * by slp and lp. 445: */ 446: pem(slp, lp) 447: register struct lbuf **slp, **lp; 448: { 449: int ncols, nrows, row, col; 450: register struct lbuf **ep; 451: 452: if (tabflg) { 453: if (colwidth <= 9) 454: colwidth = 8; 455: else 456: if (colwidth <= 17) 457: colwidth = 16; 458: } 459: ncols = 80 / colwidth; 460: if (ncols == 1 || Cflg == 0) { 461: for (ep = slp; ep < lp; ep++) 462: pentry(*ep); 463: return; 464: } 465: if (across) { 466: for (ep = slp; ep < lp; ep++) 467: pentry(*ep); 468: return; 469: } 470: if (xtraent) 471: slp--; 472: nrows = (lp - slp - 1) / ncols + 1; 473: for (row = 0; row < nrows; row++) { 474: col = row == 0 && xtraent; 475: for (; col < ncols; col++) { 476: ep = slp + (nrows * col) + row; 477: if (ep < lp) 478: pentry(*ep); 479: } 480: if (outcol) 481: printf("\n"); 482: } 483: } 484: 485: /* 486: * pputchar: like putchar but knows how to handle control chars. 487: * CAUTION: if you make ctrl chars print in ^x notation, or any 488: * other notation which is wider than one character, the column 489: * nature of things (such as files with 14 letter names) will be 490: * messed up. Weigh this carefully! 491: */ 492: pputchar(c) 493: char c; 494: { 495: char cc; 496: 497: switch (c) { 498: case '\t': 499: outcol = (outcol + 8) &~ 7; 500: break; 501: case '\n': 502: outcol = 0; 503: break; 504: default: 505: if (c < ' ' || c >= 0177) { 506: if (qflg) 507: c = '?'; 508: else if (bflg) { 509: outcol += 3; 510: putc ('\\', stdout); 511: cc = '0' + (c>>6 & 07); 512: putc (cc, stdout); 513: cc = '0' + (c>>3 & 07); 514: putc (cc, stdout); 515: c = '0' + (c & 07); 516: } 517: } 518: outcol++; 519: break; 520: } 521: putc(c, stdout); 522: } 523: 524: newline() 525: { 526: if (outcol) 527: putc('\n', stdout); 528: outcol = 0; 529: } 530: 531: /* 532: * column: get to the beginning of the next column. 533: */ 534: column() 535: { 536: 537: if (outcol == 0) 538: return; 539: if (nopad) { 540: putc(',', stdout); 541: outcol++; 542: if (outcol + colwidth + 2 > 80) { 543: putc('\n', stdout); 544: outcol = 0; 545: return; 546: } 547: putc(' ', stdout); 548: outcol++; 549: return; 550: } 551: if (Cflg == 0) { 552: putc('\n', stdout); 553: return; 554: } 555: if ((outcol / colwidth + 2) * colwidth > 80) { 556: putc('\n', stdout); 557: outcol = 0; 558: return; 559: } 560: if (tabflg && (colwidth <= 16)) { 561: if (colwidth > 8) 562: if ((outcol % 16) < 8) { 563: outcol += 8 - (outcol % 8); 564: putc ('\t', stdout); 565: } 566: outcol += 8 - (outcol % 8); 567: putc ('\t', stdout); 568: return; 569: } 570: do { 571: outcol++; 572: putc(' ', stdout); 573: } while (outcol % colwidth); 574: } 575: 576: 577: /* 578: * nblock: the number of 512 byte blocks a size byte file takes up. 579: * (Note: the number stays 512 no matter what BUFSIZ or the filesystem uses.) 580: */ 581: long 582: nblock(size) 583: long size; 584: { 585: return((size+511)>>9); 586: } 587: 588: /* 589: * This code handles the rwx- business. 590: * You figure it out. 591: */ 592: int m1[] = { 1, S_IREAD>>0, 'r', '-' }; 593: int m2[] = { 1, S_IWRITE>>0, 'w', '-' }; 594: int m3[] = { 2, S_ISUID, 's', S_IEXEC>>0, 'x', '-' }; 595: int m4[] = { 1, S_IREAD>>3, 'r', '-' }; 596: int m5[] = { 1, S_IWRITE>>3, 'w', '-' }; 597: int m6[] = { 2, S_ISGID, 's', S_IEXEC>>3, 'x', '-' }; 598: int m7[] = { 1, S_IREAD>>6, 'r', '-' }; 599: int m8[] = { 1, S_IWRITE>>6, 'w', '-' }; 600: int m9[] = { 2, S_ISVTX, 't', S_IEXEC>>6, 'x', '-' }; 601: 602: int *m[] = { m1, m2, m3, m4, m5, m6, m7, m8, m9}; 603: 604: pmode(aflag) 605: { 606: register int **mp; 607: 608: flags = aflag; 609: for (mp = &m[0]; mp < &m[sizeof(m)/sizeof(m[0])];) 610: select(*mp++); 611: } 612: 613: select(pairp) 614: register int *pairp; 615: { 616: register int n; 617: 618: n = *pairp++; 619: while (--n>=0 && (flags&*pairp++)==0) 620: pairp++; 621: pputchar(*pairp); 622: } 623: 624: /* 625: * returns cat(dir, "/", file), unless dir ends in /, when it doesn't // 626: */ 627: char * 628: makename(dir, file) 629: char *dir, *file; 630: { 631: static char dfile[100]; 632: register char *dp, *fp; 633: register int i; 634: 635: dp = dfile; 636: fp = dir; 637: while (*fp) 638: *dp++ = *fp++; 639: if (*(dp-1) != '/') 640: *dp++ = '/'; 641: fp = file; 642: for (i=0; i<DIRSIZ; i++) 643: *dp++ = *fp++; 644: *dp = 0; 645: return(dfile); 646: } 647: 648: /* 649: * readdir: read in the directory whose name is dir, 650: * starting at lastp. 651: */ 652: readdir(dir) 653: char *dir; 654: { 655: static struct direct dentry; 656: register int j, width; 657: register struct lbuf *ep; 658: 659: if ((dirf = fopen(dir, "r")) == NULL) { 660: printf("%s unreadable\n", dir); 661: return; 662: } 663: tblocks = 0; 664: for(;;) { 665: if (fread(&dentry, sizeof(dentry), 1, dirf) != 1) 666: break; 667: if (dentry.d_ino==0 || 668: aflg==0 && dentry.d_name[0]=='.' && ( 669: !Aflg || 670: dentry.d_name[1]=='\0' 671: || dentry.d_name[1]=='.' && dentry.d_name[2]=='\0')) 672: continue; 673: if (Cflg) { 674: width = strlen (dentry.d_name); 675: if (width > filewidth) 676: filewidth = width; 677: } 678: ep = gstat(makename(dir, dentry.d_name), Fflg || Rflg); 679: if (ep==NULL) 680: continue; 681: if (ep->lnum != -1) 682: ep->lnum = dentry.d_ino; 683: for (j=0; j<DIRSIZ; j++) 684: ep->ln.lname[j] = dentry.d_name[j]; 685: } 686: fclose(dirf); 687: } 688: 689: /* 690: * stat the given file and return an lbuf containing it. 691: * argfl is nonzero if a stat is required because the file is 692: * an argument, rather than having been found in a directory. 693: */ 694: struct lbuf * 695: gstat(file, argfl) 696: char *file; 697: { 698: struct stat statb; 699: register struct lbuf *rep; 700: static int nomocore; 701: 702: if (nomocore) 703: return(NULL); 704: rep = (struct lbuf *)malloc(sizeof(struct lbuf)); 705: if (rep==NULL) { 706: fprintf(stderr, "ls: out of memory\n"); 707: nomocore = 1; 708: return(NULL); 709: } 710: if (lastp >= &flist[NFILES]) { 711: static int msg; 712: lastp--; 713: if (msg==0) { 714: fprintf(stderr, "ls: too many files\n"); 715: msg++; 716: } 717: } 718: *lastp++ = rep; 719: rep->lflags = 0; 720: rep->lnum = 0; 721: rep->ltype = '-'; 722: if (argfl || statreq) { 723: if (stat(file, &statb)<0) { 724: printf("%s not found\n", file); 725: statb.st_ino = -1; 726: statb.st_size = 0; 727: statb.st_mode = 0; 728: if (argfl) { 729: lastp--; 730: return(0); 731: } 732: } 733: rep->lnum = statb.st_ino; 734: rep->lsize = statb.st_size; 735: switch(statb.st_mode&S_IFMT) { 736: 737: case S_IFDIR: 738: rep->ltype = 'd'; 739: break; 740: 741: case S_IFBLK: 742: rep->ltype = 'b'; 743: rep->lsize = statb.st_rdev; 744: break; 745: 746: case S_IFCHR: 747: rep->ltype = 'c'; 748: rep->lsize = statb.st_rdev; 749: break; 750: } 751: rep->lflags = statb.st_mode & ~S_IFMT; 752: rep->luid = statb.st_uid; 753: rep->lgid = statb.st_gid; 754: rep->lnl = statb.st_nlink; 755: if(uflg) 756: rep->lmtime = statb.st_atime; 757: else if (cflg) 758: rep->lmtime = statb.st_ctime; 759: else 760: rep->lmtime = statb.st_mtime; 761: tblocks += nblock(statb.st_size); 762: } 763: return(rep); 764: } 765: 766: /* 767: * decide whether to print pp1 before or after pp2, based on their 768: * names, various times, and the r flag. 769: */ 770: compar(pp1, pp2) 771: struct lbuf **pp1, **pp2; 772: { 773: register struct lbuf *p1, *p2; 774: 775: p1 = *pp1; 776: p2 = *pp2; 777: if (dflg==0) { 778: if (p1->lflags&ISARG && p1->ltype=='d') { 779: if (!(p2->lflags&ISARG && p2->ltype=='d')) 780: return(1); 781: } else { 782: if (p2->lflags&ISARG && p2->ltype=='d') 783: return(-1); 784: } 785: } 786: if (tflg) { 787: if(p2->lmtime == p1->lmtime) 788: return(0); 789: if(p2->lmtime > p1->lmtime) 790: return(rflg); 791: return(-rflg); 792: } 793: return(rflg * strcmp(p1->lflags&ISARG? p1->ln.namep: p1->ln.lname, 794: p2->lflags&ISARG? p2->ln.namep: p2->ln.lname)); 795: } 796: 797: /* 798: * print the entry pointed at by ap 799: */ 800: pentry(ap) 801: struct lbuf *ap; 802: { 803: struct { char dminor, dmajor;}; 804: register struct lbuf *p; 805: register char *cp; 806: char fname[100]; 807: char *pname; 808: struct passwd *getpwuid(); 809: struct passwd *pwptr; 810: struct group *getgrgid(); 811: struct group *grptr; 812: 813: fname[0] = 0; 814: p = ap; 815: if (p->lnum == -1) 816: return; 817: column(); 818: if (iflg) 819: if (nopad && !lflg) 820: printf("%d ", p->lnum); 821: else 822: printf("%5d ", p->lnum); 823: if (sflg) 824: if (nopad && !lflg) 825: printf("%D ", nblock(p->lsize)); 826: else 827: printf("%4D ", nblock(p->lsize)); 828: if (lflg) { 829: pputchar(p->ltype); 830: pmode(p->lflags); 831: printf("%2d ", p->lnl); 832: if(gflg) { 833: grptr = getgrgid(p->lgid); 834: if (nflg == 0 && grptr != 0) 835: printf("%-8.8s", grptr->gr_name); 836: else 837: printf("%-8d", p->lgid); 838: } else { 839: #ifndef UCB_PWHASH 840: char *name; 841: if (nflg == 0 && (name = getname(p->luid))) { 842: printf("%-8.8s", name); 843: } 844: #else 845: pwptr = getpwuid(p->luid); 846: if (nflg == 0 && pwptr != 0) 847: printf("%-8.8s", pwptr->pw_name); 848: #endif 849: else 850: printf("%-8d", p->luid); 851: } 852: if (p->ltype=='b' || p->ltype=='c') 853: printf("%3d,%3d", major((int)p->lsize), minor((int)p->lsize)); 854: else 855: printf("%7ld", p->lsize); 856: cp = ctime(&p->lmtime); 857: if(p->lmtime < year) 858: printf(" %-7.7s %-4.4s ", cp+4, cp+20); else 859: printf(" %-12.12s ", cp+4); 860: } 861: #ifndef UCB 862: if (Fflg) { 863: if (p->ltype == 'd') 864: strcat (fname, "["); 865: else if (p->lflags & 0111) 866: strcat (fname, "*"); 867: else if (!nopad) 868: strcat (fname, " "); 869: } 870: #endif 871: if (p->lflags & ISARG) 872: strncat (fname, p->ln.namep, 98); 873: else 874: strncat (fname, p->ln.lname, 14); 875: #ifndef UCB 876: if (Fflg) { 877: if (p->ltype == 'd') 878: strcat (fname, "]"); 879: else if (!nopad) 880: strcat (fname, " "); 881: } 882: #else 883: if (Fflg) { 884: if (p->ltype == 'd') 885: strcat (fname, "/"); 886: else if (p->lflags & 0111) 887: strcat (fname, "*"); 888: else if (!nopad) 889: strcat (fname, " "); 890: } 891: #endif 892: printf ("%s", fname); 893: free(ap); 894: } 895: 896: /* char printf_id[] = "@(#) printf.c:2.2 6/5/79";*/ 897: 898: #include "varargs.h" 899: 900: /* 901: * This version of printf is compatible with the Version 7 C 902: * printf. The differences are only minor except that this 903: * printf assumes it is to print through pputchar. Version 7 904: * printf is more general (and is much larger) and includes 905: * provisions for floating point. 906: */ 907: 908: #define MAXOCT 11 /* Maximum octal digits in a long */ 909: #define MAXINT 32767 /* largest normal length positive integer */ 910: #define BIG 1000000000 /* largest power of 10 less than an unsigned long */ 911: #define MAXDIGS 10 /* number of digits in BIG */ 912: 913: static int width, sign, fill; 914: 915: char *b_dconv(); 916: 917: printf(va_alist) 918: va_dcl 919: { 920: va_list ap; 921: register char *fmt; 922: char fcode; 923: int prec; 924: int length,mask1,nbits,n; 925: long int mask2, num; 926: register char *bptr; 927: char *ptr; 928: char buf[134]; 929: 930: va_start(ap); 931: fmt = va_arg(ap,char *); 932: for (;;) { 933: /* process format string first */ 934: while ((fcode = *fmt++)!='%') { 935: /* ordinary (non-%) character */ 936: if (fcode=='\0') 937: return; 938: pputchar(fcode); 939: } 940: /* length modifier: -1 for h, 1 for l, 0 for none */ 941: length = 0; 942: /* check for a leading - sign */ 943: sign = 0; 944: if (*fmt == '-') { 945: sign++; 946: fmt++; 947: } 948: /* a '0' may follow the - sign */ 949: /* this is the requested fill character */ 950: fill = 1; 951: if (*fmt == '0') { 952: fill--; 953: fmt++; 954: } 955: 956: /* Now comes a digit string which may be a '*' */ 957: if (*fmt == '*') { 958: width = va_arg(ap, int); 959: if (width < 0) { 960: width = -width; 961: sign = !sign; 962: } 963: fmt++; 964: } 965: else { 966: width = 0; 967: while (*fmt>='0' && *fmt<='9') 968: width = width * 10 + (*fmt++ - '0'); 969: } 970: 971: /* maybe a decimal point followed by more digits (or '*') */ 972: if (*fmt=='.') { 973: if (*++fmt == '*') { 974: prec = va_arg(ap, int); 975: fmt++; 976: } 977: else { 978: prec = 0; 979: while (*fmt>='0' && *fmt<='9') 980: prec = prec * 10 + (*fmt++ - '0'); 981: } 982: } 983: else 984: prec = -1; 985: 986: /* 987: * At this point, "sign" is nonzero if there was 988: * a sign, "fill" is 0 if there was a leading 989: * zero and 1 otherwise, "width" and "prec" 990: * contain numbers corresponding to the digit 991: * strings before and after the decimal point, 992: * respectively, and "fmt" addresses the next 993: * character after the whole mess. If there was 994: * no decimal point, "prec" will be -1. 995: */ 996: switch (*fmt) { 997: case 'L': 998: case 'l': 999: length = 2; 1000: /* no break!! */ 1001: case 'h': 1002: case 'H': 1003: length--; 1004: fmt++; 1005: break; 1006: } 1007: 1008: /* 1009: * At exit from the following switch, we will 1010: * emit the characters starting at "bptr" and 1011: * ending at "ptr"-1, unless fcode is '\0'. 1012: */ 1013: switch (fcode = *fmt++) { 1014: /* process characters and strings first */ 1015: case 'c': 1016: buf[0] = va_arg(ap, int); 1017: ptr = bptr = &buf[0]; 1018: if (buf[0] != '\0') 1019: ptr++; 1020: break; 1021: case 's': 1022: bptr = va_arg(ap,char *); 1023: if (bptr==0) 1024: bptr = "(null pointer)"; 1025: if (prec < 0) 1026: prec = MAXINT; 1027: for (n=0; *bptr++ && n < prec; n++) ; 1028: ptr = --bptr; 1029: bptr -= n; 1030: break; 1031: case 'O': 1032: length = 1; 1033: fcode = 'o'; 1034: /* no break */ 1035: case 'o': 1036: case 'X': 1037: case 'x': 1038: if (length > 0) 1039: num = va_arg(ap,long); 1040: else 1041: num = (unsigned)va_arg(ap,int); 1042: if (fcode=='o') { 1043: mask1 = 0x7; 1044: mask2 = 0x1fffffffL; 1045: nbits = 3; 1046: } 1047: else { 1048: mask1 = 0xf; 1049: mask2 = 0x0fffffffL; 1050: nbits = 4; 1051: } 1052: n = (num!=0); 1053: bptr = buf + MAXOCT + 3; 1054: /* shift and mask for speed */ 1055: do 1056: if (((int) num & mask1) < 10) 1057: *--bptr = ((int) num & mask1) + 060; 1058: else 1059: *--bptr = ((int) num & mask1) + 0127; 1060: while (num = (num >> nbits) & mask2); 1061: 1062: if (fcode=='o') { 1063: if (n) 1064: *--bptr = '0'; 1065: } 1066: else 1067: if (!sign && fill <= 0) { 1068: pputchar('0'); 1069: pputchar(fcode); 1070: width -= 2; 1071: } 1072: else { 1073: *--bptr = fcode; 1074: *--bptr = '0'; 1075: } 1076: ptr = buf + MAXOCT + 3; 1077: break; 1078: case 'D': 1079: case 'U': 1080: case 'I': 1081: length = 1; 1082: 1083: fcode = fcode + 'a' - 'A'; 1084: /* no break */ 1085: case 'd': 1086: case 'i': 1087: case 'u': 1088: if (length > 0) 1089: num = va_arg(ap,long); 1090: else { 1091: n = va_arg(ap,int); 1092: if (fcode=='u') 1093: num = (unsigned) n; 1094: else 1095: num = (long) n; 1096: } 1097: if (n = (fcode != 'u' && num < 0)) 1098: num = -num; 1099: /* now convert to digits */ 1100: bptr = b_dconv(num, buf); 1101: if (n) 1102: *--bptr = '-'; 1103: if (fill == 0) 1104: fill = -1; 1105: ptr = buf + MAXDIGS + 1; 1106: break; 1107: default: 1108: /* not a control character, 1109: * print it. 1110: */ 1111: ptr = bptr = &fcode; 1112: ptr++; 1113: break; 1114: } 1115: if (fcode != '\0') 1116: b_emit(bptr,ptr); 1117: } 1118: va_end(ap); 1119: } 1120: 1121: /* b_dconv converts the unsigned long integer "value" to 1122: * printable decimal and places it in "buffer", right-justified. 1123: * The value returned is the address of the first non-zero character, 1124: * or the address of the last character if all are zero. 1125: * The result is NOT null terminated, and is MAXDIGS characters long, 1126: * starting at buffer[1] (to allow for insertion of a sign). 1127: * 1128: * This program assumes it is running on 2's complement machine 1129: * with reasonable overflow treatment. 1130: */ 1131: char * 1132: b_dconv(value, buffer) 1133: long value; 1134: char *buffer; 1135: { 1136: register char *bp; 1137: register int svalue; 1138: int n; 1139: long lval; 1140: 1141: bp = buffer; 1142: 1143: /* zero is a special case */ 1144: if (value == 0) { 1145: bp += MAXDIGS; 1146: *bp = '0'; 1147: return(bp); 1148: } 1149: 1150: /* develop the leading digit of the value in "n" */ 1151: n = 0; 1152: while (value < 0) { 1153: value -= BIG; /* will eventually underflow */ 1154: n++; 1155: } 1156: while ((lval = value - BIG) >= 0) { 1157: value = lval; 1158: n++; 1159: } 1160: 1161: /* stash it in buffer[1] to allow for a sign */ 1162: bp[1] = n + '0'; 1163: /* 1164: * Now develop the rest of the digits. Since speed counts here, 1165: * we do it in two loops. The first gets "value" down until it 1166: * is no larger than MAXINT. The second one uses integer divides 1167: * rather than long divides to speed it up. 1168: */ 1169: bp += MAXDIGS + 1; 1170: while (value > MAXINT) { 1171: *--bp = (int)(value % 10) + '0'; 1172: value /= 10; 1173: } 1174: 1175: /* cannot lose precision */ 1176: svalue = value; 1177: while (svalue > 0) { 1178: *--bp = (svalue % 10) + '0'; 1179: svalue /= 10; 1180: } 1181: 1182: /* fill in intermediate zeroes if needed */ 1183: if (buffer[1] != '0') { 1184: while (bp > buffer + 2) 1185: *--bp = '0'; 1186: --bp; 1187: } 1188: return(bp); 1189: } 1190: 1191: /* 1192: * This program sends string "s" to pputchar. The character after 1193: * the end of "s" is given by "send". This allows the size of the 1194: * field to be computed; it is stored in "alen". "width" contains the 1195: * user specified length. If width<alen, the width will be taken to 1196: * be alen. "sign" is zero if the string is to be right-justified 1197: * in the field, nonzero if it is to be left-justified. "fill" is 1198: * 0 if the string is to be padded with '0', positive if it is to be 1199: * padded with ' ', and negative if an initial '-' should appear before 1200: * any padding in right-justification (to avoid printing "-3" as 1201: * "000-3" where "-0003" was intended). 1202: */ 1203: b_emit(s, send) 1204: register char *s; 1205: char *send; 1206: { 1207: char cfill; 1208: register int alen; 1209: int npad; 1210: 1211: alen = send - s; 1212: if (alen > width) 1213: width = alen; 1214: cfill = fill>0? ' ': '0'; 1215: 1216: /* we may want to print a leading '-' before anything */ 1217: if (*s == '-' && fill < 0) { 1218: pputchar(*s++); 1219: alen--; 1220: width--; 1221: } 1222: npad = width - alen; 1223: 1224: /* emit any leading pad characters */ 1225: if (!sign) 1226: while (--npad >= 0) 1227: pputchar(cfill); 1228: 1229: /* emit the string itself */ 1230: while (--alen >= 0) 1231: pputchar(*s++); 1232: 1233: /* emit trailing pad characters */ 1234: if (sign) 1235: while (--npad >= 0) 1236: pputchar(cfill); 1237: } 1238: 1239: #ifndef UCB_PWHASH 1240: #define NUID 2048 1241: 1242: char names[NUID][NMAX+1]; 1243: 1244: char * 1245: getname(uid) 1246: { 1247: register struct passwd *pw; 1248: static init; 1249: struct passwd *getpwent(); 1250: 1251: if (names[uid][0]) 1252: return (&names[uid][0]); 1253: if (init == 2) 1254: return (0); 1255: if (init == 0) 1256: setpwent(), init = 1; 1257: while (pw = getpwent()) { 1258: if (pw->pw_uid >= NUID) 1259: continue; 1260: if (names[pw->pw_uid][0]) 1261: continue; 1262: strncpy(names[pw->pw_uid], pw->pw_name, NMAX); 1263: if (pw->pw_uid == uid) 1264: return (&names[uid][0]); 1265: } 1266: init = 2; 1267: endpwent(); 1268: return (0); 1269: } 1270: #endif