rexxapi.c
上传用户:andy_li
上传日期:2007-01-06
资源大小:1019k
文件大小:33k
源码类别:

压缩解压

开发平台:

MultiPlatform

  1. /**********************************************************************
  2. *   REXXAPI.C                                                         *
  3. *                                                                     *
  4. *   This program adds a ZIP engine directly to the REXX language.     *
  5. *   The functions are:                                                *
  6. *       UZDropFuncs         -- Makes all functions in this package    *
  7. *                              unknown to REXX.                       *
  8. *       UZLoadFuncs         -- Makes all functions in this package    *
  9. *                              known to REXX so REXX programs may     *
  10. *                              call them.                             *
  11. *       UZFileTree          -- Searches for files matching a given    *
  12. *                              filespec, including files in           *
  13. *                              subdirectories.                        *
  14. *       UZUnZip             -- Unzip command-line entry point.        *
  15. *                              This is functionally equivalent to     *
  16. *                              using Unzip as an external program.    *
  17. *       UZUnZipToVar            -- Unzip one file to a variable       *
  18. *       UZUnZipToStem       -- Unzip files to a variable array        *
  19. *       UZVer               -- Returns the Unzip version number       *
  20. *                                                                     *
  21. **********************************************************************/
  22. /* Include files */
  23. #ifdef OS2DLL
  24. #define  INCL_DOS
  25. #define  INCL_DOSMEMMGR
  26. #include <string.h>
  27. #include <stdlib.h>
  28. #include <stdio.h>
  29. #include <stdarg.h>
  30. #define UNZIP_INTERNAL
  31. #include "../unzip.h"
  32. #include "../version.h"
  33. /*********************************************************************/
  34. /*  Various definitions used by various functions.                   */
  35. /*********************************************************************/
  36. RexxFunctionHandler UZDropFuncs;
  37. RexxFunctionHandler UZLoadFuncs;
  38. RexxFunctionHandler UZFileTree;
  39. RexxFunctionHandler UZUnZip;
  40. RexxFunctionHandler UZUnZipToVar;
  41. RexxFunctionHandler UZUnZipToStem;
  42. RexxFunctionHandler UZVer;
  43. RexxFunctionHandler UZAPIVer;
  44. int SetOutputVar(__GPRO__ const char *name);
  45. int SetOutputVarStem(__GPRO__ const char *name);
  46. int SetOutputVarLength(__GPRO);
  47. int WriteToVariable(__GPRO__ const char *name, char *buffer, int len);
  48. int PrintToSubVariable(__GPRO__ int idx, const char *format,...);
  49. int PrintToVariable(__GPRO__ const char *name, const char *format,...);
  50. int _PrintToVariable(__GPRO__ const char *name, const char *format, va_list arg_ptr);
  51. int TextSetNext(__GPRO__ char *format, int len, int all);
  52. #define EZRXSTRING(r,p)  {(r).strptr=(PCH)p;(r).strlength=(ULONG)strlen((r).strptr);}
  53. /*********************************************************************/
  54. /* RxFncTable                                                        */
  55. /*   Array of names of the UNZIPAPI functions.                       */
  56. /*   This list is used for registration and deregistration.          */
  57. /*********************************************************************/
  58. static PSZ  RxFncTable[] =
  59.    {
  60.       "UZDropFuncs",
  61.       "UZLoadFuncs",
  62.       "UZFileSearch",
  63.       "UZFileTree",
  64.       "UZUnZip",
  65.       "UZUnZipToVar",
  66.       "UZUnZipToStem",
  67.       "UZVer",
  68.    };
  69. /*********************************************************************/
  70. /* Numeric Error Return Strings                                      */
  71. /*********************************************************************/
  72. #define  NO_UTIL_ERROR    "0"          /* No error whatsoever        */
  73. #define  ERROR_NOMEM      "2"          /* Insufficient memory        */
  74. /*********************************************************************/
  75. /* Numeric Return calls                                              */
  76. /*********************************************************************/
  77. #define  INVALID_ROUTINE 40            /* Raise Rexx error           */
  78. #define  VALID_ROUTINE    0            /* Successful completion      */
  79. /*********************************************************************/
  80. /* Some useful macros                                                */
  81. /*********************************************************************/
  82. #define BUILDRXSTRING(t, s) { 
  83.   strcpy((t)->strptr,(s));
  84.   (t)->strlength = strlen((s)); 
  85. }
  86. /*********************************************************************/
  87. /****************  UNZIPAPI Supporting Functions  ********************/
  88. /****************  UNZIPAPI Supporting Functions  ********************/
  89. /****************  UNZIPAPI Supporting Functions  ********************/
  90. /*********************************************************************/
  91. int RexxReturn(__GPRO__ int nodefault, RXSTRING *retstr)
  92. {
  93.   int ret = G.os2.rexx_error;
  94.   if (G.filenotfound)
  95.     G.os2.rexx_mes = "file not found";
  96.   if (*G.os2.rexx_mes != '0') {
  97.     if (retstr->strlength > 255) {
  98.       DosFreeMem(retstr->strptr);
  99.       retstr->strptr = NULL;
  100.     }
  101.   } else if (nodefault)
  102.     goto noBuild;
  103.   BUILDRXSTRING(retstr, G.os2.rexx_mes);
  104.  noBuild:
  105.   DESTROYGLOBALS();
  106.   return ret;
  107. }
  108. /* Get a variable from REXX, return 0 if OK */
  109. int GetVariable(__GPRO__ const char *name)
  110. {
  111.   G.os2.request.shvnext = NULL;
  112.   EZRXSTRING(G.os2.request.shvname, name);
  113.   G.os2.request.shvnamelen = G.os2.request.shvname.strlength;
  114.   G.os2.request.shvvalue.strptr = G.os2.buffer;
  115.   G.os2.request.shvvalue.strlength = IBUF_LEN;
  116.   G.os2.request.shvvaluelen = IBUF_LEN;
  117.   G.os2.request.shvcode = RXSHV_SYFET;
  118.   G.os2.request.shvret = 0;
  119.   switch (RexxVariablePool(&G.os2.request)) {
  120.   case RXSHV_MEMFL:
  121.     G.os2.rexx_mes = ERROR_NOMEM;
  122.     break;
  123.   case RXSHV_BADN:
  124.   case RXSHV_NEWV:
  125.     G.os2.request.shvvaluelen = 0;
  126.   case RXSHV_OK:
  127.     *(G.os2.buffer+G.os2.request.shvvaluelen) = 0;
  128.     return G.os2.request.shvvaluelen;
  129.   }
  130.   return 0;
  131. }
  132. /* Get REXX compound variable */
  133. /* Stem must exist in G.os2.getvar_buf w/ length in G.os2.getvar_len */
  134. int GetVariableIndex(__GPRO__ int index)
  135. {
  136.   sprintf(G.os2.getvar_buf+G.os2.getvar_len,"%d",index);
  137.   return GetVariable(__G__ G.os2.getvar_buf);
  138. }
  139. /* Transfer REXX array to standard C string array */
  140. /* Returns number of elements */
  141. /* User is responsible for calling KillStringArray */
  142. int CompoundToStringArray(__GPRO__ char ***pointer, const char *name)
  143. {
  144.   int count;
  145.   int total;
  146.   char **trav;
  147.   G.os2.getvar_len = strlen(name);
  148.   memcpy(G.os2.getvar_buf,name,G.os2.getvar_len+1);
  149.   if (*(G.os2.getvar_buf+G.os2.getvar_len-1) != '.')
  150.     *(G.os2.getvar_buf+G.os2.getvar_len++) = '.', *(G.os2.getvar_buf+G.os2.getvar_len) = 0;
  151.   if (GetVariableIndex(__G__ 0))
  152.     return 0;
  153.   total = atoi(G.os2.buffer);
  154.   *pointer = (char **)malloc((total+1)<<2);
  155.   trav = *pointer;
  156.   for (count = 1; count <= total; count++) {
  157.     GetVariableIndex(__G__ count);
  158.     trav[count-1] = (char *)malloc(strlen(G.os2.buffer)+1);
  159.     strcpy(trav[count-1],G.os2.buffer);
  160.   }
  161.   trav[count-1] = NULL;
  162.   return total;
  163. }
  164. /* Kill string array created by CompoundToStringArray */
  165. void KillStringArray(char **pointer)
  166. {
  167.   char **trav=pointer;
  168.   while (*trav != NULL) {
  169.     free(*trav);
  170.     trav++;
  171.   }
  172.   free(pointer);
  173. }
  174. /*************************************************************************
  175. * Function:  UZDropFuncs                                                 *
  176. *                                                                        *
  177. * Syntax:    call UZDropFuncs                                            *
  178. *                                                                        *
  179. * Return:    NO_UTIL_ERROR - Successful.                                 *
  180. *************************************************************************/
  181. ULONG UZDropFuncs(CHAR *name, ULONG numargs, RXSTRING args[],
  182.                   CHAR *queuename, RXSTRING *retstr)
  183. {
  184.   INT     entries;                     /* Num of entries             */
  185.   INT     j;                           /* Counter                    */
  186.   if (numargs != 0)                    /* no arguments for this      */
  187.     return INVALID_ROUTINE;            /* raise an error             */
  188.   retstr->strlength = 0;               /* return a null string result*/
  189.   entries = sizeof(RxFncTable)/sizeof(PSZ);
  190.   for (j = 0; j < entries; j++)
  191.     RexxDeregisterFunction(RxFncTable[j]);
  192.   return VALID_ROUTINE;                /* no error on call           */
  193. }
  194. /*************************************************************************
  195. * Function:  UZFileTree                                                  *
  196. *                                                                        *
  197. * Syntax:    call UZFileTree zipfile, stem[, include-filespec]           *
  198. *                                [, exclude-filespec][, options]         *
  199. *                                                                        *
  200. * Params:    zipfile  - Name of zip file to search.                      *
  201. *            stem     - Name of stem var to store results in.            *
  202. *            include  - Filespec to search for (may include * and ?).    *
  203. *            exclude  - Filespec to exclude (may include * and ?).       *
  204. *            options  - Either of the following:                         *
  205. *                       'F' - Give file statistics.                      *
  206. *                          Length Date Time Name                         *
  207. *                       'Z' - Give zip statistics, too.                  *
  208. *                          Length Method Size Ratio Date Time CRC-32 Name*
  209. *                       Default is to return only filenames              *
  210. *                                                                        *
  211. * Return:    NO_UTIL_ERROR   - Successful.                               *
  212. *            ERROR_NOMEM     - Out of memory.                            *
  213. *************************************************************************/
  214. ULONG UZFileTree(CHAR *name, ULONG numargs, RXSTRING args[],
  215.                  CHAR *queuename, RXSTRING *retstr)
  216. {
  217.                                        /* validate arguments         */
  218.   char *incname[2];
  219.   char *excname[2];
  220.   CONSTRUCTGLOBALS();
  221.   if (numargs < 2 || numargs > 5 ||
  222.       !RXVALIDSTRING(args[0]) ||
  223.       !RXVALIDSTRING(args[1]) ||
  224.       args[0].strlength > 255) {
  225.     DESTROYGLOBALS();
  226.     return INVALID_ROUTINE;            /* Invalid call to routine    */
  227.   }
  228.                                        /* initialize data area       */
  229.   SetOutputVarStem(__G__ args[1].strptr);
  230.   G.wildzipfn = args[0].strptr;
  231.   G.process_all_files = TRUE;
  232.   uO.lflag = 1;
  233.   uO.zipinfo_mode = TRUE;
  234.   uO.C_flag = 1;
  235.   G.extract_flag = FALSE;
  236.   uO.qflag = 2;
  237.   if (numargs >= 3 &&                  /* check third option         */
  238.       !RXNULLSTRING(args[2]) &&
  239.       args[2].strlength > 0) {            /* a zero length string isn't */
  240.     if (!(G.filespecs = CompoundToStringArray(__G__ &G.pfnames,args[2].strptr))) {
  241.       G.pfnames = incname;
  242.       incname[0] = args[2].strptr;
  243.       incname[1] = NULL;
  244.       G.filespecs = 1;
  245.     }
  246.     G.process_all_files = FALSE;
  247.   }
  248.   if (numargs >= 4 &&                  /* check third option         */
  249.       !RXNULLSTRING(args[3]) &&
  250.       args[3].strlength > 0) {            /* a zero length string isn't */
  251.     if (!(G.xfilespecs = CompoundToStringArray(__G__ &G.pxnames,args[3].strptr))) {
  252.       G.pxnames = excname;
  253.       excname[0] = args[3].strptr;
  254.       excname[1] = NULL;
  255.       G.xfilespecs = 1;
  256.     }
  257.     G.process_all_files = FALSE;
  258.   }
  259.   if (numargs == 5 &&                  /* check third option         */
  260.       !RXNULLSTRING(args[4]) &&
  261.       args[4].strlength > 0) {            /* a zero length string isn't */
  262.     int first = *args[4].strptr & 0x5f;
  263.     if (first == 'Z')
  264.       uO.vflag = 2, uO.lflag = 0, uO.zipinfo_mode = FALSE;
  265.     else if (first == 'F')
  266.       uO.vflag = 1, uO.lflag = 0, uO.zipinfo_mode = FALSE;
  267.   }
  268.   process_zipfiles(__G);
  269.   SetOutputVarLength(__G);
  270.   if (G.filespecs > 0 && G.pfnames != incname)
  271.     KillStringArray(G.pfnames);
  272.   if (G.xfilespecs > 0 && G.pxnames != excname)
  273.     KillStringArray(G.pxnames);
  274.   return RexxReturn(__G__ 0,retstr);        /* no error on call           */
  275. }
  276. /*************************************************************************
  277. * Function:  UZUnZipToVar                                                *
  278. *                                                                        *
  279. * Syntax:    call UZUnZipToVar zipfile, filespec [, stem]                *
  280. *                                                                        *
  281. * Params:    zipfile  - Name of zip file to search.                      *
  282. *            filespec - File to extract                                  *
  283. *            stem     - If you specify a stem variable, the file will be *
  284. *                       extracted to the variable, one line per index    *
  285. *                       In this case, 0 will be returned                 *
  286. *                                                                        *
  287. * Return:    Extracted file                                              *
  288. *            ERROR_NOMEM     - Out of memory.                            *
  289. *************************************************************************/
  290. ULONG UZUnZipToVar(CHAR *name, ULONG numargs, RXSTRING args[],
  291.                           CHAR *queuename, RXSTRING *retstr)
  292. {
  293.   CONSTRUCTGLOBALS();
  294.   UzpBuffer *ub = (UzpBuffer *)retstr;
  295.                                        /* validate arguments         */
  296.   if (numargs < 2 || numargs > 3 ||
  297.       !RXVALIDSTRING(args[0]) ||
  298.       !RXVALIDSTRING(args[1]) ||
  299.       args[0].strlength == 0 ||
  300.       args[1].strlength == 0) {
  301.     DESTROYGLOBALS();
  302.     return INVALID_ROUTINE;            /* Invalid call to routine    */
  303.   }
  304.   uO.C_flag = 1;
  305.   G.redirect_data=1;
  306.   if (numargs == 3) {
  307.     if (!RXVALIDSTRING(args[2]) ||
  308.         RXNULLSTRING(args[1]) ||
  309.         args[2].strlength == 0) {
  310.       DESTROYGLOBALS();
  311.       return INVALID_ROUTINE;            /* Invalid call to routine    */
  312.     }
  313.     SetOutputVarStem(__G__ args[2].strptr);
  314.     G.redirect_text = 0;
  315.     G.redirect_data++;
  316.   }
  317.   unzipToMemory(__G__ args[0].strptr, args[1].strptr,
  318.                 G.redirect_data==1 ? ub : NULL);
  319.   return RexxReturn(__G__ G.redirect_data==1,retstr);
  320. }
  321. /*************************************************************************
  322. * Function:  UZUnZipToStem                                               *
  323. *                                                                        *
  324. * Syntax:    call UZUnZipToStem zipfile, stem[, include-filespec]        *
  325. *                                [, exclude-filespec][, mode]            *
  326. *                                                                        *
  327. * Params:    zipfile  - Name of zip file to search.                      *
  328. *            stem     - Name of stem var to store files in.              *
  329. *            include  - Filespec to search for (may include * and ?).    *
  330. *            exclude  - Filespec to exclude (may include * and ?).       *
  331. *            mode     - Specifies 'F'lat or 'T'ree mode.  Umm, this is   *
  332. *                        hard to explain so I'll give an example, too.   *
  333. *                       Assuming a file unzip.zip containing:            *
  334. *                               unzip.c                                  *
  335. *                               unshrink.c                               *
  336. *                               extract.c                                *
  337. *                               os2/makefile.os2                         *
  338. *                               os2/os2.c                                *
  339. *                               os2/dll/dll.def                          *
  340. *                               os2/dll/unzipapi.c                       *
  341. *                                                                        *
  342. *                       -- In flat mode, each file is stored in          *
  343. *                          stem.fullname i.e. stem."os2/dll/unzipapi.c"  *
  344. *                          A list of files is created in stem.<index>    *
  345. *                                                                        *
  346. *                       Flat mode returns:                               *
  347. *                               stem.0 = 7                               *
  348. *                               stem.1 = unzip.c                         *
  349. *                               stem.2 = unshrink.c                      *
  350. *                               stem.3 = extract.c                       *
  351. *                               stem.4 = os2/makefile.os2                *
  352. *                               stem.5 = os2/os2.c                       *
  353. *                               stem.6 = os2/dll/dll.def                 *
  354. *                               stem.7 = os2/dll/unzipapi.c              *
  355. *                                                                        *
  356. *                       And the following contain the contents of the    *
  357. *                       various programs:                                *
  358. *                               stem.unzip.c                             *
  359. *                               stem.unshrink.c                          *
  360. *                               stem.extract.c                           *
  361. *                               stem.os2/makefile.os2                    *
  362. *                               stem.os2/os2.c                           *
  363. *                               stem.os2/dll/dll.def                     *
  364. *                               stem.os2/dll/unzipapi.c                  *
  365. *                                                                        *
  366. *                       -- In tree mode, slashes are converted to periods*
  367. *                          in the pathname thus the above file would have*
  368. *                          been stored in stem.os2.dll.unzipapi.c        *
  369. *                          The index would then be stored in stem.OS2.   *
  370. *                          DLL.<index>.                                  *
  371. *                                                                        *
  372. *                       NOTE: All path names are converted to uppercase  *
  373. *                                                                        *
  374. *                       Tree mode returns:                               *
  375. *                               stem.0 = 4                               *
  376. *                               stem.1 = unzip.c                         *
  377. *                               stem.2 = unshrink.c                      *
  378. *                               stem.3 = extract.c                       *
  379. *                               stem.4 = OS2/                            *
  380. *                                                                        *
  381. *                               stem.OS2.0 = 3                           *
  382. *                               stem.OS2.1 = makefile.os2                *
  383. *                               stem.OS2.2 = os2.c                       *
  384. *                               stem.OS2.3 = DLL/                        *
  385. *                                                                        *
  386. *                               stem.OS2.DLL.0 = 2                       *
  387. *                               stem.OS2.DLL.1 = def                     *
  388. *                               stem.OS2.DLL.2 = unzipapi.c              *
  389. *                                                                        *
  390. *                       And the following contain the contents of the    *
  391. *                       various programs:                                *
  392. *                               stem.unzip.c                             *
  393. *                               stem.unshrink.c                          *
  394. *                               stem.extract.c                           *
  395. *                               stem.OS2.makefile.os2                    *
  396. *                               stem.OS2.os2.c                           *
  397. *                               stem.OS2.DLL.dll.def                     *
  398. *                               stem.OS2.DLL.unzipapi.c                  *
  399. *                                                                        *
  400. *                                                                        *
  401. * Return:    NO_UTIL_ERROR   - Successful.                               *
  402. *            ERROR_NOMEM     - Out of memory.                            *
  403. *************************************************************************/
  404. ULONG UZUnZipToStem(CHAR *name, ULONG numargs, RXSTRING args[],
  405.                           CHAR *queuename, RXSTRING *retstr)
  406. {
  407.   char *incname[2];
  408.   char *excname[2];
  409.   CONSTRUCTGLOBALS();
  410.                                        /* validate arguments         */
  411.   if (numargs < 2 || numargs > 5 ||
  412.       !RXVALIDSTRING(args[0]) ||
  413.       !RXVALIDSTRING(args[1]) ||
  414.       args[0].strlength > 255) {
  415.     DESTROYGLOBALS();
  416.     return INVALID_ROUTINE;            /* Invalid call to routine    */
  417.   }
  418.                                        /* initialize data area       */
  419.   G.wildzipfn = args[0].strptr;
  420.   G.process_all_files = TRUE;
  421.   uO.C_flag = 1;
  422.   G.extract_flag = TRUE;
  423.   SetOutputVarStem(__G__ args[1].strptr);
  424.   G.redirect_data = 3;
  425.   G.redirect_text = 0;
  426.   if (numargs >= 3 &&                  /* check third option         */
  427.       !RXNULLSTRING(args[2]) &&
  428.       args[2].strlength > 0) {            /* a zero length string isn't */
  429.     if (!(G.filespecs = CompoundToStringArray(__G__ &G.pfnames,args[2].strptr))) {
  430.       G.pfnames = incname;
  431.       incname[0] = args[2].strptr;
  432.       incname[1] = NULL;
  433.       G.filespecs = 1;
  434.     }
  435.     G.process_all_files = FALSE;
  436.   }
  437.   if (numargs >= 4 &&                  /* check third option         */
  438.       !RXNULLSTRING(args[3]) &&
  439.       args[3].strlength > 0) {            /* a zero length string isn't */
  440.     if (!(G.xfilespecs = CompoundToStringArray(__G__ &G.pxnames,args[3].strptr))) {
  441.       G.pxnames = excname;
  442.       excname[0] = args[3].strptr;
  443.       excname[1] = NULL;
  444.       G.xfilespecs = 1;
  445.     }
  446.     G.process_all_files = FALSE;
  447.   }
  448.   if (numargs == 5 &&                  /* check third option         */
  449.       !RXNULLSTRING(args[4]) &&
  450.       (*args[4].strptr & 0x5f) == 'T') {
  451.     G.redirect_data++;
  452.     G.os2.request.shvnext = NULL;
  453.     EZRXSTRING(G.os2.request.shvname, args[4].strptr);
  454.     G.os2.request.shvnamelen = G.os2.request.shvname.strlength;
  455.     G.os2.request.shvcode = RXSHV_SYDRO;
  456.     G.os2.request.shvret = 0;
  457.     RexxVariablePool(&G.os2.request);
  458.   }
  459.   uO.qflag = 2;
  460.   process_zipfiles(__G);
  461.   if (G.filespecs > 0 && G.pfnames != incname)
  462.     KillStringArray(G.pfnames);
  463.   if (G.xfilespecs > 0 && G.pxnames != excname)
  464.     KillStringArray(G.pxnames);
  465.   if (G.redirect_data == 3)
  466.     SetOutputVarLength(__G);
  467.   return RexxReturn(__G__ 0,retstr);            /* no error on call           */
  468. }
  469. /*************************************************************************
  470. * Function:  UZLoadFuncs                                                 *
  471. *                                                                        *
  472. * Syntax:    call UZLoadFuncs [option]                                   *
  473. *                                                                        *
  474. * Params:    none                                                        *
  475. *                                                                        *
  476. * Return:    null string                                                 *
  477. *************************************************************************/
  478. ULONG UZLoadFuncs(CHAR *name, ULONG numargs, RXSTRING args[],
  479.                            CHAR *queuename, RXSTRING *retstr)
  480. {
  481.   INT    entries;                      /* Num of entries             */
  482.   INT    j;                            /* Counter                    */
  483.   retstr->strlength = 0;               /* set return value           */
  484.                                        /* check arguments            */
  485.   if (numargs > 0)
  486.     return INVALID_ROUTINE;
  487.   entries = sizeof(RxFncTable)/sizeof(PSZ);
  488.   for (j = 0; j < entries; j++) {
  489.     RexxRegisterFunctionDll(RxFncTable[j],
  490.           "UNZIP32", RxFncTable[j]);
  491.   }
  492.   return VALID_ROUTINE;
  493. }
  494. /*************************************************************************
  495. * Function:  UZVer                                                       *
  496. *                                                                        *
  497. * Syntax:    call UZVer                                                  *
  498. *                                                                        *
  499. * Return:    Version of Unzip                                            *
  500. *************************************************************************/
  501. ULONG UZVer(CHAR *name, ULONG numargs, RXSTRING args[],
  502.                         CHAR *queuename, RXSTRING *retstr)
  503. {
  504.   if (numargs > 1)                    /* validate arg count         */
  505.     return INVALID_ROUTINE;
  506.   if (numargs == 0 || (*args[0].strptr & 0x5f) != 'L')
  507.     /* strcpy( retstr->strptr, UZ_VERNUM );    "5.13a BETA" */
  508.     sprintf( retstr->strptr, "%d.%d%d%s", UZ_MAJORVER, UZ_MINORVER,
  509.       PATCHLEVEL, BETALEVEL );
  510.   else
  511.     /* strcpy( retstr->strptr, UZ_VERSION );   UZ_VERNUM" of 26 Sep 94" */
  512.     sprintf( retstr->strptr, "%d.%d%d%s of %s", UZ_MAJORVER, UZ_MINORVER,
  513.       PATCHLEVEL, BETALEVEL, VERSION_DATE );
  514.   retstr->strlength = strlen(retstr->strptr);
  515.   return VALID_ROUTINE;
  516. }
  517. /*************************************************************************
  518. * Function:  UZUnZip                                                     *
  519. *                                                                        *
  520. * Syntax:    call UZUnZip                                                *
  521. *                                                                        *
  522. * Return:    Unzip return code                                           *
  523. *************************************************************************/
  524. ULONG UZUnZip(CHAR *name, ULONG numargs, RXSTRING args[],
  525.                         CHAR *queuename, RXSTRING *retstr)
  526. {
  527.   char *argv[30];
  528.   char *scan;
  529.   int argc=0;
  530.   int idx;
  531.   CONSTRUCTGLOBALS();
  532.   if (numargs < 1 || numargs > 2 ||
  533.       args[0].strlength > 255) {
  534.     DESTROYGLOBALS();
  535.     return INVALID_ROUTINE;            /* Invalid call to routine    */
  536.   }
  537.                                        /* initialize data area       */
  538.   if (numargs == 2)
  539.     SetOutputVarStem(__G__ args[1].strptr);
  540.   scan = args[0].strptr;
  541.   argv[argc++] = "";         /* D:\SOURCECODE\UNZIP51S\UNZIP.COM"; */
  542.   while (*scan == ' ')
  543.     scan++;
  544.   argv[argc++] = scan;
  545.   while ( (scan = strchr(scan,' ')) != NULL) {
  546.     *scan++ = 0;
  547.     while (*scan == ' ')
  548.       scan++;
  549.     argv[argc++] = scan;
  550.   }
  551.   if (*argv[argc-1] == 0)
  552.     argc--;
  553.   argv[argc] = 0;
  554.          /* GRR:  should resetMainFlags() be called in here somewhere? */
  555.   sprintf(retstr->strptr, "%d", unzip(__G__ argc, argv));   /* a.k.a. MAIN() */
  556.   if (numargs == 2)
  557.     SetOutputVarLength(__G);
  558.   retstr->strlength = strlen(retstr->strptr);
  559.   return RexxReturn(__G__ 1,retstr);
  560. }
  561. int varmessage(__GPRO__ uch *buf, ulg size)
  562. {
  563.   if (size > 0)
  564.     memcpy(G.os2.buffer+G.os2.putchar_idx,buf,size);
  565.     G.os2.putchar_idx = TextSetNext(__G__ G.os2.buffer, size+G.os2.putchar_idx,0);
  566.   return 0;
  567. }
  568. int varputchar(__GPRO__ int c)
  569. {
  570.   G.os2.buffer[G.os2.putchar_idx++] = c;
  571.   if (c == 'n') {
  572.     G.os2.buffer[G.os2.putchar_idx] = 0;
  573.     if (G.os2.output_var[0])
  574.       G.os2.putchar_idx = TextSetNext(__G__ G.os2.buffer, G.os2.putchar_idx,0);
  575.     else {
  576.       G.os2.buffer[--G.os2.putchar_idx] = 0;
  577.       puts(G.os2.buffer);
  578.       G.os2.putchar_idx = 0;
  579.     }
  580.   }
  581.   return 1;
  582. }
  583. int SetOutputVarStem(__GPRO__ const char *name)
  584. {
  585.   int len=strlen(name);
  586.   G.redirect_text=1;
  587.   G.os2.output_idx = 0;
  588.   strcpy(G.os2.output_var, name);
  589.   if (len) {
  590.     strupr(G.os2.output_var);                 /* uppercase the name         */
  591.     if (*(G.os2.output_var+len-1) != '.') {
  592.       *(G.os2.output_var+len) = '.';
  593.       len++;
  594.       *(G.os2.output_var+len) = 0;
  595.     }
  596.     WriteToVariable(__G__ G.os2.output_var,"",0);
  597.   }
  598.   G.os2.stem_len = len;
  599.   return G.os2.stem_len;
  600. }
  601. int SetOutputVar(__GPRO__ const char *name)
  602. {
  603.   int len=strlen(name);
  604.   G.redirect_text=1;
  605.   G.os2.output_idx = 0;
  606.   strcpy(G.os2.output_var, name);
  607.   strupr(G.os2.output_var);                 /* uppercase the name         */
  608.   if (*(name+len-1) == '.')
  609.     G.os2.stem_len = len;
  610.   else
  611.     G.os2.stem_len = 0;
  612.   return G.os2.stem_len;
  613. }
  614. int SetOutputVarLength(__GPRO)
  615. {
  616.   if (G.os2.stem_len > 0) {
  617.     if (G.os2.putchar_idx)
  618.       TextSetNext(__G__ G.os2.buffer,G.os2.putchar_idx,1);
  619.     return PrintToSubVariable(__G__ 0,"%d",G.os2.output_idx);
  620.   }
  621.   return 0;
  622. }
  623. int PrintToVariable(__GPRO__ const char *name, const char *format,...)
  624. {
  625.   va_list arg_ptr;
  626.   int ret;
  627.   va_start(arg_ptr, format);
  628.   ret = _PrintToVariable(__G__ name, format, arg_ptr);
  629.   va_end(arg_ptr);
  630.   return ret;
  631. }
  632. int WriteToVariable(__GPRO__ const char *name, char *buffer, int len)
  633. {
  634.   G.os2.request.shvnext = NULL;
  635.   EZRXSTRING(G.os2.request.shvname, name);
  636.   G.os2.request.shvnamelen = G.os2.request.shvname.strlength;
  637.   G.os2.request.shvvalue.strptr = buffer;
  638.   G.os2.request.shvvalue.strlength = len;
  639.   G.os2.request.shvvaluelen = len;
  640.   G.os2.request.shvcode = RXSHV_SET;
  641.   G.os2.request.shvret = 0;
  642.   switch (RexxVariablePool(&G.os2.request)) {
  643.   case RXSHV_BADN:
  644.     G.os2.rexx_error = INVALID_ROUTINE;
  645.     break;
  646.   case RXSHV_MEMFL:
  647.     G.os2.rexx_mes = ERROR_NOMEM;
  648.     break;
  649.   case RXSHV_OK:
  650.     return 0;
  651.   }
  652.   return INVALID_ROUTINE;      /* error on non-zero          */
  653. }
  654. int _PrintToVariable(__GPRO__ const char *name, const char *format, va_list arg_ptr)
  655. {
  656.   int ret = vsprintf(G.os2.buffer, format, arg_ptr);
  657.   WriteToVariable(__G__ name, G.os2.buffer, strlen(G.os2.buffer));
  658.   return ret;
  659. }
  660. int PrintToSubVariable(__GPRO__ int idx, const char *format, ...)
  661. {
  662.   va_list arg_ptr;
  663.   int ret;
  664.   if (G.os2.stem_len == 0)
  665.     return INVALID_ROUTINE;      /* error on non-zero          */
  666.   sprintf(G.os2.output_var+G.os2.stem_len,"%d",idx);
  667.   va_start(arg_ptr, format);
  668.   ret = _PrintToVariable(__G__ G.os2.output_var, format, arg_ptr);
  669.   va_end(arg_ptr);
  670.   return ret;
  671. }
  672. int WriteToNextVariable(__GPRO__ char *buffer, int len)
  673. {
  674.   if (G.os2.stem_len > 0) {
  675.     G.os2.output_idx++;
  676.     sprintf(G.os2.output_var+G.os2.stem_len,"%d",G.os2.output_idx);
  677.   }
  678.   return WriteToVariable(__G__ G.os2.output_var, buffer, len);
  679. }
  680. int TextSetNext(__GPRO__ char *buffer, int len, int all)
  681. {
  682.   char *scan = buffer, *next, *base=buffer;
  683.   int remaining=len;
  684.   int ret;
  685.   while ((next = strchr(scan,'n')) != NULL && remaining > 0) {
  686.     if (next > scan && *(next-1) == 0xd)
  687.       *(next-1) = 0;
  688.     else
  689.       *next = 0;
  690.     if (WriteToNextVariable(__G__ scan,strlen(scan)))
  691.       return 0;
  692.     next++;
  693.     remaining -= (next-scan);
  694.     scan = next;
  695.   }
  696.   if (remaining > 0)
  697.     if (all) {
  698.       *(scan+remaining) = 0;
  699.       WriteToNextVariable(__G__ scan,remaining);
  700.     } else {
  701.       memcpy(buffer,scan,remaining);
  702.       return remaining;
  703.     }
  704.   return 0;
  705. }
  706. int finish_REXX_redirect(__GPRO)
  707. {
  708.   char *scan, *ptr;
  709.   int idx=0, first=1, offset;
  710.   if (!G.redirect_size)
  711.     return 0;
  712.   switch(G.redirect_data) {
  713.   case 1:
  714.     break;
  715.   case 2:
  716.     TextSetNext(__G__ G.redirect_buffer, G.redirect_size, 1);
  717.     SetOutputVarLength(__G);
  718.     DosFreeMem(G.redirect_buffer);
  719.     G.redirect_buffer = NULL;
  720.     G.redirect_size = 0;
  721.     break;
  722.   case 3:
  723.     WriteToNextVariable(__G__ G.filename,strlen(G.filename));
  724.     sprintf(G.os2.output_var+G.os2.stem_len,G.filename);
  725.     WriteToVariable(__G__ G.os2.output_var, G.redirect_buffer, G.redirect_size);
  726.     DosFreeMem(G.redirect_buffer);
  727.     G.redirect_buffer = NULL;
  728.     G.redirect_size = 0;
  729.     break;
  730.   case 4:
  731.     if ((scan = strrchr(G.filename,'/')) != NULL) {
  732.       idx = *scan;
  733.       *scan = 0;
  734.       strupr(G.filename);
  735.       *scan = idx;
  736.     }
  737.     scan = G.os2.output_var+G.os2.stem_len;
  738.     strcpy(scan,G.filename);
  739.     while ((scan = strchr(scan,'/')) != NULL)
  740.       *scan = '.';
  741.     WriteToVariable(__G__ G.os2.output_var, G.redirect_buffer, G.redirect_size);
  742.     DosFreeMem(G.redirect_buffer);
  743.     G.redirect_buffer = NULL;
  744.     G.redirect_size = 0;
  745.     strcpy(G.os2.getvar_buf, G.os2.output_var);
  746.     do {
  747.       if ((scan = strrchr(G.filename,'/')) == NULL)
  748.         offset = 0;
  749.       else
  750.         offset = scan-G.filename+1;
  751.       if (first || !GetVariable(__G__ G.os2.output_var)) {
  752.         ptr = G.os2.getvar_buf+offset+G.os2.stem_len;
  753.         *ptr = '0';
  754.         *(ptr+1) = 0;
  755.         if (!GetVariable(__G__ G.os2.getvar_buf))
  756.           idx = 1;
  757.         else
  758.           idx = atoi(G.os2.buffer)+1;
  759.         PrintToVariable(__G__ G.os2.getvar_buf,"%d",idx);
  760.         sprintf(ptr,"%d",idx);
  761.         if (!first) {
  762.           PrintToVariable(__G__ G.os2.output_var,"%d",idx);
  763.           idx = strlen(G.filename);
  764.           *(G.filename+idx)   = '/';
  765.           *(G.filename+idx+1) = 0;
  766.         }
  767.         WriteToVariable(__G__ G.os2.getvar_buf,G.filename+offset,strlen(G.filename+offset));
  768.         first=0;
  769.       }
  770.       if (offset) {
  771.         *(G.os2.output_var+G.os2.stem_len+offset-1)   = 0;
  772.         *scan = 0;
  773.       }
  774.     } while (offset);
  775.     break;
  776.   }
  777.   return 0;
  778. }
  779. #endif /* OS2DLL */