home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 9 Archive / 09-Archive.zip / zip21.zip / zipnote.c < prev    next >
C/C++ Source or Header  |  1996-04-01  |  13KB  |  501 lines

  1. /*
  2.  
  3.  Copyright (C) 1990-1996 Mark Adler, Richard B. Wales, Jean-loup Gailly,
  4.  Kai Uwe Rommel, Onno van der Linden and Igor Mandrichenko.
  5.  Permission is granted to any individual or institution to use, copy, or
  6.  redistribute this software so long as all of the original files are included,
  7.  that it is not sold for profit, and that this copyright notice is retained.
  8.  
  9. */
  10.  
  11. /*
  12.  *  zipnote.c by Mark Adler.
  13.  */
  14.  
  15. #define UTIL
  16. #include "zip.h"
  17. #include "revision.h"
  18. #include <signal.h>
  19.  
  20.  
  21. /* Character to mark zip entry names in the comment file */
  22. #define MARK '@'
  23. #define MARKE " (comment above this line)"
  24. #define MARKZ " (zip file comment below this line)"
  25.  
  26. /* Temporary zip file name and file pointer */
  27. local char *tempzip;
  28. local FILE *tempzf;
  29.  
  30.  
  31. /* Local functions */
  32. local void handler OF((int));
  33. local void license OF((void));
  34. local void help OF((void));
  35. local void version_info OF((void));
  36. local void putclean OF((char *, int));
  37. local int catalloc OF((char * far *, char *));
  38. int main OF((int, char **));
  39.  
  40.  
  41. void ziperr(c, h)
  42. int c;                  /* error code from the ZE_ class */
  43. char *h;                /* message about how it happened */
  44. /* Issue a message for the error, clean up files and memory, and exit. */
  45. {
  46.   if (PERR(c))
  47.     perror("zipnote error");
  48.   fprintf(stderr, "zipnote error: %s (%s)\n", errors[c-1], h);
  49.   if (tempzf != NULL)
  50.     fclose(tempzf);
  51.   if (tempzip != NULL)
  52.   {
  53.     destroy(tempzip);
  54.     free((zvoid *)tempzip);
  55.   }
  56.   if (zipfile != NULL)
  57.     free((zvoid *)zipfile);
  58.   EXIT(c);
  59. }
  60.  
  61.  
  62. local void handler(s)
  63. int s;                  /* signal number (ignored) */
  64. /* Upon getting a user interrupt, abort cleanly using ziperr(). */
  65. {
  66. #ifndef MSDOS
  67.   putc('\n', stderr);
  68. #endif /* !MSDOS */
  69.   ziperr(ZE_ABORT, "aborting");
  70.   s++;                                  /* keep some compilers happy */
  71. }
  72.  
  73.  
  74. void zipwarn(a, b)
  75. char *a, *b;            /* message strings juxtaposed in output */
  76. /* Print a warning message to stderr and return. */
  77. {
  78.   fprintf(stderr, "zipnote warning: %s%s\n", a, b);
  79. }
  80.  
  81.  
  82. local void license()
  83. /* Print license information to stdout. */
  84. {
  85.   extent i;             /* counter for copyright array */
  86.  
  87.   for (i = 0; i < sizeof(copyright)/sizeof(char *); i++) {
  88.     printf(copyright[i], "zipnote");
  89.     putchar('\n');
  90.   }
  91.   for (i = 0; i < sizeof(disclaimer)/sizeof(char *); i++)
  92.     puts(disclaimer[i]);
  93. }
  94.  
  95.  
  96. local void help()
  97. /* Print help (along with license info) to stdout. */
  98. {
  99.   extent i;             /* counter for help array */
  100.  
  101.   /* help array */
  102.   static const char *text[] = {
  103. "",
  104. "ZipNote %s (%s)",
  105. "Usage:  zipnote [-w] [-b path] zipfile",
  106. "  the default action is to write the comments in zipfile to stdout",
  107. "  -w   write the zipfile comments from stdin",
  108. "  -b   use \"path\" for the temporary zip file",
  109. "  -h   show this help    -v   show version info    -L   show software license",
  110. "",
  111. "Example:",
  112. #ifdef VMS
  113. "     define/user sys$output foo.tmp",
  114. "     zipnote foo.zip",
  115. "     edit foo.tmp",
  116. "     ... then you edit the comments, save, and exit ...",
  117. "     define/user sys$input foo.tmp",
  118. "     zipnote -w foo.zip",
  119. #else /* !VMS */
  120. #  ifdef RISCOS
  121. "     zipnote foo/zip > foo/tmp",
  122. "     <!Edit> foo/tmp",
  123. "     ... then you edit the comments, save, and exit ...",
  124. "     zipnote -w foo/zip < foo/tmp",
  125. #  else /* !VMS && !RISCOS */
  126. "     zipnote foo.zip > foo.tmp",
  127. "     ed foo.tmp",
  128. "     ... then you edit the comments, save, and exit ...",
  129. "     zipnote -w foo.zip < foo.tmp",
  130. #  endif /* ?RISCOS */
  131. #endif /* ?VMS */
  132. "",
  133. "  \"@ name\" can be followed by an \"@=newname\" line to change the name"
  134.   };
  135.  
  136.   for (i = 0; i < sizeof(copyright)/sizeof(char *); i++) {
  137.     printf(copyright[i], "zipnote");
  138.     putchar('\n');
  139.   }
  140.   for (i = 0; i < sizeof(text)/sizeof(char *); i++)
  141.   {
  142.     printf(text[i], VERSION, REVDATE);
  143.     putchar('\n');
  144.   }
  145. }
  146.  
  147.  
  148. local void version_info()
  149. /* Print verbose info about program version and compile time options
  150.    to stdout. */
  151. {
  152.   extent i;             /* counter in text arrays */
  153.  
  154.   static const char CompiledWith[] = "Compiled with %s%s for %s%s%s.\n\n";
  155.  
  156.   /* Options info array */
  157.   static const char *comp_opts[] = {
  158. #ifdef DEBUG
  159.     "DEBUG",
  160. #endif
  161.     NULL
  162.   };
  163.  
  164.   for (i = 0; i < sizeof(copyright)/sizeof(char *); i++)
  165.   {
  166.     printf(copyright[i], "zip");
  167.     putchar('\n');
  168.   }
  169.  
  170.   for (i = 0; i < sizeof(versinfolines)/sizeof(char *); i++)
  171.   {
  172.     printf(versinfolines[i], "ZipNote", VERSION, REVDATE);
  173.     putchar('\n');
  174.   }
  175.  
  176.   printf(CompiledWith,
  177.  
  178. #ifdef __GNUC__
  179.       "gcc ", __VERSION__,
  180. #else
  181.       "(OS specific) cc ", "",
  182. #endif
  183.  
  184. #ifdef RISCOS
  185.       "RISC OS (Acorn Computers Ltd)",
  186. #else
  187. #ifdef AMIGA
  188.       "AmigaDOS"
  189. #else
  190. #ifdef ATARI
  191. #  ifdef __MINT__
  192.       "Atari TOS/MiNT",
  193. #  else
  194.       "Atari TOS",
  195. #  endif
  196. #else
  197. #ifdef CMS_MVS
  198. #  ifdef VM_CMS
  199.       "VM/CMS",
  200. #  else
  201.       "MVS",
  202. #  endif
  203. #else
  204. #ifdef __human68k__
  205.       "Human68k (X68000)",
  206. #else
  207. #ifdef DOS
  208.       "MS-DOS",
  209. #else
  210. #ifdef OS2
  211.       "OS/2",
  212. #else
  213. #ifdef TOPS20
  214.       "TOPS-20",
  215. #else
  216. #ifdef UNIX
  217.       "Unix",
  218. #else
  219. #ifdef VMS
  220.       "VMS",
  221. #else
  222. #ifdef WIN32
  223.       "\n\tWindows 95 / Windows NT (32-bit)",
  224. #else
  225.       "[unrecognized OS]",
  226. #endif /* WIN32 */
  227. #endif /* VMS */
  228. #endif /* UNIX */
  229. #endif /* TOPS20 */
  230. #endif /* OS2 */
  231. #endif /* DOS */
  232. #endif /* __human68k__ */
  233. #endif /* CMS_MVS */
  234. #endif /* ATARI */
  235. #endif /* AMIGA */
  236. #endif /* RISCOS */
  237.  
  238. #ifdef __DATE__
  239.       " on ", __DATE__
  240. #else
  241.       "", ""
  242. #endif
  243.     );
  244.  
  245.   puts("ZipNote special compilation options:");
  246.   for (i = 0; (int)i < (int)(sizeof(comp_opts)/sizeof(char *) - 1); i++)
  247.   {
  248.     printf("\t%s\n",comp_opts[i]);
  249.   }
  250.   if (i == 0)
  251.       puts("\t[none]");
  252. }
  253.  
  254.  
  255. local void putclean(s, n)
  256. char *s;                /* string to write to stdout */
  257. int n;                  /* length of string */
  258. /* Write the string s to stdout, filtering out control characters that are
  259.    not tab or newline (mainly to remove carriage returns), and prefix MARK's
  260.    and backslashes with a backslash.  Also, terminate with a newline if
  261.    needed. */
  262. {
  263.   int c;                /* next character in string */
  264.   int e;                /* last character written */
  265.  
  266.   e = '\n';                     /* if empty, write nothing */
  267.   while (n--)
  268.   {
  269.     c = *(uch *)s++;
  270.     if (c == MARK || c == '\\')
  271.       putchar('\\');
  272.     if (c >= ' ' || c == '\t' || c == '\n')
  273.       { e=c; putchar(e); }
  274.   }
  275.   if (e != '\n')
  276.     putchar('\n');
  277. }
  278.  
  279.  
  280. local int catalloc(a, s)
  281. char * far *a;          /* pointer to a pointer to a malloc'ed string */
  282. char *s;                /* string to concatenate on a */
  283. /* Concatentate the string s to the malloc'ed string pointed to by a.
  284.    Preprocess s by removing backslash escape characters. */
  285. {
  286.   char *p;              /* temporary pointer */
  287.   char *q;              /* temporary pointer */
  288.  
  289.   for (p = q = s; *q; *p++ = *q++)
  290.     if (*q == '\\' && *(q+1))
  291.       q++;
  292.   *p = 0;
  293.   if ((p = malloc(strlen(*a) + strlen(s) + 3)) == NULL)
  294.     return ZE_MEM;
  295.   strcat(strcat(strcpy(p, *a), **a ? "\r\n" : ""), s);
  296.   free((zvoid *)*a);
  297.   *a = p;
  298.   return ZE_OK;
  299. }
  300.  
  301.  
  302. int main(argc, argv)
  303. int argc;               /* number of tokens in command line */
  304. char **argv;            /* command line tokens */
  305. /* Write the comments in the zipfile to stdout, or read them from stdin. */
  306. {
  307.   char a[FNMAX+1];      /* input line buffer */
  308.   ulg c;                /* start of central directory */
  309.   int k;                /* next argument type */
  310.   char *q;              /* steps through option arguments */
  311.   int r;                /* arg counter, temporary variable */
  312.   ulg s;                /* length of central directory */
  313.   int t;                /* attributes of zip file */
  314.   int w;                /* true if updating zip file from stdin */
  315.   FILE *x, *y;          /* input and output zip files */
  316.   struct zlist far *z;  /* steps through zfiles linked list */
  317.  
  318.  
  319.   /* If no args, show help */
  320.   if (argc == 1)
  321.   {
  322.     help();
  323.     EXIT(0);
  324.   }
  325.  
  326.   init_upper();           /* build case map table */
  327.  
  328.   /* Go through args */
  329.   zipfile = tempzip = NULL;
  330.   tempzf = NULL;
  331.   signal(SIGINT, handler);
  332. #ifdef SIGTERM              /* AMIGA has no SIGTERM */
  333.   signal(SIGTERM, handler);
  334. #endif
  335.   k = w = 0;
  336.   for (r = 1; r < argc; r++)
  337.     if (*argv[r] == '-')
  338.       if (argv[r][1])
  339.         for (q = argv[r]+1; *q; q++)
  340.           switch(*q)
  341.           {
  342.             case 'b':   /* Specify path for temporary file */
  343.               if (k)
  344.                 ziperr(ZE_PARMS, "use -b before zip file name");
  345.               else
  346.                 k = 1;          /* Next non-option is path */
  347.               break;
  348.             case 'h':   /* Show help */
  349.               help();  EXIT(0);
  350.             case 'l':  case 'L':  /* Show copyright and disclaimer */
  351.               license();  EXIT(0);
  352.             case 'v':   /* Show version info */
  353.               version_info();  EXIT(0);
  354.             case 'w':
  355.               w = 1;  break;
  356.             default:
  357.               ziperr(ZE_PARMS, "unknown option");
  358.           }
  359.       else
  360.         ziperr(ZE_PARMS, "zip file cannot be stdin");
  361.     else
  362.       if (k == 0)
  363.         if (zipfile == NULL)
  364.         {
  365.           if ((zipfile = ziptyp(argv[r])) == NULL)
  366.             ziperr(ZE_MEM, "was processing arguments");
  367.         }
  368.         else
  369.           ziperr(ZE_PARMS, "can only specify one zip file");
  370.       else
  371.       {
  372.         tempath = argv[r];
  373.         k = 0;
  374.       }
  375.   if (zipfile == NULL)
  376.     ziperr(ZE_PARMS, "need to specify zip file");
  377.  
  378.   /* Read zip file */
  379.   if ((r = readzipfile()) != ZE_OK)
  380.     ziperr(r, zipfile);
  381.   if (zfiles == NULL)
  382.     ziperr(ZE_NAME, zipfile);
  383.  
  384.   /* Put comments to stdout, if not -w */
  385.   if (!w)
  386.   {
  387.     for (z = zfiles; z != NULL; z = z->nxt)
  388.     {
  389.       printf("%c %s\n", MARK, z->zname);
  390.       putclean(z->comment, z->com);
  391.       printf("%c%s\n", MARK, MARKE);
  392.     }
  393.     printf("%c%s\n", MARK, MARKZ);
  394.     putclean(zcomment, zcomlen);
  395.     EXIT(ZE_OK);
  396.   }
  397.  
  398.   /* If updating comments, make sure zip file is writeable */
  399.   if ((x = fopen(zipfile, "a")) == NULL)
  400.     ziperr(ZE_CREAT, zipfile);
  401.   fclose(x);
  402.   t = getfileattr(zipfile);
  403.  
  404.   /* Process stdin, replacing comments */
  405.   z = zfiles;
  406.   while (gets(a) != NULL && (a[0] != MARK || strcmp(a + 1, MARKZ)))
  407.   {                                     /* while input and not file comment */
  408.     if (a[0] != MARK || a[1] != ' ')    /* better be "@ name" */
  409.       ziperr(ZE_NOTE, "unexpected input");
  410.     while (z != NULL && strcmp(a + 2, z->zname))
  411.       z = z->nxt;                       /* allow missing entries in order */
  412.     if (z == NULL)
  413.       ziperr(ZE_NOTE, "unknown entry name");
  414.     if (gets(a) != NULL && a[0] == MARK && a[1] == '=')
  415.     {
  416.       if (z->name != z->zname)
  417.         free((zvoid *)z->zname);
  418.       if ((z->zname = malloc(strlen(a+1))) == NULL)
  419.         ziperr(ZE_MEM, "was changing name");
  420.       strcpy(z->zname, a+2);
  421. /*
  422.  * Don't update z->nam here, we need the old value a little later.....
  423.  * The update is handled in zipcopy().
  424.  */
  425.       gets(a);
  426.     }
  427.     if (z->com)                         /* change zip entry comment */
  428.       free((zvoid *)z->comment);
  429.     z->comment = malloc(1);  *(z->comment) = 0;
  430.     while (a != NULL && *a != MARK)
  431.     {
  432.       if ((r = catalloc(&(z->comment), a)) != ZE_OK)
  433.         ziperr(r, "was building new comments");
  434.       gets(a);
  435.     }
  436.     z->com = strlen(z->comment);
  437.     z = z->nxt;                         /* point to next entry */
  438.   }
  439.   if (a != NULL)                        /* change zip file comment */
  440.   {
  441.     zcomment = malloc(1);  *zcomment = 0;
  442.     while (gets(a) != NULL)
  443.       if ((r = catalloc(&zcomment, a)) != ZE_OK)
  444.         ziperr(r, "was building new comments");
  445.     zcomlen = strlen(zcomment);
  446.   }
  447.  
  448.   /* Open output zip file for writing */
  449.   if ((tempzf = y = fopen(tempzip = tempname(zipfile), FOPW)) == NULL)
  450.     ziperr(ZE_TEMP, tempzip);
  451.  
  452.   /* Open input zip file again, copy preamble if any */
  453.   if ((x = fopen(zipfile, FOPR)) == NULL)
  454.     ziperr(ZE_NAME, zipfile);
  455.   if (zipbeg && (r = fcopy(x, y, zipbeg)) != ZE_OK)
  456.     ziperr(r, r == ZE_TEMP ? tempzip : zipfile);
  457.   tempzn = zipbeg;
  458.  
  459.   /* Go through local entries, copying them over as is */
  460.   fix = 3; /* needed for zipcopy if name changed */
  461.   for (z = zfiles; z != NULL; z = z->nxt) {
  462.     if ((r = zipcopy(z, x, y)) != ZE_OK)
  463.       ziperr(r, "was copying an entry");
  464.   }
  465.   fclose(x);
  466.  
  467.   /* Write central directory and end of central directory with new comments */
  468.   if ((c = ftell(y)) == (ulg)(-1L))    /* get start of central */
  469.     ziperr(ZE_TEMP, tempzip);
  470.   for (z = zfiles; z != NULL; z = z->nxt)
  471.     if ((r = putcentral(z, y)) != ZE_OK)
  472.       ziperr(r, tempzip);
  473.   if ((s = ftell(y)) == -1L)    /* get end of central */
  474.     ziperr(ZE_TEMP, tempzip);
  475.   s -= c;                       /* compute length of central */
  476.   if ((r = putend((int)zcount, s, c, zcomlen, zcomment, y)) != ZE_OK)
  477.     ziperr(r, tempzip);
  478.   tempzf = NULL;
  479.   if (fclose(y))
  480.     ziperr(ZE_TEMP, tempzip);
  481.   if ((r = replace(zipfile, tempzip)) != ZE_OK)
  482.   {
  483.     zipwarn("new zip file left as: ", tempzip);
  484.     free((zvoid *)tempzip);
  485.     tempzip = NULL;
  486.     ziperr(r, "was replacing the original zip file");
  487.   }
  488.   free((zvoid *)tempzip);
  489.   tempzip = NULL;
  490.   setfileattr(zipfile, t);
  491. #ifdef RISCOS
  492.   /* Set the filetype of the zipfile to &DDC */
  493.   setfiletype(zipfile,0xDDC);
  494. #endif
  495.   free((zvoid *)zipfile);
  496.   zipfile = NULL;
  497.  
  498.   /* Done! */
  499.   RETURN(0);
  500. }
  501.