[comp.sys.mac.programmer] Fast unshar program for MPW C 3.0

amanda@lts.UUCP (Amanda Walker) (02/18/89)

Here's something that some of you might find useful.  It's a short
C program for MPW 3.0 that's just barely smart enough to unpack
shar files from comp.sources.unix.  It does create subdirectories
if necessary, and it's orders of magnitude faster than the MPW shell
unshar that was posted a while back.  The source is a lot shorter than
the binary, so I thought I'd just post it--that way folks who use THINK C
and so on can tweak it themselves if they want...

--------------------------CUT HERE AND AT BOTTOM-----------------------------
/* unshar for MPW that's good enough for comp.sources.unix archives */

#include <stdio.h>
#include <Files.h>
#include <Errors.h>

int force = 0;  /* force overwriting existing files */
char *progname;

main(argc, argv)
int argc;
char **argv;
{
  progname = *argv;

  if (argc == 1) {
    fprintf(stderr, "### %s - Not enough parameters were specified.\n",
	    progname);
    fprintf(stderr, "# Usage - %s [-f] file [file...]\n", progname);
  } else while (--argc) {
    if (**++argv == '-') {
      switch ((*argv)[1]) {
        case 'f':
          force = 1;
        break;
      }
    } else
      unshar(*argv);
  }
}

unshar(s)
char *s;
{
  char buffer[BUFSIZ];
  char *cp;
  int force;
  FILE *infp, *outfp;
  char unixfilename[64], mpwfilename[64];
  int line;
  short v;
  long dirID, dID;

  infp = fopen(s, "r");
  if (!infp) {
    fprintf(stderr, "### %s - Could not open file %s\n", progname, s);
    return;
  }

  /* skip over news header lines etc. */
  for (line = 1; cp = fgets(buffer, sizeof(buffer), infp); line++)
    if (buffer[0] == '#') break;
  if (!cp) {
    fprintf(stderr, "### %s - Could not locate start of archive in file %s\n",
            progname, s);
    return;
  }

  /* now we should be at the start of the shar archive itself */
  while (cp = fgets(buffer, sizeof(buffer), infp)) {
    line++;
    if (buffer[0] == '#') continue;    /* comment line */
    if (buffer[0] == 'e') { fclose(infp); return; }  /* exit */
    if (buffer[0] == 'i') {
        if (!strncmp(buffer, "if test -f", 10)) {
        /* testing to see if a file is there */
        if (sscanf(buffer, "if test -f '%s'", unixfilename) == 1) {
          /* make Mac relative pathname */
          sprintf(mpwfilename, ":%s", unixfilename);
          /* convert '/' to ':' & vice versa */
          for (cp = mpwfilename+1; *cp; cp++)
            if (*cp == '/')
              *cp = ':';
            else if (*cp == ':')
              *cp = '/';
          cp[-1] = 0;  /* drop trailing quote mark */
          outfp = fopen(mpwfilename, "r");
          if (outfp && !force) {
            fclose(outfp);
            fprintf(stderr, "### %s - Will not clobber existing file '%s'\n",
                progname, mpwfilename);
            while (buffer[0] != 'f') {  /* skip to size "fi" */
              fgets(buffer, sizeof(buffer), infp);
            }
            fgets(buffer, sizeof(buffer), infp);  /* skip over ending comment */
            fgets(buffer, sizeof(buffer), infp);  /* skip over test "fi" */
          } else {
            if (outfp) fclose(outfp);
            create(mpwfilename, 0, 'MPS ', 'TEXT');
            outfp = fopen(mpwfilename, "w");
            fprintf(stderr, "### %s - Extracting '%s'\n", mpwfilename);
            while (buffer[0] != 'X')
              fgets(buffer, sizeof(buffer), infp);
            do {
              fputs(buffer+1, outfp);
              fgets(buffer, sizeof(buffer), infp);
            } while (buffer[0] == 'X');
            fclose(outfp);
            fgets(buffer, sizeof(buffer), infp);  /* skip to next if */
            fgets(buffer, sizeof(buffer), infp);
            fgets(buffer, sizeof(buffer), infp);
            fgets(buffer, sizeof(buffer), infp);
            fgets(buffer, sizeof(buffer), infp);
          }
        } else {
          fprintf(stderr, "### %s - Cannot understand 'if' statement, aborting file:\n", progname);
          fprintf(stderr, "File %s; Line %d # %s", s, line, buffer);
          fclose(infp);
          return;
        }
      } else if (!strncmp(buffer, "if test ! -d", 12)) {
        /* testing to see if a directory is there */
        if (sscanf(buffer, "if test ! -d '%s'", unixfilename) == 1) {
          /* make Mac relative pathname */
          sprintf(mpwfilename, ":%s", unixfilename);
          /* convert '/' to ':' & vice versa */
          for (cp = mpwfilename+1; *cp; cp++)
            if (*cp == '/')
              *cp = ':';
            else if (*cp == ':')
              *cp = '/';
          cp[-1] = 0;  /* drop trailing quote mark */

          /* I wish MPW C had mkdir(), but at least we don't have to do parameter blocks */
          HGetVol(unixfilename, &v, &dirID);
          c2pstr(mpwfilename);
          DirCreate(v, dirID, mpwfilename, &dID);
          fgets(buffer, sizeof(buffer), infp);
          fgets(buffer, sizeof(buffer), infp);
          fgets(buffer, sizeof(buffer), infp);
        }
      }
    }
  }
  fclose(infp);
}
--------------------------------Cut Here-------------------------------

Enjoy,

-- 
Amanda Walker			...!uunet!lts!amanda / lts!amanda@uunet.uu.net
			  InterCon, 11732 Bowman Green Drive, Reston, VA 22090
--
Calm down; it's only ones and zeros...