--- /dev/null
+/**********************************************************************
+* REXXAPI.C *
+* *
+* This program adds a ZIP engine directly to the REXX language. *
+* The functions are: *
+* UZDropFuncs -- Makes all functions in this package *
+* unknown to REXX. *
+* UZLoadFuncs -- Makes all functions in this package *
+* known to REXX so REXX programs may *
+* call them. *
+* UZFileTree -- Searches for files matching a given *
+* filespec, including files in *
+* subdirectories. *
+* UZUnZip -- Unzip command-line entry point. *
+* This is functionally equivalent to *
+* using Unzip as an external program. *
+* UZUnZipToVar -- Unzip one file to a variable *
+* UZUnZipToStem -- Unzip files to a variable array *
+* UZVer -- Returns the Unzip version number *
+* *
+**********************************************************************/
+/* Include files */
+
+#ifdef OS2DLL
+
+#define INCL_DOS
+#define INCL_DOSMEMMGR
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+
+#define UNZIP_INTERNAL
+#include "../unzip.h"
+#include "../version.h"
+
+
+/*********************************************************************/
+/* Various definitions used by various functions. */
+/*********************************************************************/
+
+RexxFunctionHandler UZDropFuncs;
+RexxFunctionHandler UZLoadFuncs;
+RexxFunctionHandler UZFileTree;
+RexxFunctionHandler UZUnZip;
+RexxFunctionHandler UZUnZipToVar;
+RexxFunctionHandler UZUnZipToStem;
+RexxFunctionHandler UZVer;
+RexxFunctionHandler UZAPIVer;
+
+
+int SetOutputVar(__GPRO__ const char *name);
+int SetOutputVarStem(__GPRO__ const char *name);
+int SetOutputVarLength(__GPRO);
+int WriteToVariable(__GPRO__ const char *name, char *buffer, int len);
+int PrintToSubVariable(__GPRO__ int idx, const char *format,...);
+int PrintToVariable(__GPRO__ const char *name, const char *format,...);
+int _PrintToVariable(__GPRO__ const char *name, const char *format, va_list arg_ptr);
+int TextSetNext(__GPRO__ char *format, int len, int all);
+
+#define EZRXSTRING(r,p) {(r).strptr=(PCH)p;(r).strlength=(ULONG)strlen((r).strptr);}
+
+
+/*********************************************************************/
+/* RxFncTable */
+/* Array of names of the UNZIPAPI functions. */
+/* This list is used for registration and deregistration. */
+/*********************************************************************/
+
+static PSZ RxFncTable[] =
+ {
+ "UZDropFuncs",
+ "UZLoadFuncs",
+ "UZFileSearch",
+ "UZFileTree",
+ "UZUnZip",
+ "UZUnZipToVar",
+ "UZUnZipToStem",
+ "UZVer",
+ };
+
+/*********************************************************************/
+/* Numeric Error Return Strings */
+/*********************************************************************/
+
+#define NO_UTIL_ERROR "0" /* No error whatsoever */
+#define ERROR_NOMEM "2" /* Insufficient memory */
+
+/*********************************************************************/
+/* Numeric Return calls */
+/*********************************************************************/
+
+#define INVALID_ROUTINE 40 /* Raise Rexx error */
+#define VALID_ROUTINE 0 /* Successful completion */
+
+/*********************************************************************/
+/* Some useful macros */
+/*********************************************************************/
+
+#define BUILDRXSTRING(t, s) { \
+ strcpy((t)->strptr,(s));\
+ (t)->strlength = strlen((s)); \
+}
+
+
+/*********************************************************************/
+/**************** UNZIPAPI Supporting Functions ********************/
+/**************** UNZIPAPI Supporting Functions ********************/
+/**************** UNZIPAPI Supporting Functions ********************/
+/*********************************************************************/
+
+
+int RexxReturn(__GPRO__ int nodefault, RXSTRING *retstr)
+{
+ int ret = G.os2.rexx_error;
+ if (G.filenotfound)
+ G.os2.rexx_mes = "file not found";
+ if (*G.os2.rexx_mes != '0') {
+ if (retstr->strlength > 255) {
+ DosFreeMem(retstr->strptr);
+ retstr->strptr = NULL;
+ }
+ } else if (nodefault)
+ goto noBuild;
+ BUILDRXSTRING(retstr, G.os2.rexx_mes);
+ noBuild:
+ DESTROYGLOBALS();
+ return ret;
+}
+
+/* Get a variable from REXX, return 0 if OK */
+int GetVariable(__GPRO__ const char *name)
+{
+ G.os2.request.shvnext = NULL;
+ EZRXSTRING(G.os2.request.shvname, name);
+ G.os2.request.shvnamelen = G.os2.request.shvname.strlength;
+ G.os2.request.shvvalue.strptr = G.os2.buffer;
+ G.os2.request.shvvalue.strlength = IBUF_LEN;
+ G.os2.request.shvvaluelen = IBUF_LEN;
+ G.os2.request.shvcode = RXSHV_SYFET;
+ G.os2.request.shvret = 0;
+ switch (RexxVariablePool(&G.os2.request)) {
+ case RXSHV_MEMFL:
+ G.os2.rexx_mes = ERROR_NOMEM;
+ break;
+ case RXSHV_BADN:
+ case RXSHV_NEWV:
+ G.os2.request.shvvaluelen = 0;
+ case RXSHV_OK:
+ *(G.os2.buffer+G.os2.request.shvvaluelen) = 0;
+ return G.os2.request.shvvaluelen;
+ }
+ return 0;
+}
+
+
+/* Get REXX compound variable */
+/* Stem must exist in G.os2.getvar_buf w/ length in G.os2.getvar_len */
+int GetVariableIndex(__GPRO__ int index)
+{
+ sprintf(G.os2.getvar_buf+G.os2.getvar_len,"%d",index);
+ return GetVariable(__G__ G.os2.getvar_buf);
+}
+
+
+/* Transfer REXX array to standard C string array */
+/* Returns number of elements */
+/* User is responsible for calling KillStringArray */
+
+int CompoundToStringArray(__GPRO__ char ***pointer, const char *name)
+{
+ int count;
+ int total;
+ char **trav;
+
+ G.os2.getvar_len = strlen(name);
+ memcpy(G.os2.getvar_buf,name,G.os2.getvar_len+1);
+ if (*(G.os2.getvar_buf+G.os2.getvar_len-1) != '.')
+ *(G.os2.getvar_buf+G.os2.getvar_len++) = '.', *(G.os2.getvar_buf+G.os2.getvar_len) = 0;
+
+ if (GetVariableIndex(__G__ 0))
+ return 0;
+
+ total = atoi(G.os2.buffer);
+ *pointer = (char **)malloc((total+1)<<2);
+ trav = *pointer;
+ for (count = 1; count <= total; count++) {
+ GetVariableIndex(__G__ count);
+ trav[count-1] = (char *)malloc(strlen(G.os2.buffer)+1);
+ strcpy(trav[count-1],G.os2.buffer);
+ }
+ trav[count-1] = NULL;
+ return total;
+}
+
+
+/* Kill string array created by CompoundToStringArray */
+
+void KillStringArray(char **pointer)
+{
+ char **trav=pointer;
+ while (*trav != NULL) {
+ free(*trav);
+ trav++;
+ }
+ free(pointer);
+}
+
+
+/*************************************************************************
+* Function: UZDropFuncs *
+* *
+* Syntax: call UZDropFuncs *
+* *
+* Return: NO_UTIL_ERROR - Successful. *
+*************************************************************************/
+
+ULONG UZDropFuncs(CHAR *name, ULONG numargs, RXSTRING args[],
+ CHAR *queuename, RXSTRING *retstr)
+{
+ INT entries; /* Num of entries */
+ INT j; /* Counter */
+
+ if (numargs != 0) /* no arguments for this */
+ return INVALID_ROUTINE; /* raise an error */
+
+ retstr->strlength = 0; /* return a null string result*/
+
+ entries = sizeof(RxFncTable)/sizeof(PSZ);
+
+ for (j = 0; j < entries; j++)
+ RexxDeregisterFunction(RxFncTable[j]);
+
+ return VALID_ROUTINE; /* no error on call */
+}
+
+
+/*************************************************************************
+* Function: UZFileTree *
+* *
+* Syntax: call UZFileTree zipfile, stem[, include-filespec] *
+* [, exclude-filespec][, options] *
+* *
+* Params: zipfile - Name of zip file to search. *
+* stem - Name of stem var to store results in. *
+* include - Filespec to search for (may include * and ?). *
+* exclude - Filespec to exclude (may include * and ?). *
+* options - Either of the following: *
+* 'F' - Give file statistics. *
+* Length Date Time Name *
+* 'Z' - Give zip statistics, too. *
+* Length Method Size Ratio Date Time CRC-32 Name*
+* Default is to return only filenames *
+* *
+* Return: NO_UTIL_ERROR - Successful. *
+* ERROR_NOMEM - Out of memory. *
+*************************************************************************/
+
+ULONG UZFileTree(CHAR *name, ULONG numargs, RXSTRING args[],
+ CHAR *queuename, RXSTRING *retstr)
+{
+ /* validate arguments */
+ char *incname[2];
+ char *excname[2];
+ CONSTRUCTGLOBALS();
+
+ if (numargs < 2 || numargs > 5 ||
+ !RXVALIDSTRING(args[0]) ||
+ !RXVALIDSTRING(args[1]) ||
+ args[0].strlength > 255) {
+ DESTROYGLOBALS();
+ return INVALID_ROUTINE; /* Invalid call to routine */
+ }
+ /* initialize data area */
+ SetOutputVarStem(__G__ args[1].strptr);
+ G.wildzipfn = args[0].strptr;
+ G.process_all_files = TRUE;
+
+ uO.lflag = 1;
+ uO.zipinfo_mode = TRUE;
+ uO.C_flag = 1;
+ G.extract_flag = FALSE;
+ uO.qflag = 2;
+
+ if (numargs >= 3 && /* check third option */
+ !RXNULLSTRING(args[2]) &&
+ args[2].strlength > 0) { /* a zero length string isn't */
+ if (!(G.filespecs = CompoundToStringArray(__G__ &G.pfnames,args[2].strptr))) {
+ G.pfnames = incname;
+ incname[0] = args[2].strptr;
+ incname[1] = NULL;
+ G.filespecs = 1;
+ }
+ G.process_all_files = FALSE;
+ }
+
+ if (numargs >= 4 && /* check third option */
+ !RXNULLSTRING(args[3]) &&
+ args[3].strlength > 0) { /* a zero length string isn't */
+ if (!(G.xfilespecs = CompoundToStringArray(__G__ &G.pxnames,args[3].strptr))) {
+ G.pxnames = excname;
+ excname[0] = args[3].strptr;
+ excname[1] = NULL;
+ G.xfilespecs = 1;
+ }
+ G.process_all_files = FALSE;
+ }
+
+ if (numargs == 5 && /* check third option */
+ !RXNULLSTRING(args[4]) &&
+ args[4].strlength > 0) { /* a zero length string isn't */
+ int first = *args[4].strptr & 0x5f;
+
+ if (first == 'Z')
+ uO.vflag = 2, uO.lflag = 0, uO.zipinfo_mode = FALSE;
+ else if (first == 'F')
+ uO.vflag = 1, uO.lflag = 0, uO.zipinfo_mode = FALSE;
+ }
+
+ process_zipfiles(__G);
+ SetOutputVarLength(__G);
+ if (G.filespecs > 0 && G.pfnames != incname)
+ KillStringArray(G.pfnames);
+ if (G.xfilespecs > 0 && G.pxnames != excname)
+ KillStringArray(G.pxnames);
+ return RexxReturn(__G__ 0,retstr); /* no error on call */
+}
+
+
+/*************************************************************************
+* Function: UZUnZipToVar *
+* *
+* Syntax: call UZUnZipToVar zipfile, filespec [, stem] *
+* *
+* Params: zipfile - Name of zip file to search. *
+* filespec - File to extract *
+* stem - If you specify a stem variable, the file will be *
+* extracted to the variable, one line per index *
+* In this case, 0 will be returned *
+* *
+* Return: Extracted file *
+* ERROR_NOMEM - Out of memory. *
+*************************************************************************/
+
+ULONG UZUnZipToVar(CHAR *name, ULONG numargs, RXSTRING args[],
+ CHAR *queuename, RXSTRING *retstr)
+{
+ CONSTRUCTGLOBALS();
+ UzpBuffer *ub = (UzpBuffer *)retstr;
+ /* validate arguments */
+ if (numargs < 2 || numargs > 3 ||
+ !RXVALIDSTRING(args[0]) ||
+ !RXVALIDSTRING(args[1]) ||
+ args[0].strlength == 0 ||
+ args[1].strlength == 0) {
+ DESTROYGLOBALS();
+ return INVALID_ROUTINE; /* Invalid call to routine */
+ }
+
+ uO.C_flag = 1;
+ G.redirect_data=1;
+ if (numargs == 3) {
+ if (!RXVALIDSTRING(args[2]) ||
+ RXNULLSTRING(args[1]) ||
+ args[2].strlength == 0) {
+ DESTROYGLOBALS();
+ return INVALID_ROUTINE; /* Invalid call to routine */
+ }
+ SetOutputVarStem(__G__ args[2].strptr);
+ G.redirect_text = 0;
+ G.redirect_data++;
+ }
+ unzipToMemory(__G__ args[0].strptr, args[1].strptr,
+ G.redirect_data==1 ? ub : NULL);
+ return RexxReturn(__G__ G.redirect_data==1,retstr);
+}
+
+
+/*************************************************************************
+* Function: UZUnZipToStem *
+* *
+* Syntax: call UZUnZipToStem zipfile, stem[, include-filespec] *
+* [, exclude-filespec][, mode] *
+* *
+* Params: zipfile - Name of zip file to search. *
+* stem - Name of stem var to store files in. *
+* include - Filespec to search for (may include * and ?). *
+* exclude - Filespec to exclude (may include * and ?). *
+* mode - Specifies 'F'lat or 'T'ree mode. Umm, this is *
+* hard to explain so I'll give an example, too. *
+* Assuming a file unzip.zip containing: *
+* unzip.c *
+* unshrink.c *
+* extract.c *
+* os2/makefile.os2 *
+* os2/os2.c *
+* os2/dll/dll.def *
+* os2/dll/unzipapi.c *
+* *
+* -- In flat mode, each file is stored in *
+* stem.fullname i.e. stem."os2/dll/unzipapi.c" *
+* A list of files is created in stem.<index> *
+* *
+* Flat mode returns: *
+* stem.0 = 7 *
+* stem.1 = unzip.c *
+* stem.2 = unshrink.c *
+* stem.3 = extract.c *
+* stem.4 = os2/makefile.os2 *
+* stem.5 = os2/os2.c *
+* stem.6 = os2/dll/dll.def *
+* stem.7 = os2/dll/unzipapi.c *
+* *
+* And the following contain the contents of the *
+* various programs: *
+* stem.unzip.c *
+* stem.unshrink.c *
+* stem.extract.c *
+* stem.os2/makefile.os2 *
+* stem.os2/os2.c *
+* stem.os2/dll/dll.def *
+* stem.os2/dll/unzipapi.c *
+* *
+* -- In tree mode, slashes are converted to periods*
+* in the pathname thus the above file would have*
+* been stored in stem.os2.dll.unzipapi.c *
+* The index would then be stored in stem.OS2. *
+* DLL.<index>. *
+* *
+* NOTE: All path names are converted to uppercase *
+* *
+* Tree mode returns: *
+* stem.0 = 4 *
+* stem.1 = unzip.c *
+* stem.2 = unshrink.c *
+* stem.3 = extract.c *
+* stem.4 = OS2/ *
+* *
+* stem.OS2.0 = 3 *
+* stem.OS2.1 = makefile.os2 *
+* stem.OS2.2 = os2.c *
+* stem.OS2.3 = DLL/ *
+* *
+* stem.OS2.DLL.0 = 2 *
+* stem.OS2.DLL.1 = def *
+* stem.OS2.DLL.2 = unzipapi.c *
+* *
+* And the following contain the contents of the *
+* various programs: *
+* stem.unzip.c *
+* stem.unshrink.c *
+* stem.extract.c *
+* stem.OS2.makefile.os2 *
+* stem.OS2.os2.c *
+* stem.OS2.DLL.dll.def *
+* stem.OS2.DLL.unzipapi.c *
+* *
+* *
+* Return: NO_UTIL_ERROR - Successful. *
+* ERROR_NOMEM - Out of memory. *
+*************************************************************************/
+
+ULONG UZUnZipToStem(CHAR *name, ULONG numargs, RXSTRING args[],
+ CHAR *queuename, RXSTRING *retstr)
+{
+ char *incname[2];
+ char *excname[2];
+ CONSTRUCTGLOBALS();
+ /* validate arguments */
+ if (numargs < 2 || numargs > 5 ||
+ !RXVALIDSTRING(args[0]) ||
+ !RXVALIDSTRING(args[1]) ||
+ args[0].strlength > 255) {
+ DESTROYGLOBALS();
+ return INVALID_ROUTINE; /* Invalid call to routine */
+ }
+ /* initialize data area */
+ G.wildzipfn = args[0].strptr;
+ G.process_all_files = TRUE;
+
+ uO.C_flag = 1;
+ G.extract_flag = TRUE;
+ SetOutputVarStem(__G__ args[1].strptr);
+ G.redirect_data = 3;
+ G.redirect_text = 0;
+
+ if (numargs >= 3 && /* check third option */
+ !RXNULLSTRING(args[2]) &&
+ args[2].strlength > 0) { /* a zero length string isn't */
+ if (!(G.filespecs = CompoundToStringArray(__G__ &G.pfnames,args[2].strptr))) {
+ G.pfnames = incname;
+ incname[0] = args[2].strptr;
+ incname[1] = NULL;
+ G.filespecs = 1;
+ }
+ G.process_all_files = FALSE;
+ }
+
+ if (numargs >= 4 && /* check third option */
+ !RXNULLSTRING(args[3]) &&
+ args[3].strlength > 0) { /* a zero length string isn't */
+ if (!(G.xfilespecs = CompoundToStringArray(__G__ &G.pxnames,args[3].strptr))) {
+ G.pxnames = excname;
+ excname[0] = args[3].strptr;
+ excname[1] = NULL;
+ G.xfilespecs = 1;
+ }
+ G.process_all_files = FALSE;
+ }
+
+ if (numargs == 5 && /* check third option */
+ !RXNULLSTRING(args[4]) &&
+ (*args[4].strptr & 0x5f) == 'T') {
+ G.redirect_data++;
+ G.os2.request.shvnext = NULL;
+ EZRXSTRING(G.os2.request.shvname, args[4].strptr);
+ G.os2.request.shvnamelen = G.os2.request.shvname.strlength;
+ G.os2.request.shvcode = RXSHV_SYDRO;
+ G.os2.request.shvret = 0;
+ RexxVariablePool(&G.os2.request);
+ }
+
+
+ uO.qflag = 2;
+
+ process_zipfiles(__G);
+ if (G.filespecs > 0 && G.pfnames != incname)
+ KillStringArray(G.pfnames);
+ if (G.xfilespecs > 0 && G.pxnames != excname)
+ KillStringArray(G.pxnames);
+ if (G.redirect_data == 3)
+ SetOutputVarLength(__G);
+ return RexxReturn(__G__ 0,retstr); /* no error on call */
+}
+
+
+/*************************************************************************
+* Function: UZLoadFuncs *
+* *
+* Syntax: call UZLoadFuncs [option] *
+* *
+* Params: none *
+* *
+* Return: null string *
+*************************************************************************/
+
+ULONG UZLoadFuncs(CHAR *name, ULONG numargs, RXSTRING args[],
+ CHAR *queuename, RXSTRING *retstr)
+{
+ INT entries; /* Num of entries */
+ INT j; /* Counter */
+
+ retstr->strlength = 0; /* set return value */
+ /* check arguments */
+ if (numargs > 0)
+ return INVALID_ROUTINE;
+
+ entries = sizeof(RxFncTable)/sizeof(PSZ);
+
+ for (j = 0; j < entries; j++) {
+ RexxRegisterFunctionDll(RxFncTable[j],
+ "UNZIP32", RxFncTable[j]);
+ }
+ return VALID_ROUTINE;
+}
+
+
+
+/*************************************************************************
+* Function: UZVer *
+* *
+* Syntax: call UZVer *
+* *
+* Return: Version of Unzip *
+*************************************************************************/
+
+ULONG UZVer(CHAR *name, ULONG numargs, RXSTRING args[],
+ CHAR *queuename, RXSTRING *retstr)
+{
+ if (numargs > 1) /* validate arg count */
+ return INVALID_ROUTINE;
+
+ if (numargs == 0 || (*args[0].strptr & 0x5f) != 'L')
+ /* strcpy( retstr->strptr, UZ_VERNUM ); "5.13a BETA" */
+ sprintf( retstr->strptr, "%d.%d%d%s", UZ_MAJORVER, UZ_MINORVER,
+ PATCHLEVEL, BETALEVEL );
+ else
+ /* strcpy( retstr->strptr, UZ_VERSION ); UZ_VERNUM" of 26 Sep 94" */
+ sprintf( retstr->strptr, "%d.%d%d%s of %s", UZ_MAJORVER, UZ_MINORVER,
+ PATCHLEVEL, BETALEVEL, VERSION_DATE );
+ retstr->strlength = strlen(retstr->strptr);
+ return VALID_ROUTINE;
+}
+
+
+/*************************************************************************
+* Function: UZUnZip *
+* *
+* Syntax: call UZUnZip *
+* *
+* Return: Unzip return code *
+*************************************************************************/
+
+ULONG UZUnZip(CHAR *name, ULONG numargs, RXSTRING args[],
+ CHAR *queuename, RXSTRING *retstr)
+{
+ char *argv[30];
+ char *scan;
+ int argc=0;
+ int idx;
+ CONSTRUCTGLOBALS();
+
+ if (numargs < 1 || numargs > 2 ||
+ args[0].strlength > 255) {
+ DESTROYGLOBALS();
+ return INVALID_ROUTINE; /* Invalid call to routine */
+ }
+ /* initialize data area */
+ if (numargs == 2)
+ SetOutputVarStem(__G__ args[1].strptr);
+
+ scan = args[0].strptr;
+ argv[argc++] = ""; /* D:\\SOURCECODE\\UNZIP51S\\UNZIP.COM"; */
+ while (*scan == ' ')
+ scan++;
+ argv[argc++] = scan;
+ while ( (scan = strchr(scan,' ')) != NULL) {
+ *scan++ = 0;
+ while (*scan == ' ')
+ scan++;
+ argv[argc++] = scan;
+ }
+ if (*argv[argc-1] == 0)
+ argc--;
+ argv[argc] = 0;
+
+ /* GRR: should resetMainFlags() be called in here somewhere? */
+
+ sprintf(retstr->strptr, "%d", unzip(__G__ argc, argv)); /* a.k.a. MAIN() */
+ if (numargs == 2)
+ SetOutputVarLength(__G);
+ retstr->strlength = strlen(retstr->strptr);
+ return RexxReturn(__G__ 1,retstr);
+}
+
+int varmessage(__GPRO__ uch *buf, ulg size)
+{
+ if (size > 0)
+ memcpy(G.os2.buffer+G.os2.putchar_idx,buf,size);
+ G.os2.putchar_idx = TextSetNext(__G__ G.os2.buffer, size+G.os2.putchar_idx,0);
+ return 0;
+}
+
+int varputchar(__GPRO__ int c)
+{
+ G.os2.buffer[G.os2.putchar_idx++] = c;
+ if (c == '\n') {
+ G.os2.buffer[G.os2.putchar_idx] = 0;
+ if (G.os2.output_var[0])
+ G.os2.putchar_idx = TextSetNext(__G__ G.os2.buffer, G.os2.putchar_idx,0);
+ else {
+ G.os2.buffer[--G.os2.putchar_idx] = 0;
+ puts(G.os2.buffer);
+ G.os2.putchar_idx = 0;
+ }
+ }
+ return 1;
+}
+
+
+
+int SetOutputVarStem(__GPRO__ const char *name)
+{
+ int len=strlen(name);
+ G.redirect_text=1;
+ G.os2.output_idx = 0;
+ strcpy(G.os2.output_var, name);
+ if (len) {
+ strupr(G.os2.output_var); /* uppercase the name */
+ if (*(G.os2.output_var+len-1) != '.') {
+ *(G.os2.output_var+len) = '.';
+ len++;
+ *(G.os2.output_var+len) = 0;
+ }
+ WriteToVariable(__G__ G.os2.output_var,"",0);
+ }
+ G.os2.stem_len = len;
+ return G.os2.stem_len;
+}
+
+int SetOutputVar(__GPRO__ const char *name)
+{
+ int len=strlen(name);
+ G.redirect_text=1;
+ G.os2.output_idx = 0;
+ strcpy(G.os2.output_var, name);
+ strupr(G.os2.output_var); /* uppercase the name */
+ if (*(name+len-1) == '.')
+ G.os2.stem_len = len;
+ else
+ G.os2.stem_len = 0;
+ return G.os2.stem_len;
+}
+
+int SetOutputVarLength(__GPRO)
+{
+ if (G.os2.stem_len > 0) {
+ if (G.os2.putchar_idx)
+ TextSetNext(__G__ G.os2.buffer,G.os2.putchar_idx,1);
+ return PrintToSubVariable(__G__ 0,"%d",G.os2.output_idx);
+ }
+ return 0;
+}
+
+int PrintToVariable(__GPRO__ const char *name, const char *format,...)
+{
+ va_list arg_ptr;
+ int ret;
+
+ va_start(arg_ptr, format);
+ ret = _PrintToVariable(__G__ name, format, arg_ptr);
+ va_end(arg_ptr);
+ return ret;
+}
+
+int WriteToVariable(__GPRO__ const char *name, char *buffer, int len)
+{
+ G.os2.request.shvnext = NULL;
+ EZRXSTRING(G.os2.request.shvname, name);
+ G.os2.request.shvnamelen = G.os2.request.shvname.strlength;
+ G.os2.request.shvvalue.strptr = buffer;
+ G.os2.request.shvvalue.strlength = len;
+ G.os2.request.shvvaluelen = len;
+ G.os2.request.shvcode = RXSHV_SET;
+ G.os2.request.shvret = 0;
+ switch (RexxVariablePool(&G.os2.request)) {
+ case RXSHV_BADN:
+ G.os2.rexx_error = INVALID_ROUTINE;
+ break;
+ case RXSHV_MEMFL:
+ G.os2.rexx_mes = ERROR_NOMEM;
+ break;
+ case RXSHV_OK:
+ return 0;
+ }
+ return INVALID_ROUTINE; /* error on non-zero */
+}
+
+int _PrintToVariable(__GPRO__ const char *name, const char *format, va_list arg_ptr)
+{
+ int ret = vsprintf(G.os2.buffer, format, arg_ptr);
+ WriteToVariable(__G__ name, G.os2.buffer, strlen(G.os2.buffer));
+ return ret;
+}
+
+int PrintToSubVariable(__GPRO__ int idx, const char *format, ...)
+{
+ va_list arg_ptr;
+ int ret;
+
+ if (G.os2.stem_len == 0)
+ return INVALID_ROUTINE; /* error on non-zero */
+ sprintf(G.os2.output_var+G.os2.stem_len,"%d",idx);
+
+ va_start(arg_ptr, format);
+ ret = _PrintToVariable(__G__ G.os2.output_var, format, arg_ptr);
+ va_end(arg_ptr);
+ return ret;
+}
+
+
+int WriteToNextVariable(__GPRO__ char *buffer, int len)
+{
+ if (G.os2.stem_len > 0) {
+ G.os2.output_idx++;
+ sprintf(G.os2.output_var+G.os2.stem_len,"%d",G.os2.output_idx);
+ }
+ return WriteToVariable(__G__ G.os2.output_var, buffer, len);
+}
+
+
+int TextSetNext(__GPRO__ char *buffer, int len, int all)
+{
+ char *scan = buffer, *next, *base=buffer;
+ int remaining=len;
+ int ret;
+
+ while ((next = strchr(scan,'\n')) != NULL && remaining > 0) {
+ if (next > scan && *(next-1) == 0xd)
+ *(next-1) = 0;
+ else
+ *next = 0;
+ if (WriteToNextVariable(__G__ scan,strlen(scan)))
+ return 0;
+ next++;
+ remaining -= (next-scan);
+ scan = next;
+ }
+ if (remaining > 0)
+ if (all) {
+ *(scan+remaining) = 0;
+ WriteToNextVariable(__G__ scan,remaining);
+ } else {
+ memcpy(buffer,scan,remaining);
+ return remaining;
+ }
+
+ return 0;
+}
+
+int finish_REXX_redirect(__GPRO)
+{
+ char *scan, *ptr;
+ int idx=0, first=1, offset;
+
+ if (!G.redirect_size)
+ return 0;
+ switch(G.redirect_data) {
+ case 1:
+ break;
+ case 2:
+ TextSetNext(__G__ G.redirect_buffer, G.redirect_size, 1);
+ SetOutputVarLength(__G);
+ DosFreeMem(G.redirect_buffer);
+ G.redirect_buffer = NULL;
+ G.redirect_size = 0;
+ break;
+ case 3:
+ WriteToNextVariable(__G__ G.filename,strlen(G.filename));
+ sprintf(G.os2.output_var+G.os2.stem_len,G.filename);
+ WriteToVariable(__G__ G.os2.output_var, G.redirect_buffer, G.redirect_size);
+ DosFreeMem(G.redirect_buffer);
+ G.redirect_buffer = NULL;
+ G.redirect_size = 0;
+ break;
+ case 4:
+ if ((scan = strrchr(G.filename,'/')) != NULL) {
+ idx = *scan;
+ *scan = 0;
+ strupr(G.filename);
+ *scan = idx;
+ }
+ scan = G.os2.output_var+G.os2.stem_len;
+ strcpy(scan,G.filename);
+ while ((scan = strchr(scan,'/')) != NULL)
+ *scan = '.';
+ WriteToVariable(__G__ G.os2.output_var, G.redirect_buffer, G.redirect_size);
+ DosFreeMem(G.redirect_buffer);
+ G.redirect_buffer = NULL;
+ G.redirect_size = 0;
+ strcpy(G.os2.getvar_buf, G.os2.output_var);
+ do {
+ if ((scan = strrchr(G.filename,'/')) == NULL)
+ offset = 0;
+ else
+ offset = scan-G.filename+1;
+ if (first || !GetVariable(__G__ G.os2.output_var)) {
+ ptr = G.os2.getvar_buf+offset+G.os2.stem_len;
+ *ptr = '0';
+ *(ptr+1) = 0;
+ if (!GetVariable(__G__ G.os2.getvar_buf))
+ idx = 1;
+ else
+ idx = atoi(G.os2.buffer)+1;
+ PrintToVariable(__G__ G.os2.getvar_buf,"%d",idx);
+ sprintf(ptr,"%d",idx);
+ if (!first) {
+ PrintToVariable(__G__ G.os2.output_var,"%d",idx);
+ idx = strlen(G.filename);
+ *(G.filename+idx) = '/';
+ *(G.filename+idx+1) = 0;
+ }
+ WriteToVariable(__G__ G.os2.getvar_buf,G.filename+offset,strlen(G.filename+offset));
+ first=0;
+ }
+ if (offset) {
+ *(G.os2.output_var+G.os2.stem_len+offset-1) = 0;
+ *scan = 0;
+ }
+ } while (offset);
+ break;
+ }
+ return 0;
+}
+
+#endif /* OS2DLL */