# 2.11BSD#431 - /usr/src/usr.bin/shar/shar.c

##### Functions

    archive           X
    beginfile         X
    copyout           X
    endfile           X
    footer            X
    header            X
    initial           X
    main              X
    outdec            X
    outline           X
    shar              X
    uuarchive         X
    uuencode          X

##### Variables

    Basename          X
    Count             X
    Ctrlcount         X
    Delim             X
    Filter            X
    Lastchar          X
    Modeset           X
    Overcheck         X
    Prefix            X
    Uucode            X
    Verbose           X

##### Macros

    CAT               X
    CHDIR             X
    CHMOD             X
    DECODE            X
    ECHO              X
    ENC               X
    EXTRACT           X
    FAILURE           X
    FALSE             X
    MKDIR             X
    PATH              X
    SED               X
    SUCCESS           X
    TEST              X
    TRUE              X
    WC_C              X
    badctrl           X

##### typedef's

    Boole             X
    Status            X

       1: /*
       2: 	Shar puts readable text files together in a package
       3: 	from which they are extracted with /bin/sh and friends.
       4: */
       5:
       6: #include <stdio.h>
       7: #include <sys/types.h>
       8: #include <sys/stat.h>
       9: #include <ctype.h>
      10:
      11: #ifndef lint
      12: static  char    sccsid[] = "@(#)shar.c 2.0 (Usenet) 3/11/86";
      13: #endif
      14:
      15: typedef int     Boole;
      16: #define TRUE    ((Boole) 1)
      17: #define FALSE   ((Boole) 0)
      18: typedef int     Status;
      19: #define SUCCESS 0
      20: #define FAILURE 1
      21:
      22: /* GLOBALS */
      23: int     Lastchar;   /* the last character printed */
      24: int     Ctrlcount;  /* how many bad control characters are in file */
      25:
      26: /* COMMANDS */
      27: #define EXTRACT "#! /bin/sh"          /* magic exec string at shar file start */
      28: #define PATH    "/bin:/usr/bin:$PATH" /* search path for programs */
      29: #define CAT     "cat";                /* /bin/cat */
      30: #define SED     "sed 's/^%s//'"       /* /bin/sed removes Prefix from lines */
      31: #define MKDIR   "mkdir"               /* make a new dirctory */
      32: #define CHMOD   "chmod"               /* change file mode */
      33: #define CHDIR   "cd"                  /* change current directory */
      34: #define TEST    "test"                /* /bin/test files */
      35: #define WC_C    "wc -c <"             /* counts chars in file */
      36: #define ECHO    "echo shar:"          /* echo a message to extractor */
      37: #define DECODE  "uudecode"            /* used to decode uuencoded files */
      38:
      39: /*FUNCTION main: traverse files to make archive to standard output */
      40: main (argc, argv) char **argv;
      41:     {
      42:     int     shar ();
      43:     int     optind;
      44:
      45:     if ((optind = initial (argc, argv)) < 0)
      46:         exit (FAILURE);
      47:
      48:     if (header (argc, argv, optind))
      49:         exit (FAILURE);
      50:
      51:     while (optind < argc)
      52:         traverse (argv[optind++], shar);
      53:
      54:     footer ();
      55:
      56:     exit (SUCCESS);
      57:     }
      58:
      59: /* OPTIONS */
      60: Boole   Verbose = FALSE;       /* provide append/extract feedback */
      61: Boole   Basename = FALSE;      /* extract into basenames */
      62: Boole   Count = FALSE;         /* count characters to check transfer */
      63: Boole   Overcheck = TRUE;      /* check overwriting */
      64: Boole   Uucode = FALSE;        /* uuencode the file */
      65: char    *Delim = "SHAR_EOF";   /* put after each file */
      66: char    Filter[100] = CAT;     /* used to extract archived files */
      67: char    *Prefix = NULL;        /* line prefix to avoid funny chars */
      68: Boole   Modeset = FALSE;       /* set exact modes on extraction */
      69:
      70: /*FUNCTION: initial: do option parsing and any setup */
      71: int /* returns the index of the first operand file */
      72: initial (argc, argv) char **argv;
      73:     {
      74:     int     errflg = 0;
      75:     extern  int     optind;
      76:     extern  char    *optarg;
      77:     int     C;
      78:     char    *optstring = "abcmsuvp:d:";
      79:     char    *usage = "[-abcmsuv] [-p prefix] [-d delim] files > archive";
      80:
      81:     while ((C = getopt (argc, argv, optstring)) != EOF)
      82:         switch (C)
      83:             {
      84:             case 'u': Uucode = TRUE; break;
      85:             case 'b': Basename = TRUE; break;
      86:             case 'c': Count = TRUE; break;
      87:             case 'd': Delim = optarg; break;
      88:             case 'm': Modeset = TRUE; break;
      89:             case 's': /* silent running */
      90:                 Overcheck = FALSE;
      91:                 Verbose = FALSE;
      92:                 Count = FALSE;
      93:                 Prefix = NULL;
      94:                 break;
      95:             case 'a': /* all the options */
      96:                 Verbose = TRUE;
      97:                 Count = TRUE;
      98:                 Basename = TRUE;
      99:                 /* fall through to set prefix */
     100:                 optarg = "	X";
     101:                 /* FALLTHROUGH */
     102:             case 'p': (void) sprintf (Filter, SED, Prefix = optarg); break;
     103:             case 'v': Verbose = TRUE; break;
     104:             default: errflg++;
     105:             }
     106:
     107:     if (errflg || optind == argc)
     108:         {
     109:         if (optind == argc)
     110:             fprintf (stderr, "shar: No input files\n");
     111:         fprintf (stderr, "Usage: shar %s\n", usage);
     112:         return (-1);
     113:         }
     114:
     115:     return (optind);
     116:     }
     117:
     118: /*FUNCTION header: print header for archive */
     119: header (argc, argv, optind)
     120: char    **argv;
     121:     {
     122:     int     i;
     123:     Boole   problems = FALSE;
     124:     long    clock;
     125:     char    *ctime ();
     126:     char    *getenv ();
     127:     char    *NAME = getenv ("NAME");
     128:     char    *ORG = getenv ("ORGANIZATION");
     129:
     130:     for (i = optind; i < argc; i++)
     131:         if (access (argv[i], 4)) /* check read permission */
     132:             {
     133:             fprintf (stderr, "shar: Can't read '%s'\n", argv[i]);
     134:             problems++;
     135:             }
     136:
     137:     if (problems)
     138:         return (FAILURE);
     139:
     140:     printf ("%s\n", EXTRACT);
     141:     printf ("# This is a shell archive, meaning:\n");
     142:     printf ("# 1. Remove everything above the %s line.\n", EXTRACT);
     143:     printf ("# 2. Save the resulting text in a file.\n");
     144:     printf ("# 3. Execute the file with /bin/sh (not csh) to create:\n");
     145:     for (i = optind; i < argc; i++)
     146:         printf ("#\t%s\n", argv[i]);
     147:     (void) time (&clock);
     148:     printf ("# This archive created: %s", ctime (&clock));
     149:     if (NAME)
     150:         printf ("# By:\t%s (%s)\n", NAME, ORG ? ORG : "");
     151:     printf ("export PATH; PATH=%s\n", PATH);
     152:     return (SUCCESS);
     153:     }
     154:
     155: /*FUNCTION footer: print end of shell archive */
     156: footer ()
     157:     {
     158:     printf ("exit 0\n");
     159:     printf ("#\tEnd of shell archive\n");
     160:     }
     161:
     162: /* uuencode options available to send cntrl and non-ascii chars */
     163: /* really, this is getting to be too much like cpio or tar */
     164:
     165: /* ENC is the basic 1 character encoding function to make a char printing */
     166: #define ENC(c) (((c) & 077) + ' ')
     167:
     168: /*FUNCTION uuarchive: simulate uuencode to send files */
     169: Status
     170: uuarchive (input, protection, output)
     171: char    *input;
     172: int     protection;
     173: char    *output;
     174:     {
     175:     FILE    *in;
     176:     if (in = fopen (input, "r"))
     177:         {
     178:         printf ("%s << \\%s\n", DECODE, Delim);
     179:         printf ("begin %o %s\n", protection, output);
     180:         uuencode (in, stdout);
     181:         printf ("end\n");
     182:         fclose (in);
     183:         return (SUCCESS);
     184:         }
     185:     return (FAILURE);
     186:     }
     187:
     188: uuencode (in, out)
     189: FILE *in, *out;
     190:     {
     191:     char    buf[80];
     192:     int     i, n;
     193:     for (;;)
     194:         {
     195:         n = fread (buf, 1, 45, in);
     196:         putc (ENC(n), out);
     197:         for (i = 0; i < n; i += 3)
     198:             outdec (&buf[i], out);
     199:         putc ('\n', out);
     200:         if (n <= 0)
     201:             break;
     202:         }
     203:     }
     204:
     205: /* output one group of 3 bytes, pointed at by p, on file ioptr */
     206: outdec (p, ioptr)
     207: char    *p;
     208: FILE    *ioptr;
     209:     {
     210:     int c1, c2, c3, c4;
     211:     c1 = *p >> 2;
     212:     c2 = (*p << 4) & 060 | (p[1] >> 4) & 017;
     213:     c3 = (p[1] << 2) & 074 | (p[2] >> 6) & 03;
     214:     c4 = p[2] & 077;
     215:     putc (ENC(c1), ioptr);
     216:     putc (ENC(c2), ioptr);
     217:     putc (ENC(c3), ioptr);
     218:     putc (ENC(c4), ioptr);
     219:     }
     220:
     221: /*FUNCTION archive: make archive of input file to be extracted to output */
     222: archive (input, output)
     223: char    *input, *output;
     224:     {
     225:     char    buf[BUFSIZ];
     226:     FILE    *ioptr;
     227:
     228:     if (ioptr = fopen (input, "r"))
     229:         {
     230:         Ctrlcount = 0;    /* no bad control characters so far */
     231:         Lastchar = '\n';  /* simulate line start */
     232:
     233:         printf ("%s << \\%s > '%s'\n", Filter, Delim, output);
     234:
     235:         if (Prefix)
     236:             {
     237:             while (fgets (buf, BUFSIZ, ioptr))
     238:                 {
     239:                 outline (Prefix);
     240:                 outline (buf);
     241:                 }
     242:             }
     243:         else copyout (ioptr);
     244:
     245:         if (Lastchar != '\n') /* incomplete last line */
     246:             putchar ('\n');   /* Delim MUST begin new line! */
     247:
     248:         if (Count == TRUE && Lastchar != '\n')
     249:             printf ("%s \"a missing newline was added to '%s'\"\n", ECHO, input);
     250:         if (Count == TRUE && Ctrlcount)
     251:             printf ("%s \"%d control character%s may be missing from '%s'\"\n",
     252:                 ECHO, Ctrlcount, Ctrlcount > 1 ? "s" : "", input);
     253:
     254:         (void) fclose (ioptr);
     255:         return (SUCCESS);
     256:         }
     257:     else
     258:         {
     259:         fprintf (stderr, "shar: Can't open '%s'\n", input);
     260:         return (FAILURE);
     261:         }
     262:     }
     263:
     264: /*FUNCTION copyout: copy ioptr to stdout */
     265: /*
     266: 	Copyout copies its ioptr almost as fast as possible
     267: 	except that it has to keep track of the last character
     268: 	printed.  If the last character is not a newline, then
     269: 	shar has to add one so that the end of file delimiter
     270: 	is recognized by the shell.  This checking costs about
     271: 	a 10% difference in user time.  Otherwise, it is about
     272: 	as fast as cat.  It also might count control characters.
     273: */
     274: #define badctrl(c) (iscntrl (c) && !isspace (c))
     275: copyout (ioptr)
     276: register    FILE    *ioptr;
     277:     {
     278:     register    int     C;
     279:     register    int     L;
     280:     register    count;
     281:
     282:     count = Count;
     283:
     284:     while ((C = getc (ioptr)) != EOF)
     285:         {
     286:         if (count == TRUE && badctrl (C))
     287:             Ctrlcount++;
     288:         L = putchar (C);
     289:         }
     290:
     291:     Lastchar = L;
     292:     }
     293:
     294: /*FUNCTION outline: output a line, recoring last character */
     295: outline (s)
     296: register    char    *s;
     297:     {
     298:     if (*s)
     299:         {
     300:         while (*s)
     301:             {
     302:             if (Count == TRUE && badctrl (*s)) Ctrlcount++;
     303:             putchar (*s++);
     304:             }
     305:         Lastchar = *(s-1);
     306:         }
     307:     }
     308:
     309: /*FUNCTION shar: main archiving routine passed to directory traverser */
     310: shar (file, type, pos)
     311: char    *file;     /* file or directory to be processed */
     312: int     type;      /* either 'f' for file or 'd' for directory */
     313: int     pos;       /* 0 going in to a file or dir, 1 going out */
     314:     {
     315:     struct  stat    statbuf;
     316:     char    *basefile = file;
     317:     int     protection;
     318:
     319:     if (!strcmp (file, "."))
     320:         return;
     321:
     322:     if (stat (file, &statbuf))
     323:         statbuf.st_size = 0;
     324:     else
     325:         protection = statbuf.st_mode & 07777;
     326:
     327:     if (Basename == TRUE)
     328:         {
     329:         while (*basefile) basefile++; /* go to end of name */
     330:         while (basefile > file && *(basefile-1) != '/')
     331:             basefile--;
     332:         }
     333:
     334:     if (pos == 0) /* before the file starts */
     335:         {
     336:         beginfile (basefile, type, statbuf.st_size, protection);
     337:         if (type == 'f')
     338:             {
     339:             if (Uucode)
     340:                 {
     341:                 if (uuarchive (file, protection, basefile) != SUCCESS)
     342:                     exit (FAILURE);
     343:                 }
     344:             else
     345:                 if (archive (file, basefile) != SUCCESS)
     346:                     exit (FAILURE);
     347:             }
     348:         }
     349:     else /* pos == 1, after the file is archived */
     350:         endfile (basefile, type, statbuf.st_size, protection);
     351:     }
     352:
     353: /*FUNCTION beginfile: do activities before packing up a file */
     354: beginfile (basefile, type, size, protection)
     355: char    *basefile;  /* name of the target file */
     356: int     type;       /* either 'd' for directory, or 'f' for file */
     357: long    size;       /* size of the file */
     358: int     protection; /* chmod protection bits */
     359:     {
     360:     if (type == 'd')
     361:         {
     362:         printf ("if %s ! -d '%s'\n", TEST, basefile);
     363:         printf ("then\n");
     364:         if (Verbose == TRUE)
     365:             printf ("	%s \"creating directory '%s'\"\n", ECHO, basefile);
     366:         printf ("	%s '%s'\n", MKDIR, basefile);
     367:         printf ("fi\n");
     368:         if (Verbose == TRUE)
     369:             printf ("%s \"entering directory '%s'\"\n", ECHO, basefile);
     370:         printf ("%s '%s'\n", CHDIR, basefile);
     371:         }
     372:     else /* type == 'f' */
     373:         {
     374:         if (Verbose == TRUE)
     375:             printf ("%s \"extracting '%s'\" '(%ld character%s)'\n",
     376:                 ECHO, basefile, size, size == 1 ? "" : "s");
     377:
     378:         if (Overcheck == TRUE)
     379:             {
     380:             printf ("if %s -f '%s'\n", TEST, basefile);
     381:             printf ("then\n");
     382:             printf ("	%s \"will not over-write existing file '%s'\"\n",
     383:                 ECHO, basefile);
     384:             printf ("else\n");
     385:             }
     386:
     387:         }
     388:     }
     389:
     390: /*FUNCTION endfile: do activities after packing up a file */
     391: endfile (basefile, type, size, protection)
     392: char    *basefile;  /* name of the target file */
     393: int     type;       /* either 'd' for directory, or 'f' for file */
     394: long    size;       /* size of the file */
     395: int     protection; /* chmod protection bits */
     396:     {
     397:     if (type == 'd')
     398:         {
     399:         if (Modeset == TRUE)
     400:             printf ("%s %o .\n", CHMOD, protection);
     401:         if (Verbose == TRUE)
     402:             printf ("%s \"done with directory '%s'\"\n", ECHO, basefile);
     403:         printf ("%s ..\n", CHDIR);
     404:         }
     405:     else /* type == 'f' (plain file) */
     406:         {
     407:         printf ("%s\n", Delim);
     408:         if (Count == TRUE)
     409:             {
     410:             printf ("if %s %ld -ne \"`%s '%s'`\"\n", TEST, size, WC_C, basefile);
     411:             printf ("then\n");
     412:             printf ("	%s \"error transmitting '%s'\" ", ECHO, basefile);
     413:             printf ("'(should have been %ld character%s)'\n",
     414:                 size, size == 1 ? "" : "s");
     415:             printf ("fi\n");
     416:             }
     417:         if (Uucode == FALSE) /* might have to chmod by hand */
     418:             {
     419:             if (Modeset == TRUE) /* set all protection bits (W McKeeman) */
     420:                 printf ("%s %o '%s'\n",
     421:                         CHMOD, protection, basefile);
     422:             else if (protection & 0111) /* executable -> chmod +x */
     423:                 printf ("%s +x '%s'\n", CHMOD, basefile);
     424:             }
     425:         if (Overcheck == TRUE)
     426:             printf ("fi\n");
     427:         }
     428:     }

