|
|
1.1 ! root 1: /* $Source: /src386/usr/bin/pax/list.c,v $ ! 2: * ! 3: * $Revision: 1.1 $ ! 4: * ! 5: * list.c - List all files on an archive ! 6: * ! 7: * DESCRIPTION ! 8: * ! 9: * These function are needed to support archive table of contents and ! 10: * verbose mode during extraction and creation of achives. ! 11: * ! 12: * AUTHOR ! 13: * ! 14: * Mark H. Colburn, NAPS International ([email protected]) ! 15: * ! 16: * Sponsored by The USENIX Association for public distribution. ! 17: * ! 18: * Copyright (c) 1989 Mark H. Colburn. ! 19: * All rights reserved. ! 20: * ! 21: * Redistribution and use in source and binary forms are permitted ! 22: * provided that the above copyright notice is duplicated in all such ! 23: * forms and that any documentation, advertising materials, and other ! 24: * materials related to such distribution and use acknowledge that the ! 25: * software was developed * by Mark H. Colburn and sponsored by The ! 26: * USENIX Association. ! 27: * ! 28: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR ! 29: * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED ! 30: * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. ! 31: * ! 32: * $Log: list.c,v $ ! 33: * Revision 1.1 92/08/28 08:02:15 bin ! 34: * Initial revision ! 35: * ! 36: * Revision 1.1 89/02/14 16:47:59 jep ! 37: * Initial revision ! 38: * ! 39: * Revision 1.1 88/12/23 18:02:14 mark ! 40: * Initial revision ! 41: * ! 42: */ ! 43: ! 44: #ifndef lint ! 45: static char *ident = "$Id: list.c,v 1.1 92/08/28 08:02:15 bin Exp Locker: bin $"; ! 46: static char *copyright = "Copyright (c) 1989 Mark H. Colburn.\nAll rights reserved.\n"; ! 47: #endif /* ! lint */ ! 48: ! 49: ! 50: /* Headers */ ! 51: ! 52: #include "pax.h" ! 53: ! 54: ! 55: /* Defines */ ! 56: ! 57: /* ! 58: * isodigit returns non zero iff argument is an octal digit, zero otherwise ! 59: */ ! 60: #define ISODIGIT(c) (((c) >= '0') && ((c) <= '7')) ! 61: ! 62: ! 63: /* Function Prototypes */ ! 64: ! 65: #if __STDC__ ! 66: ! 67: static void cpio_entry(char *, Stat *); ! 68: static void tar_entry(char *, Stat *); ! 69: static void pax_entry(char *, Stat *); ! 70: static void print_mode(ushort); ! 71: static long from_oct(int digs, char *where); ! 72: ! 73: #else /* !__STDC__ */ ! 74: ! 75: static void cpio_entry(); ! 76: static void tar_entry(); ! 77: static void pax_entry(); ! 78: static void print_mode(); ! 79: static long from_oct(); ! 80: ! 81: #endif /* __STDC__ */ ! 82: ! 83: ! 84: /* Internal Identifiers */ ! 85: ! 86: static char *monnames[] = { ! 87: "Jan", "Feb", "Mar", "Apr", "May", "Jun", ! 88: "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" ! 89: }; ! 90: ! 91: ! 92: /* read_header - read a header record ! 93: * ! 94: * DESCRIPTION ! 95: * ! 96: * Read a record that's supposed to be a header record. Return its ! 97: * address in "head", and if it is good, the file's size in ! 98: * asb->sb_size. Decode things from a file header record into a "Stat". ! 99: * Also set "head_standard" to !=0 or ==0 depending whether header record ! 100: * is "Unix Standard" tar format or regular old tar format. ! 101: * ! 102: * PARAMETERS ! 103: * ! 104: * char *name - pointer which will contain name of file ! 105: * Stat *asb - pointer which will contain stat info ! 106: * ! 107: * RETURNS ! 108: * ! 109: * Return 1 for success, 0 if the checksum is bad, EOF on eof, 2 for a ! 110: * record full of zeros (EOF marker). ! 111: */ ! 112: ! 113: #if __STDC__ ! 114: ! 115: int read_header(char *name, Stat *asb) ! 116: ! 117: #else ! 118: ! 119: int read_header(name, asb) ! 120: char *name; ! 121: Stat *asb; ! 122: ! 123: #endif ! 124: { ! 125: int i; ! 126: long sum; ! 127: long recsum; ! 128: Link *link; ! 129: char *p; ! 130: char hdrbuf[BLOCKSIZE]; ! 131: ! 132: memset((char *)asb, 0, sizeof(Stat)); ! 133: /* read the header from the buffer */ ! 134: if (buf_read(hdrbuf, BLOCKSIZE) != 0) { ! 135: return (EOF); ! 136: } ! 137: ! 138: strcpy(name, hdrbuf); ! 139: ! 140: recsum = from_oct(8, &hdrbuf[148]); ! 141: sum = 0; ! 142: p = hdrbuf; ! 143: for (i = 0 ; i < 500; i++) { ! 144: ! 145: /* ! 146: * We can't use unsigned char here because of old compilers, e.g. V7. ! 147: */ ! 148: sum += 0xFF & *p++; ! 149: } ! 150: ! 151: /* Adjust checksum to count the "chksum" field as blanks. */ ! 152: for (i = 0; i < 8; i++) { ! 153: sum -= 0xFF & hdrbuf[148 + i]; ! 154: } ! 155: sum += ' ' * 8; ! 156: ! 157: if (sum == 8 * ' ') { ! 158: ! 159: /* ! 160: * This is a zeroed record...whole record is 0's except for the 8 ! 161: * blanks we faked for the checksum field. ! 162: */ ! 163: return (2); ! 164: } ! 165: if (sum == recsum) { ! 166: /* ! 167: * Good record. Decode file size and return. ! 168: */ ! 169: if (hdrbuf[156] != LNKTYPE) { ! 170: asb->sb_size = from_oct(1 + 12, &hdrbuf[124]); ! 171: } ! 172: asb->sb_mtime = from_oct(1 + 12, &hdrbuf[136]); ! 173: asb->sb_mode = from_oct(8, &hdrbuf[100]); ! 174: ! 175: if (strcmp(&hdrbuf[257], TMAGIC) == 0) { ! 176: /* Unix Standard tar archive */ ! 177: head_standard = 1; ! 178: #ifdef NONAMES ! 179: asb->sb_uid = from_oct(8, &hdrbuf[108]); ! 180: asb->sb_gid = from_oct(8, &hdrbuf[116]); ! 181: #else ! 182: asb->sb_uid = finduid(&hdrbuf[265]); ! 183: asb->sb_gid = findgid(&hdrbuf[297]); ! 184: #endif ! 185: switch (hdrbuf[156]) { ! 186: case BLKTYPE: ! 187: case CHRTYPE: ! 188: asb->sb_rdev = makedev(from_oct(8, &hdrbuf[329]), ! 189: from_oct(8, &hdrbuf[337])); ! 190: break; ! 191: default: ! 192: /* do nothing... */ ! 193: break; ! 194: } ! 195: } else { ! 196: /* Old fashioned tar archive */ ! 197: head_standard = 0; ! 198: asb->sb_uid = from_oct(8, &hdrbuf[108]); ! 199: asb->sb_gid = from_oct(8, &hdrbuf[116]); ! 200: } ! 201: ! 202: switch (hdrbuf[156]) { ! 203: case REGTYPE: ! 204: case AREGTYPE: ! 205: /* ! 206: * Berkeley tar stores directories as regular files with a ! 207: * trailing / ! 208: */ ! 209: if (name[strlen(name) - 1] == '/') { ! 210: name[strlen(name) - 1] = '\0'; ! 211: asb->sb_mode |= S_IFDIR; ! 212: } else { ! 213: asb->sb_mode |= S_IFREG; ! 214: } ! 215: break; ! 216: case LNKTYPE: ! 217: asb->sb_nlink = 2; ! 218: linkto(&hdrbuf[157], asb); ! 219: linkto(name, asb); ! 220: asb->sb_mode |= S_IFREG; ! 221: break; ! 222: case BLKTYPE: ! 223: asb->sb_mode |= S_IFBLK; ! 224: break; ! 225: case CHRTYPE: ! 226: asb->sb_mode |= S_IFCHR; ! 227: break; ! 228: case DIRTYPE: ! 229: asb->sb_mode |= S_IFDIR; ! 230: break; ! 231: #ifdef S_IFLNK ! 232: case SYMTYPE: ! 233: asb->sb_mode |= S_IFLNK; ! 234: strcpy(asb->sb_link, &hdrbuf[157]); ! 235: break; ! 236: #endif ! 237: #ifdef S_IFIFO ! 238: case FIFOTYPE: ! 239: asb->sb_mode |= S_IFIFO; ! 240: break; ! 241: #endif ! 242: #ifdef S_IFCTG ! 243: case CONTTYPE: ! 244: asb->sb_mode |= S_IFCTG; ! 245: break; ! 246: #endif ! 247: } ! 248: return (1); ! 249: } ! 250: return (0); ! 251: } ! 252: ! 253: ! 254: /* print_entry - print a single table-of-contents entry ! 255: * ! 256: * DESCRIPTION ! 257: * ! 258: * Print_entry prints a single line of file information. The format ! 259: * of the line is the same as that used by the LS command. For some ! 260: * archive formats, various fields may not make any sense, such as ! 261: * the link count on tar archives. No error checking is done for bad ! 262: * or invalid data. ! 263: * ! 264: * PARAMETERS ! 265: * ! 266: * char *name - pointer to name to print an entry for ! 267: * Stat *asb - pointer to the stat structure for the file ! 268: */ ! 269: ! 270: #if __STDC__ ! 271: ! 272: void print_entry(char *name, Stat *asb) ! 273: ! 274: #else ! 275: ! 276: void print_entry(name, asb) ! 277: char *name; ! 278: Stat *asb; ! 279: ! 280: #endif ! 281: { ! 282: switch (ar_interface) { ! 283: case TAR: ! 284: tar_entry(name, asb); ! 285: break; ! 286: case CPIO: ! 287: cpio_entry(name, asb); ! 288: break; ! 289: case PAX: pax_entry(name, asb); ! 290: break; ! 291: } ! 292: } ! 293: ! 294: ! 295: /* cpio_entry - print a verbose cpio-style entry ! 296: * ! 297: * DESCRIPTION ! 298: * ! 299: * Print_entry prints a single line of file information. The format ! 300: * of the line is the same as that used by the traditional cpio ! 301: * command. No error checking is done for bad or invalid data. ! 302: * ! 303: * PARAMETERS ! 304: * ! 305: * char *name - pointer to name to print an entry for ! 306: * Stat *asb - pointer to the stat structure for the file ! 307: */ ! 308: ! 309: #if __STDC__ ! 310: ! 311: static void cpio_entry(char *name, Stat *asb) ! 312: ! 313: #else ! 314: ! 315: static void cpio_entry(name, asb) ! 316: char *name; ! 317: Stat *asb; ! 318: ! 319: #endif ! 320: { ! 321: struct tm *atm; ! 322: Link *from; ! 323: struct passwd *pwp; ! 324: struct group *grp; ! 325: ! 326: if (f_list && f_verbose) { ! 327: fprintf(msgfile, "%-7o", asb->sb_mode); ! 328: atm = localtime(&asb->sb_mtime); ! 329: if (pwp = getpwuid((int) USH(asb->sb_uid))) { ! 330: fprintf(msgfile, "%-6s", pwp->pw_name); ! 331: } else { ! 332: fprintf(msgfile, "%-6u", USH(asb->sb_uid)); ! 333: } ! 334: fprintf(msgfile,"%7ld %3s %2d %02d:%02d:%02d %4d ", ! 335: asb->sb_size, monnames[atm->tm_mon], ! 336: atm->tm_mday, atm->tm_hour, atm->tm_min, ! 337: atm->tm_sec, atm->tm_year + 1900); ! 338: } ! 339: fprintf(msgfile, "%s", name); ! 340: if ((asb->sb_nlink > 1) && (from = islink(name, asb))) { ! 341: fprintf(msgfile, " linked to %s", from->l_name); ! 342: } ! 343: #ifdef S_IFLNK ! 344: if ((asb->sb_mode & S_IFMT) == S_IFLNK) { ! 345: fprintf(msgfile, " symbolic link to %s", asb->sb_link); ! 346: } ! 347: #endif /* S_IFLNK */ ! 348: putc('\n', msgfile); ! 349: } ! 350: ! 351: ! 352: /* tar_entry - print a tar verbose mode entry ! 353: * ! 354: * DESCRIPTION ! 355: * ! 356: * Print_entry prints a single line of tar file information. The format ! 357: * of the line is the same as that produced by the traditional tar ! 358: * command. No error checking is done for bad or invalid data. ! 359: * ! 360: * PARAMETERS ! 361: * ! 362: * char *name - pointer to name to print an entry for ! 363: * Stat *asb - pointer to the stat structure for the file ! 364: */ ! 365: ! 366: #if __STDC__ ! 367: ! 368: static void tar_entry(char *name, Stat *asb) ! 369: ! 370: #else ! 371: ! 372: static void tar_entry(name, asb) ! 373: char *name; ! 374: Stat *asb; ! 375: ! 376: #endif ! 377: { ! 378: struct tm *atm; ! 379: int i; ! 380: int mode; ! 381: char *symnam = "NULL"; ! 382: Link *link; ! 383: ! 384: if ((mode = asb->sb_mode & S_IFMT) == S_IFDIR) { ! 385: return; /* don't print directories */ ! 386: } ! 387: if (f_extract) { ! 388: switch (mode) { ! 389: #ifdef S_IFLNK ! 390: case S_IFLNK: /* This file is a symbolic link */ ! 391: i = readlink(name, symnam, PATH_MAX - 1); ! 392: if (i < 0) { /* Could not find symbolic link */ ! 393: warn("can't read symbolic link", strerror()); ! 394: } else { /* Found symbolic link filename */ ! 395: symnam[i] = '\0'; ! 396: fprintf(msgfile, "x %s symbolic link to %s\n", name, symnam); ! 397: } ! 398: break; ! 399: #endif ! 400: case S_IFREG: /* It is a link or a file */ ! 401: if ((asb->sb_nlink > 1) && (link = islink(name, asb))) { ! 402: fprintf(msgfile, "%s linked to %s\n", name, link->l_name); ! 403: } else { ! 404: fprintf(msgfile, "x %s, %ld bytes, %d tape blocks\n", ! 405: name, asb->sb_size, ROUNDUP(asb->sb_size, ! 406: BLOCKSIZE) / BLOCKSIZE); ! 407: } ! 408: } ! 409: } else if (f_append || f_create) { ! 410: switch (mode) { ! 411: #ifdef S_IFLNK ! 412: case S_IFLNK: /* This file is a symbolic link */ ! 413: i = readlink(name, symnam, PATH_MAX - 1); ! 414: if (i < 0) { /* Could not find symbolic link */ ! 415: warn("can't read symbolic link", strerror()); ! 416: } else { /* Found symbolic link filename */ ! 417: symnam[i] = '\0'; ! 418: fprintf(msgfile, "a %s symbolic link to %s\n", name, symnam); ! 419: } ! 420: break; ! 421: #endif ! 422: case S_IFREG: /* It is a link or a file */ ! 423: fprintf(msgfile, "a %s ", name); ! 424: if ((asb->sb_nlink > 1) && (link = islink(name, asb))) { ! 425: fprintf(msgfile, "link to %s\n", link->l_name); ! 426: } else { ! 427: fprintf(msgfile, "%ld Blocks\n", ! 428: ROUNDUP(asb->sb_size, BLOCKSIZE) / BLOCKSIZE); ! 429: } ! 430: break; ! 431: } ! 432: } else if (f_list) { ! 433: if (f_verbose) { ! 434: atm = localtime(&asb->sb_mtime); ! 435: print_mode(asb->sb_mode); ! 436: fprintf(msgfile," %d/%d %6d %3s %2d %02d:%02d %4d %s", ! 437: asb->sb_uid, asb->sb_gid, asb->sb_size, ! 438: monnames[atm->tm_mon], atm->tm_mday, atm->tm_hour, ! 439: atm->tm_min, atm->tm_year + 1900, name); ! 440: } else { ! 441: fprintf(msgfile, "%s", name); ! 442: } ! 443: switch (mode) { ! 444: #ifdef S_IFLNK ! 445: case S_IFLNK: /* This file is a symbolic link */ ! 446: i = readlink(name, symnam, PATH_MAX - 1); ! 447: if (i < 0) { /* Could not find symbolic link */ ! 448: warn("can't read symbolic link", strerror()); ! 449: } else { /* Found symbolic link filename */ ! 450: symnam[i] = '\0'; ! 451: fprintf(msgfile, " symbolic link to %s", symnam); ! 452: } ! 453: break; ! 454: #endif ! 455: case S_IFREG: /* It is a link or a file */ ! 456: if ((asb->sb_nlink > 1) && (link = islink(name, asb))) { ! 457: fprintf(msgfile, " linked to %s", link->l_name); ! 458: } ! 459: break; /* Do not print out directories */ ! 460: } ! 461: fputc('\n', msgfile); ! 462: } else { ! 463: fprintf(msgfile, "? %s %ld blocks\n", name, ! 464: ROUNDUP(asb->sb_size, BLOCKSIZE) / BLOCKSIZE); ! 465: } ! 466: } ! 467: ! 468: ! 469: /* pax_entry - print a verbose cpio-style entry ! 470: * ! 471: * DESCRIPTION ! 472: * ! 473: * Print_entry prints a single line of file information. The format ! 474: * of the line is the same as that used by the LS command. ! 475: * No error checking is done for bad or invalid data. ! 476: * ! 477: * PARAMETERS ! 478: * ! 479: * char *name - pointer to name to print an entry for ! 480: * Stat *asb - pointer to the stat structure for the file ! 481: */ ! 482: ! 483: #if __STDC__ ! 484: ! 485: static void pax_entry(char *name, Stat *asb) ! 486: ! 487: #else ! 488: ! 489: static void pax_entry(name, asb) ! 490: char *name; ! 491: Stat *asb; ! 492: ! 493: #endif ! 494: { ! 495: struct tm *atm; ! 496: Link *from; ! 497: struct passwd *pwp; ! 498: struct group *grp; ! 499: ! 500: if (f_list && f_verbose) { ! 501: print_mode(asb->sb_mode); ! 502: fprintf(msgfile, " %2d", asb->sb_nlink); ! 503: atm = localtime(&asb->sb_mtime); ! 504: if (pwp = getpwuid((int) USH(asb->sb_uid))) { ! 505: fprintf(msgfile, " %-8s", pwp->pw_name); ! 506: } else { ! 507: fprintf(msgfile, " %-8u", USH(asb->sb_uid)); ! 508: } ! 509: if (grp = getgrgid((int) USH(asb->sb_gid))) { ! 510: fprintf(msgfile, " %-8s", grp->gr_name); ! 511: } else { ! 512: fprintf(msgfile, " %-8u", USH(asb->sb_gid)); ! 513: } ! 514: switch (asb->sb_mode & S_IFMT) { ! 515: case S_IFBLK: ! 516: case S_IFCHR: ! 517: fprintf(msgfile, "\t%3d, %3d", ! 518: major(asb->sb_rdev), minor(asb->sb_rdev)); ! 519: break; ! 520: case S_IFREG: ! 521: fprintf(msgfile, "\t%8ld", asb->sb_size); ! 522: break; ! 523: default: ! 524: fprintf(msgfile, "\t "); ! 525: } ! 526: fprintf(msgfile," %3s %2d %02d:%02d ", ! 527: monnames[atm->tm_mon], atm->tm_mday, ! 528: atm->tm_hour, atm->tm_min); ! 529: } ! 530: fprintf(msgfile, "%s", name); ! 531: if ((asb->sb_nlink > 1) && (from = islink(name, asb))) { ! 532: fprintf(msgfile, " == %s", from->l_name); ! 533: } ! 534: #ifdef S_IFLNK ! 535: if ((asb->sb_mode & S_IFMT) == S_IFLNK) { ! 536: fprintf(msgfile, " -> %s", asb->sb_link); ! 537: } ! 538: #endif /* S_IFLNK */ ! 539: putc('\n', msgfile); ! 540: } ! 541: ! 542: ! 543: /* print_mode - fancy file mode display ! 544: * ! 545: * DESCRIPTION ! 546: * ! 547: * Print_mode displays a numeric file mode in the standard unix ! 548: * representation, ala ls (-rwxrwxrwx). No error checking is done ! 549: * for bad mode combinations. FIFOS, sybmbolic links, sticky bits, ! 550: * block- and character-special devices are supported if supported ! 551: * by the hosting implementation. ! 552: * ! 553: * PARAMETERS ! 554: * ! 555: * ushort mode - The integer representation of the mode to print. ! 556: */ ! 557: ! 558: #if __STDC__ ! 559: ! 560: static void print_mode(ushort mode) ! 561: ! 562: #else ! 563: ! 564: static void print_mode(mode) ! 565: ushort mode; ! 566: ! 567: #endif ! 568: { ! 569: /* Tar does not print the leading identifier... */ ! 570: if (ar_interface != TAR) { ! 571: switch (mode & S_IFMT) { ! 572: case S_IFDIR: ! 573: putc('d', msgfile); ! 574: break; ! 575: #ifdef S_IFLNK ! 576: case S_IFLNK: ! 577: putc('l', msgfile); ! 578: break; ! 579: #endif /* S_IFLNK */ ! 580: case S_IFBLK: ! 581: putc('b', msgfile); ! 582: break; ! 583: case S_IFCHR: ! 584: putc('c', msgfile); ! 585: break; ! 586: #ifdef S_IFIFO ! 587: case S_IFIFO: ! 588: putc('p', msgfile); ! 589: break; ! 590: #endif /* S_IFIFO */ ! 591: case S_IFREG: ! 592: default: ! 593: putc('-', msgfile); ! 594: break; ! 595: } ! 596: } ! 597: putc(mode & 0400 ? 'r' : '-', msgfile); ! 598: putc(mode & 0200 ? 'w' : '-', msgfile); ! 599: putc(mode & 0100 ! 600: ? mode & 04000 ? 's' : 'x' ! 601: : mode & 04000 ? 'S' : '-', msgfile); ! 602: putc(mode & 0040 ? 'r' : '-', msgfile); ! 603: putc(mode & 0020 ? 'w' : '-', msgfile); ! 604: putc(mode & 0010 ! 605: ? mode & 02000 ? 's' : 'x' ! 606: : mode & 02000 ? 'S' : '-', msgfile); ! 607: putc(mode & 0004 ? 'r' : '-', msgfile); ! 608: putc(mode & 0002 ? 'w' : '-', msgfile); ! 609: putc(mode & 0001 ! 610: ? mode & 01000 ? 't' : 'x' ! 611: : mode & 01000 ? 'T' : '-', msgfile); ! 612: } ! 613: ! 614: ! 615: /* from_oct - quick and dirty octal conversion ! 616: * ! 617: * DESCRIPTION ! 618: * ! 619: * From_oct will convert an ASCII representation of an octal number ! 620: * to the numeric representation. The number of characters to convert ! 621: * is given by the parameter "digs". If there are less numbers than ! 622: * specified by "digs", then the routine returns -1. ! 623: * ! 624: * PARAMETERS ! 625: * ! 626: * int digs - Number to of digits to convert ! 627: * char *where - Character representation of octal number ! 628: * ! 629: * RETURNS ! 630: * ! 631: * The value of the octal number represented by the first digs ! 632: * characters of the string where. Result is -1 if the field ! 633: * is invalid (all blank, or nonoctal). ! 634: * ! 635: * ERRORS ! 636: * ! 637: * If the field is all blank, then the value returned is -1. ! 638: * ! 639: */ ! 640: ! 641: #if __STDC__ ! 642: ! 643: static long from_oct(int digs, char *where) ! 644: ! 645: #else ! 646: ! 647: static long from_oct(digs, where) ! 648: int digs; /* number of characters to convert */ ! 649: char *where; /* character representation of octal number */ ! 650: ! 651: #endif ! 652: { ! 653: long value; ! 654: ! 655: while (isspace(*where)) { /* Skip spaces */ ! 656: where++; ! 657: if (--digs <= 0) { ! 658: return(-1); /* All blank field */ ! 659: } ! 660: } ! 661: value = 0; ! 662: while (digs > 0 && ISODIGIT(*where)) { /* Scan til nonoctal */ ! 663: value = (value << 3) | (*where++ - '0'); ! 664: --digs; ! 665: } ! 666: ! 667: if (digs > 0 && *where && !isspace(*where)) { ! 668: return(-1); /* Ended on non-space/nul */ ! 669: } ! 670: return(value); ! 671: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.