|
|
1.1 ! root 1: /* Copyright (c) 1979 Regents of the University of California */ ! 2: # ! 3: /* ! 4: * ls - list file or directory ! 5: * ! 6: * Modified by Bill Joy UCB May/August 1977 ! 7: * ! 8: * This version of ls is designed for graphic terminals and to ! 9: * list directories with lots of files in them compactly. ! 10: * It supports three variants for listings: ! 11: * ! 12: * 1) Columnar output. ! 13: * 2) Stream output. ! 14: * 3) Old one per line format. ! 15: * ! 16: * Columnar output is the default. ! 17: * If, however, the standard output is not a teletype, the default ! 18: * is one-per-line. ! 19: * ! 20: * With columnar output, the items are sorted down the columns. ! 21: * We use columns only for a directory we are interpreting. ! 22: * Thus, in particular, we do not use columns for ! 23: * ! 24: * ls /usr/bin/p* ! 25: * ! 26: * This version of ls also prints non-printing characters as '?' if ! 27: * the standard output is a teletype. ! 28: * ! 29: * Flags relating to these and other new features are: ! 30: * ! 31: * -m force stream output. ! 32: * ! 33: * -1 force one entry per line, e.g. to a teletype ! 34: * ! 35: * -q force non-printings to be '?'s, e.g. to a file ! 36: * ! 37: * -c force columnar output, e.g. into a file ! 38: * ! 39: * -n like -l, but user/group id's in decimal rather than ! 40: * looking in /etc/passwd to save time ! 41: */ ! 42: ! 43: #include <sys/param.h> ! 44: #include <sys/stat.h> ! 45: #include <sys/dir.h> ! 46: #include <stdio.h> ! 47: #include <ctype.h> ! 48: ! 49: ! 50: #define NFILES 1024 ! 51: FILE *pwdf, *dirf; ! 52: ! 53: struct lbuf { ! 54: union { ! 55: char lname[15]; ! 56: char *namep; ! 57: } ln; ! 58: char ltype; ! 59: short lnum; ! 60: short lflags; ! 61: short lnl; ! 62: short luid; ! 63: short lgid; ! 64: long lsize; ! 65: long lmtime; ! 66: }; ! 67: ! 68: int aflg, dflg, lflg, sflg, tflg, uflg, iflg, fflg, gflg, cflg; ! 69: int Aflg, nflg, qflg, across; ! 70: int nopad; ! 71: char buff[32]; ! 72: int rflg = 1; ! 73: long year; ! 74: int flags; ! 75: int lastuid = -1; ! 76: char tbuf[16]; ! 77: long tblocks; ! 78: int statreq; ! 79: struct lbuf *flist[NFILES]; ! 80: struct lbuf **lastp = flist; ! 81: struct lbuf **firstp = flist; ! 82: char *dotp = "."; ! 83: ! 84: char *makename(); ! 85: struct lbuf *gstat(); ! 86: char *ctime(); ! 87: long nblock(); ! 88: ! 89: #define ISARG 0100000 ! 90: int colwidth = 15; ! 91: int outcol; ! 92: ! 93: char obuf[BUFSIZ]; ! 94: ! 95: main(argc, argv) ! 96: char *argv[]; ! 97: { ! 98: int i; ! 99: register struct lbuf *ep, **ep1; ! 100: register struct lbuf **slastp; ! 101: struct lbuf **epp; ! 102: struct lbuf lb; ! 103: char *t; ! 104: char *cp; ! 105: int compar(); ! 106: ! 107: Aflg = getuid() == 0; ! 108: setbuf(stdout, obuf); ! 109: time(&lb.lmtime); ! 110: year = lb.lmtime - 6L*30L*24L*60L*60L; /* 6 months ago */ ! 111: qflg = gtty(1, buff) == 0; ! 112: /* ! 113: * If the standard output is not a teletype, ! 114: * then we default to one-per-line format ! 115: * otherwise decide between stream and ! 116: * columnar based on our name. ! 117: */ ! 118: if (qflg) { ! 119: cflg = 1; ! 120: for (cp = argv[0]; cp[0] && cp[1]; cp++) ! 121: continue; ! 122: /* ! 123: * Name ends in l => stream ! 124: */ ! 125: if (cp[0] == 'l') ! 126: nopad = 1, cflg = 0; ! 127: /* ! 128: * ... if doesn't end in l or s ==> columns sorted across ! 129: * ! 130: else if (cp[0] == 'x') ! 131: across = 1; ! 132: */ ! 133: } ! 134: if (--argc > 0 && *argv[1] == '-') { ! 135: argv++; ! 136: while (*++*argv) switch (**argv) { ! 137: /* ! 138: * c - force columnar output ! 139: */ ! 140: case 'c': ! 141: cflg = 1; ! 142: nopad = 0; ! 143: continue; ! 144: /* ! 145: * m - force stream output ! 146: */ ! 147: case 'm': ! 148: cflg = 0; ! 149: nopad = 1; ! 150: continue; ! 151: /* ! 152: * x - force sort across ! 153: */ ! 154: case 'x': ! 155: across = 1; ! 156: nopad = 0; ! 157: cflg = 1; ! 158: continue; ! 159: /* ! 160: * q - force ?'s in output ! 161: */ ! 162: case 'q': ! 163: qflg = 1; ! 164: continue; ! 165: /* ! 166: * 1 - force 1/line in output ! 167: */ ! 168: case '1': ! 169: cflg = 0; ! 170: nopad = 0; ! 171: continue; ! 172: /* STANDARD FLAGS */ ! 173: case 'a': ! 174: aflg++; ! 175: continue; ! 176: ! 177: case 'A': ! 178: Aflg = !Aflg; ! 179: continue; ! 180: ! 181: case 's': ! 182: colwidth += 5; ! 183: sflg++; ! 184: statreq++; ! 185: continue; ! 186: ! 187: case 'd': ! 188: dflg++; ! 189: continue; ! 190: ! 191: /* ! 192: * n - don't look in password file ! 193: */ ! 194: case 'n': ! 195: nflg++; ! 196: case 'l': ! 197: lflg++; ! 198: statreq++; ! 199: continue; ! 200: ! 201: case 'r': ! 202: rflg = -1; ! 203: continue; ! 204: ! 205: case 't': ! 206: tflg++; ! 207: statreq++; ! 208: continue; ! 209: ! 210: case 'u': ! 211: uflg++; ! 212: continue; ! 213: ! 214: case 'i': ! 215: colwidth += 5; ! 216: iflg++; ! 217: continue; ! 218: ! 219: case 'f': ! 220: fflg++; ! 221: continue; ! 222: ! 223: case 'g': ! 224: gflg++; ! 225: continue; ! 226: ! 227: default: ! 228: continue; ! 229: } ! 230: argc--; ! 231: } ! 232: if (fflg) { ! 233: aflg++; ! 234: lflg = 0; ! 235: sflg = 0; ! 236: tflg = 0; ! 237: statreq = 0; ! 238: } ! 239: if(lflg) { ! 240: cflg = 0; ! 241: t = "/etc/passwd"; ! 242: if (gflg) ! 243: t = "/etc/group"; ! 244: nopad = 0; ! 245: colwidth = 70; ! 246: pwdf = fopen(t, "r"); ! 247: } ! 248: if (argc==0) { ! 249: argc++; ! 250: argv = &dotp - 1; ! 251: } ! 252: for (i=0; i < argc; i++) { ! 253: if ((ep = gstat(*++argv, 1))==NULL) ! 254: continue; ! 255: ep->ln.namep = *argv; ! 256: ep->lflags |= ISARG; ! 257: } ! 258: qsort(firstp, lastp - firstp, sizeof *lastp, compar); ! 259: slastp = lastp; ! 260: for (epp=firstp; epp<slastp; epp++) { ! 261: ep = *epp; ! 262: if (ep->ltype=='d' && dflg==0 || fflg) { ! 263: if (argc>1) ! 264: printf("\n%s:\n", ep->ln.namep); ! 265: lastp = slastp; ! 266: readdir(ep->ln.namep); ! 267: if (fflg==0) ! 268: qsort(slastp,lastp - slastp,sizeof *lastp,compar); ! 269: if (lflg || sflg) ! 270: printf("total %D", tblocks); ! 271: pem(slastp, lastp); ! 272: newline(); ! 273: } else ! 274: pentry(ep); ! 275: } ! 276: if (outcol) ! 277: putc('\n', stdout); ! 278: fflush(stdout); ! 279: } ! 280: ! 281: pem(slp, lp) ! 282: register struct lbuf **slp, **lp; ! 283: { ! 284: int ncols, nrows, row, col; ! 285: register struct lbuf **ep; ! 286: ! 287: ncols = 80 / colwidth; ! 288: if (ncols == 1 || cflg == 0) { ! 289: for (ep = slp; ep < lp; ep++) ! 290: pentry(*ep); ! 291: return; ! 292: } ! 293: if (across) { ! 294: for (ep = slp; ep < lp; ep++) ! 295: pentry(*ep); ! 296: return; ! 297: } ! 298: if (statreq) ! 299: slp--; ! 300: nrows = (lp - slp - 1) / ncols + 1; ! 301: for (row = 0; row < nrows; row++) { ! 302: col = row == 0 && statreq; ! 303: for (; col < ncols; col++) { ! 304: ep = slp + (nrows * col) + row; ! 305: if (ep < lp) ! 306: pentry(*ep); ! 307: } ! 308: if (outcol) ! 309: printf("\n"); ! 310: } ! 311: } ! 312: ! 313: pputchar(c) ! 314: char c; ! 315: { ! 316: ! 317: switch (c) { ! 318: case '\t': ! 319: outcol = (outcol + 8) &~ 7; ! 320: break; ! 321: case '\n': ! 322: outcol = 0; ! 323: break; ! 324: default: ! 325: if (qflg && (c < ' ' || c >= 0177)) ! 326: c = '?'; ! 327: outcol++; ! 328: break; ! 329: } ! 330: putc(c, stdout); ! 331: } ! 332: ! 333: newline() ! 334: { ! 335: if (outcol) ! 336: putc('\n', stdout); ! 337: outcol = 0; ! 338: } ! 339: ! 340: column() ! 341: { ! 342: ! 343: if (outcol == 0) ! 344: return; ! 345: if (nopad) { ! 346: putc(',', stdout); ! 347: outcol++; ! 348: if (outcol + colwidth + 2 > 80) { ! 349: putc('\n', stdout); ! 350: outcol = 0; ! 351: return; ! 352: } ! 353: putc(' ', stdout); ! 354: outcol++; ! 355: return; ! 356: } ! 357: if (cflg == 0) { ! 358: putc('\n', stdout); ! 359: return; ! 360: } ! 361: if ((outcol / colwidth + 2) * colwidth > 80) { ! 362: putc('\n', stdout); ! 363: outcol = 0; ! 364: return; ! 365: } ! 366: do { ! 367: outcol++; ! 368: putc(' ', stdout); ! 369: } while (outcol % colwidth); ! 370: } ! 371: ! 372: ! 373: getname(uid, buf) ! 374: int uid; ! 375: char buf[]; ! 376: { ! 377: int j, c, n, i; ! 378: ! 379: if (uid==lastuid) ! 380: return(0); ! 381: if(pwdf == NULL) ! 382: return(-1); ! 383: rewind(pwdf); ! 384: lastuid = -1; ! 385: do { ! 386: i = 0; ! 387: j = 0; ! 388: n = 0; ! 389: while((c=fgetc(pwdf)) != '\n') { ! 390: if (c==EOF) ! 391: return(-1); ! 392: if (c==':') { ! 393: j++; ! 394: c = '0'; ! 395: } ! 396: if (j==0) ! 397: buf[i++] = c; ! 398: if (j==2) ! 399: n = n*10 + c - '0'; ! 400: } ! 401: } while (n != uid); ! 402: buf[i++] = '\0'; ! 403: lastuid = uid; ! 404: return(0); ! 405: } ! 406: ! 407: long ! 408: nblock(size) ! 409: long size; ! 410: { ! 411: return((size+511)>>9); ! 412: } ! 413: ! 414: int m1[] = { 1, S_IREAD>>0, 'r', '-' }; ! 415: int m2[] = { 1, S_IWRITE>>0, 'w', '-' }; ! 416: int m3[] = { 2, S_ISUID, 's', S_IEXEC>>0, 'x', '-' }; ! 417: int m4[] = { 1, S_IREAD>>3, 'r', '-' }; ! 418: int m5[] = { 1, S_IWRITE>>3, 'w', '-' }; ! 419: int m6[] = { 2, S_ISGID, 's', S_IEXEC>>3, 'x', '-' }; ! 420: int m7[] = { 1, S_IREAD>>6, 'r', '-' }; ! 421: int m8[] = { 1, S_IWRITE>>6, 'w', '-' }; ! 422: int m9[] = { 2, S_ISVTX, 't', S_IEXEC>>6, 'x', '-' }; ! 423: ! 424: int *m[] = { m1, m2, m3, m4, m5, m6, m7, m8, m9}; ! 425: ! 426: pmode(aflag) ! 427: { ! 428: register int **mp; ! 429: ! 430: flags = aflag; ! 431: for (mp = &m[0]; mp < &m[sizeof(m)/sizeof(m[0])];) ! 432: select(*mp++); ! 433: } ! 434: ! 435: select(pairp) ! 436: register int *pairp; ! 437: { ! 438: register int n; ! 439: ! 440: n = *pairp++; ! 441: while (--n>=0 && (flags&*pairp++)==0) ! 442: pairp++; ! 443: pputchar(*pairp); ! 444: } ! 445: ! 446: char * ! 447: makename(dir, file) ! 448: char *dir, *file; ! 449: { ! 450: static char dfile[100]; ! 451: register char *dp, *fp; ! 452: register int i; ! 453: ! 454: dp = dfile; ! 455: fp = dir; ! 456: while (*fp) ! 457: *dp++ = *fp++; ! 458: *dp++ = '/'; ! 459: fp = file; ! 460: for (i=0; i<DIRSIZ; i++) ! 461: *dp++ = *fp++; ! 462: *dp = 0; ! 463: return(dfile); ! 464: } ! 465: ! 466: readdir(dir) ! 467: char *dir; ! 468: { ! 469: static struct direct dentry; ! 470: register int j; ! 471: register struct lbuf *ep; ! 472: ! 473: if ((dirf = fopen(dir, "r")) == NULL) { ! 474: printf("%s unreadable\n", dir); ! 475: return; ! 476: } ! 477: tblocks = 0; ! 478: for(;;) { ! 479: if (fread(&dentry, sizeof(dentry), 1, dirf) != 1) ! 480: break; ! 481: if (dentry.d_ino==0 || ! 482: aflg==0 && dentry.d_name[0]=='.' && ( ! 483: !Aflg || ! 484: dentry.d_name[1]=='\0' ! 485: || dentry.d_name[1]=='.' && dentry.d_name[2]=='\0')) ! 486: continue; ! 487: ep = gstat(makename(dir, dentry.d_name), 0); ! 488: if (ep==NULL) ! 489: continue; ! 490: if (ep->lnum != -1) ! 491: ep->lnum = dentry.d_ino; ! 492: for (j=0; j<DIRSIZ; j++) ! 493: ep->ln.lname[j] = dentry.d_name[j]; ! 494: } ! 495: fclose(dirf); ! 496: } ! 497: ! 498: struct lbuf * ! 499: gstat(file, argfl) ! 500: char *file; ! 501: { ! 502: struct stat statb; ! 503: register struct lbuf *rep; ! 504: static int nomocore; ! 505: ! 506: if (nomocore) ! 507: return(NULL); ! 508: rep = (struct lbuf *)malloc(sizeof(struct lbuf)); ! 509: if (rep==NULL) { ! 510: fprintf(stderr, "ls: out of memory\n"); ! 511: nomocore = 1; ! 512: return(NULL); ! 513: } ! 514: if (lastp >= &flist[NFILES]) { ! 515: static int msg; ! 516: lastp--; ! 517: if (msg==0) { ! 518: fprintf(stderr, "ls: too many files\n"); ! 519: msg++; ! 520: } ! 521: } ! 522: *lastp++ = rep; ! 523: rep->lflags = 0; ! 524: rep->lnum = 0; ! 525: rep->ltype = '-'; ! 526: if (argfl || statreq) { ! 527: if (stat(file, &statb)<0) { ! 528: printf("%s not found\n", file); ! 529: statb.st_ino = -1; ! 530: statb.st_size = 0; ! 531: statb.st_mode = 0; ! 532: if (argfl) { ! 533: lastp--; ! 534: return(0); ! 535: } ! 536: } ! 537: rep->lnum = statb.st_ino; ! 538: rep->lsize = statb.st_size; ! 539: switch(statb.st_mode&S_IFMT) { ! 540: ! 541: case S_IFDIR: ! 542: rep->ltype = 'd'; ! 543: break; ! 544: ! 545: case S_IFBLK: ! 546: rep->ltype = 'b'; ! 547: rep->lsize = statb.st_rdev; ! 548: break; ! 549: ! 550: case S_IFCHR: ! 551: rep->ltype = 'c'; ! 552: rep->lsize = statb.st_rdev; ! 553: break; ! 554: } ! 555: rep->lflags = statb.st_mode & ~S_IFMT; ! 556: rep->luid = statb.st_uid; ! 557: rep->lgid = statb.st_gid; ! 558: rep->lnl = statb.st_nlink; ! 559: if(uflg) ! 560: rep->lmtime = statb.st_atime; ! 561: else if (cflg) ! 562: rep->lmtime = statb.st_ctime; ! 563: else ! 564: rep->lmtime = statb.st_mtime; ! 565: tblocks += nblock(statb.st_size); ! 566: } ! 567: return(rep); ! 568: } ! 569: ! 570: compar(pp1, pp2) ! 571: struct lbuf **pp1, **pp2; ! 572: { ! 573: register struct lbuf *p1, *p2; ! 574: ! 575: p1 = *pp1; ! 576: p2 = *pp2; ! 577: if (dflg==0) { ! 578: if (p1->lflags&ISARG && p1->ltype=='d') { ! 579: if (!(p2->lflags&ISARG && p2->ltype=='d')) ! 580: return(1); ! 581: } else { ! 582: if (p2->lflags&ISARG && p2->ltype=='d') ! 583: return(-1); ! 584: } ! 585: } ! 586: if (tflg) { ! 587: if(p2->lmtime == p1->lmtime) ! 588: return(0); ! 589: if(p2->lmtime > p1->lmtime) ! 590: return(rflg); ! 591: return(-rflg); ! 592: } ! 593: return(rflg * strcmp(p1->lflags&ISARG? p1->ln.namep: p1->ln.lname, ! 594: p2->lflags&ISARG? p2->ln.namep: p2->ln.lname)); ! 595: } ! 596: pentry(ap) ! 597: struct lbuf *ap; ! 598: { ! 599: struct { char dminor, dmajor;}; ! 600: register t; ! 601: register struct lbuf *p; ! 602: register char *cp; ! 603: ! 604: p = ap; ! 605: if (p->lnum == -1) ! 606: return; ! 607: column(); ! 608: if (iflg) ! 609: if (nopad && !lflg) ! 610: printf("%d ", p->lnum); ! 611: else ! 612: printf("%5d ", p->lnum); ! 613: if (sflg) ! 614: if (nopad && !lflg) ! 615: printf("%D ", nblock(p->lsize)); ! 616: else ! 617: printf("%4D ", nblock(p->lsize)); ! 618: if (lflg) { ! 619: pputchar(p->ltype); ! 620: pmode(p->lflags); ! 621: printf("%2d ", p->lnl); ! 622: t = p->luid; ! 623: if(gflg) ! 624: t = p->lgid; ! 625: if (nflg == 0 && getname(t, tbuf)==0) ! 626: printf("%-8.8s", tbuf); ! 627: else ! 628: printf("%-8d", t); ! 629: if (p->ltype=='b' || p->ltype=='c') ! 630: printf("%3d,%3d", major((int)p->lsize), minor((int)p->lsize)); ! 631: else ! 632: printf("%7ld", p->lsize); ! 633: cp = ctime(&p->lmtime); ! 634: if(p->lmtime < year) ! 635: printf(" %-7.7s %-4.4s ", cp+4, cp+20); else ! 636: printf(" %-12.12s ", cp+4); ! 637: } ! 638: if (p->lflags&ISARG) ! 639: printf("%s", p->ln.namep); ! 640: else ! 641: printf("%.14s", p->ln.lname); ! 642: } ! 643: /* char printf_id[] = "@(#) printf.c:2.2 6/5/79";*/ ! 644: #include "varargs.h" ! 645: /* This version of printf is compatible with the Version 7 C ! 646: * printf. The differences are only minor except that this ! 647: * printf assumes it is to print through pputchar. Version 7 ! 648: * printf is more general (and is much larger) and includes ! 649: * provisions for floating point. ! 650: */ ! 651: ! 652: ! 653: #define MAXOCT 11 /* Maximum octal digits in a long */ ! 654: #define MAXINT 32767 /* largest normal length positive integer */ ! 655: #define BIG 1000000000 /* largest power of 10 less than an unsigned long */ ! 656: #define MAXDIGS 10 /* number of digits in BIG */ ! 657: ! 658: static int width, sign, fill; ! 659: ! 660: char *b_dconv(); ! 661: ! 662: printf(va_alist) ! 663: va_dcl ! 664: { ! 665: va_list ap; ! 666: register char *fmt; ! 667: char fcode; ! 668: int prec; ! 669: int length,mask1,nbits,n; ! 670: long int mask2, num; ! 671: register char *bptr; ! 672: char *ptr; ! 673: char buf[134]; ! 674: ! 675: va_start(ap); ! 676: fmt = va_arg(ap,char *); ! 677: for (;;) { ! 678: /* process format string first */ ! 679: while ((fcode = *fmt++)!='%') { ! 680: /* ordinary (non-%) character */ ! 681: if (fcode=='\0') ! 682: return; ! 683: pputchar(fcode); ! 684: } ! 685: /* length modifier: -1 for h, 1 for l, 0 for none */ ! 686: length = 0; ! 687: /* check for a leading - sign */ ! 688: sign = 0; ! 689: if (*fmt == '-') { ! 690: sign++; ! 691: fmt++; ! 692: } ! 693: /* a '0' may follow the - sign */ ! 694: /* this is the requested fill character */ ! 695: fill = 1; ! 696: if (*fmt == '0') { ! 697: fill--; ! 698: fmt++; ! 699: } ! 700: ! 701: /* Now comes a digit string which may be a '*' */ ! 702: if (*fmt == '*') { ! 703: width = va_arg(ap, int); ! 704: if (width < 0) { ! 705: width = -width; ! 706: sign = !sign; ! 707: } ! 708: fmt++; ! 709: } ! 710: else { ! 711: width = 0; ! 712: while (*fmt>='0' && *fmt<='9') ! 713: width = width * 10 + (*fmt++ - '0'); ! 714: } ! 715: ! 716: /* maybe a decimal point followed by more digits (or '*') */ ! 717: if (*fmt=='.') { ! 718: if (*++fmt == '*') { ! 719: prec = va_arg(ap, int); ! 720: fmt++; ! 721: } ! 722: else { ! 723: prec = 0; ! 724: while (*fmt>='0' && *fmt<='9') ! 725: prec = prec * 10 + (*fmt++ - '0'); ! 726: } ! 727: } ! 728: else ! 729: prec = -1; ! 730: ! 731: /* ! 732: * At this point, "sign" is nonzero if there was ! 733: * a sign, "fill" is 0 if there was a leading ! 734: * zero and 1 otherwise, "width" and "prec" ! 735: * contain numbers corresponding to the digit ! 736: * strings before and after the decimal point, ! 737: * respectively, and "fmt" addresses the next ! 738: * character after the whole mess. If there was ! 739: * no decimal point, "prec" will be -1. ! 740: */ ! 741: switch (*fmt) { ! 742: case 'L': ! 743: case 'l': ! 744: length = 2; ! 745: /* no break!! */ ! 746: case 'h': ! 747: case 'H': ! 748: length--; ! 749: fmt++; ! 750: break; ! 751: } ! 752: ! 753: /* ! 754: * At exit from the following switch, we will ! 755: * emit the characters starting at "bptr" and ! 756: * ending at "ptr"-1, unless fcode is '\0'. ! 757: */ ! 758: switch (fcode = *fmt++) { ! 759: /* process characters and strings first */ ! 760: case 'c': ! 761: buf[0] = va_arg(ap, int); ! 762: ptr = bptr = &buf[0]; ! 763: if (buf[0] != '\0') ! 764: ptr++; ! 765: break; ! 766: case 's': ! 767: bptr = va_arg(ap,char *); ! 768: if (bptr==0) ! 769: bptr = "(null pointer)"; ! 770: if (prec < 0) ! 771: prec = MAXINT; ! 772: for (n=0; *bptr++ && n < prec; n++) ; ! 773: ptr = --bptr; ! 774: bptr -= n; ! 775: break; ! 776: case 'O': ! 777: length = 1; ! 778: fcode = 'o'; ! 779: /* no break */ ! 780: case 'o': ! 781: case 'X': ! 782: case 'x': ! 783: if (length > 0) ! 784: num = va_arg(ap,long); ! 785: else ! 786: num = (unsigned)va_arg(ap,int); ! 787: if (fcode=='o') { ! 788: mask1 = 0x7; ! 789: mask2 = 0x1fffffffL; ! 790: nbits = 3; ! 791: } ! 792: else { ! 793: mask1 = 0xf; ! 794: mask2 = 0x0fffffffL; ! 795: nbits = 4; ! 796: } ! 797: n = (num!=0); ! 798: bptr = buf + MAXOCT + 3; ! 799: /* shift and mask for speed */ ! 800: do ! 801: if (((int) num & mask1) < 10) ! 802: *--bptr = ((int) num & mask1) + 060; ! 803: else ! 804: *--bptr = ((int) num & mask1) + 0127; ! 805: while (num = (num >> nbits) & mask2); ! 806: ! 807: if (fcode=='o') { ! 808: if (n) ! 809: *--bptr = '0'; ! 810: } ! 811: else ! 812: if (!sign && fill <= 0) { ! 813: pputchar('0'); ! 814: pputchar(fcode); ! 815: width -= 2; ! 816: } ! 817: else { ! 818: *--bptr = fcode; ! 819: *--bptr = '0'; ! 820: } ! 821: ptr = buf + MAXOCT + 3; ! 822: break; ! 823: case 'D': ! 824: case 'U': ! 825: case 'I': ! 826: length = 1; ! 827: fcode = fcode + 'a' - 'A'; ! 828: /* no break */ ! 829: case 'd': ! 830: case 'i': ! 831: case 'u': ! 832: if (length > 0) ! 833: num = va_arg(ap,long); ! 834: else { ! 835: n = va_arg(ap,int); ! 836: if (fcode=='u') ! 837: num = (unsigned) n; ! 838: else ! 839: num = (long) n; ! 840: } ! 841: if (n = (fcode != 'u' && num < 0)) ! 842: num = -num; ! 843: /* now convert to digits */ ! 844: bptr = b_dconv(num, buf); ! 845: if (n) ! 846: *--bptr = '-'; ! 847: if (fill == 0) ! 848: fill = -1; ! 849: ptr = buf + MAXDIGS + 1; ! 850: break; ! 851: default: ! 852: /* not a control character, ! 853: * print it. ! 854: */ ! 855: ptr = bptr = &fcode; ! 856: ptr++; ! 857: break; ! 858: } ! 859: if (fcode != '\0') ! 860: b_emit(bptr,ptr); ! 861: } ! 862: va_end(ap); ! 863: } ! 864: ! 865: /* b_dconv converts the unsigned long integer "value" to ! 866: * printable decimal and places it in "buffer", right-justified. ! 867: * The value returned is the address of the first non-zero character, ! 868: * or the address of the last character if all are zero. ! 869: * The result is NOT null terminated, and is MAXDIGS characters long, ! 870: * starting at buffer[1] (to allow for insertion of a sign). ! 871: * ! 872: * This program assumes it is running on 2's complement machine ! 873: * with reasonable overflow treatment. ! 874: */ ! 875: char * ! 876: b_dconv(value, buffer) ! 877: long value; ! 878: char *buffer; ! 879: { ! 880: register char *bp; ! 881: register int svalue; ! 882: int n; ! 883: long lval; ! 884: ! 885: bp = buffer; ! 886: ! 887: /* zero is a special case */ ! 888: if (value == 0) { ! 889: bp += MAXDIGS; ! 890: *bp = '0'; ! 891: return(bp); ! 892: } ! 893: ! 894: /* develop the leading digit of the value in "n" */ ! 895: n = 0; ! 896: while (value < 0) { ! 897: value -= BIG; /* will eventually underflow */ ! 898: n++; ! 899: } ! 900: while ((lval = value - BIG) >= 0) { ! 901: value = lval; ! 902: n++; ! 903: } ! 904: ! 905: /* stash it in buffer[1] to allow for a sign */ ! 906: bp[1] = n + '0'; ! 907: /* ! 908: * Now develop the rest of the digits. Since speed counts here, ! 909: * we do it in two loops. The first gets "value" down until it ! 910: * is no larger than MAXINT. The second one uses integer divides ! 911: * rather than long divides to speed it up. ! 912: */ ! 913: bp += MAXDIGS + 1; ! 914: while (value > MAXINT) { ! 915: *--bp = (int)(value % 10) + '0'; ! 916: value /= 10; ! 917: } ! 918: ! 919: /* cannot lose precision */ ! 920: svalue = value; ! 921: while (svalue > 0) { ! 922: *--bp = (svalue % 10) + '0'; ! 923: svalue /= 10; ! 924: } ! 925: ! 926: /* fill in intermediate zeroes if needed */ ! 927: if (buffer[1] != '0') { ! 928: while (bp > buffer + 2) ! 929: *--bp = '0'; ! 930: --bp; ! 931: } ! 932: return(bp); ! 933: } ! 934: ! 935: /* ! 936: * This program sends string "s" to pputchar. The character after ! 937: * the end of "s" is given by "send". This allows the size of the ! 938: * field to be computed; it is stored in "alen". "width" contains the ! 939: * user specified length. If width<alen, the width will be taken to ! 940: * be alen. "sign" is zero if the string is to be right-justified ! 941: * in the field, nonzero if it is to be left-justified. "fill" is ! 942: * 0 if the string is to be padded with '0', positive if it is to be ! 943: * padded with ' ', and negative if an initial '-' should appear before ! 944: * any padding in right-justification (to avoid printing "-3" as ! 945: * "000-3" where "-0003" was intended). ! 946: */ ! 947: b_emit(s, send) ! 948: register char *s; ! 949: char *send; ! 950: { ! 951: char cfill; ! 952: register int alen; ! 953: int npad; ! 954: ! 955: alen = send - s; ! 956: if (alen > width) ! 957: width = alen; ! 958: cfill = fill>0? ' ': '0'; ! 959: ! 960: /* we may want to print a leading '-' before anything */ ! 961: if (*s == '-' && fill < 0) { ! 962: pputchar(*s++); ! 963: alen--; ! 964: width--; ! 965: } ! 966: npad = width - alen; ! 967: ! 968: /* emit any leading pad characters */ ! 969: if (!sign) ! 970: while (--npad >= 0) ! 971: pputchar(cfill); ! 972: ! 973: /* emit the string itself */ ! 974: while (--alen >= 0) ! 975: pputchar(*s++); ! 976: ! 977: /* emit trailing pad characters */ ! 978: if (sign) ! 979: while (--npad >= 0) ! 980: pputchar(cfill); ! 981: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.