/* Copyright (c) 1990-2004 Info-ZIP. All rights reserved. See the accompanying file LICENSE, version 2000-Apr-09 or later (the contents of which are also included in unzip.h) for terms of use. If, for some reason, all these files are missing, the Info-ZIP license also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html */ /********************************************************************** * 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 #include #include #include #define UNZIP_INTERNAL #include "../unzip.h" #include "../unzvers.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. * * * * 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.. * * * * 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, UZ_PATCHLEVEL, UZ_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, UZ_PATCHLEVEL, UZ_BETALEVEL, UZ_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__ ZCONST 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)); strcpy(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 */