#### Defined functions

archive defined in line 222; used 1 times

- in line 345

beginfile defined in line 354; used 1 times

- in line 336

copyout defined in line 275; used 1 times

- in line 243

endfile defined in line 391; used 1 times

- in line 350

footer defined in line 156; used 1 times

- in line 54

header defined in line 119; used 1 times

- in line 48

initial defined in line 71; used 1 times

- in line 45

main defined in line 40; never used
outdec defined in line 206; used 1 times

- in line 198

outline defined in line 295; used 2 times

- in line 239-240(2)

shar defined in line 310; used 2 times

- in line 42, 52

uuarchive defined in line 169; used 1 times

- in line 341

uuencode defined in line 188; used 1 times

- in line 180

#### Defined variables

Basename defined in line 61; used 3 times

- in line 85, 98, 327

Count defined in line 62; used 8 times

- in line 86, 92-97(2), 248-250(2), 282, 302, 408

Ctrlcount defined in line 24; used 6 times

- in line 230, 250-252(3), 287, 302

Delim defined in line 65; used 4 times

- in line 87, 178, 233, 407

Filter defined in line 66; used 2 times

- in line 102, 233

Lastchar defined in line 23; used 5 times

- in line 231, 245-248(2), 291, 305

Modeset defined in line 68; used 3 times

