home *** CD-ROM | disk | FTP | other *** search
/ The CDPD Public Domain Collection for CDTV 4 / CDPD_IV.bin / fish / 911-930 / ff912 / uuarc / uuarc.c < prev    next >
C/C++ Source or Header  |  1994-05-04  |  36KB  |  1,155 lines

  1. /*                                                          */
  2. /*                  UUARC V1.1 08/07/93                     */
  3. /*                      J.G.Brandon                         */
  4. /*                                                          */
  5. /*                                                          */
  6. /*  Archiving system based on the 'UU' encoding/decoding    */
  7. /*  algorythms.                                             */
  8. /*                                                          */
  9. /*  Written in 'C' for the public domain using NorthC V1.3  */
  10. /*  on a Commodore Amiga.  Ought to compile/run under most  */
  11. /*  compilers/environments.                                 */
  12. /*                                                          */
  13. /*  No system specific commands/libraries/includes/headers  */
  14. /*  used to make 'C' source portable.  The only system      */
  15. /*  specific part of the program is the pre-processor       */
  16. /*  defined function to identify 'directory separator'      */
  17. /*  characters, used to separate file-names from their      */
  18. /*  paths.                                                  */
  19. /*                                                          */
  20. /*  As NorthC V1.3 isn't completely ANSI 'C' and does not   */
  21. /*  allow prototyping, prototypes have not been used.       */
  22. /*                                                          */
  23.  
  24.  
  25.  
  26. /* If required, comment the next line to stop checksums being added */
  27. /* (This only effects encoding output, decoding will still check    */
  28. /*  checksums if checksums are present)                             */
  29. #define ADDCHECK
  30.  
  31.  
  32.  
  33. /*  Title/version definitions   */
  34.  
  35. #define TITLE       "UUArc"
  36. #define AUTHOR      "Miss J.G.Brandon"
  37. #define VERSION     1
  38. #define REVISION    1
  39. #define TITLESTR    "\n%s Version %d.%d by %s %s.\n\n"
  40. #define TITLESTRPAR TITLE, VERSION, REVISION, AUTHOR, __DATE__
  41.  
  42.  
  43.  
  44. /*  Required standard libraries */
  45.  
  46. #include    <stdio.h>
  47. #include    <ctype.h>
  48. #include    <string.h>
  49. #include    <stdlib.h>
  50. #include    <signal.h>
  51.  
  52. /*  When are standard includes not standard includes?       */
  53. /*  When they miss out definitions that should be there.    */
  54. /*  I'll name no names; but it's a very popular compiler... */
  55. /*  (VERY naughty, as it sets the _STDC_ flag to indicate   */
  56. /*   that it is completely ANSI standard conforming;        */
  57. /*   and these are just the ones missed out that this       */
  58. /*   program needs, there are many more.)                   */
  59.  
  60. #ifndef EXIT_SUCCESS
  61. #define EXIT_SUCCESS        0
  62. #endif
  63.  
  64. #ifndef EXIT_FAILURE
  65. #define EXIT_FAILURE        20
  66. #endif
  67.  
  68. #ifndef L_tmpnam
  69. #define L_tmpnam            0x0FF
  70. #endif
  71.  
  72.  
  73.  
  74. /*  Define conditional close function; attempts to close a file indicated   */
  75. /*  by the supplied file pointer if the pointer is not null                 */
  76.  
  77. #define COND_CLOSE(fptr)    if (fptr != NULL) fclose(fptr)
  78.  
  79.  
  80. /*  Define 'directory-separator' identifier - system specific unfortunately */
  81.  
  82. #define DIR_CHAR(c)         ((c == 0x02F) || (c == 0x03A))
  83.  
  84.  
  85. /*  Define uuencoding/decoding/checking functions   */
  86.  
  87. #define VALIDATE(c)         ((c < 0x020) || (c > 0x060))
  88. #define DECODE(c)           ((c - 0x020) & 0x03F)
  89. #define ENCODE(c)           (c ? ((c & 0x03F) + 0x20) : 0x060)
  90.  
  91.  
  92. /*  Definitions required by program */
  93.  
  94. #define LISTCOM             'l'
  95. #define TESTCOM             't'
  96. #define EXTRACTCOM          'x'
  97. #define DELETECOM           'd'
  98. #define ADDCOM              'a'
  99. #define MOVECOM             'm'
  100. #define PATHCOM             'p'
  101.  
  102. #define BUFSIZE             0x0FF
  103.  
  104. #define ENCODESIZE          45
  105. #define DEFAULTMODE         0744
  106.  
  107. #define NOFILE              0
  108. #define FOUNDFILE           1
  109.  
  110. #define DATALINE            0
  111. #define BEGINLINE           1
  112. #define ENDLINE             2
  113. #define SIZELINE            3
  114. #define BADLINE             4
  115.  
  116. #define STRIPPATH           0
  117. #define LEAVEPATH           1
  118.  
  119. #define SHOWUSAGE           0
  120. #define NOUSAGE             1
  121.  
  122. #define DUNNO               0
  123. #define YES                 1
  124. #define NO                  2
  125.  
  126. #define CHECKSIZE           64
  127.  
  128.  
  129.  
  130. /*  Globally accessable archive, file and temporary file details    */
  131.  
  132. FILE *arc_fptr = NULL, *file_fptr = NULL, *temp_fptr = NULL;
  133. char temp_name[L_tmpnam] = "";
  134.  
  135.  
  136. /*  Globally accessable number of errors counter    */
  137.  
  138. long numerrors = 0;
  139.  
  140.  
  141. /*  Globally accessable path strip flag */
  142.  
  143. int pathflag = STRIPPATH;
  144.  
  145.  
  146.  
  147.  
  148. /*  Strip path name from a filename if required */
  149.  
  150. char *prname(filename, flag)
  151. char *filename;
  152. int flag;
  153. {
  154.     char *stripname;
  155.  
  156.     /*  If full path has been requested, leave it in    */
  157.     if (flag == LEAVEPATH)
  158.         return filename;
  159.  
  160.     /*  Hunt from left to right for a path-indicator character  */
  161.     for(stripname = filename+strlen(filename);
  162.         ((stripname > filename) && (!DIR_CHAR(*stripname)));
  163.         stripname--)
  164.         ;
  165.  
  166.     /*  If path-indicator character found, increment pointer to */
  167.     /*  point to start of file name                             */
  168.     if DIR_CHAR(*stripname)
  169.         stripname++;
  170.  
  171.     /*  Return pointer to filename without path extension   */
  172.     return stripname;
  173. }
  174.  
  175.  
  176.  
  177. /*  String comparison, ignoring case - result same as strcmp */
  178.  
  179. int anycasecmp(string1, string2)
  180. char *string1, *string2;
  181. {
  182.     int i;
  183.     for (i = 0; toupper(string1[i]) == toupper(string2[i]); i++)
  184.         if (string1[i] == '\0')
  185.             return 0;
  186.     return toupper(string1[i]) - toupper(string2[i]);
  187. }
  188.  
  189.  
  190.  
  191. /*  Print archive header information    */
  192.  
  193. void pr_head(archive)
  194. char *archive;
  195. {
  196.     printf(" archive '%s':\n", archive);
  197.     printf("---------------------------------------------\n");
  198. }
  199.  
  200.  
  201.  
  202. /*  Print archive tail information  */
  203.  
  204. void pr_tail()
  205. {
  206.     printf("---------------------------------------------\n");
  207. }
  208.  
  209.  
  210.  
  211. /*  Outputs details of an operation, taking plurals into account    */
  212.  
  213. void operout(operstr,numfiles)
  214. char *operstr;
  215. int numfiles;
  216. {
  217.     if (numfiles == 0)
  218.         printf("No ");
  219.     else
  220.         printf("%d ",numfiles);
  221.  
  222.     if (numfiles != 1)
  223.         printf("files ");
  224.     else
  225.         printf("file ");
  226.  
  227.     printf("%s.\n",operstr);
  228. }
  229.  
  230.  
  231.  
  232. /*  Outputs details of success of an operation  */
  233.  
  234. void succout(operstr, numerrs)
  235. char *operstr;
  236. int numerrs;
  237. {
  238.     if (numerrs == 0)
  239.         printf("%s successful.\n\n",operstr);
  240.     else
  241.         fprintf(stderr,"%s not entirely successful.\n\n",operstr);
  242. }
  243.  
  244.  
  245.  
  246. /*  Outputs details of errors, taking plurals into account  */
  247.  
  248. void errsout(numerrs)
  249. long numerrs;
  250. {
  251.     if (numerrs != 0) {
  252.         fprintf(stderr, "%d error", numerrs);
  253.         if (numerrs != 1)
  254.             fprintf(stderr, "s.\n");
  255.         else
  256.             fprintf(stderr, ".\n");
  257.     }
  258. }
  259.  
  260.  
  261.  
  262. /*  Sends details of command usage to output stream 'ostrm'  */
  263.  
  264. void usage(ostrm)
  265. FILE *ostrm;
  266. {
  267.     fprintf(ostrm,
  268.         "\nUSAGE:\t%s -<command>[%c] <archive> [<filename>]\n",
  269.         TITLE, PATHCOM);
  270.  
  271.     fprintf(ostrm, "\nWhere <command> is one of-\n");
  272.     fprintf(ostrm, "\t%c = List contents of <archive>.\n", LISTCOM);
  273.     fprintf(ostrm, "\t%c = Test contents of <archive>.\n", TESTCOM);
  274.     fprintf(ostrm, "\t%c = Add <filename> to <archive>.\n", ADDCOM);
  275.     fprintf(ostrm, "\t%c = Move <filename> to <archive>.\n", MOVECOM);
  276.     fprintf(ostrm, "\t%c = Extract <filename> from <archive>.\n", EXTRACTCOM);
  277.     fprintf(ostrm,  "\t    (All files if <filename> is missing.)\n");
  278.     fprintf(ostrm, "\t%c = Delete <filename> from <archive>.\n", DELETECOM);
  279.     fprintf(ostrm,  "\t    (All files if <filename> is missing.)\n");
  280.  
  281.     fprintf(ostrm,
  282.         "\nIf included after the archiver command, the '%c' option\n",
  283.         PATHCOM);
  284.     fprintf(ostrm,
  285.         "specifies full path names to be considered; otherwise path\n");
  286.     fprintf(ostrm,
  287.         "names will be ignored by default.\n");
  288.  
  289.     fprintf(ostrm,
  290.         "\nIf applicable, <archive> must include the '.uue' extension.\n\n");
  291. }
  292.  
  293.  
  294.  
  295. /*  A 'clean' exit routine; closes any open files, deletes the temporary    */
  296. /*  file if used, and exits with return code 'retcode'                      */
  297.  
  298. void cleanexit(retcode)
  299. int retcode;
  300. {
  301.     COND_CLOSE(arc_fptr);
  302.     COND_CLOSE(file_fptr);
  303.     COND_CLOSE(temp_fptr);
  304.     if (strcmp(temp_name,"") != 0)
  305.         remove(temp_name);
  306.  
  307.     exit(retcode);
  308. }
  309.  
  310.  
  311.  
  312. /*  Exit routine for errors; displays error 'errorstr' and command usage    */
  313. /*  to the standard error output stream, then 'cleanexit's with a failure   */
  314. /*  return code                                                             */
  315.  
  316. void errorexit(errorstr, usageflag)
  317. char *errorstr;
  318. int usageflag;
  319. {
  320.     fprintf(stderr, "\n\aERROR: %s.\n\n", errorstr);
  321.  
  322.     if (usageflag == SHOWUSAGE)
  323.         usage(stderr);
  324.  
  325.     cleanexit(EXIT_FAILURE);
  326. }
  327.  
  328.  
  329.  
  330. /*  Deal with abnormal program termination */
  331.  
  332. void abnormalexit()
  333. {
  334.     fprintf(stderr, "\n\aERROR: Program aborted.\n\n");
  335.     cleanexit(EXIT_FAILURE);
  336. }
  337.  
  338.  
  339.  
  340. /*  List files in the opened archive    */
  341.  
  342. int listarc()
  343. {
  344.     char buffer[BUFSIZE], filestr[BUFSIZE];
  345.     int filemode, numfiles = 0;
  346.  
  347.     /*  Go through archive until error/end-of-file, listing any files found */
  348.  
  349.     while(fgets(buffer, BUFSIZE, arc_fptr) != NULL) {
  350.         if (sscanf(buffer, "begin %o %s", &filemode, filestr) == 2) {
  351.             numfiles++;
  352.             printf("Found                 - %s\n", filestr);
  353.         }
  354.     }
  355.  
  356.     return numfiles;
  357. }
  358.  
  359.  
  360.  
  361. /*  Delete files from an archive    */
  362.  
  363. int deletearc(arcname, filename)
  364. char *arcname, *filename;
  365. {
  366.     char buffer[BUFSIZE], filestr[BUFSIZE], arcfile[BUFSIZE];
  367.     int filemode, numdel = 0, fileflag = NOFILE;
  368.     int deleteflag = NOFILE, lastdelete = NOFILE;
  369.     int linetype, lastline = DATALINE;
  370.     long expectedsize;
  371.  
  372.  
  373.     /*  Open archive for input, and a temporary file for output/input   */
  374.  
  375.     if (arc_fptr == NULL)
  376.         if ((arc_fptr = fopen(arcname, "r")) == NULL)
  377.             errorexit("Can't open archive for input", SHOWUSAGE);
  378.  
  379.     if ((temp_fptr = fopen((tmpnam(temp_name)), "w+")) == NULL)
  380.         errorexit("Can't open temporary file", NOUSAGE);
  381.  
  382.  
  383.     /*  Deal with each line in archive until end-of-file/error  */
  384.  
  385.     while(fgets(buffer, BUFSIZE, arc_fptr) != NULL) {
  386.  
  387.  
  388.         /*  Signal a data line by default   */
  389.         linetype = DATALINE;
  390.  
  391.  
  392.         /*  Deal with a begin statement */
  393.  
  394.         if (sscanf(buffer, "begin %o %s", &filemode, filestr) == 2) {
  395.  
  396.             /*  Indicate command line */
  397.             linetype = BEGINLINE;
  398.  
  399.             /*  If already dealing with a file, error - missing end */
  400.             if (fileflag == FOUNDFILE) {
  401.                 fprintf(stderr, "Missing 'end'         - %s\n", arcfile);
  402.                 numerrors++;
  403.                 printf("Deleted               - %s\n", arcfile);
  404.                 numdel++;
  405.             }
  406.  
  407.             /*  Remember file name, signal that a file's been found */
  408.             strcpy(arcfile, filestr);
  409.             fileflag = FOUNDFILE;
  410.  
  411.             /*  Store previous delete status    */
  412.             lastdelete = deleteflag;
  413.  
  414.             /*  Signal whether or not file is to be deleted */
  415.             if ((filename == NULL) ||
  416.                 (anycasecmp(prname(filename, STRIPPATH),
  417.                 prname(arcfile, STRIPPATH)) == 0))
  418.                 deleteflag = FOUNDFILE;
  419.             else
  420.                 deleteflag = NOFILE;
  421.  
  422.         }
  423.  
  424.  
  425.         /*  Deal with a size statement */
  426.  
  427.         if (sscanf(buffer, "size %d", &expectedsize) == 1) {
  428.  
  429.             /*  Indicate command line */
  430.             linetype = SIZELINE;
  431.  
  432.             /*  A size statement is only expected after an end statement    */
  433.             if (lastline != ENDLINE) {
  434.                 fprintf(stderr, "Misplaced 'size'      - %s\n", arcfile);
  435.                 numerrors++;
  436.             }
  437.         }
  438.  
  439.  
  440.         /*  Copy lines not to be deleted from archive to temporary file */
  441.  
  442.         if (!((deleteflag == FOUNDFILE) ||
  443.              ((lastline == ENDLINE) &&
  444.               (linetype == SIZELINE) &&
  445.               (lastdelete == FOUNDFILE))))
  446.             if (fputs(buffer, temp_fptr) == EOF)
  447.                 errorexit("File error writing to temporary file", NOUSAGE);
  448.  
  449.  
  450.         /*  Deal with an end statement  */
  451.  
  452.         if (strncmp(buffer, "end", 3) == 0) {
  453.             
  454.             /*  Indicate command line */
  455.             linetype = ENDLINE;
  456.  
  457.             /*  An end statement; so make sure we had a start statement */
  458.             if (fileflag == FOUNDFILE) {
  459.                 /*  Signal that file has been processed, and increment  */
  460.                 /*  number of files deleted counter if necessary        */
  461.                 if (deleteflag == FOUNDFILE) {
  462.                     printf("Deleted               - %s\n", arcfile);
  463.                     numdel++;
  464.                 }
  465.                 else
  466.                     printf("Skipped               - %s\n", arcfile);
  467.             }
  468.             else {
  469.                 /*  If no relevant start statement, error - missing begin   */
  470.                 fprintf(stderr, "Missing 'begin'       - ?\n");
  471.                 numerrors++;
  472.             }
  473.  
  474.             /*  Store previous delete status    */
  475.             lastdelete = deleteflag;
  476.  
  477.             /*  Clear deletion and processing a file    */
  478.             deleteflag = NOFILE;
  479.             fileflag = NOFILE;
  480.  
  481.         }
  482.  
  483.         lastline = linetype;
  484.  
  485.     }
  486.  
  487.     /*  If we hit end of archive file whilst still expecting data, error    */
  488.     if (fileflag != NOFILE) {
  489.         fprintf(stderr, "Missing (final) 'end' - %s\n", arcfile);
  490.         numerrors++;
  491.         printf("Deleted               - %s\n", arcfile);
  492.         numdel++;
  493.     }
  494.  
  495.  
  496.     /*  Go back to start of temporary file  */
  497.     rewind(temp_fptr);
  498.  
  499.     /*  Close archive file, and re-open it (cleared) for output */
  500.     COND_CLOSE(arc_fptr);
  501.     if ((arc_fptr = fopen(arcname, "w")) == NULL)
  502.         errorexit("Can't open archive for output", SHOWUSAGE);
  503.  
  504.     /*  Copy contents of temporary file to archive file */
  505.     while(fgets(buffer, BUFSIZE, temp_fptr) != NULL)
  506.         if (fputs(buffer, arc_fptr) == EOF)
  507.             errorexit("File error writing to archive file", NOUSAGE);
  508.  
  509.  
  510.     /*  Return number of files deleted  */
  511.     return numdel;
  512. }
  513.  
  514.  
  515.  
  516. /*  Extract/Test files in the opened archive    */
  517.  
  518. int extractarc(extcom,filename)
  519. char extcom;
  520. char *filename;
  521. {
  522.     char buffer[BUFSIZE], filestr[BUFSIZE], arcfile[BUFSIZE], outstr[BUFSIZE];
  523.     int ic1, ic2, ic3, ic4;
  524.     int filemode, numfiles = 0, fileflag = NOFILE, checksum;
  525.     int checkflag;
  526.     int linetype, lastline = DATALINE, numdata, datapos, linelen;
  527.     long filesize = 0, expectsize;
  528.  
  529.  
  530.     /*  Go through archive until error/end-of-file  */
  531.  
  532.     while(fgets(buffer, BUFSIZE, arc_fptr) != NULL) {
  533.  
  534.  
  535.         /*  As a default, assume line to be a line of UUencoded data    */
  536.  
  537.         linetype = DATALINE;
  538.  
  539.  
  540.         /*  Deal with a begin statement */
  541.  
  542.         if (sscanf(buffer, "begin %o %s", &filemode, filestr) == 2) {
  543.  
  544.             /*  Flag line as being a command line   */
  545.             linetype = BEGINLINE;
  546.  
  547.             /*  If already dealing with a file, error - missing end */
  548.             if (fileflag == FOUNDFILE) {
  549.                 fprintf(stderr, "Missing 'end'         - %s\n", arcfile);
  550.                 numerrors++;
  551.                 COND_CLOSE(file_fptr);
  552.                 file_fptr = NULL;
  553.                 /*  If just testing archive, indicate that file has been    */
  554.                 /*  processed and increment number of files counter         */
  555.                 if (extcom == TESTCOM) {
  556.                     printf("%21d - %s\n", filesize, arcfile);
  557.                     numfiles++;
  558.                 }
  559.                 else {
  560.                     /*  If extracting, indicate that file has been      */
  561.                     /*  processed and increment number of files counter */
  562.                     /*  if necessary                                    */
  563.                     if (file_fptr != NULL) {
  564.                         printf("%21d - %s\n", filesize, arcfile);
  565.                         numfiles++;
  566.                     }
  567.                     else
  568.                         printf("Skipped               - %s\n", arcfile);
  569.                 }
  570.             }
  571.  
  572.             /*  Remember file name, signal that a file's been found,    */
  573.             /*  set file size counter to 0, and reset checksum status   */
  574.             strcpy(arcfile, filestr);
  575.             fileflag = FOUNDFILE;
  576.             filesize = 0;
  577.             checkflag = DUNNO;
  578.  
  579.             /*  If not just testing the archive, open file for output   */
  580.             if ((extcom != TESTCOM) && ((filename == NULL) ||
  581.                 (anycasecmp(prname(filename, STRIPPATH),
  582.                     prname(arcfile, STRIPPATH)) == 0)))
  583.                 if ((file_fptr = fopen(prname(arcfile,
  584.                     pathflag), "w"))== NULL) {
  585.                     fprintf(stderr, "Can't open for output - %s\n",
  586.                         prname(arcfile, pathflag));
  587.                     numerrors++;
  588.                 }
  589.         }
  590.  
  591.  
  592.         /*  Deal with an end statement  */
  593.  
  594.         if (strncmp(buffer, "end", 3) == 0) {
  595.             
  596.             /*  Flag line as being a command line   */
  597.             linetype = ENDLINE;
  598.  
  599.             /*  An end statement; so make sure we had a start statement */
  600.             if (fileflag == FOUNDFILE) {
  601.                 /*  If just testing archive, indicate that file has been    */
  602.                 /*  processed and increment number of files counter         */
  603.                 fileflag = NOFILE;
  604.                 if (extcom == TESTCOM) {
  605.                     printf("%21d - %s\n", filesize, arcfile);
  606.                     numfiles++;
  607.                 }
  608.                 else {
  609.                     /*  If extracting, indicate that file has been      */
  610.                     /*  processed and increment number of files counter */
  611.                     /*  if necessary                                    */
  612.                     if (file_fptr != NULL) {
  613.                         printf("%21d - %s\n", filesize, arcfile);
  614.                         numfiles++;
  615.                     }
  616.                     else
  617.                         printf("Skipped               - %s\n", arcfile);
  618.                 }
  619.             }
  620.             else {
  621.                 /*  If no relevant start statement, error - missing begin   */
  622.                 fprintf(stderr, "Missing 'begin'       - ?\n");
  623.                 numerrors++;
  624.             }
  625.  
  626.             COND_CLOSE(file_fptr);
  627.             file_fptr = NULL;
  628.  
  629.         }
  630.  
  631.  
  632.         /*  Deal with a size statement  */
  633.  
  634.         if (sscanf(buffer, "size %d", &expectsize) == 1) {
  635.  
  636.             /*  Flag line as being a command line   */
  637.             linetype = SIZELINE;
  638.  
  639.             /*  A size statement is only expected after an end statement    */
  640.             if (lastline != ENDLINE) {
  641.                 fprintf(stderr, "Misplaced 'size'      - %s\n", arcfile);
  642.                 numerrors++;
  643.             }
  644.             else {
  645.                 /*  Check the size of the file was as expected  */
  646.                 if (filesize != expectsize) {
  647.                     fprintf(stderr, "File size wrong       - %s\n", arcfile);
  648.                     numerrors++;
  649.                 }
  650.             }
  651.         }
  652.  
  653.  
  654.         /*  Deal with a line of data    */
  655.  
  656.         if (linetype == DATALINE) {
  657.  
  658.             /*  Only want data lines within begin/end statements    */
  659.             if (fileflag == FOUNDFILE) {
  660.  
  661.                 /*  Strip any white-space characters from end of line   */
  662.                 if ((datapos = strlen(buffer)-1) >= 0)
  663.                     while(isspace(buffer[datapos]) && (datapos >= 0)) {
  664.                         buffer[datapos] = '\0';
  665.                         datapos--;
  666.                     }
  667.  
  668.                 linelen=strlen(buffer);
  669.  
  670.                 /*  If any data is in the line  */
  671.                 if (linelen > 0) {
  672.  
  673.                     /*  Reset line checksum status  */
  674.                     checksum = 0;
  675.  
  676.                     /*  Error if any characters not within limits   */
  677.                     for(datapos = 0;
  678.                         ((datapos < linelen) && (linetype == DATALINE));
  679.                         datapos++)
  680.                         if VALIDATE(buffer[datapos]) {
  681.                             fprintf(stderr,
  682.                                 "Corrupt byte in line  - %s\n", arcfile);
  683.                             numerrors++;
  684.                             linetype = BADLINE;
  685.                         }
  686.  
  687.  
  688.                     /*  Attempt to decode line  */
  689.                     if (linetype == DATALINE) {
  690.                         /*  Fetch total number of bytes to written out  */
  691.                         numdata = DECODE(*buffer);
  692.                         /*  Decode relevant number of bytes from archive    */
  693.                         for(datapos = 1;
  694.                             (((datapos+numdata)<linelen) && (numdata>0));
  695.                             datapos+=4) {
  696.                             ic1 = DECODE(buffer[datapos]);
  697.                             ic2 = DECODE(buffer[datapos+1]);
  698.                             ic3 = DECODE(buffer[datapos+2]);
  699.                             ic4 = DECODE(buffer[datapos+3]);
  700.                             outstr[numdata+2] = ic1 << 2 | ic2 >> 4;
  701.                             outstr[numdata+1] = ic2 << 4 | ic3 >> 2;
  702.                             outstr[numdata] =   ic3 << 6 | ic4     ;
  703.                             checksum = ( checksum +
  704.                                          outstr[numdata+2] +
  705.                                          outstr[numdata+1] +
  706.                                          outstr[numdata]     ) % CHECKSIZE;
  707.                             numdata-=3;  
  708.                         }
  709.  
  710.                         /*  Error if not enough data in line    */
  711.                         if ((numdata > 0) || ((checkflag == YES) &&
  712.                             ((linelen-datapos) < 1))) {
  713.                             fprintf(stderr,
  714.                                 "Data line too short   - %s\n", arcfile);
  715.                             numerrors++;
  716.                             linetype = BADLINE;
  717.                         }
  718.  
  719.                         /*  If line is okay, and checksums have been        */
  720.                         /*  present, then analyse checksum                  */
  721.                         if ((checkflag == YES) && (linetype == DATALINE)) {
  722.                             if (ENCODE(checksum) != buffer[datapos]) {
  723.                                 fprintf(stderr,
  724.                                     "Checksum error        - %s\n", arcfile);
  725.                                 numerrors++;
  726.                                 linetype = BADLINE;
  727.                             }
  728.                         }
  729.  
  730.                         /*  Error if too much data in line  */
  731.                         if (((checkflag != NO) && ((linelen-datapos) > 2)) ||
  732.                             ((checkflag == NO) && ((linelen-datapos) > 1))) {
  733.                             fprintf(stderr,
  734.                                 "Data line too long    - %s\n", arcfile);
  735.                             numerrors++;
  736.                             linetype = BADLINE;
  737.                         }
  738.  
  739.                         /*  If the line was okay, and file checksum status  */
  740.                         /*  is still unknown, then establish the status     */
  741.                         if ((checkflag == DUNNO) && (linetype == DATALINE)) {
  742.                             if ((linelen-datapos) == 0)
  743.                                 checkflag = NO;
  744.                             else {
  745.                                 if (ENCODE(checksum) == buffer[datapos]) {
  746.                                     checkflag = YES;
  747.                                 }
  748.                                 else {
  749.                                     fprintf(stderr,
  750.                                         "Bad checksum/linesize - %s\n",
  751.                                         arcfile);
  752.                                     numerrors++;
  753.                                     linetype = BADLINE;
  754.                                 }
  755.                             }
  756.                         }
  757.                     }
  758.  
  759.                     /*  If line is completely error free    */
  760.                     if (linetype == DATALINE) {
  761.                         /*  Increment file size counter */
  762.                         filesize += (numdata = DECODE(*buffer));
  763.                         /*  If file has been opened for output, write out   */
  764.                         /*  decoded bytes                                   */
  765.                         if (file_fptr != NULL)
  766.                             while(numdata > 0) {
  767.                                 if (fputc(outstr[numdata+2],
  768.                                     file_fptr) == EOF)
  769.                                     errorexit("File error writing file",
  770.                                         NOUSAGE);
  771.                                 numdata--;
  772.                             }
  773.                     }
  774.  
  775.                 }
  776.  
  777.                 else {
  778.                     fprintf(stderr, "Missing data          - %s\n", arcfile);
  779.                     numerrors++;
  780.                 }
  781.  
  782.             }
  783.  
  784.         }
  785.  
  786.         lastline = linetype;
  787.  
  788.     }
  789.  
  790.     /*  If we hit end of archive file whilst still expecting data, error    */
  791.     if (fileflag != NOFILE) {
  792.         fprintf(stderr, "Missing (final) 'end' - %s\n", arcfile);
  793.         numerrors++;
  794.         /*  If just testing archive, indicate that file has been    */
  795.         /*  processed and increment number of files counter         */
  796.         if (extcom == TESTCOM) {
  797.             printf("%21d - %s\n", filesize, arcfile);
  798.             numfiles++;
  799.         }
  800.         else {
  801.             /*  If extracting, indicate that file has been      */
  802.             /*  processed and increment number of files counter */
  803.             /*  if necessary                                    */
  804.             if (file_fptr != NULL) {
  805.                 printf("%21d - %s\n", filesize, arcfile);
  806.                 numfiles++;
  807.             }
  808.             else
  809.                 printf("Skipped               - %s\n", arcfile);
  810.         }
  811.     }
  812.  
  813.     /*  Return number of files extracted    */
  814.     return numfiles;
  815. }
  816.  
  817.  
  818.  
  819. /*  Read from file, dealing with with any errors    */
  820.  
  821. int fileread(buf)
  822. char *buf;
  823. {
  824.     int numread;
  825.  
  826.     /*  Read data into buffer   */
  827.     numread = fread(buf, sizeof(char), ENCODESIZE, file_fptr);
  828.  
  829.     /*  If an error occured, exit cleanly with an error */
  830.     if ferror(file_fptr)
  831.         errorexit("File error reading file", NOUSAGE);
  832.  
  833.     /*  Return number of bytes read */
  834.     return numread;
  835. }
  836.  
  837.  
  838.  
  839. /*  Add an opened file to the opened archive    */
  840.  
  841. int addarc()
  842. {
  843.     char buffer[BUFSIZE], outstr[BUFSIZE];
  844.     int ic1, ic2, ic3, oc1, oc2, oc3, oc4;
  845.     int inpos, outpos, n = 1;
  846.     long filesize = 0;
  847. #ifdef  ADDCHECK
  848.     int checksum;
  849. #endif
  850.  
  851.     /*  Read and encode from file whilst data is available  */
  852.  
  853.     while (n > 0) {
  854.  
  855.         n = fileread(buffer);
  856.  
  857.         /*  Encode number of bytes read into first character in line    */
  858.         *outstr = ENCODE(n);
  859.  
  860. #ifdef  ADDCHECK
  861.         /*  Reset checksum  */
  862.         checksum = 0;
  863. #endif
  864.  
  865.         /*  Encode data */
  866.         outpos = 1;
  867.         for(inpos = 0; inpos < n; inpos += 3) {
  868.             ic1 = buffer[inpos];
  869.             ic2 = buffer[inpos+1];
  870.             ic3 = buffer[inpos+2];
  871.             oc1 =  ic1 >> 2;
  872.             oc2 = (ic1 << 4) & 0x030 | (ic2 >> 4) & 0x00F;
  873.             oc3 = (ic2 << 2) & 0x03C | (ic3 >> 6) & 0x003;
  874.             oc4 =     ic3    & 0x03F;
  875.             outstr[outpos]   = ENCODE(oc1);
  876.             outstr[outpos+1] = ENCODE(oc2);
  877.             outstr[outpos+2] = ENCODE(oc3);
  878.             outstr[outpos+3] = ENCODE(oc4);
  879.             outpos += 4;
  880. #ifdef  ADDCHECK
  881.             checksum = ( checksum + ic1 + ic2 + ic3 ) % CHECKSIZE;
  882. #endif 
  883.        }
  884.  
  885.         /*  Add termination to output string    */
  886. #ifdef  ADDCHECK
  887.         outstr[outpos]   = ENCODE(checksum);
  888.         outpos++;
  889. #endif
  890.         outstr[outpos]   = '\n';
  891.         outstr[outpos+1] = '\0';
  892.  
  893.         /*  Write data into archive */
  894.         if (fputs(outstr, arc_fptr) == EOF)
  895.             errorexit("File error writing to archive", NOUSAGE);
  896.  
  897.         filesize += n;
  898.     }
  899.  
  900.     return filesize;
  901. }
  902.  
  903.  
  904.  
  905. /*  Main entry point, taking standard "main" style parameters   */
  906.  
  907. void main(argc, argv)
  908. int argc;
  909. char *argv[];
  910. {
  911.     char command[BUFSIZE];
  912.     int numfiles, numdel, comlen;
  913.     long numbytes;
  914.  
  915.     /*  Trap program interruption, to exit cleanly  */
  916. #ifdef SIGABRT
  917.     signal(SIGABRT, (int (*)()) abnormalexit);
  918. #endif
  919. #ifdef SIGINT
  920.     signal(SIGINT, (int (*)()) abnormalexit);
  921. #endif
  922. #ifdef SIGTERM
  923.     signal(SIGTERM, (int (*)()) abnormalexit);
  924. #endif
  925.  
  926.     /*  Display program title    */
  927.     printf(TITLESTR, TITLESTRPAR);
  928.  
  929.     /*  If no arguments specified, display usage and exit   */
  930.     if (argc < 2) {
  931.         usage(stderr);
  932.         cleanexit(EXIT_FAILURE);
  933.     }
  934.  
  935.     /*  If only argument is a question-mark, display usage and exit */
  936.     if (strcmp(argv[1], "?") == 0) {
  937.         usage(stdout);
  938.         cleanexit(EXIT_FAILURE);
  939.     }
  940.  
  941.     /*  Check existance of an archiver command  */
  942.     if (sscanf(argv[1], "-%s", command) != 1)
  943.         errorexit("Archiver command missing/invalid", SHOWUSAGE);
  944.     comlen = strlen(command);
  945.  
  946.     /*  Check command is right length   */
  947.     if ((comlen < 1) && (comlen > 2))
  948.         errorexit("Archiver command missing/invalid", SHOWUSAGE);
  949.  
  950.     /*  Deal with path option if given  */
  951.     if (comlen = 2)
  952.         if (tolower(command[1]) == PATHCOM)
  953.             pathflag = LEAVEPATH;
  954.  
  955.     /*  Remove case dependancy of command   */
  956.     *command = tolower(*command);
  957.  
  958.     /*  Check validity of supplied archiver command */
  959.     if ((*command != LISTCOM) &&
  960.         (*command != TESTCOM) &&
  961.         (*command != EXTRACTCOM) &&
  962.         (*command != DELETECOM) &&
  963.         (*command != MOVECOM) &&
  964.         (*command != ADDCOM))
  965.         errorexit("Invalid archiver command", SHOWUSAGE);
  966.  
  967.  
  968.     /*  Perform required action dependant upon user supplied command    */
  969.  
  970.     switch(*command) {
  971.  
  972.         /*  In the case of an archive listing request   */
  973.  
  974.         case LISTCOM:
  975.  
  976.             /*  Check number of arguments   */
  977.             if (argc != 3)
  978.                 errorexit("Wrong number of arguments", SHOWUSAGE);
  979.  
  980.             /*  Open archive for input  */
  981.             if ((arc_fptr = fopen(argv[2], "r")) == NULL)
  982.                 errorexit("Can't open archive for input", SHOWUSAGE);
  983.  
  984.             /*  Print header information    */
  985.             printf("Listing");
  986.             pr_head(argv[2]);
  987.  
  988.             /*  Perform listing operation   */
  989.             numfiles = listarc();
  990.  
  991.             /*  Print tail information  */
  992.             pr_tail();
  993.  
  994.             /*  Give operation statistics   */
  995.             operout("found",numfiles);
  996.             succout("Listing", numerrors);
  997.  
  998.             /*  Exit program cleanly    */
  999.             cleanexit(EXIT_SUCCESS);
  1000.  
  1001.  
  1002.         /*  In the case of an archive deletion request      */
  1003.  
  1004.         case DELETECOM:
  1005.  
  1006.             /*  Check number of arguments   */
  1007.             if ((argc < 3) || (argc > 4))
  1008.                 errorexit("Wrong number of arguments", SHOWUSAGE);
  1009.  
  1010.             /*  Print header information    */
  1011.             printf("Deleting from");
  1012.             pr_head(argv[2]);
  1013.  
  1014.             /*  Perform deletion operation  */
  1015.             if (argc == 3)
  1016.                 numdel = deletearc(argv[2],NULL);
  1017.             else
  1018.                 numdel = deletearc(argv[2],argv[3]);
  1019.  
  1020.             /*  Print tail information  */
  1021.             pr_tail();
  1022.  
  1023.             /*  Give operation statistics   */
  1024.             operout("deleted", numdel);
  1025.             errsout(numerrors);
  1026.             succout("Deletion", numerrors);
  1027.  
  1028.             /*  Exit program cleanly    */
  1029.             if (numerrors == 0)
  1030.                 cleanexit(EXIT_SUCCESS);
  1031.             else
  1032.                 cleanexit(EXIT_FAILURE);
  1033.  
  1034.  
  1035.         /*  In the case of an archive extraction/testing request    */
  1036.  
  1037.         case TESTCOM:
  1038.         case EXTRACTCOM:
  1039.  
  1040.             /*  Check number of arguments   */
  1041.             if (((*command == TESTCOM) && (argc != 3)) ||
  1042.                 ((*command != TESTCOM) && ((argc < 3) || (argc > 4))))
  1043.                 errorexit("Wrong number of arguments", SHOWUSAGE);
  1044.  
  1045.             /*  Open archive for input  */
  1046.             if ((arc_fptr = fopen(argv[2], "r")) == NULL)
  1047.                 errorexit("Can't open archive for input", SHOWUSAGE);
  1048.  
  1049.             /*  Print header information    */
  1050.             if (*command == TESTCOM)
  1051.                 printf("Testing ");
  1052.             else
  1053.                 printf("Extracting from ");
  1054.             pr_head(argv[2]);
  1055.  
  1056.             /*  Perform extraction operation    */
  1057.             if (argc == 3)
  1058.                 numfiles = extractarc(*command, NULL);
  1059.             else
  1060.                 numfiles = extractarc(*command, argv[3]);
  1061.  
  1062.             /*  Print tail information  */
  1063.             pr_tail();
  1064.  
  1065.             /*  Give operation statistics   */
  1066.             if (*command != TESTCOM) {
  1067.                 operout("extracted",numfiles);
  1068.                 errsout(numerrors);
  1069.                 succout("Extraction", numerrors);
  1070.             }
  1071.             else {
  1072.                 operout("tested",numfiles);
  1073.                 errsout(numerrors);
  1074.                 succout("Testing", numerrors);
  1075.             }
  1076.  
  1077.             /*  Exit program cleanly    */
  1078.             if (numerrors == 0)
  1079.                 cleanexit(EXIT_SUCCESS);
  1080.             else
  1081.                 cleanexit(EXIT_FAILURE);
  1082.  
  1083.  
  1084.         /*  In the case of an add/move to an archive request    */
  1085.  
  1086.         case ADDCOM:
  1087.         case MOVECOM:
  1088.  
  1089.             /*  Check number of arguments   */
  1090.             if (argc != 4)
  1091.                 errorexit("Wrong number of arguments", SHOWUSAGE);
  1092.  
  1093.             /*  Open archive for update  */
  1094.             if ((arc_fptr = fopen(argv[2], "a")) == NULL)
  1095.                 errorexit("Can't open archive", SHOWUSAGE);
  1096.  
  1097.             /*  Open file for input */
  1098.             if ((file_fptr = fopen(argv[3], "r")) == NULL)
  1099.                 errorexit("Can't open file for input", SHOWUSAGE);
  1100.  
  1101.             /*  Print header information    */
  1102.             if (*command == ADDCOM)
  1103.                 printf("Adding to");
  1104.             else
  1105.                 printf("Moving to");
  1106.             pr_head(argv[2]);
  1107.  
  1108.             /*  Write begin statement   */
  1109.             fprintf(arc_fptr,
  1110.                 "\nbegin %o %s\n", DEFAULTMODE, prname(argv[3], pathflag));
  1111.  
  1112.             /*  Perform add operation   */
  1113.             numbytes = addarc();
  1114.  
  1115.             /*  Write end statement   */
  1116.             fprintf(arc_fptr, "end\n");
  1117.             fprintf(arc_fptr, "size %d\n", numbytes);
  1118.  
  1119.             /*  Indicate that file has been processed   */
  1120.             printf("%21d - %s\n", numbytes, prname(argv[3], pathflag));
  1121.  
  1122.             /*  In the case of a move command, delete file  */
  1123.             if (*command == MOVECOM) {
  1124.                 COND_CLOSE(file_fptr);
  1125.                 file_fptr = NULL;
  1126.                 remove(argv[3]);
  1127.             }
  1128.  
  1129.             /*  Print tail information  */
  1130.             pr_tail();
  1131.  
  1132.             /*  Give operation statistics   */
  1133.             if (*command == ADDCOM) {
  1134.                 operout("added", 1);
  1135.                 errsout(numerrors);
  1136.                 succout("Adding", numerrors);
  1137.             }
  1138.             else {
  1139.                 operout("moved", 1);
  1140.                 errsout(numerrors);
  1141.                 succout("Moving", numerrors);
  1142.             }
  1143.  
  1144.             /*  Exit program cleanly    */
  1145.             if (numerrors == 0)
  1146.                 cleanexit(EXIT_SUCCESS);
  1147.             else
  1148.                 cleanexit(EXIT_FAILURE);
  1149.  
  1150.     }
  1151.  
  1152.     /*  By logic the program should never get this far */
  1153.     errorexit("Internal error - improper program execution", NOUSAGE);
  1154. }
  1155.