home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 9 Archive / 09-Archive.zip / unshar2.zip / UNSHAR2.CPP < prev    next >
Text File  |  1997-02-12  |  13KB  |  490 lines

  1. #include <stdlib.h>
  2. #include <io.h>
  3. #include <direct.h>
  4.  
  5. #include <fstream.h>
  6. #include <iostream.h>
  7.  
  8. /*═══════════════════════════════════════════════════════════════════════════╗
  9. ║                                                                            ║
  10. ║                              U n S h a r / 2                               ║
  11. ║                                                                            ║
  12. ║                           ported by SolDev Team                            ║
  13. ║                                                                            ║
  14. ╠════════════════════════════════════════════════════════════════════════════╣
  15. ║ Name       : UnShar2.CPP                                                   ║
  16. ║ Purpose    : extract files from shell archive                              ║
  17. ║ Developer  : Andreas Just(SCORPIO)   - based on - see above..              ║
  18. ║ Usage      : see usage()                                                   ║
  19. ╠─────────────────┬─────────────────┬─────────────────┬──────────────────────╣
  20. ║ Date Begin      │ Date End        │ Betatest        │ Finaltest            ║
  21. ╠─────────────────┼─────────────────┼─────────────────┼──────────────────────╣
  22. ║                 │                 │                 │                      ║
  23. ╠─────────────────┴─────────────────┴─────────────────┴──────────────────────╣
  24. ║                                                                            ║
  25. ║  Written by Warren Toomey. Nov, 1989. You may freely copy or give away     ║
  26. ║  this source as long as this notice remains intact.                        ║
  27. ║                                                                            ║
  28. ║  Feb 1990--Fred C. Smith--Added make_subdir() which handles shar files     ║
  29. ║  which require extracted files to be inserted into a non-existent subdir.  ║
  30. ║  Added APPEND mode in which unshar checks for existence of a file before   ║
  31. ║  unsharing, and if already exists it appends to it. Also outputs a message ║
  32. ║  for each file indicating whether it is creating or appending.             ║
  33. ║                                                                            ║
  34. ║  Dez 1996--Andreas Just--ported to OS/2 - changed to CPP-FileStreams       ║
  35. ║  ANSI sequences added, included modified optlink, some small changes       ║
  36. ║                                                                            ║
  37. ╚═══════════════════════════════════════════════════════════════════════════*/
  38. #pragma comment (user,"SolDev Team (SCORPIO) 1997")
  39.  
  40. // Global variables
  41. int  table;        // Generate a table, or extract
  42. int  verbose;      // Unshar verbosely - debugging
  43. int  numext;       // Number of files to extract
  44. char *exfile[100]; // Files to extract
  45. int  useAnsi;      // use ANSI codes for some color
  46.  
  47. fstream ifs;       // input filestream
  48.  
  49. //simple ANSI Color
  50. #define GR    ((useAnsi)?"\x1B[32m\x1B[1m":"")<<
  51. #define CY    ((useAnsi)?"\x1B[36m\x1B[1m":"")<<
  52. #define DC    ((useAnsi)?"\x1B[36m\x1B[0m":"")<<
  53. #define RD    ((useAnsi)?"\x1B[31m\x1B[1m":"")<<
  54. #define RESET ((useAnsi)?"\x1B[37m\x1B[0m":"")<<
  55.  
  56.  
  57. // Methods of unsharing
  58. #define UNKNOWN  0
  59. #define BRUTAL   1
  60. #define APPEND   2
  61.  
  62. // Whitespace indicators
  63. #define WHITE    0
  64. #define NOWHITE  1
  65.  
  66. // Leading character indicators
  67. #define NOX      0
  68. #define YESX     1
  69.  
  70. // Emulation types available
  71. #define SED      1
  72. #define GRES     2
  73. #define CAT      3
  74. #define NUMTOKS  4
  75.  
  76. #define BUFSIZE 1024
  77.  
  78. static char *token[NUMTOKS] =  // The list of emulation types
  79.  {
  80.   "",
  81.   "sed",
  82.   "gres",
  83.   "cat"
  84.  };
  85.  
  86.  
  87. // commandline options
  88. char   *optarg;
  89. int    opterr = 1;
  90. int    optind = 1;
  91. int    optopt;
  92.  
  93. char *index(char* s, char c)
  94.  {
  95.   do
  96.    {
  97.     if (*s == c)
  98.     return(s);
  99.    } while (*s++ != 0);
  100.   return(0);
  101.  }
  102.  
  103.  
  104. int getopt(int argc, char** argv, char* opts)
  105.  {
  106.   int    sp = 1;
  107.   int    c;
  108.   char   *cp;
  109.  
  110.   if(sp == 1)
  111.    {
  112.     if(optind >= argc || argv[optind][0] != '-' || argv[optind][1] == '\0')
  113.       return(EOF);
  114.     else if(strcmp(argv[optind], "--") == NULL)
  115.      {
  116.       optind++;
  117.       return(EOF);
  118.      }
  119.    }
  120.  
  121.   optopt = c = argv[optind][sp];
  122.   if(c == ':' || (cp=index(opts, c)) == NULL)
  123.    {
  124.     cout <<RD "Commandline: illegal option !" << endl;
  125.     if(argv[optind][++sp] == '\0')
  126.      {
  127.       optind++;
  128.       sp = 1;
  129.      }
  130.     return('?');
  131.    }
  132.  
  133.   if(*++cp == ':')
  134.    {
  135.     if     (argv[optind][sp+1] != '\0')  optarg = &argv[optind++][sp+1];
  136.     else if(++optind >= argc)
  137.      {
  138.       cout <<RD "Commandline: option requires an argument !" << endl;
  139.       sp = 1;
  140.       return('?');
  141.      }
  142.     else  optarg = argv[optind++];
  143.     sp = 1;
  144.    }
  145.   else
  146.    {
  147.     if(argv[optind][++sp] == '\0')
  148.      {
  149.       sp = 1;
  150.       optind++;
  151.      }
  152.     optarg = NULL;
  153.    }
  154.   return(c);
  155.  }
  156.  
  157.  
  158.  
  159.  
  160. // UnShar2 functions
  161. int getLine(long how, char* buf)
  162.  {
  163.   ifs.setf(how);                // because ios::skipws is defined as
  164.   ifs.getline(buf, 1024);       // 0x0000001 we can directly use int how
  165.   return ifs.eof();
  166.  }
  167.  
  168.  
  169. int firstword(char* buf)       // Return token value of first word in the buffer.
  170.  {                             // Assume no leading whitespace in the buffer
  171.   int i;
  172.  
  173.   for (i=1;i<NUMTOKS;i++)
  174.     if (strncmp(buf,token[i],strlen(token[i]))==0) return(i);
  175.  
  176.   return(UNKNOWN);
  177.  }
  178.  
  179.  
  180. char *getstring(char* buf)                     // Get the next string from the buffer
  181.  {
  182.   char out[BUFSIZE];
  183.   char *temp=out;
  184.   while ((*buf==' ') || (*buf=='\t')) buf++;   // Skip whitespace
  185.  
  186.   switch(*buf)                                 // Now check first char
  187.    {
  188.     case '\'' :
  189.       buf++;
  190.       while (*buf!='\'') *temp++ = *buf++;
  191.       *temp=NULL;
  192.       return(out);
  193.  
  194.     case '\"' :
  195.       buf++;
  196.       while (*buf!='\"') *temp++ = *buf++;
  197.       *temp=NULL;
  198.       return(out);
  199.  
  200.     case NULL :
  201.       return(NULL);
  202.  
  203.     default   :
  204.       while ((*buf!=' ') && (*buf!='\t'))
  205.       if (*buf!='\\') *temp++ = *buf++;
  206.       else            buf++;
  207.       *temp=NULL;
  208.       return(out);
  209.    }
  210.  }
  211.  
  212.  
  213.  
  214. void getnames(char* buf, char* file, char* word)    // Get the file & end word
  215.  {
  216.   char *temp = buf;
  217.   if (verbose) cout <<CY "Getnames: buf is " << buf << endl;
  218.  
  219.   while (*temp!=NULL)                               // Scan along buffer
  220.    {
  221.     switch(*temp)                                   // Get file or end word
  222.      {
  223.       case '>' :                                    // Get the file name
  224.         strcpy(file,getstring(++temp));
  225.         break;
  226.  
  227.       case '<' :
  228.         if (*(++temp)=='<') ++temp;                 // Skip 2nd <
  229.         strcpy(word,getstring(temp));               // Get next word
  230.         break;
  231.  
  232.       default  :
  233.         temp++;
  234.      }
  235.    }
  236.  }
  237.  
  238.  
  239.  
  240. int mustget(char* s1)            // Return 1 if s1 is in the list of
  241.  {                               // files to extract. Return 0 if not
  242.   int i;
  243.  
  244.   if (numext==0) return(0);
  245.   for (i=0;i<numext;i++) if (!strcmp(s1,exfile[i])) return(1);
  246.   return(0);
  247.  }
  248.  
  249.  
  250.  
  251. int make_subdir (char* fullpath)
  252.  {
  253.   char localpath [256];
  254.   int index;
  255.  
  256.   index = 0;
  257.   if (fullpath[1] == ':')
  258.    {
  259.     localpath[0] = fullpath[0];
  260.     localpath[1] = fullpath[1];
  261.     if (fullpath[2] == '\\' || fullpath[2] == '/')
  262.       localpath[2] = fullpath[2];
  263.     localpath[3] = (char) 0;
  264.     index = 3;
  265.    }
  266.   else if (fullpath[0]== '\\' || fullpath[0] == '/')
  267.    {
  268.     localpath[0] = fullpath[0];
  269.     localpath[1] = (char) 0;
  270.     index = 2;
  271.    }
  272.  
  273.   for ( ; index < strlen(fullpath) ; index++)
  274.    {
  275.     if (fullpath[index] == '\\' || fullpath[index] == '/')
  276.      {
  277.       // the stuff in localpath should be a full pathname of
  278.       // a subdirectory which might need to be made. check
  279.       // it, and if so, make it.
  280.       localpath[index] = (char) 0;
  281.       if (access(localpath, 0) == -1)     // i.e., does not exist
  282.        {
  283.         if (mkdir(localpath) == -1)
  284.         return (-1);                       // mkdir failed
  285.        }
  286.      }
  287.     localpath[index] = fullpath[index];
  288.    }
  289.  
  290.   return (0);
  291.  }
  292.  
  293.  
  294.  
  295.  
  296. void extract(int how, char* file, char* end, int lead, int method)    // Extract file, up until end word
  297.  {                                                                    // If how==YESX, then ignore lead
  298.   fstream ofs;                                                        // character on every line
  299.   char    line[BUFSIZE];
  300.   char    *temp;
  301.   long    openmode;
  302.   int     ch;
  303.  
  304.   if (make_subdir(file) != 0)                                         // make subdirs as required for file
  305.    {
  306.     cout <<RD  "Cannot create subdirectory for " << file << endl;
  307.     return;
  308.    }
  309.  
  310.   if (access(file, 02) == 0 && method == APPEND)
  311.    {
  312.     openmode = ios::out|ios::app;
  313.     cout <<DC " (appending)" << endl;
  314.    }
  315.   else
  316.    {
  317.     openmode = ios::out;
  318.     cout <<DC " (creating)" << endl;
  319.    }
  320.  
  321.   ofs.open(file,openmode);
  322.   if (ofs.fail())
  323.    {
  324.     cout <<RD "Cannot open file "<< file <<". Enter new name or <ENTER> to skip: ";
  325.     cin.getline(line, 1024);
  326.     if (line[0] != '\0')
  327.      {
  328.       ofs.open(file,openmode);
  329.       if (ofs.fail())
  330.        {
  331.         cout <<RD "UnShar2: ERROR Opening file  " << line << endl;
  332.         return;
  333.        }
  334.      }
  335.    }
  336.  
  337.   while(1)
  338.    {
  339.     ch=getLine(WHITE,line);                   // Get a line of file
  340.     temp=line;
  341.     if (ch)                                   // EndOfFile
  342.      {
  343.       ofs << line << endl;
  344.       ofs.close();
  345.       return;
  346.      }
  347.  
  348.     if (strncmp(line,end,strlen(end))==0)     // If end word
  349.      {
  350.       ofs.close();
  351.       return;
  352.      }
  353.  
  354.     if ((how==YESX) && (*temp==lead)) temp++; // Skip any lead
  355.  
  356.     ofs << temp << endl;
  357.    }
  358.  }
  359.  
  360.  
  361.  
  362.  
  363. void disembowel(int method)
  364.  {
  365.   char buf[BUFSIZE];         // Line buffer
  366.   char file[BUFSIZE];        // File name
  367.   char word[BUFSIZE];        // Word buffer
  368.   int  ch,x;
  369.  
  370.   if (verbose) cout <<CY "Entering disembowel" << endl;
  371.  
  372.   x='X';                     // Leading X character
  373.  
  374.   while(1)
  375.    {
  376.     ch = getLine(NOWHITE, buf);  // Get a line from file
  377.     if (ch) return;
  378.  
  379.     switch(firstword(buf))       // Extract, depending on first word
  380.      {
  381.       case CAT  :
  382.       case GRES :
  383.       case SED  :
  384.         if (verbose) cout <<CY "About to do getnames" << endl;
  385.         getnames(buf,file,word);
  386.         if (table==0)
  387.          {
  388.           if ((numext==0) || (mustget(file)))
  389.            {
  390.             cout <<GR "Extracting : " <<CY file;
  391.             if (verbose) cout <<RD "\nstopping at " << word << endl;
  392.             extract(YESX,file,word,x,method);
  393.            }
  394.          }
  395.         else cout <<CY file << endl;
  396.         break;
  397.  
  398.       default   :
  399.         break;
  400.      }
  401.    }
  402.  }
  403.  
  404.  
  405.  
  406. void usage()
  407.  {
  408.   cout <<GR "Usage:\n"
  409.        <<CY " UnShar2 [-b] [-t] [-v] [-a] [file(s)]\n\n"
  410.        <<GR "      -b "<<CY" extract brutally : overwrite existing files - default: append\n"
  411.        <<GR "      -t "<<CY" table: shows filenames in archive\n"
  412.        <<GR "      -v "<<CY" verbose: show more info\n"
  413.        <<GR "      -a "<<CY" turn of ANSI sequences\n"
  414.        <<GR " file(s) "<<CY" file(s) to extract\n" <<RESET endl;
  415.   exit(0);
  416.  }
  417.  
  418.  
  419. void main(int argc, char* argv[])
  420.  {
  421.   int i,c,first;
  422.  
  423.   int method;                      // Method of unsharing
  424.  
  425.   method  = APPEND;                // default used to be BRUTAL
  426.   table   = 0;                     // Don't generate a table
  427.   verbose = 0;                     // Nor be very verbose
  428.   numext  = 0;                     // Initially no files to extract
  429.   useAnsi = 1;
  430.  
  431.   if (argc==1) usage();            // any argument needed
  432.  
  433.   while ((c=getopt(argc,argv,"x:atbv"))!=EOF)
  434.    {
  435.     switch(c)                      // Get the various options
  436.      {
  437.       case 'a' :
  438.         useAnsi = 0;
  439.         break;
  440.  
  441.       case 't' :
  442.         table=1;
  443.         break;
  444.  
  445.       case 'b' :
  446.         method= BRUTAL;
  447.         break;
  448.  
  449.       case 'v' :
  450.         verbose=1;
  451.         break;
  452.  
  453.       case 'x' :
  454.         exfile[numext] = new char[strlen(optarg)+1];
  455.         strcpy(exfile[numext++],optarg);
  456.         break;
  457.  
  458.       default  :
  459.         usage();
  460.      }
  461.    }
  462.  
  463.   for (first=1;first<argc;first++) if (argv[first][0]!='-') break;
  464.  
  465.   for (i=first; i < argc; i++)         // open stdio with every file
  466.    {
  467.     ifs.close();
  468.     ifs.open(argv[i],ios::in);
  469.     if (ifs.fail())
  470.      {
  471.       cout <<RD "UnShar2: ERROR Opening file: " << argv[i]  <<RESET endl;
  472.       exit(1);
  473.      }
  474.  
  475.     switch(method)
  476.      {
  477.       case BRUTAL:                     // Unshar brutally!
  478.       case APPEND:
  479.         disembowel(method);            // Unshar somewhat less brutally!
  480.         cout <<RESET endl;
  481.         break;
  482.  
  483.       default:
  484.         cout <<RD "UnShar2: ERROR Unknown method of unsharing" <<RESET endl;
  485.         exit(1);
  486.      }
  487.    }
  488.   exit(0);
  489.  }
  490.