- in line 88, 399, 419

Overcheck defined in line 63; used 3 times

- in line 90, 378, 425

Prefix defined in line 67; used 4 times

- in line 93, 102, 235-239(2)

Uucode defined in line 64; used 3 times

- in line 84, 339, 417

Verbose defined in line 60; used 7 times

- in line 91-96(2), 103, 364-368(2), 374, 401

sccsid defined in line 12; never used

#### Defined typedef's

Boole defined in line 15; used 9 times

- in line 60-17(8), 123

Status defined in line 18; used 1 times

- in line 169

#### Defined macros

CAT defined in line 29; used 1 times

- in line 66

CHDIR defined in line 33; used 2 times

- in line 370, 403

CHMOD defined in line 32; used 3 times

- in line 400, 421-423(2)

DECODE defined in line 37; used 1 times

- in line 178

ECHO defined in line 36; used 8 times

- in line 249-252(2), 365-369(2), 376, 383, 402, 412

ENC defined in line 166; used 5 times

- in line 196, 215-218(4)

EXTRACT defined in line 27; used 2 times

- in line 140-142(2)

FAILURE defined in line 20; used 7 times

- in line 46-49(2), 138, 185, 260, 342-346(2)

FALSE defined in line 17; used 10 times

- in line 60-68(5), 90-92(3), 123, 417

MKDIR defined in line 31; used 1 times

- in line 366

PATH defined in line 28; used 1 times

- in line 151

SED defined in line 30; used 1 times

- in line 102

SUCCESS defined in line 19; used 6 times

- in line 56, 152, 183, 255, 341-345(2)

TEST defined in line 34; used 3 times

- in line 362, 380, 410

TRUE defined in line 16; used 23 times

- in line 63, 84-88(4), 96-103(4), 248-250(2), 286, 302, 327, 364-368(2), 374-378(2), 399-401(2), 408, 419, 425

WC_C defined in line 35; used 1 times

- in line 410

badctrl defined in line 274; used 2 times

- in line 286, 302

Last modified: 1986-03-18 Generated: 2016-12-26 | Generated by src2html V0.67 page hit count: 1594 |