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
beginfile defined in line 354; used 1 times
copyout defined in line 275; used 1 times
endfile defined in line 391; used 1 times
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
outline defined in line 295; used 2 times
shar defined in line 310; used 2 times
uuarchive defined in line 169; used 1 times
uuencode defined in line 188; used 1 times

Defined variables

Basename defined in line 61; used 3 times
Count defined in line 62; used 8 times
Ctrlcount defined in line 24; used 6 times
Delim defined in line 65; used 4 times
Filter defined in line 66; used 2 times
Lastchar defined in line 23; used 5 times
Modeset defined in line 68; used 3 times
Overcheck defined in line 63; used 3 times
Prefix defined in line 67; used 4 times
Uucode defined in line 64; used 3 times
Verbose defined in line 60; used 7 times
sccsid defined in line 12; never used

Defined typedef's

Boole defined in line 15; used 9 times
Status defined in line 18; used 1 times

Defined macros

CAT defined in line 29; used 1 times
  • in line 66
CHDIR defined in line 33; used 2 times
CHMOD defined in line 32; used 3 times
DECODE defined in line 37; used 1 times
ECHO defined in line 36; used 8 times
ENC defined in line 166; used 5 times
EXTRACT defined in line 27; used 2 times
FAILURE defined in line 20; used 7 times
FALSE defined in line 17; used 10 times
MKDIR defined in line 31; used 1 times
PATH defined in line 28; used 1 times
SED defined in line 30; used 1 times
SUCCESS defined in line 19; used 6 times
TEST defined in line 34; used 3 times
TRUE defined in line 16; used 23 times
WC_C defined in line 35; used 1 times
badctrl defined in line 274; used 2 times
Last modified: 1986-03-18
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 3574
Valid CSS Valid XHTML 1.0 Strict