home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / viscobv6.zip / vac22os2 / ibmcobol / samples / toolkit / rexx / api / rexxutil / rexxutil.c < prev    next >
C/C++ Source or Header  |  1996-11-19  |  120KB  |  2,532 lines

  1. /**********************************************************************
  2. *   REXXUTIL.C                                                        *
  3. *                                                                     *
  4. *   This program extends the REXX language by providing many          *
  5. *   REXX external functions.                                          *
  6. *   This sample program contains a subset of the functions            *
  7. *   provided in the version of REXXUTIL.DLL that is included in       *
  8. *   the base OS/2 product.                                            *
  9. *   These functions are:                                              *
  10. *       SysCls              -- Clear the screen in an OS/2 fullscreen *
  11. *                              or windowed command prompt session.    *
  12. *       SysCurPos           -- Set and/or Query the cursor position   *
  13. *                              in an OS/2 fullscreen or windowed      *
  14. *                              command prompt session.                *
  15. *       SysCurState         -- Make the cursor visible or invisible   *
  16. *                              in an OS/2 fullscreen or windowed      *
  17. *                              command prompt session.                *
  18. *       SysDriveInfo        -- Returns information about a specific   *
  19. *                              drive.                                 *
  20. *       SysDriveMap         -- Returns a list of the drives on the    *
  21. *                              machine                                *
  22. *       SysDropFuncs        -- Makes all functions in this package    *
  23. *                              unknown to REXX.                       *
  24. *       SysFileDelete       -- Deletes a file                         *
  25. *       SysFileSearch       -- Searches for a file matching a given   *
  26. *                              filespec.                              *
  27. *       SysFileTree         -- Searches for files matching a given    *
  28. *                              filespec, including files in           *
  29. *                              subdirectories.                        *
  30. *       SysGetMessage       -- Retrieves a message text from an OS/2  *
  31. *                              message file, substituting values      *
  32. *                              provided.                              *
  33. *       SysIni              -- Reads and/or updates entries in .INI   *
  34. *                              files.                                 *
  35. *       SysLoadFuncs        -- Makes all functions in this package    *
  36. *                              known to REXX so REXX programs may     *
  37. *                              call them.                             *
  38. *       SysMkDir            -- Creates a directory                    *
  39. *       SysOS2Ver           -- Returns the OS/2 Version number        *
  40. *       SysRmDir            -- Removes a directory                    *
  41. *       SysSearchPath       -- Searches throught a specified path     *
  42. *                              for a file.                            *
  43. *       SysSleep            -- Suspends execution for a number of     *
  44. *                              seconds.                               *
  45. *       SysTempFileName     -- Creates a unique filename              *
  46. *       SysTextScreenRead   -- Reads characters from the screen,      *
  47. *                              in an OS/2 fullscreen or windowed      *
  48. *                              command prompt session.                *
  49. *       SysTextScreenSize   -- Returns the size of the window in      *
  50. *                              rows and columns,                      *
  51. *                              in an OS/2 fullscreen or windowed      *
  52. *                              command prompt session.                *
  53. *       SysGetEA            -- Reads an extended attribute            *
  54. *                              for a file.                            *
  55. *       SysPutEA            -- Writes an extended attribute           *
  56. *                              for a file.                            *
  57. *       SysWaitNamedPipe    -- Wait on a named pipe.                  *
  58. *       SysMakeNamedPipe    -- Create a named pipe.                   *
  59. *       SysConnectNamedPipe -- Prepare a named pipe for connection.   *
  60. *       SysDisConnectNamedPipe -- Release a pipe connection.          *
  61. *                                                                     *
  62. *   To compile:    MAKE REXXUTIL                                      *
  63. *                                                                     *
  64. **********************************************************************/
  65. /* Include files */
  66.  
  67. #define  INCL_WINSHELLDATA
  68. #define  INCL_VIO
  69. #define  INCL_DOS
  70. #define  INCL_DOSFILEMGR
  71. #define  INCL_DOSMEMMGR
  72. #define  INCL_DOSMISC
  73. #define  INCL_DOSNMPIPES
  74. #define  INCL_ERRORS
  75. #define  INCL_REXXSAA
  76. #include <os2.h>
  77. #include <rexxsaa.h>
  78. #include <memory.h>
  79. #include <malloc.h>
  80. #include <fcntl.h>
  81. #include <ctype.h>
  82. #include <string.h>
  83. #include <stdlib.h>
  84. #include <stdio.h>
  85. #include <conio.h>
  86.  
  87.  
  88. /*********************************************************************/
  89. /*  Declare all exported functions as REXX functions.                */
  90. /*********************************************************************/
  91. RexxFunctionHandler SysCls;
  92. RexxFunctionHandler SysCurPos;
  93. RexxFunctionHandler SysCurState;
  94. RexxFunctionHandler SysDriveInfo;
  95. RexxFunctionHandler SysDriveMap;
  96. RexxFunctionHandler SysDropFuncs;
  97. RexxFunctionHandler SysFileDelete;
  98. RexxFunctionHandler SysFileSearch;
  99. RexxFunctionHandler SysFileTree;
  100. RexxFunctionHandler SysGetMessage;
  101. RexxFunctionHandler SysIni;
  102. RexxFunctionHandler SysLoadFuncs;
  103. RexxFunctionHandler SysMkDir;
  104. RexxFunctionHandler SysOS2Ver;
  105. RexxFunctionHandler SysRmDir;
  106. RexxFunctionHandler SysSearchPath;
  107. RexxFunctionHandler SysSleep;
  108. RexxFunctionHandler SysTempFileName;
  109. RexxFunctionHandler SysTextScreenRead;
  110. RexxFunctionHandler SysTextScreenSize;
  111. RexxFunctionHandler SysGetEA;
  112. RexxFunctionHandler SysPutEA;
  113. RexxFunctionHandler SysWaitNamedPipe;
  114.  
  115.  
  116. /*********************************************************************/
  117. /*  Various definitions used by various functions.                   */
  118. /*********************************************************************/
  119.  
  120. #define  MAX_DIGITS     9          /* maximum digits in numeric arg  */
  121. #define  MAX            256        /* temporary buffer length        */
  122. #define  IBUF_LEN       4096       /* Input buffer length            */
  123. #define  AllocFlag      PAG_COMMIT | PAG_WRITE  /* for DosAllocMem   */
  124.  
  125. /*********************************************************************/
  126. /*  Defines used by SysDriveMap                                      */
  127. /*********************************************************************/
  128.  
  129. #define  USED           0
  130. #define  FREE           1
  131. #define  DETACHED       2
  132. #define  REMOTE         3
  133. #define  LOCAL          4
  134.  
  135. /*********************************************************************/
  136. /* Defines uses by SysTree                                           */
  137. /*********************************************************************/
  138.  
  139. #define  FIRST_TIME     0x0001
  140. #define  RECURSE        0x0002
  141. #define  DO_DIRS        0x0004
  142. #define  DO_FILES       0x0008
  143. #define  NAME_ONLY      0x0010
  144. #define  EDITABLE_TIME  0x0020
  145. #define  IGNORE         2              /* Ignore attributes entirely */
  146. #define  AllAtts        FILE_NORMAL | FILE_READONLY | FILE_HIDDEN | \
  147. FILE_SYSTEM | FILE_DIRECTORY | FILE_ARCHIVED
  148.  
  149. /*********************************************************************/
  150. /* Structures used throughout REXXUTIL.C                              */
  151. /*********************************************************************/
  152.  
  153. /*********************************************************************/
  154. /* RxTree Structure used by SysTree.                                 */
  155. /*********************************************************************/
  156.  
  157. typedef struct RxTreeData {
  158.     ULONG count;                       /* Number of lines processed  */
  159.  
  160.     SHVBLOCK shvb;                     /* Request block for RxVar    */
  161.     ULONG open_action;                 /* Action taken opening the   */
  162.                                        /* file                       */
  163.     ULONG stemlen;                     /* Length of stem             */
  164.     ULONG vlen;                        /* Length of variable value   */
  165.     CHAR TargetSpec[MAX];              /* Filespec RxTree is looking */
  166.                                        /* for                        */
  167.     CHAR truefile[MAX];                /* Used to hold actual file   */
  168.                                        /* name                       */
  169.     CHAR tempfile[MAX];                /* Used to hold temp file name*/
  170.     CHAR Temp[MAX];                    /* Used when building stem    */
  171.                                        /* element                    */
  172.     CHAR ibuf[IBUF_LEN];               /* Input buffer               */
  173.     CHAR varname[MAX];                 /* Buffer for the variable    */
  174.                                        /* name                       */
  175.     ULONG j;                           /* Temp counter               */
  176.     ULONG nattrib;                     /* New attrib, diff for each  */
  177.                                        /* file                       */
  178. } RXTREEDATA;
  179.  
  180. /*********************************************************************/
  181. /* RxStemData                                                        */
  182. /*   Structure which describes as generic                            */
  183. /*   stem variable.                                                  */
  184. /*********************************************************************/
  185.  
  186. typedef struct RxStemData {
  187.     SHVBLOCK shvb;                     /* Request block for RxVar    */
  188.     CHAR ibuf[IBUF_LEN];               /* Input buffer               */
  189.     CHAR varname[MAX];                 /* Buffer for the variable    */
  190.                                        /* name                       */
  191.     CHAR stemname[MAX];                /* Buffer for the variable    */
  192.                                        /* name                       */
  193.     ULONG stemlen;                     /* Length of stem.            */
  194.     ULONG vlen;                        /* Length of variable value   */
  195.     ULONG j;                           /* Temp counter               */
  196.     ULONG tlong;                       /* Temp counter               */
  197.     ULONG count;                       /* Number of elements         */
  198.                                        /* processed                  */
  199. } RXSTEMDATA;
  200.  
  201. /*********************************************************************/
  202. /* RxFncTable                                                        */
  203. /*   Array of names of the REXXUTIL functions.                       */
  204. /*   This list is used for registration and deregistration.          */
  205. /*********************************************************************/
  206.  
  207. static PSZ  RxFncTable[] =
  208.    {
  209.       "SysCls",
  210.       "SysCurpos",
  211.       "SysCurState",
  212.       "SysDriveInfo",
  213.       "SysDriveMap",
  214.       "SysDropFuncs",
  215.       "SysFileDelete",
  216.       "SysFileSearch",
  217.       "SysFileTree",
  218.       "SysGetEA",
  219.       "SysGetMessage",
  220.       "SysIni",
  221.       "SysLoadFuncs",
  222.       "SysMkDir",
  223.       "SysOS2Ver",
  224.       "SysRmDir",
  225.       "SysSearchPath",
  226.       "SysSleep",
  227.       "SysTempFileName",
  228.       "SysTextScreenRead",
  229.       "SysTextScreenSize",
  230.       "SysGetEA",
  231.       "SysPutEA",
  232.       "SysWaitNamedPipe",
  233.    };
  234.  
  235. /*********************************************************************/
  236. /* Numeric Error Return Strings                                      */
  237. /*********************************************************************/
  238.  
  239. #define  NO_UTIL_ERROR    "0"          /* No error whatsoever        */
  240. #define  ERROR_NOMEM      "2"          /* Insufficient memory        */
  241. #define  ERROR_FILEOPEN   "3"          /* Error opening text file    */
  242.  
  243. /*********************************************************************/
  244. /* Alpha Numeric Return Strings                                      */
  245. /*********************************************************************/
  246.  
  247. #define  ERROR_RETSTR   "ERROR:"
  248.  
  249. /*********************************************************************/
  250. /* Numeric Return calls                                              */
  251. /*********************************************************************/
  252.  
  253. #define  INVALID_ROUTINE 40            /* Raise Rexx error           */
  254. #define  VALID_ROUTINE    0            /* Successful completion      */
  255.  
  256. /*********************************************************************/
  257. /* Some useful macros                                                */
  258. /*********************************************************************/
  259.  
  260. #define BUILDRXSTRING(t, s) { \
  261.   strcpy((t)->strptr,(s));\
  262.   (t)->strlength = strlen((s)); \
  263. }
  264.  
  265.  
  266. /*********************************************************************/
  267. /****************  REXXUTIL Supporting Functions  ********************/
  268. /****************  REXXUTIL Supporting Functions  ********************/
  269. /****************  REXXUTIL Supporting Functions  ********************/
  270. /*********************************************************************/
  271.  
  272. /********************************************************************
  273. * Function:  SetFileMode(file, attributes)                          *
  274. *                                                                   *
  275. * Purpose:   Change file attribute bits                             *
  276. *            without PM.                                            *
  277. *                                                                   *
  278. * RC:        0    -  File attributes successfully changed           *
  279. *            1    -  Unable to change attributes                    *
  280. *********************************************************************/
  281. INT  SetFileMode(
  282.   PSZ      file,                       /* file name                  */
  283.   ULONG    attr )                      /* new file attributes        */
  284. {
  285.  
  286.   FILESTATUS3   status;                /* status information         */
  287.   INT           rc;                    /* function return code       */
  288.  
  289.                                        /* get the file status        */
  290.   rc = DosQueryPathInfo(file, FIL_STANDARD, (PSZ)&status,
  291.       sizeof(status));
  292.   if (!rc) {                           /* worked?                    */
  293.     status.attrFile = (USHORT)attr;    /* set new attributes         */
  294.                                        /* set the file info          */
  295.     rc = DosSetPathInfo(file, FIL_STANDARD, (PVOID)&status,
  296.          sizeof(FILESTATUS3), 0);
  297.   }
  298.   return rc;                           /* give back success flag     */
  299. }
  300.  
  301. /********************************************************************
  302. * Function:  string2long(string, number)                            *
  303. *                                                                   *
  304. * Purpose:   Validates and converts an ASCII-Z string from string   *
  305. *            form to an unsigned long.  Returns FALSE if the number *
  306. *            is not valid, TRUE if the number was successfully      *
  307. *            converted.                                             *
  308. *                                                                   *
  309. * RC:        TRUE - Good number converted                           *
  310. *            FALSE - Invalid number supplied.                       *
  311. *********************************************************************/
  312.  
  313. BOOL string2long(PSZ string, LONG *number)
  314. {
  315.   ULONG    accumulator;                /* converted number           */
  316.   INT      length;                     /* length of number           */
  317.   INT      sign;                       /* sign of number             */
  318.  
  319.   sign = 1;                            /* set default sign           */
  320.   if (*string == '-') {                /* negative?                  */
  321.     sign = -1;                         /* change sign                */
  322.     string++;                          /* step past sign             */
  323.   }
  324.  
  325.   length = strlen(string);             /* get length of string       */
  326.   if (length == 0 ||                   /* if null string             */
  327.       length > MAX_DIGITS)             /* or too long                */
  328.     return FALSE;                      /* not valid                  */
  329.  
  330.   accumulator = 0;                     /* start with zero            */
  331.  
  332.   while (length) {                     /* while more digits          */
  333.     if (!isdigit(*string))             /* not a digit?               */
  334.       return FALSE;                    /* tell caller                */
  335.                                        /* add to accumulator         */
  336.     accumulator = accumulator *10 + (*string - '0');
  337.     length--;                          /* reduce length              */
  338.     string++;                          /* step pointer               */
  339.   }
  340.   *number = accumulator * sign;        /* return the value           */
  341.   return TRUE;                         /* good number                */
  342. }
  343.  
  344. /********************************************************************
  345. * Function:  mystrstr(haystack, needle, hlen, nlen, sensitive)      *
  346. *                                                                   *
  347. * Purpose:   Determines if the string 'needle' is in the            *
  348. *            string 'haystack' by returning it's position or        *
  349. *            a NULL if not found.  The length of haystack and       *
  350. *            needle are given by 'hlen' and 'nlen' respectively.    *
  351. *                                                                   *
  352. *            If 'sensitive' is true, then the search is case        *
  353. *            sensitive, else it is case insensitive.                *
  354. *                                                                   *
  355. * RC:        num  - The pos where needle was found.                 *
  356. *            NULL - needle not found.                               *
  357. *                                                                   *
  358. * Used By:   SysFileSearch()                                        *
  359. *********************************************************************/
  360.  
  361. ULONG mystrstr(CHAR *haystack,CHAR *needle,ULONG hlen,ULONG nlen,
  362.                 BOOL sensitive)
  363.  
  364. {
  365.   CHAR line[MAX];
  366.   CHAR target[MAX];
  367.   ULONG p;
  368.  
  369.  /* Copy line  - Change nulls to spaces and uppercase if needed      */
  370.  
  371.   for (p = 0; p < hlen; p++) {
  372.  
  373.     if (haystack[p] == '\0')
  374.       line[p] = ' ';
  375.     else if (sensitive)
  376.       line[p] = haystack[p];
  377.     else line[p] = (CHAR)toupper(haystack[p]);
  378.   }
  379.   line[p] = '\0';
  380.  
  381.  /* Copy target  - Change nulls to spaces and uppercase if needed    */
  382.  
  383.   for (p = 0; p < nlen; p++) {
  384.  
  385.     if (needle[p] == '\0')
  386.       target[p] = ' ';
  387.     else if (sensitive)
  388.       target[p] = needle[p];
  389.     else target[p] = (CHAR)toupper(needle[p]);
  390.   }
  391.   target[p] = '\0';
  392.  
  393.   return ((ULONG)strstr(line, target));
  394. }
  395.  
  396.  
  397. /*****************************************************************
  398. * Function:  getpath(string, path, filename)                     *
  399. *                                                                *
  400. * Purpose:  This function gets the PATH and FILENAME of the file *
  401. *           target contained in STRING.  The path will end with  *
  402. *           the '\' char if a path is supplied.                  *
  403. *                                                                *
  404. * Used By:  RecursiveFindFile()                                  *
  405. ****************************************************************     */
  406.  
  407. VOID getpath(CHAR *string,CHAR *path,CHAR *filename)
  408. {
  409.   int len;
  410.   int LastSlashPos;
  411.  
  412.   len = strlen(string);                /* Get length of full file    */
  413.                                        /* spec                       */
  414.   LastSlashPos = len;                  /* Get max pos of last '\'    */
  415.  
  416.     /* Step back through string until at begin or at '\' char        */
  417.  
  418.   while (string[LastSlashPos] != '\\' && LastSlashPos >= 0)
  419.     --LastSlashPos;
  420.  
  421.     /* Copy filespec up to and including last '\' to path            */
  422.   memcpy(path, string, LastSlashPos+1);
  423.   path[LastSlashPos+1] = '\0';
  424.  
  425.     /* Get file name from filespec (just after last '\')             */
  426.   strcpy(filename, &string[LastSlashPos+1]);
  427.  
  428. }
  429.  
  430.  
  431. /*********************************************************************/
  432. /* Function: ULONG SameAttr(mask, attr)                              */
  433. /*                                                                   */
  434. /* Purpose:  Returns the value TRUE if the attribute is identical to */
  435. /*           that specified by the mask.  If not the same, then      */
  436. /*           returns the value FALSE.                                */
  437. /*                                                                   */
  438. /* Used By:  RecursiveFindFile()                                     */
  439. /*********************************************************************/
  440.  
  441. ULONG SameAttr(INT *mask,ULONG attr)
  442. {
  443.  
  444.   if (mask[0] == IGNORE)
  445.     return  TRUE;
  446.  
  447.   if (mask[0] < 0 && attr&FILE_ARCHIVED)
  448.     return  FALSE;
  449.  
  450.   if (mask[0] > 0 && !(attr&FILE_ARCHIVED))
  451.     return  FALSE;
  452.  
  453.   if (mask[1] < 0 && attr&FILE_DIRECTORY)
  454.     return  FALSE;
  455.  
  456.   if (mask[1] > 0 && !(attr&FILE_DIRECTORY))
  457.     return  FALSE;
  458.  
  459.   if (mask[2] < 0 && attr&FILE_HIDDEN)
  460.     return  FALSE;
  461.  
  462.   if (mask[2] > 0 && !(attr&FILE_HIDDEN))
  463.     return  FALSE;
  464.  
  465.   if (mask[3] < 0 && attr&FILE_READONLY)
  466.     return  FALSE;
  467.  
  468.   if (mask[3] > 0 && !(attr&FILE_READONLY))
  469.     return  FALSE;
  470.  
  471.   if (mask[4] < 0 && attr&FILE_SYSTEM)
  472.     return  FALSE;
  473.  
  474.   if (mask[4] > 0 && !(attr&FILE_SYSTEM))
  475.     return  FALSE;
  476.   return  TRUE;
  477. }
  478.  
  479.  
  480. /*********************************************************************/
  481. /* Function: ULONG NewAttr(mask, attr)                              */
  482. /*                                                                   */
  483. /* Purpose:  Returns the new file attribute, given the mask of       */
  484. /*           attributes to be cleared/set and the current attribute  */
  485. /*           settings.                                               */
  486. /*                                                                   */
  487. /* Used By:  RecursiveFindFile()                                     */
  488. /*********************************************************************/
  489.  
  490. ULONG NewAttr(INT *mask,ULONG attr)
  491. {
  492.  
  493.   if (mask[0] == IGNORE)
  494.     return  attr;
  495.  
  496.   if (mask[0] < 0)
  497.     attr &= ~FILE_ARCHIVED;            /* Clear                      */
  498.  
  499.   if (mask[0] > 0)
  500.     attr |= FILE_ARCHIVED;             /* Set                        */
  501.  
  502.   if (mask[1] < 0)
  503.     attr &= ~FILE_DIRECTORY;           /* Clear                      */
  504.  
  505.   if (mask[1] > 0)
  506.     attr |= FILE_DIRECTORY;            /* Set                        */
  507.  
  508.   if (mask[2] < 0)
  509.     attr &= ~FILE_HIDDEN;              /* Clear                      */
  510.  
  511.   if (mask[2] > 0)
  512.     attr |= FILE_HIDDEN;               /* Set                        */
  513.  
  514.   if (mask[3] < 0)
  515.     attr &= ~FILE_READONLY;            /* Clear                      */
  516.  
  517.   if (mask[3] > 0)
  518.     attr |= FILE_READONLY;             /* Set                        */
  519.  
  520.   if (mask[4] < 0)
  521.     attr &= ~FILE_SYSTEM;              /* Clear                      */
  522.  
  523.   if (mask[4] > 0)
  524.     attr |= FILE_SYSTEM;               /* Set                        */
  525.   return  attr;
  526. }
  527.  
  528.  
  529. /*****************************************************************************
  530. * Function: RecursiveFindFile( FileSpec, lpd, smask, dmask, options )        *
  531. *                                                                            *
  532. * Purpose:  Finds all files starting with FileSpec, and will look down the   *
  533. *           directory tree if required.                                      *
  534. *                                                                            *
  535. * Params:   FileSpec - ASCIIZ string which designates filespec to search     *
  536. *                       for.                                                 *
  537. *                                                                            *
  538. *           ldp      - Pointer to local data structure.                      *
  539. *                                                                            *
  540. *           smask    - Array of integers which describe the source attribute *
  541. *                       mask.  Only files with attributes matching this mask *
  542. *                       will be found.                                       *
  543. *                                                                            *
  544. *           dmask    - Array of integers which describe the target attribute *
  545. *                       mask.  Attributes of all found files will be set     *
  546. *                       using this mask.                                     *
  547. *                                                                            *
  548. *             Note:  Both source and targets mask are really arrays of       *
  549. *                    integers.  Each index of the mask corresponds           *
  550. *                    to a different file attribute.  Each indexe and         *
  551. *                    its associated attribute follows:                       *
  552. *                                                                            *
  553. *                         mask[0] = FILE_ARCHIVED                            *
  554. *                         mask[1] = FILE_DIRECTORY                           *
  555. *                         mask[2] = FILE_HIDDEN                              *
  556. *                         mask[3] = FILE_READONLY                            *
  557. *                         mask[4] = FILE_SYSTEM                              *
  558. *                                                                            *
  559. *                    A negative value at a given index indicates that        *
  560. *                    the attribute bit of the file is not set.  A positive   *
  561. *                    number indicates that the attribute should be set.      *
  562. *                    A value of 0 indicates a "Don't Care" setting.          *
  563. *                                                                            *
  564. *           options  - The search/output options.  The following options     *
  565. *                       may be ORed together when calling this function:     *
  566. *                                                                            *
  567. *                    FIRST_TIME  - Indicates this is initial call.  This     *
  568. *                                   should always be used.                   *
  569. *                    RECURSE     - Indicates that function should search     *
  570. *                                   all child subdirectories recursively.    *
  571. *                    DO_DIRS     - Indicates that directories should be      *
  572. *                                   included in the search.                  *
  573. *                    DO_FILES    - Indicates that files should be included   *
  574. *                                   in the search.                           *
  575. *                    NAME_ONLY   - Indicates that the output should be       *
  576. *                                   restricted to filespecs only.            *
  577. *                    EDITABLE_TIME - Indicates time and date fields should   *
  578. *                                   be output as one timestamp.              *
  579. *                                                                            *
  580. * Used By:  SysFileTree()                                                    *
  581. *****************************************************************************/
  582.  
  583. LONG RecursiveFindFile(FileSpec,ldp,smask,dmask,options)
  584.   CHAR       *FileSpec;                /* Filespecs to search for    */
  585.   RXTREEDATA *ldp;                     /* Pointer to local data      */
  586.   INT        *smask;                   /* Mask of attributes to      */
  587.                                        /* search for                 */
  588.   INT        *dmask;                   /* Mask of attributes to set  */
  589.   ULONG       options;                 /* Search and output format   */
  590.                                        /* options                    */
  591. {
  592.   FILEFINDBUF3 finfo;                  /* OS2 File Find Utility      */
  593.                                        /* Structure                  */
  594.   ULONG SearchCount = 1;               /* Num things searching for   */
  595.                                        /* per DosFindFirst           */
  596.   HDIR    DirHandle = 0xFFFF;          /* Directory handle used by   */
  597.                                        /* DosFindFirst()             */
  598.   CHAR    path[MAX];                   /* Path to target file(s)     */
  599.   CHAR    filename[MAX];               /* Current file name          */
  600.   BOOL    IsaDotdir = FALSE;           /* Boolean for determining if */
  601.                                        /* file is ./..               */
  602.   BOOL    IsaSubdir = FALSE;           /* Boolean for determining if */
  603.                                        /* file is a dir              */
  604.  
  605.   /********************************************************************
  606.   * Search Strategy Explained:                                        *
  607.   *                                                                   *
  608.   * Get path and filespec to be searched.                             *
  609.   *                                                                   *
  610.   * If this is the initial call (see FIRST_TIME) and                  *
  611.   * searching recursively, make sure to look for the                  *
  612.   * original filespec in the initial directory.                       *
  613.   *                                                                   *
  614.   * From then on, look for a filespec of *.* to expand                *
  615.   * the subdirectories.  Once a subdirectory is expanded,             *
  616.   * search for the initial filespec again.                            *
  617.   ********************************************************************/
  618.  
  619.   getpath(FileSpec, path, filename);
  620.  
  621.   /********************************************************************
  622.   * Initial Recursive case:                                           *
  623.   *                                                                   *
  624.   * This section of code recurses to call itself in the               *
  625.   * non-recursive form.  It will allow the function to                *
  626.   * gather all the files in the initial subdirectory.                 *
  627.   *                                                                   *
  628.   * It also saves the initial filespec to be searched                 *
  629.   * for in all directories which will be expanded (see                *
  630.   * ldp->TargetSpec).  From then on, the recursive case               *
  631.   * will search for directories by examining all files                *
  632.   * matching the spec *.*.                                            *
  633.   ********************************************************************/
  634.  
  635.                                        /* Onye executed first time   */
  636.   if ((options&FIRST_TIME) && (options&RECURSE)) {
  637.     if (RecursiveFindFile(FileSpec, ldp, smask, dmask,
  638.         options&~RECURSE&~FIRST_TIME))
  639.       return INVALID_ROUTINE;
  640.     strcpy(ldp->TargetSpec, filename);
  641.     strcpy(filename, "*.*");
  642.     sprintf(FileSpec, "%s*.*", path);
  643.     options &= ~FIRST_TIME;
  644.   }
  645.  
  646.   /********************************************************************
  647.   * Non-Recursive case:                                               *
  648.   *                                                                   *
  649.   * This section of code finds all files matching the                 *
  650.   * filespec (filtering out . and ..) and stores them                 *
  651.   * in stem elements if they meet the appropriate file                *
  652.   * attribute requirements.  Each found file's attributes             *
  653.   * are set as required if needed.                                    *
  654.   ********************************************************************/
  655.  
  656.   if (!(options&RECURSE)) {
  657.  
  658.     if (!DosFindFirst((PSZ)FileSpec, (PHDIR)&DirHandle, (ULONG)
  659.         AllAtts, (PVOID)&finfo, (ULONG)sizeof(finfo), (PULONG)
  660.         &SearchCount, FIL_STANDARD)) {
  661.  
  662.       IsaSubdir = (BOOL)(finfo.attrFile&FILE_DIRECTORY);
  663.       IsaDotdir = (BOOL)(!strcmp(finfo.achName, ".") ||
  664.           !strcmp(finfo.achName, ".."));
  665.  
  666.       if (!IsaDotdir && SameAttr(smask, finfo.attrFile) &&
  667.           ((IsaSubdir && (options&DO_DIRS)) ||
  668.           (!IsaSubdir && (options&DO_FILES)))) {
  669.         sprintf(ldp->tempfile, "%s%s", path, finfo.achName);
  670.                                        /* Get full path              */
  671.         DosQueryPathInfo(ldp->tempfile, 5, ldp->truefile,
  672.             sizeof(ldp->truefile));
  673.  
  674.         if (options&NAME_ONLY)
  675.           strcpy(ldp->Temp, ldp->truefile);
  676.         else {
  677.           if (options&EDITABLE_TIME)
  678.             sprintf(ldp->Temp, "%02d/%02d/%02d/%02d/%02d  %10lu  ",
  679.                 (finfo.fdateLastWrite.year+80)%100,
  680.                 finfo.fdateLastWrite.month,
  681.                 finfo.fdateLastWrite.day,
  682.                 finfo.ftimeLastWrite.hours,
  683.                 finfo.ftimeLastWrite.minutes,
  684.                 finfo.cbFile);
  685.           else
  686.             sprintf(ldp->Temp, "%2d/%02d/%02d  %2d:%02d%c  %10lu  ",
  687.                 finfo.fdateLastWrite.month,
  688.                 finfo.fdateLastWrite.day,
  689.                 (finfo.fdateLastWrite.year+80)%100,
  690.                 (finfo.ftimeLastWrite.hours < 13?
  691.                 finfo.ftimeLastWrite.hours:
  692.                 (finfo.ftimeLastWrite.hours-(SHORT)12)),
  693.                 finfo.ftimeLastWrite.minutes,
  694.                 ((finfo.ftimeLastWrite.hours < 12 ||
  695.                 finfo.ftimeLastWrite.hours == 24)?'a':'p'),
  696.                 finfo.cbFile);
  697.           ldp->nattrib = NewAttr((INT *)dmask, finfo.attrFile);
  698.  
  699.           if (ldp->nattrib != finfo.attrFile) {
  700.             sprintf(ldp->tempfile, "%s%s", path, finfo.achName);
  701.  
  702.             if (SetFileMode(ldp->tempfile, (USHORT)(ldp->nattrib&~
  703.                 FILE_DIRECTORY)))      /* Set the new file mode      */
  704.               ldp->nattrib = finfo.attrFile;/* Just in case of       */
  705.                                        /* failure                    */
  706.           }
  707.           sprintf(ldp->Temp, "%s%c%c%c%c%c  %s", ldp->Temp,
  708.               ((ldp->nattrib&FILE_ARCHIVED)?'A':'-'),
  709.               ((ldp->nattrib&FILE_DIRECTORY)?'D':'-'),
  710.               ((ldp->nattrib&FILE_HIDDEN)?'H':'-'),
  711.               ((ldp->nattrib&FILE_READONLY)?'R':'-'),
  712.               ((ldp->nattrib&FILE_SYSTEM)?'S':'-'),
  713.               ldp->truefile);
  714.         }
  715.                                        /* Place new string in Stem   */
  716.         memcpy(ldp->ibuf, ldp->Temp, strlen(ldp->Temp));
  717.         ldp->vlen = strlen(ldp->Temp);
  718.         ldp->count++;
  719.         sprintf(ldp->varname+ldp->stemlen,"%d", ldp->count);
  720.         ldp->shvb.shvnext = NULL;
  721.         ldp->shvb.shvname.strptr = ldp->varname;
  722.         ldp->shvb.shvname.strlength = strlen(ldp->varname);
  723.         ldp->shvb.shvvalue.strptr = ldp->ibuf;
  724.         ldp->shvb.shvvalue.strlength = ldp->vlen;
  725.         ldp->shvb.shvnamelen = ldp->shvb.shvname.strlength;
  726.         ldp->shvb.shvvaluelen = ldp->vlen;
  727.         ldp->shvb.shvcode = RXSHV_SET;
  728.         ldp->shvb.shvret = 0;
  729.         if (RexxVariablePool(&ldp->shvb) == RXSHV_BADN)
  730.           return INVALID_ROUTINE;      /* error on non-zero          */
  731.       }
  732.  
  733.         /* Get the rest of the files ................................*/
  734.  
  735.       while (!DosFindNext((HDIR)DirHandle, (PVOID)&finfo,
  736.           (ULONG)sizeof(finfo), (PULONG)&SearchCount)) {
  737.  
  738.         IsaSubdir = (BOOL)(finfo.attrFile&FILE_DIRECTORY);
  739.         IsaDotdir = (BOOL)(!strcmp(finfo.achName, ".") ||
  740.             !strcmp(finfo.achName, ".."));
  741.  
  742.         if (!IsaDotdir && SameAttr(smask, finfo.attrFile) &&
  743.             ((IsaSubdir && (options&DO_DIRS)) ||
  744.             (!IsaSubdir && (options&DO_FILES)))) {
  745.           sprintf(ldp->tempfile, "%s%s", path, finfo.achName);
  746.                                        /* Get full path              */
  747.           DosQueryPathInfo(ldp->tempfile, 5, ldp->truefile,
  748.               sizeof(ldp->truefile));
  749.  
  750.           if (options&NAME_ONLY)
  751.             strcpy(ldp->Temp, ldp->truefile);
  752.  
  753.           else {
  754.             if (options&EDITABLE_TIME)
  755.               sprintf(ldp->Temp, "%02d/%02d/%02d/%02d/%02d  %10lu  ",
  756.                   (finfo.fdateLastWrite.year+80)%100,
  757.                   finfo.fdateLastWrite.month,
  758.                   finfo.fdateLastWrite.day,
  759.                   finfo.ftimeLastWrite.hours,
  760.                   finfo.ftimeLastWrite.minutes, finfo.cbFile);
  761.             else
  762.               sprintf(ldp->Temp,
  763.                   "%2d/%02d/%02d  %2d:%02d%c  %10lu  ",
  764.                   finfo.fdateLastWrite.month,
  765.                   finfo.fdateLastWrite.day,
  766.                   (finfo.fdateLastWrite.year+80)%100,
  767.                   (finfo.ftimeLastWrite.hours < 13?
  768.                   finfo.ftimeLastWrite.hours:
  769.                   (finfo.ftimeLastWrite.hours - (SHORT)12)),
  770.                   finfo.ftimeLastWrite.minutes,
  771.                   ((finfo.ftimeLastWrite.hours < 12 ||
  772.                   finfo.ftimeLastWrite.hours == 24)?'a':'p'),
  773.                   finfo.cbFile);
  774.             ldp->nattrib = NewAttr((INT *)dmask, finfo.attrFile);
  775.  
  776.             if (ldp->nattrib != finfo.attrFile) {
  777.               sprintf(ldp->tempfile, "%s%s", path, finfo.achName);
  778.  
  779.               if (SetFileMode(ldp->tempfile, (USHORT)(ldp->nattrib&~
  780.                   FILE_DIRECTORY)))    /* Set the new file mode      */
  781.                 ldp->nattrib = finfo.attrFile;/* Just in case of     */
  782.                                        /* failure                    */
  783.             }
  784.             sprintf(ldp->Temp, "%s%c%c%c%c%c  %s", ldp->Temp,
  785.                 ((ldp->nattrib&FILE_ARCHIVED)?'A':'-'),
  786.                 ((ldp->nattrib&FILE_DIRECTORY)?'D':'-'),
  787.                 ((ldp->nattrib&FILE_HIDDEN)?'H':'-'),
  788.                 ((ldp->nattrib&FILE_READONLY)?'R':'-'),
  789.                 ((ldp->nattrib&FILE_SYSTEM)?'S':'-'),
  790.                 ldp->truefile);
  791.           }
  792.                                        /* Place new string in Stem   */
  793.           memcpy(ldp->ibuf, ldp->Temp, strlen(ldp->Temp));
  794.           ldp->vlen = strlen(ldp->Temp);
  795.           ldp->count++;
  796.           sprintf(ldp->varname+ldp->stemlen, "%d", ldp->count);
  797.           ldp->shvb.shvnext = NULL;
  798.           ldp->shvb.shvname.strptr = ldp->varname;
  799.           ldp->shvb.shvname.strlength = strlen(ldp->varname);
  800.           ldp->shvb.shvvalue.strptr = ldp->ibuf;
  801.           ldp->shvb.shvvalue.strlength = ldp->vlen;
  802.           ldp->shvb.shvnamelen = ldp->shvb.shvname.strlength;
  803.           ldp->shvb.shvvaluelen = ldp->vlen;
  804.           ldp->shvb.shvcode = RXSHV_SET;
  805.           ldp->shvb.shvret = 0;
  806.           if (RexxVariablePool(&ldp->shvb) == RXSHV_BADN)
  807.             return INVALID_ROUTINE;    /* error on non-zero          */
  808.  
  809.         }
  810.       }
  811.     }
  812.     DosFindClose(DirHandle);
  813.   }
  814.  
  815.   /********************************************************
  816.   * Recursive case:                                       *
  817.   *                                                       *
  818.   * This section of code searches for directories given   *
  819.   * the current FileSpec.  When one is found, the         *
  820.   * function is called in the non-recursive mode to find  *
  821.   * all files matching the initial filespec.  It is also  *
  822.   * called in the recursive mode to expand all subdirect- *
  823.   * ories under the new found directory.                  *
  824.   *********************************************************/
  825.  
  826.   else {
  827.  
  828.     if (!DosFindFirst((PSZ)FileSpec, (PHDIR)&DirHandle,
  829.         (ULONG)AllAtts, (PVOID)&finfo, (ULONG)sizeof(finfo),
  830.         (PULONG)&SearchCount, FIL_STANDARD)) {
  831.  
  832.       IsaSubdir = (BOOL)(finfo.attrFile&FILE_DIRECTORY);
  833.       IsaDotdir = (BOOL)(!strcmp(finfo.achName, ".") ||
  834.           !strcmp(finfo.achName, ".."));
  835.  
  836.       if (!IsaDotdir && IsaSubdir) {
  837.         sprintf(ldp->tempfile, "%s%s\\%s", path, finfo.achName,
  838.             ldp->TargetSpec);
  839.         if (RecursiveFindFile(ldp->tempfile, ldp, smask, dmask,
  840.             options&~RECURSE))
  841.           return INVALID_ROUTINE;
  842.         sprintf(ldp->tempfile, "%s%s\\%s", path, finfo.achName,
  843.             filename);
  844.         if (RecursiveFindFile(ldp->tempfile, ldp, smask, dmask, options))
  845.           return INVALID_ROUTINE;
  846.       }
  847.  
  848.         /* Get the rest of the files ................................*/
  849.  
  850.       while (!DosFindNext((HDIR)DirHandle, (PVOID)&finfo,
  851.           (ULONG)sizeof(finfo), (PULONG)&SearchCount)) {
  852.  
  853.         IsaSubdir = (BOOL)(finfo.attrFile&FILE_DIRECTORY);
  854.         IsaDotdir = (BOOL)(!strcmp(finfo.achName, ".") ||
  855.             !strcmp(finfo.achName, ".."));
  856.  
  857.         if (!IsaDotdir && IsaSubdir) {
  858.           sprintf(ldp->tempfile, "%s%s\\%s", path, finfo.achName,
  859.               ldp->TargetSpec);
  860.           if (RecursiveFindFile(ldp->tempfile, ldp, smask, dmask,
  861.               options&~RECURSE))
  862.             return INVALID_ROUTINE;
  863.           sprintf(ldp->tempfile, "%s%s\\%s", path, finfo.achName,
  864.               filename);
  865.           if (RecursiveFindFile(ldp->tempfile, ldp, smask, dmask,
  866.               options))
  867.             return INVALID_ROUTINE;
  868.         }
  869.       }
  870.     }
  871.     DosFindClose(DirHandle);
  872.   }
  873.   return VALID_ROUTINE;
  874. }
  875.  
  876.  
  877. /****************************************************************
  878. * Function: GetUniqueFileName(Template, Filler, file)           *
  879. *                                                               *
  880. * Purpose:  This function returns a unique temporary file name  *
  881. *           given a template and a filler character.            *
  882. *                                                               *
  883. * Params:   CHAR* Template - The template.  Must contain at     *
  884. *                            least one or more filler chars.    *
  885. *                                                               *
  886. *                            Example:  "C:\TEMP\FILE????.DAT    *
  887. *                                                               *
  888. *           CHAR Filler    - The character in the Template to   *
  889. *                            be replaced with numbers.  For     *
  890. *                            the above example, the filler char *
  891. *                            would be '?'.                      *
  892. *           CHAR* file     - file name produced (output)        *
  893. *                                                               *
  894. * Used By:  RxTempFileName()                                    *
  895. ****************************************************************/
  896.  
  897. VOID GetUniqueFileName(CHAR *Template,CHAR Filler,CHAR *file)
  898. {
  899.   CHAR numstr[6];
  900.   BOOL Unique = FALSE;
  901.  
  902.   ULONG rc,                            /* return code for OS/2 call  */
  903.         x,                             /* loop index                 */
  904.         i,                             /*                            */
  905.         j = 0,                         /* number of filler chars     */
  906.                                        /* found                      */
  907.         num,                           /* temporary random number    */
  908.         start,                         /* first random number        */
  909.         max = 1;                       /* maximum random number      */
  910.  
  911.   ULONG SearchCount;                   /* count of files to search   */
  912.                                        /* for.                       */
  913.   HDIR DirHandle;                      /* handle for found file      */
  914.   INT  seed;                           /* to get current time        */
  915.   FILEFINDBUF3 finfo;                  /* OS2 File Find Utility      */
  916.                                        /* Structure                  */
  917.   DATETIME DT;                         /* The date and time structure*/
  918.  
  919.  /** Determine number of filler characters *                         */
  920.  
  921.   for (x = 0; Template[x] != 0; x++)
  922.  
  923.     if (Template[x] == Filler) {
  924.       max = max *10;
  925.       j++;
  926.     }
  927.  
  928.  /** Return NULL string if less than 1 or greater than 4 *           */
  929.  
  930.   if (j == 0 || j > 5) {
  931.     Unique = TRUE;
  932.     strcpy(file, "");
  933.   }
  934.  
  935.  /** Get a random number in the appropriate range                    */
  936.  
  937.   DosGetDateTime((PDATETIME)&DT);      /* Get the time               */
  938.   seed = DT.hours*60 + DT.minutes;     /* convert to hundreths       */
  939.   seed = seed*60 + DT.seconds;
  940.   seed = seed*100 + DT.hundredths;
  941.   srand((INT)seed);                    /* Set random number seed     */
  942.   num = (ULONG)rand()%max;
  943.   start = num;
  944.  
  945.  /** Do until a unique name is found                                 */
  946.  
  947.   while (!Unique) {
  948.  
  949.     /** Generate string which represents the number                  */
  950.  
  951.     switch (j) {
  952.       case 1 :
  953.         sprintf(numstr, "%01u", num);
  954.         break;
  955.       case 2 :
  956.         sprintf(numstr, "%02u", num);
  957.         break;
  958.       case 3 :
  959.         sprintf(numstr, "%03u", num);
  960.         break;
  961.       case 4 :
  962.         sprintf(numstr, "%04u", num);
  963.         break;
  964.       case 5 :
  965.         sprintf(numstr, "%05u", num);
  966.         break;
  967.     }
  968.  
  969.     /** Subsitute filler characters with numeric string              */
  970.  
  971.     i = 0;
  972.  
  973.     for (x = 0; Template[x] != 0; x++)
  974.  
  975.       if (Template[x] == Filler)
  976.         file[x] = numstr[i++];
  977.  
  978.       else
  979.         file[x] = Template[x];
  980.     file[x] = '\0';
  981.  
  982.     /** See if the file exists                                       */
  983.  
  984.     DosError(0);                       /* Disable Hard-Error popups  */
  985.     DirHandle = 0xFFFF;
  986.     SearchCount = 1;
  987.     rc = DosFindFirst(file, &DirHandle, AllAtts, (PVOID)&finfo,
  988.         (ULONG)sizeof(finfo), (PULONG)&SearchCount, FIL_STANDARD);
  989.  
  990.     if (rc == 2 || rc == 18)
  991.       Unique = TRUE;
  992.     DosFindClose(DirHandle);
  993.     DosError(1);                       /* Enable Hard-Error popups   */
  994.  
  995.     /** Make sure we are not wasting our time                        */
  996.  
  997.     num = (num+1)%max;
  998.  
  999.     if (num == start && !Unique) {
  1000.       Unique = TRUE;
  1001.       strcpy(file, "");
  1002.     }
  1003.   }
  1004. }
  1005.  
  1006.  
  1007. /*************************************************************************
  1008. ***             <<<<<< REXXUTIL Functions Follow >>>>>>>               ***
  1009. ***             <<<<<< REXXUTIL Functions Follow >>>>>>>               ***
  1010. ***             <<<<<< REXXUTIL Functions Follow >>>>>>>               ***
  1011. ***             <<<<<< REXXUTIL Functions Follow >>>>>>>               ***
  1012. *************************************************************************/
  1013. /*************************************************************************
  1014. * Function:  SysCls                                                      *
  1015. *                                                                        *
  1016. * Syntax:    call SysCls                                                 *
  1017. *                                                                        *
  1018. * Return:    NO_UTIL_ERROR - Successful.                                 *
  1019. *************************************************************************/
  1020.  
  1021. ULONG SysCls(PUCHAR name, ULONG numargs, RXSTRING args[],
  1022.                     PSZ queuename, RXSTRING *retstr)
  1023. {
  1024.   BYTE bCell[2];                       /* Char/Attribute array       */
  1025.  
  1026.   if (numargs)                         /* arguments specified?       */
  1027.     return INVALID_ROUTINE;            /* raise the error            */
  1028.  
  1029.   bCell[0] = 0x20;                     /* Space Character            */
  1030.   bCell[1] = 0x07;                     /* Default Attrib             */
  1031.   VioScrollDn( 0, 0, (USHORT)0xFFFF, (USHORT)0XFFFF,
  1032.                      (USHORT)0xFFFF, bCell, (HVIO) 0);/* CLS         */
  1033.   VioSetCurPos(0, 0, (HVIO) 0);        /*                Pos cursor  */
  1034.   BUILDRXSTRING(retstr, NO_UTIL_ERROR);/* pass back result           */
  1035.   return VALID_ROUTINE;                /* no error on call           */
  1036. }
  1037.  
  1038. /*************************************************************************
  1039. * Function:  SysCurPos - positions cursor in OS/2 session                *
  1040. *                                                                        *
  1041. * Syntax:    call SysCurPos [row, col]                                   *
  1042. *                                                                        *
  1043. * Params:    row   - row to place cursor on                              *
  1044. *            col   - column to place cursor on                           *
  1045. *                                                                        *
  1046. * Return:    row, col                                                    *
  1047. *************************************************************************/
  1048.  
  1049. ULONG SysCurPos(PUCHAR name, ULONG numargs, RXSTRING args[],
  1050.     PSZ queuename, RXSTRING *retstr)
  1051. {
  1052.   USHORT start_row;                    /* Row at start               */
  1053.   USHORT start_col;                    /* Col at start               */
  1054.   LONG   new_row;                      /* Row to change to           */
  1055.   LONG   new_col;                      /* Col to change to           */
  1056.  
  1057.   BUILDRXSTRING(retstr, NO_UTIL_ERROR);/* set default result         */
  1058.                                        /* check arguments            */
  1059.   if ((numargs != 0 && numargs != 2))  /* wrong number?              */
  1060.     return INVALID_ROUTINE;            /* raise an error             */
  1061.  
  1062.   VioGetCurPos(&start_row, &start_col, (HVIO)0); /* Get position     */
  1063.   sprintf(retstr->strptr, "%d %d", (int)start_row, (int)start_col);
  1064.   retstr->strlength = strlen(retstr->strptr);
  1065.  
  1066.   if (numargs != 0) {                  /* reset position to given    */
  1067.     if (!RXVALIDSTRING(args[0]) ||     /* not real arguments given?  */
  1068.         !RXVALIDSTRING(args[1]))
  1069.       return INVALID_ROUTINE;          /* raise an error             */
  1070.                                        /* convert row to binary      */
  1071.     if (!string2long(args[0].strptr, &new_row) || new_row < 0)
  1072.       return INVALID_ROUTINE;          /* return error               */
  1073.                                        /* convert row to binary      */
  1074.     if (!string2long(args[1].strptr, &new_col) || new_col < 0)
  1075.       return INVALID_ROUTINE;          /* return error               */
  1076.  
  1077.     /* Set the cursor position, using the input values.               */
  1078.     VioSetCurPos((USHORT) new_row, (USHORT) new_col, (HVIO) 0);
  1079.   }
  1080.  
  1081.   return VALID_ROUTINE;                /* no error on call           */
  1082. }
  1083.  
  1084. /*************************************************************************
  1085. * Function:  SysCurState                                                 *
  1086. *                                                                        *
  1087. * Syntax:    call SysCurState state                                      *
  1088. *                                                                        *
  1089. * Params:    state - Either 'ON' or 'OFF'.                               *
  1090. *                                                                        *
  1091. * Return:    NO_UTIL_ERROR - Successful.                                 *
  1092. *************************************************************************/
  1093.  
  1094. ULONG SysCurState(PUCHAR name, ULONG numargs, RXSTRING args[],
  1095.     PSZ queuename, RXSTRING *retstr)
  1096. {
  1097.   USHORT state;                        /* State                      */
  1098.   VIOCURSORINFO vioci;                 /* Cursor info struct         */
  1099.  
  1100.   BUILDRXSTRING(retstr, NO_UTIL_ERROR);/* pass back result           */
  1101.                                        /* validate the arguments     */
  1102.   if (numargs != 1)
  1103.     return INVALID_ROUTINE;
  1104.                                        /* Get state and validate     */
  1105.   if (stricmp(args[0].strptr, "ON") == 0)
  1106.     state = (USHORT) 0;
  1107.   else if (stricmp(args[0].strptr, "OFF") == 0)
  1108.     state = (USHORT) -1;
  1109.   else
  1110.     return INVALID_ROUTINE;            /* Invalid state              */
  1111.  
  1112.   VioGetCurType(&vioci, (HVIO) 0);     /* Get current state          */
  1113.   vioci.attr= state;                   /* Set state info             */
  1114.   VioSetCurType(&vioci, (HVIO) 0);     /* Set new state              */
  1115.   return VALID_ROUTINE;                /* no error on call           */
  1116. }
  1117.  
  1118. /*************************************************************************
  1119. * Function:  SysDriveInfo                                                *
  1120. *                                                                        *
  1121. * Syntax:    call SysDriveInfo drive                                     *
  1122. *                                                                        *
  1123. * Params:    drive - 'C', 'D', 'E', etc.                                 *
  1124. *                                                                        *
  1125. * Return:    disk free total label                                       *
  1126. *************************************************************************/
  1127.  
  1128. ULONG SysDriveInfo(PUCHAR name, ULONG numargs, RXSTRING args[],
  1129.                            PSZ queuename, RXSTRING *retstr)
  1130. {
  1131.   PSZ       arg;                       /* Temp var for holding args  */
  1132.   UCHAR     buf[256];                  /* Give DosQFSInfo 256 bytes  */
  1133.  
  1134.   ULONG     drivenum;                  /* Drive number (A=1, B=2,    */
  1135.                                        /* etc)                       */
  1136.   FSALLOCATE FSInfoBuf;                /* Structure required by      */
  1137.                                        /* DosQfsInfo                 */
  1138.   LONG      rc;                        /* OS/2 return code           */
  1139.  
  1140.                                        /* validate arguments         */
  1141.   if (numargs != 1 ||
  1142.       args[0].strlength > 2 ||
  1143.       args[0].strlength == 0)
  1144.     return INVALID_ROUTINE;
  1145.                                        /* validate the arg           */
  1146.   arg = args[0].strptr;                /* get argument pointer       */
  1147.                                        /* drive letter?              */
  1148.   if ((strlen(arg) == 2 &&
  1149.       arg[1] != ':') ||
  1150.       !isalpha(arg[0]))
  1151.     return INVALID_ROUTINE;
  1152.   else                                 /* yep, convert to a number   */
  1153.     drivenum = toupper(arg[0])-'A'+1;  /* Get the drive number       */
  1154.  
  1155.                                        /* query the disk             */
  1156.   DosError(0);                         /* Disable hard-error pop-up  */
  1157.                                        /* Get the drive info         */
  1158.   rc = DosQueryFSInfo(drivenum, 2, buf, sizeof(buf));
  1159.   DosQueryFSInfo(drivenum, 1, (char *)&FSInfoBuf, sizeof(FSInfoBuf));
  1160.  
  1161.   if (rc == 0 || rc == 125) {
  1162.     sprintf(retstr->strptr,
  1163.             "%c:  %-12lu %-12lu %-13s",
  1164.             (drivenum+'A'-1),
  1165.             FSInfoBuf.cSectorUnit * FSInfoBuf.cbSector *
  1166.             FSInfoBuf.cUnitAvail,
  1167.             FSInfoBuf.cSectorUnit * FSInfoBuf.cbSector *
  1168.             FSInfoBuf.cUnit, &buf[5]);
  1169.                                        /* create return string       */
  1170.     retstr->strlength = strlen(retstr->strptr);
  1171.   }
  1172.   else
  1173.     retstr->strlength = 0;             /* return null string         */
  1174.  
  1175.   DosError(1);                         /* Enable hard-error pop-up   */
  1176.   return VALID_ROUTINE;                /* no error on call           */
  1177.  
  1178. }
  1179.  
  1180. /*************************************************************************
  1181. * Function:  SysDriveMap                                                 *
  1182. *                                                                        *
  1183. * Syntax:    call SysDriveMap [drive] [,mode]                            *
  1184. *                                                                        *
  1185. * Params:    drive - 'C', 'D', 'E', etc.  The drive to start the search  *
  1186. *                     with.                                              *
  1187. *            mode  - Any of the following:  'FREE', 'USED', 'DETACHED',  *
  1188. *                                           'LOCAL', 'REMOTE'            *
  1189. *                                                                        *
  1190. * Return:    'A: B: C: D: ...'                                           *
  1191. *************************************************************************/
  1192.  
  1193. ULONG SysDriveMap(PUCHAR name, ULONG numargs, RXSTRING args[],
  1194.                           PSZ queuename, RXSTRING *retstr)
  1195. {
  1196.   CHAR     temp[MAX];                  /* Entire drive map built here*/
  1197.  
  1198.   CHAR     tmpstr[MAX];                /* Single drive entries built */
  1199.                                        /* here                       */
  1200.   CHAR     buf[256];                   /* Give DosQFSInfo 256 bytes  */
  1201.   CHAR     DeviceName[3];              /* Device name or drive letter*/
  1202.                                        /* string                     */
  1203.   ULONG    CurDrive;                   /* Current drive              */
  1204.   ULONG    DriveMap;                   /* Drive map                  */
  1205.   ULONG    Ordinal;                    /* Ordinal of entry in name   */
  1206.                                        /* list                       */
  1207.   ULONG    FSAInfoLevel;               /* Type of attached FSD data  */
  1208.                                        /* required                   */
  1209.   ULONG    DataBufferLen;              /* Buffer length              */
  1210.   ULONG    dnum;                       /* Disk num variable          */
  1211.   ULONG    start = 3;                  /* Initial disk num           */
  1212.   ULONG    Mode = USED;                /* Query mode USED, FREE,     */
  1213.                                        /* LOCAL, etc                 */
  1214.   FSQBUFFER2 DataBuffer;               /* Returned data buffer       */
  1215.   LONG     rc;                         /* OS/2 return codes          */
  1216.  
  1217.   Ordinal = (ULONG )0;
  1218.   FSAInfoLevel = (ULONG )1;
  1219.  
  1220.   temp[0] = '\0';
  1221.  
  1222.   if (numargs > 2)                     /* validate arguments         */
  1223.     return INVALID_ROUTINE;
  1224.                                        /* check starting drive letter*/
  1225.   if (numargs >= 1 && args[0].strptr) {
  1226.  
  1227.     if ((strlen(args[0].strptr) == 2 &&
  1228.         args[0].strptr[1] != ':') ||
  1229.         strlen(args[0].strptr) > 2 ||
  1230.         strlen(args[0].strptr) == 0 ||
  1231.         !isalpha(args[0].strptr[0]))
  1232.       return INVALID_ROUTINE;
  1233.     start = toupper(args[0].strptr[0])-'A'+1;
  1234.   }
  1235.                                        /* check the mode             */
  1236.   if (numargs == 2 && args[1].strlength != 0) {
  1237.  
  1238.     if (!stricmp(args[1].strptr, "FREE"))
  1239.       Mode = FREE;
  1240.     else if (!stricmp(args[1].strptr, "USED"))
  1241.       Mode = USED;
  1242.     else if (!stricmp(args[1].strptr, "DETACHED"))
  1243.       Mode = DETACHED;
  1244.     else if (!stricmp(args[1].strptr, "REMOTE"))
  1245.       Mode = REMOTE;
  1246.     else if (!stricmp(args[1].strptr, "LOCAL"))
  1247.       Mode = LOCAL;
  1248.     else
  1249.       return INVALID_ROUTINE;
  1250.   }
  1251.                                        /* perform the query          */
  1252.   DosError(0);                         /* Disable Hard-Error Popups  */
  1253.   DosQueryCurrentDisk(&CurDrive, &DriveMap);
  1254.   DriveMap>>=start-1;                  /* Shift to the first drive   */
  1255.   temp[0] = '\0';                      /* Clear temporary buffer     */
  1256.  
  1257.   for (dnum = start; dnum <= 26; dnum++) {
  1258.  
  1259.                                        /* Hey, we have a free drive  */
  1260.     if (!(DriveMap&(ULONG)1) && Mode == FREE) {
  1261.       sprintf(tmpstr, "%c: ", dnum+'A'-1);
  1262.       strcat(temp, tmpstr);
  1263.     }
  1264.                                        /* Hey, we have a used drive  */
  1265.     else if ((DriveMap&(ULONG)1) && Mode == USED) {
  1266.       sprintf(tmpstr, "%c: ", dnum+'A'-1);
  1267.       strcat(temp, tmpstr);
  1268.     }
  1269.  
  1270.     else if (DriveMap&(ULONG)1) {      /* Check specific drive info  */
  1271.       sprintf(DeviceName, "%c:", dnum+'A'-1);
  1272.       DataBufferLen = sizeof DataBuffer;
  1273.       DosQueryFSAttach(DeviceName, Ordinal, FSAInfoLevel,
  1274.           &DataBuffer, &DataBufferLen);
  1275.       rc = DosQueryFSInfo(dnum, 2, buf, sizeof(buf));
  1276.  
  1277.       if (rc == 67 && DataBuffer.iType == 4 && Mode == DETACHED) {
  1278.                                        /* Hey, we have a detached    */
  1279.                                        /* drive                      */
  1280.         sprintf(tmpstr, "%c: ", dnum+'A'-1);
  1281.         strcat(temp, tmpstr);
  1282.       }
  1283.  
  1284.       else if (DataBuffer.iType == 4 && Mode == REMOTE) {
  1285.         sprintf(tmpstr, "%c: ", dnum+'A'-1);
  1286.         strcat(temp, tmpstr);
  1287.       }
  1288.  
  1289.       else if (DataBuffer.iType == 3 && Mode == LOCAL) {
  1290.         sprintf(tmpstr, "%c: ", dnum+'A'-1);
  1291.         strcat(temp, tmpstr);
  1292.       }
  1293.     }
  1294.     DriveMap>>=1;                      /* Shift to the next drive    */
  1295.   }
  1296.  
  1297.   BUILDRXSTRING(retstr, temp);         /* pass back result           */
  1298.   if (retstr->strlength)               /* if not a null string       */
  1299.     retstr->strlength--;               /* Get rid of last space      */
  1300.   DosError(1);                         /* Enable Hard-Error Popups   */
  1301.   return VALID_ROUTINE;                /* no error on call           */
  1302. }
  1303.  
  1304.  
  1305. /*************************************************************************
  1306. * Function:  SysDropFuncs                                                *
  1307. *                                                                        *
  1308. * Syntax:    call SysDropFuncs                                           *
  1309. *                                                                        *
  1310. * Return:    NO_UTIL_ERROR - Successful.                                 *
  1311. *************************************************************************/
  1312.  
  1313. ULONG SysDropFuncs(PUCHAR name, ULONG numargs, RXSTRING args[],
  1314.                           PSZ queuename, RXSTRING *retstr)
  1315. {
  1316.   INT     entries;                     /* Num of entries             */
  1317.   INT     j;                           /* Counter                    */
  1318.  
  1319.   if (numargs != 0)                    /* no arguments for this      */
  1320.     return INVALID_ROUTINE;            /* raise an error             */
  1321.  
  1322.   retstr->strlength = 0;               /* return a null string result*/
  1323.  
  1324.   entries = sizeof(RxFncTable)/sizeof(PSZ);
  1325.  
  1326.   for (j = 0; j < entries; j++)
  1327.     RexxDeregisterFunction(RxFncTable[j]);
  1328.  
  1329.   return VALID_ROUTINE;                /* no error on call           */
  1330. }
  1331.  
  1332. /*************************************************************************
  1333. * Function:  SysFileDelete                                               *
  1334. *                                                                        *
  1335. * Syntax:    call SysFileDelete file                                     *
  1336. *                                                                        *
  1337. * Params:    file - file to be deleted.                                  *
  1338. *                                                                        *
  1339. * Return:    Return code from DosDelete() function.                      *
  1340. *************************************************************************/
  1341.  
  1342. ULONG SysFileDelete(PUCHAR name, ULONG numargs, RXSTRING args[],
  1343.                             PSZ queuename, RXSTRING *retstr)
  1344. {
  1345.   ULONG  rc;                           /* Ret code                   */
  1346.  
  1347.   if (numargs != 1)                    /* we need one argument       */
  1348.     return INVALID_ROUTINE;            /* raise an error             */
  1349.  
  1350.   rc = DosDelete(args[0].strptr);      /* delete the file            */
  1351.                                        /* pass back return code      */
  1352.   sprintf(retstr->strptr, "%d", rc);
  1353.   retstr->strlength = strlen(retstr->strptr);
  1354.  
  1355.   return VALID_ROUTINE;                /* finished                   */
  1356. }
  1357.  
  1358. /*************************************************************************
  1359. * Function:  SysFileSearch                                               *
  1360. *                                                                        *
  1361. * Syntax:    call SysFileSearch target, file, stem [, options]           *
  1362. *                                                                        *
  1363. * Params:    target  - String to search for.                             *
  1364. *            file    - Filespec to search.                               *
  1365. *            stem    - Stem variable name to place results in.           *
  1366. *            options - Any combo of the following:                       *
  1367. *                       'C' - Case sensitive search (non-default).       *
  1368. *                       'N' - Preceed each found string in result stem   *
  1369. *                              with it line number in file (non-default).*
  1370. *                                                                        *
  1371. * Return:    NO_UTIL_ERROR   - Successful.                               *
  1372. *            ERROR_NOMEM     - Out of memory.                            *
  1373. *************************************************************************/
  1374.  
  1375. ULONG SysFileSearch(PUCHAR name, ULONG numargs, RXSTRING args[],
  1376.                             PSZ queuename, RXSTRING *retstr)
  1377. {
  1378.   PSZ         target;                  /* search string              */
  1379.   PSZ         file;                    /* search file                */
  1380.   PSZ         opts;                    /* option string              */
  1381.   CHAR        line[MAX];               /* Line read from file        */
  1382.   ULONG       ptr;                     /* Pointer to char str found  */
  1383.   ULONG       num = 0;                 /* Line number                */
  1384.   ULONG       len;                     /* Length of string           */
  1385.   ULONG       len2;                    /* Length of string           */
  1386.   ULONG       rc = 0;                  /* Return code of this func   */
  1387.   BOOL        linenums = FALSE;        /* Set TRUE for linenums in   */
  1388.                                        /* output                     */
  1389.   BOOL        sensitive = FALSE;       /* Set TRUE for case-sens     */
  1390.                                        /* search                     */
  1391.   FILE       *fp;                      /* Pointer to file to search  */
  1392.   RXSTEMDATA  ldp;                     /* stem data                  */
  1393.  
  1394.   BUILDRXSTRING(retstr, NO_UTIL_ERROR);/* pass back result           */
  1395.                                        /* validate arguments         */
  1396.   if (numargs < 3 || numargs > 4 ||
  1397.       !RXVALIDSTRING(args[0]) ||
  1398.       !RXVALIDSTRING(args[1]) ||
  1399.       !RXVALIDSTRING(args[2]))
  1400.     return INVALID_ROUTINE;            /* raise an error             */
  1401.  
  1402.   target = args[0].strptr;             /* get target pointer         */
  1403.   file = args[1].strptr;               /* get file name              */
  1404.  
  1405.   if (numargs == 4) {                  /* process options            */
  1406.     opts = args[3].strptr;             /* point to the options       */
  1407.     if (strstr(opts, "N") || strstr(opts, "n"))
  1408.       linenums = TRUE;
  1409.  
  1410.     if (strstr(opts, "C") || strstr(opts, "c"))
  1411.       sensitive = TRUE;
  1412.   }
  1413.  
  1414.                                        /* Initialize data area       */
  1415.   ldp.count = 0;
  1416.   strcpy(ldp.varname, args[2].strptr);
  1417.   ldp.stemlen = args[2].strlength;
  1418.   strupr(ldp.varname);                 /* uppercase the name         */
  1419.  
  1420.   if (ldp.varname[ldp.stemlen-1] != '.')
  1421.     ldp.varname[ldp.stemlen++] = '.';
  1422.  
  1423.   fp = fopen(file, "r");               /* Open the file              */
  1424.  
  1425.   if (fp == NULL) {                    /* Open error?                */
  1426.     BUILDRXSTRING(retstr, ERROR_FILEOPEN);
  1427.     return VALID_ROUTINE;              /* finished                   */
  1428.   }
  1429.                                        /* do the search...found lines*/
  1430.                                        /* are saved in stem vars     */
  1431.   while (fgets(line, MAX - 1, fp) != NULL) {
  1432.     len = strlen(line);
  1433.     num++;
  1434.     ptr = mystrstr(line, target, len, args[0].strlength, sensitive);
  1435.  
  1436.     if (ptr != '\0') {
  1437.  
  1438.       if (linenums) {
  1439.         sprintf(ldp.ibuf, "%d ", num);
  1440.         len2 = strlen(ldp.ibuf);
  1441.         memcpy(ldp.ibuf+len2, line, len);
  1442.         ldp.vlen = len+len2;
  1443.       }
  1444.       else {
  1445.         memcpy(ldp.ibuf, line, len);
  1446.         ldp.vlen = len;
  1447.       }
  1448.       ldp.count++;
  1449.       sprintf(ldp.varname+ldp.stemlen, "%d", ldp.count);
  1450.  
  1451.       if (ldp.ibuf[ldp.vlen-1] == '\n')
  1452.         ldp.vlen--;
  1453.       ldp.shvb.shvnext = NULL;
  1454.       ldp.shvb.shvname.strptr = ldp.varname;
  1455.       ldp.shvb.shvname.strlength = strlen(ldp.varname);
  1456.       ldp.shvb.shvnamelen = ldp.shvb.shvname.strlength;
  1457.       ldp.shvb.shvvalue.strptr = ldp.ibuf;
  1458.       ldp.shvb.shvvalue.strlength = ldp.vlen;
  1459.       ldp.shvb.shvvaluelen = ldp.vlen;
  1460.       ldp.shvb.shvcode = RXSHV_SET;
  1461.       ldp.shvb.shvret = 0;
  1462.       if (RexxVariablePool(&ldp.shvb) == RXSHV_BADN)
  1463.         return INVALID_ROUTINE;      /* error on non-zero          */
  1464.     }
  1465.   }
  1466.  
  1467.   fclose(fp);                        /* Close that file            */
  1468.                                      /* set stem.0 to lines read   */
  1469.   sprintf(ldp.ibuf, "%d", ldp.count);
  1470.   ldp.varname[ldp.stemlen] = '0';
  1471.   ldp.varname[ldp.stemlen+1] = 0;
  1472.   ldp.shvb.shvnext = NULL;
  1473.   ldp.shvb.shvname.strptr = ldp.varname;
  1474.   ldp.shvb.shvname.strlength = ldp.stemlen+1;
  1475.   ldp.shvb.shvnamelen = ldp.stemlen+1;
  1476.   ldp.shvb.shvvalue.strptr = ldp.ibuf;
  1477.   ldp.shvb.shvvalue.strlength = strlen(ldp.ibuf);
  1478.   ldp.shvb.shvvaluelen = ldp.shvb.shvvalue.strlength;
  1479.   ldp.shvb.shvcode = RXSHV_SET;
  1480.   ldp.shvb.shvret = 0;
  1481.   if (RexxVariablePool(&ldp.shvb) == RXSHV_BADN)
  1482.     return INVALID_ROUTINE;            /* error on non-zero          */
  1483.  
  1484.   return VALID_ROUTINE;                /* no error on call           */
  1485. }
  1486.  
  1487. /*************************************************************************
  1488. * Function:  SysFileTree                                                 *
  1489. *                                                                        *
  1490. * Syntax:    call SysFileTree filespec, stem [, options]                 *
  1491. *                                                                        *
  1492. * Params:    filespec - Filespec to search for (may include * and ?).    *
  1493. *            stem     - Name of stem var to store results in.            *
  1494. *            options  - Any combo of the following:                      *
  1495. *                        'B' - Search for files and directories.         *
  1496. *                        'D' - Search for directories only.              *
  1497. *                        'F' - Search for files only.                    *
  1498. *                        'O' - Only output file names.                   *
  1499. *                        'S' - Recursively scan subdirectories.          *
  1500. *                        'T' - Combine time & date fields into one.      *
  1501. *                                                                        *
  1502. * Return:    NO_UTIL_ERROR   - Successful.                               *
  1503. *            ERROR_NOMEM     - Out of memory.                            *
  1504. *************************************************************************/
  1505.  
  1506. ULONG SysFileTree(PUCHAR name, ULONG numargs, RXSTRING args[],
  1507.                           PSZ queuename, RXSTRING *retstr)
  1508. {
  1509.   CHAR        FileSpec[MAX];           /* File spec to look for      */
  1510.  
  1511.   CHAR        Opts[64];                /* Search options             */
  1512.   ULONG       options;                 /* Mask of options            */
  1513.   ULONG       x;                       /* Temp counter               */
  1514.   ULONG       y;                       /* Temp counter (II)          */
  1515.   INT         smask[5];                /* Source attribute mask      */
  1516.   INT         dmask[5];                /* Target attribute mask      */
  1517.   RXTREEDATA  ldp;                     /* local data                 */
  1518.  
  1519.   options = FIRST_TIME|DO_FILES|DO_DIRS;/* Clear if we should not    */
  1520.                                        /* display files              */
  1521.   smask[0] = IGNORE;                   /* No mask unless specified   */
  1522.   dmask[0] = IGNORE;                   /* No mask unless specified   */
  1523.   BUILDRXSTRING(retstr, NO_UTIL_ERROR);/* pass back result           */
  1524.  
  1525.                                        /* validate arguments         */
  1526.   if (numargs < 2 || numargs > 5 ||
  1527.       !RXVALIDSTRING(args[0]) ||
  1528.       !RXVALIDSTRING(args[1]) ||
  1529.       args[0].strlength > 255)
  1530.     return INVALID_ROUTINE;            /* Invalid call to routine    */
  1531.                                        /* initialize data area       */
  1532.   ldp.count = 0;
  1533.   strcpy(ldp.varname, args[1].strptr);
  1534.   ldp.stemlen = args[1].strlength;
  1535.   strupr(ldp.varname);                 /* uppercase the name         */
  1536.  
  1537.   if (ldp.varname[ldp.stemlen-1] != '.')
  1538.     ldp.varname[ldp.stemlen++] = '.';
  1539.  
  1540.   strcpy(FileSpec, args[0].strptr);    /* get file spec              */
  1541.  
  1542.    /** If FileSpec ends in \ then append *.*  *                    */
  1543.  
  1544.   if (FileSpec[strlen(FileSpec)-1] == '\\')
  1545.     strcat(FileSpec, "*.*");
  1546.  
  1547.   if (numargs >= 3 &&                  /* check third option         */
  1548.       !RXNULLSTRING(args[2])) {
  1549.     if (!args[2].strlength)            /* a zero length string isn't */
  1550.       return INVALID_ROUTINE;          /* valid                      */
  1551.     strcpy(Opts, args[2].strptr);
  1552.     strupr(Opts);                      /* Uppercase the string       */
  1553.  
  1554.     if (strchr(Opts, 'S') != NULL)
  1555.       options |= RECURSE;              /* Should we recurse          */
  1556.  
  1557.     if (strchr(Opts, 'O') != NULL)
  1558.       options |= NAME_ONLY;            /* Should include names only  */
  1559.  
  1560.     if (strchr(Opts, 'T') != NULL)
  1561.       options |= EDITABLE_TIME;          /* Should create editable     */
  1562.                                        /* timestamp                  */
  1563.  
  1564.     if (strchr(Opts, 'F') != NULL) {
  1565.       options &= ~DO_DIRS;             /* Should not include dirs !  */
  1566.       options |= DO_FILES;             /* Should include files !     */
  1567.     }
  1568.  
  1569.     if (strchr(Opts, 'D') != NULL) {
  1570.       options |= DO_DIRS;              /* Should include dirs !      */
  1571.       options &= ~DO_FILES;            /* Should not include files ! */
  1572.     }
  1573.  
  1574.     if (strchr(Opts, 'B') != NULL) {
  1575.       options |= DO_DIRS;              /* Should include dirs !      */
  1576.       options |= DO_FILES;             /* Should include files !     */
  1577.     }
  1578.   }
  1579.  
  1580.   if (numargs >= 4) {                  /* check fourth option        */
  1581.     strcpy(Opts, args[3].strptr);
  1582.  
  1583.     smask[0] = smask[1] = smask[2] = smask[3] = smask[4] = 0;
  1584.     x = min(5, strlen(Opts));
  1585.  
  1586.     for (y = 0; y < x; y++) {
  1587.  
  1588.       if (Opts[y] == '+')
  1589.         smask[y] = 1;
  1590.  
  1591.       if (Opts[y] == '-')
  1592.         smask[y] = -1;
  1593.     }
  1594.   }
  1595.  
  1596.   if (numargs == 5) {                  /* check fifth argument       */
  1597.     strcpy(Opts, args[4].strptr);      /* point to string            */
  1598.     dmask[0] = dmask[1] = dmask[2] = dmask[3] = dmask[4] = 0;
  1599.  
  1600.     x = min(5, strlen(Opts));
  1601.  
  1602.     for (y = 0; y < x; y++) {
  1603.  
  1604.       if (Opts[y] == '+')
  1605.         dmask[y] = 1;
  1606.  
  1607.       if (Opts[y] == '-')
  1608.         dmask[y] = -1;
  1609.     }
  1610.     dmask[1] = 0;                      /* Ignore directory bit of    */
  1611.                                        /* destination mask           */
  1612.   }
  1613.                                        /* recursively search         */
  1614.   if (RecursiveFindFile(FileSpec, &ldp, smask, dmask, options))
  1615.     return INVALID_ROUTINE;
  1616.                                        /* return lines read          */
  1617.   sprintf(ldp.ibuf, "%d", ldp.count);
  1618.   ldp.varname[ldp.stemlen] = '0';
  1619.   ldp.varname[ldp.stemlen+1] = 0;
  1620.   ldp.shvb.shvnext = NULL;
  1621.   ldp.shvb.shvname.strptr = ldp.varname;
  1622.   ldp.shvb.shvname.strlength = ldp.stemlen+1;
  1623.   ldp.shvb.shvnamelen = ldp.stemlen+1;
  1624.   ldp.shvb.shvvalue.strptr = ldp.ibuf;
  1625.   ldp.shvb.shvvalue.strlength = strlen(ldp.ibuf);
  1626.   ldp.shvb.shvvaluelen = ldp.shvb.shvvalue.strlength;
  1627.   ldp.shvb.shvcode = RXSHV_SET;
  1628.   ldp.shvb.shvret = 0;
  1629.   if (RexxVariablePool(&ldp.shvb) == RXSHV_BADN)
  1630.     return INVALID_ROUTINE;            /* error on non-zero          */
  1631.  
  1632.   return VALID_ROUTINE;                /* no error on call           */
  1633. }
  1634.  
  1635.  
  1636. /*************************************************************************
  1637. * Function:  SysGetMessage                                               *
  1638. *                                                                        *
  1639. * Syntax:    call SysGetMessage [file], msgnum [,str1] ... [,str9]       *
  1640. *                                                                        *
  1641. * Params:    file           - Name of message file to get message from.  *
  1642. *                              Default is OSO001.MSG.                    *
  1643. *            msgnum         - Number of message being queried.           *
  1644. *            str1 ... str9  - Insertion strings.  For messages which     *
  1645. *                              contain %1, %2, etc, the str1, str2, etc  *
  1646. *                              strings will be inserted (if given).      *
  1647. *                                                                        *
  1648. * Return:    The message with the inserted strings (if given).           *
  1649. *************************************************************************/
  1650.  
  1651. ULONG SysGetMessage(PUCHAR name, ULONG numargs, RXSTRING args[],
  1652.                             PSZ queuename, RXSTRING *retstr)
  1653. {
  1654.   PCHAR   ivtable[9];                  /* Array of pointers to       */
  1655.                                        /* variables                  */
  1656.   CHAR    dataarea[500];               /* Buffer address to return   */
  1657.                                        /* message                    */
  1658.   ULONG   msglen;                      /* Length of the returned     */
  1659.                                        /* message                    */
  1660.   ULONG   datalen = 500;               /* Length of the input buffer */
  1661.   ULONG   file_handle = 1;             /* Output device handle for   */
  1662.                                        /* the screen                 */
  1663.   ULONG   ivcount = 3;                 /* Number of variables to     */
  1664.                                        /* insert = 0                 */
  1665.   LONG    msgnum;                      /* Message number to get      */
  1666.   LONG    x;                           /* Loop counter               */
  1667.   PSZ     msgfile;                     /* Message file               */
  1668.  
  1669.   if (numargs < 1 || numargs > 11 ||   /* validate arguments         */
  1670.       !RXVALIDSTRING(args[0]))
  1671.     return INVALID_ROUTINE;            /* exit with error            */
  1672.                                        /* get message number         */
  1673.   if (!string2long(args[0].strptr, &msgnum) || msgnum < 0)
  1674.     return INVALID_ROUTINE;            /* exit with error            */
  1675.                                        /* Get message file name.     */
  1676.                                        /* Use "OSO001.MSG if not     */
  1677.                                        /* given                      */
  1678.   if (numargs >= 2 && RXVALIDSTRING(args[1]))
  1679.     msgfile = args[1].strptr;          /* use provided message file  */
  1680.   else
  1681.     msgfile = "OSO001.MSG";
  1682.  
  1683.                                        /* copy insertion string      */
  1684.                                        /* pointers                   */
  1685.   for (x = 2; x < numargs; x++) {
  1686.     if (RXNULLSTRING(args[x]))         /* must be valid string       */
  1687.       return INVALID_ROUTINE;          /* leave now if bad           */
  1688.     ivtable[x-2] = args[x].strptr;
  1689.   }
  1690.                                        /* set number of insertions   */
  1691.   if (numargs >= 2)
  1692.     ivcount = numargs-2;
  1693.   else
  1694.     ivcount = 0;
  1695.                                        /* get the message            */
  1696.   DosGetMessage(ivtable, ivcount, dataarea, datalen, msgnum, msgfile,
  1697.       &msglen);
  1698.                                        /* save the message           */
  1699.   if (msglen > retstr->strlength)
  1700.     if (DosAllocMem((PPVOID)&retstr->strptr, msglen, AllocFlag)) {
  1701.       BUILDRXSTRING(retstr, ERROR_NOMEM);
  1702.       return VALID_ROUTINE;
  1703.     }
  1704.   memcpy(retstr->strptr, dataarea, msglen);
  1705.   retstr->strlength = msglen;
  1706.  
  1707.   return VALID_ROUTINE;                /* no error on call           */
  1708. }
  1709.  
  1710. /*************************************************************************
  1711. * Function:  SysIni                                                      *
  1712. *                                                                        *
  1713. * Syntax:    call SysIni [inifile], app [,key/stem] [,val/stem]          *
  1714. *                                                                        *
  1715. * Params:    inifile - INI file from which to query or write info.  The  *
  1716. *                       default is the current user INI file.            *
  1717. *            app     - Application title to work with.  May be either    *
  1718. *                       of the following:                                *
  1719. *                        'ALL:' - All app titles will be returned in the *
  1720. *                                  stem variable specified by the next   *
  1721. *                                  parameter.                            *
  1722. *                        other  - Specific app to work with.             *
  1723. *            key     - Key to work with.  May be any of the following:   *
  1724. *                        'ALL:'    - All key titles will be returned in  *
  1725. *                                     the stem variable specified by the *
  1726. *                                     next parameter.                    *
  1727. *                        'DELETE:' - All keys associated with the app    *
  1728. *                                     will be deleted.                   *
  1729. *                        other     - Specific key to work with.          *
  1730. *            val     - Key to work with. May be either of the following: *
  1731. *                        'DELETE:' - Delete app/key pair.                *
  1732. *                        other     - Set app/key pair info to data spec- *
  1733. *                                     ified.                             *
  1734. *            stem    - Name of stem variable in which to store results.  *
  1735. *                      Stem.0 = Number found (n).                        *
  1736. *                      Stem.1 - Stem.n = Entries found.                  *
  1737. *                                                                        *
  1738. * Return:    other          - Info queried from specific app/key pair.   *
  1739. *            ''             - Info queried and placed in stem or data    *
  1740. *                              deleted successfully.                     *
  1741. *            ERROR_NOMEM    - Out of memory.                             *
  1742. *            ERROR_RETSTR   - Error opening INI or querying/writing info.*
  1743. *************************************************************************/
  1744.  
  1745. ULONG SysIni(PUCHAR name, ULONG numargs, RXSTRING args[],
  1746.                      PSZ queuename, RXSTRING *retstr)
  1747. {
  1748.   HAB         hab;                     /* Anchor block               */
  1749.   HINI        hini;                    /* Ini file handle            */
  1750.   ULONG       x;                       /* Temp counter               */
  1751.   ULONG       len;                     /* Len var used when creating */
  1752.                                        /* stem                       */
  1753.   ULONG       lSize;                   /* Size of queried info buffer*/
  1754.                                        /* area                       */
  1755.   PSZ         IniFile;                 /* Ini file (USER, SYSTEM,    */
  1756.                                        /* BOTH, file)                */
  1757.   PSZ         App;                     /* Application field          */
  1758.   PSZ         Key;                     /* Key field                  */
  1759.   CHAR       *Val;                     /* Ptr to data associated w/  */
  1760.                                        /* App->Key                   */
  1761.   CHAR        Temp[256];               /* Temp string var            */
  1762.   CHAR        UserName[256];           /* Filename of User INI       */
  1763.                                        /* profile                    */
  1764.   CHAR        SysName[256];            /* Filename of System INI     */
  1765.                                        /* profile                    */
  1766.   PRFPROFILE  PrfInfo;                 /* Profile name structure     */
  1767.   LONG        Error = FALSE;           /* Set to true if error       */
  1768.                                        /* encountered                */
  1769.   BOOL        WildCard = FALSE;        /* Set to true if a wildcard  */
  1770.                                        /* operation                  */
  1771.   BOOL        QueryApps;               /* Set to true if a query     */
  1772.                                        /* operation                  */
  1773.   BOOL        terminate = TRUE;        /* perform WinTerminate call  */
  1774.   RXSTEMDATA  ldp;                     /* local data                 */
  1775.  
  1776.   IniFile = "";
  1777.   Key = "";
  1778.                                        /* validate arguments         */
  1779.   if (numargs < 2 ||
  1780.       numargs > 4 ||
  1781.       !RXVALIDSTRING(args[1]))
  1782.     return INVALID_ROUTINE;
  1783.                                        /* get pointers to args       */
  1784.   IniFile = args[0].strptr;
  1785.   App = args[1].strptr;
  1786.  
  1787.   if (numargs >= 3 && args[2].strptr)
  1788.     Key = args[2].strptr;
  1789.  
  1790.   if (numargs == 4)
  1791.     Val = args[3].strptr;
  1792.                                        /* Check KEY and APP values   */
  1793.                                        /* for "WildCard"             */
  1794.   if (!stricmp(App, "ALL:")) {
  1795.     App = "";
  1796.     QueryApps = TRUE;
  1797.     WildCard = TRUE;
  1798.  
  1799.     if (numargs != 3)
  1800.       return INVALID_ROUTINE;          /* Error - Not enough args    */
  1801.     else
  1802.       x = 2;                           /* Arg number of STEM variable*/
  1803.   }
  1804.  
  1805.   else if (!stricmp(Key, "ALL:")) {
  1806.     Key = "";
  1807.     Val = "";
  1808.     QueryApps = FALSE;
  1809.     WildCard = TRUE;
  1810.  
  1811.     if (numargs != 4)
  1812.       return INVALID_ROUTINE;          /* Error - Not enough args    */
  1813.  
  1814.     else
  1815.       x = 3;                           /* Arg number of STEM variable*/
  1816.   }
  1817.                                        /* If this is a "WildCard     */
  1818.                                        /* search, then allocate mem  */
  1819.                                        /* for stem struct and get the*/
  1820.                                        /* stem name                  */
  1821.   if (WildCard == TRUE) {
  1822.  
  1823.     ldp.count = 0;                     /* get the stem variable name */
  1824.     strcpy(ldp.varname, args[x].strptr);
  1825.     ldp.stemlen = args[x].strlength;
  1826.     strupr(ldp.varname);                 /* uppercase the name         */
  1827.  
  1828.     if (ldp.varname[ldp.stemlen-1] != '.')
  1829.       ldp.varname[ldp.stemlen++] = '.';
  1830.   }
  1831.  
  1832.   hab = WinInitialize((USHORT)0);      /* create anchor block        */
  1833.   if (!hab) {                          /* already done?              */
  1834.                                        /* get desktop anchor         */
  1835.     hab = WinQueryAnchorBlock(HWND_DESKTOP);
  1836.     terminate = FALSE;                 /* don't terminate            */
  1837.   }
  1838.  
  1839.       /**************************************************************
  1840.       * The following section of code gets the INI file handle      *
  1841.       * given the INI file spec (IniFile).                          *
  1842.       *                                                             *
  1843.       * Possible Ini file specs:                                    *
  1844.       *                                                             *
  1845.       *   NULL     - Same as USERPROFILE   ( OS2.INI )              *
  1846.       *   "BOTH"   - Same as PROFILE       ( OS2.INI & OS2SYS.INI ) *
  1847.       *   "USER"   - Same as USERPROFILE   ( OS2.INI )              *
  1848.       *   "SYSTEM" - Same as SYSTEMPROFILE ( OS2SYS.INI)            *
  1849.       *   other    - Filespec of INI file.                          *
  1850.       **************************************************************/
  1851.  
  1852.   hini = NULLHANDLE;
  1853.  
  1854.   if (!IniFile)
  1855.     hini = HINI_USERPROFILE;
  1856.   else if (!stricmp(IniFile, "BOTH"))
  1857.     hini = HINI_PROFILE;
  1858.   else if (!stricmp(IniFile, "USER"))
  1859.     hini = HINI_USERPROFILE;
  1860.   else if (!stricmp(IniFile, "SYSTEM"))
  1861.     hini = HINI_SYSTEMPROFILE;
  1862.  
  1863.       /***********************************************************
  1864.       * If Ini file spec is 'other' then make sure it does not   *
  1865.       * specify the current USER or SYSTEM profiles.             *
  1866.       *                                                          *
  1867.       * Trying to open the current USER or SYSTEM ini file via   *
  1868.       * PrfOpenProfile() will fail.  Therefore, use the function *
  1869.       * PrfQueryProfile() to query the current USER and SYSTEM   *
  1870.       * ini file specs. If the IniFile string matches either     *
  1871.       * the current USER or SYSTEM file specs, then use either   *
  1872.       * HINI_USERPROFILE or HINI_SYSTEMPROFILE as appropriate.   *
  1873.       *                                                          *
  1874.       * If IniFile does not specify the current USER or SYSTEM   *
  1875.       * ini file then use PrfOpenProfile() to get the ini file   *
  1876.       * handle.                                                  *
  1877.       ***********************************************************/
  1878.  
  1879.   else {
  1880.     PrfInfo.pszUserName = UserName;
  1881.     PrfInfo.cchUserName = sizeof(UserName);
  1882.     PrfInfo.pszSysName = SysName;
  1883.     PrfInfo.cchSysName = sizeof(SysName);
  1884.  
  1885.     if (PrfQueryProfile(hab, &PrfInfo)) {
  1886.  
  1887.       if (!stricmp(IniFile, PrfInfo.pszUserName))
  1888.         hini = HINI_USERPROFILE;
  1889.       else if (!stricmp(IniFile, PrfInfo.pszSysName))
  1890.         hini = HINI_SYSTEMPROFILE;
  1891.       else
  1892.         hini = PrfOpenProfile(hab, IniFile);
  1893.     }
  1894.     else
  1895.       hini = PrfOpenProfile(hab, IniFile);
  1896.  
  1897.       /**************************************************
  1898.       * Exit with INI FILE error if the ini file handle *
  1899.       * is NULL at this point (and if IniFile != BOTH,  *
  1900.       * as that would make the handle NULL also).       *
  1901.       **************************************************/
  1902.  
  1903.     if (hini == NULLHANDLE && stricmp(IniFile, "BOTH")) {
  1904.       BUILDRXSTRING(retstr, ERROR_RETSTR);
  1905.       if (terminate)
  1906.         WinTerminate(hab);
  1907.       return VALID_ROUTINE;
  1908.     }
  1909.   }
  1910.                                        /* get value if is a query    */
  1911.   if ((numargs == 3 && stricmp(Key, "DELETE:")) ||
  1912.       WildCard == TRUE) {
  1913.     lSize = 0x0000ffffL;
  1914.                                        /* Allocate a large buffer    */
  1915.     if (DosAllocMem((PPVOID)&Val, lSize, AllocFlag)) {
  1916.       PrfCloseProfile(hini);           /* close the INI file         */
  1917.       if (terminate)
  1918.         WinTerminate(hab);
  1919.       BUILDRXSTRING(retstr, ERROR_NOMEM);
  1920.       return VALID_ROUTINE;
  1921.     }
  1922.  
  1923.     if (WildCard && QueryApps)
  1924.       Error = !PrfQueryProfileData(hini, NULL, NULL, Val, &lSize);
  1925.     else if (WildCard && !QueryApps)
  1926.       Error = !PrfQueryProfileData(hini, App, NULL, Val, &lSize);
  1927.     else
  1928.       Error = !PrfQueryProfileData(hini, App, Key, Val, &lSize);
  1929.  
  1930.     if (Error) {
  1931.       BUILDRXSTRING(retstr, ERROR_RETSTR);
  1932.     }
  1933.     else if (WildCard == FALSE) {
  1934.       if (lSize > retstr->strlength)
  1935.         if (DosAllocMem((PPVOID)&retstr->strptr, lSize, AllocFlag)) {
  1936.           DosFreeMem(Val);             /* release buffer             */
  1937.           PrfCloseProfile(hini);       /* close the INI file         */
  1938.           if (terminate)
  1939.             WinTerminate(hab);
  1940.           BUILDRXSTRING(retstr, ERROR_NOMEM);
  1941.           return VALID_ROUTINE;
  1942.         }
  1943.       memcpy(retstr->strptr, Val, lSize);
  1944.       retstr->strlength = lSize;
  1945.       DosFreeMem(Val);                 /* release buffer             */
  1946.     }
  1947.   }
  1948.   else {
  1949.                                        /* set the var to new value   */
  1950.     if (!stricmp(Key, "DELETE:") ||
  1951.         !RXVALIDSTRING(args[2]))
  1952.       Error = !PrfWriteProfileData(hini, App, NULL, NULL, 0L);
  1953.     else if (!stricmp(Val, "DELETE:") ||
  1954.         !RXVALIDSTRING(args[3]))
  1955.       Error = !PrfWriteProfileData(hini, App, Key, NULL, 0L);
  1956.     else {
  1957.       lSize = args[3].strlength;
  1958.       Error = !PrfWriteProfileData(hini, App, Key, Val, lSize);
  1959.     }
  1960.  
  1961.     if (Error) {
  1962.       BUILDRXSTRING(retstr, ERROR_RETSTR);
  1963.     }
  1964.   }
  1965.  
  1966.   PrfCloseProfile(hini);               /* close the INI file         */
  1967.  
  1968.   if (terminate)
  1969.     WinTerminate(hab);                 /* destroy anchor block       */
  1970.  
  1971.       /******************************************
  1972.       * If this was a wildcard search, change   *
  1973.       * the Val variable from one long string   *
  1974.       * of values to a REXX stem variable.      *
  1975.       ******************************************/
  1976.  
  1977.   if (WildCard == TRUE) {              /* fill stem variable         */
  1978.  
  1979.     if (Error == FALSE) {
  1980.       x = 0;
  1981.       ldp.count = 0;
  1982.  
  1983.       do {
  1984.   /* Copy string terminated by \0 to Temp.  Last string will end     */
  1985.   /* in \0\0 and thus have a length of 0.                            */
  1986.         len = 0;
  1987.  
  1988.         while (Val[x+len] != '\0')
  1989.           Temp[len++] = Val[x+len];
  1990.         Temp[len] = '\0';
  1991.                                        /* if non-zero length, then   */
  1992.                                        /* set the stem element       */
  1993.         if (len != 0) {
  1994.           x += (len+1);                /* Increment pointer past the */
  1995.                                        /* new string                 */
  1996.           memcpy(ldp.ibuf, Temp, len);
  1997.           ldp.vlen = len;
  1998.           ldp.count++;
  1999.           sprintf(ldp.varname+ldp.stemlen, "%d", ldp.count);
  2000.  
  2001.           if (ldp.ibuf[ldp.vlen-1] == '\n')
  2002.             ldp.vlen--;
  2003.           ldp.shvb.shvnext = NULL;
  2004.           ldp.shvb.shvname.strptr = ldp.varname;
  2005.           ldp.shvb.shvname.strlength = strlen(ldp.varname);
  2006.           ldp.shvb.shvvalue.strptr = ldp.ibuf;
  2007.           ldp.shvb.shvvalue.strlength = ldp.vlen;
  2008.           ldp.shvb.shvnamelen = ldp.shvb.shvname.strlength;
  2009.           ldp.shvb.shvvaluelen = ldp.vlen;
  2010.           ldp.shvb.shvcode = RXSHV_SET;
  2011.           ldp.shvb.shvret = 0;
  2012.           if (RexxVariablePool(&ldp.shvb) == RXSHV_BADN)
  2013.             return INVALID_ROUTINE;    /* error on non-zero          */
  2014.         }
  2015.       }
  2016.  
  2017.       while (Val[x] != '\0');
  2018.     }
  2019.  
  2020.     else
  2021.       ldp.count = 0;
  2022.                                        /* set number returned        */
  2023.     sprintf(ldp.ibuf, "%d", ldp.count);
  2024.     ldp.varname[ldp.stemlen] = '0';
  2025.     ldp.varname[ldp.stemlen+1] = 0;
  2026.     ldp.shvb.shvnext = NULL;
  2027.     ldp.shvb.shvname.strptr = ldp.varname;
  2028.     ldp.shvb.shvname.strlength = ldp.stemlen+1;
  2029.     ldp.shvb.shvnamelen = ldp.stemlen+1;
  2030.     ldp.shvb.shvvalue.strptr = ldp.ibuf;
  2031.     ldp.shvb.shvvalue.strlength = strlen(ldp.ibuf);
  2032.     ldp.shvb.shvvaluelen = ldp.shvb.shvvalue.strlength;
  2033.     ldp.shvb.shvcode = RXSHV_SET;
  2034.     ldp.shvb.shvret = 0;
  2035.     if (RexxVariablePool(&ldp.shvb) == RXSHV_BADN)
  2036.       return INVALID_ROUTINE;          /* error on non-zero          */
  2037.  
  2038.   }                                    /* * End - IF (Wildcard ... * */
  2039.  
  2040.   return VALID_ROUTINE;                /* no error on call           */
  2041. }
  2042.  
  2043.  
  2044. /*************************************************************************
  2045. * Function:  SysLoadFuncs                                                *
  2046. *                                                                        *
  2047. * Syntax:    call SysLoadFuncs [option]                                  *
  2048. *                                                                        *
  2049. * Params:    none                                                        *
  2050. *                                                                        *
  2051. * Return:    null string                                                 *
  2052. *************************************************************************/
  2053.  
  2054. ULONG SysLoadFuncs(PUCHAR name, ULONG numargs, RXSTRING args[],
  2055.                            PSZ queuename, RXSTRING *retstr)
  2056. {
  2057.   INT    entries;                      /* Num of entries             */
  2058.   INT    j;                            /* Counter                    */
  2059.  
  2060.   retstr->strlength = 0;               /* set return value           */
  2061.                                        /* check arguments            */
  2062.   if (numargs > 0)
  2063.     return INVALID_ROUTINE;
  2064.  
  2065.   entries = sizeof(RxFncTable)/sizeof(PSZ);
  2066.  
  2067.   for (j = 0; j < entries; j++) {
  2068.     RexxRegisterFunctionDll(RxFncTable[j],
  2069.           "REXXUTIL", RxFncTable[j]);
  2070.   }
  2071.   return VALID_ROUTINE;
  2072. }
  2073.  
  2074.  
  2075. /*************************************************************************
  2076. * Function:  SysMkDir                                                    *
  2077. *                                                                        *
  2078. * Syntax:    call SysMkDir dir                                           *
  2079. *                                                                        *
  2080. * Params:    dir - Directory to be created.                              *
  2081. *                                                                        *
  2082. * Return:    NO_UTIL_ERROR                                               *
  2083. *            Return code from DosMkDir()                                 *
  2084. *************************************************************************/
  2085.  
  2086. ULONG SysMkDir(PUCHAR name, ULONG numargs, RXSTRING args[],
  2087.                        PSZ queuename, RXSTRING *retstr)
  2088. {
  2089.   ULONG  rc;                           /* Ret code of func           */
  2090.  
  2091.   if (numargs != 1)
  2092.                                        /* If no args, then its an    */
  2093.                                        /* incorrect call             */
  2094.     return INVALID_ROUTINE;
  2095.   rc = DosMkDir(args[0].strptr, 0L);   /* make the directory         */
  2096.   sprintf(retstr->strptr, "%d", rc);   /* result is return code      */
  2097.   retstr->strlength = strlen(retstr->strptr);
  2098.   return VALID_ROUTINE;
  2099. }
  2100.  
  2101.  
  2102. /*************************************************************************
  2103. * Function:  SysOS2Ver                                                   *
  2104. *                                                                        *
  2105. * Syntax:    call SysOS2Ver                                              *
  2106. *                                                                        *
  2107. * Return:    OS/2 Version in for 1.1, 1.2, 1.3, 2.0.                     *
  2108. *************************************************************************/
  2109.  
  2110. ULONG SysOS2Ver(PUCHAR name, ULONG numargs, RXSTRING args[],
  2111.                         PSZ queuename, RXSTRING *retstr)
  2112. {
  2113.   ULONG  rc = 0;                       /* Return code of this func   */
  2114.   ULONG  Versions[2];                  /* Major version number       */
  2115.  
  2116.   if (numargs != 0)                    /* validate arg count         */
  2117.     return INVALID_ROUTINE;
  2118.  
  2119.   DosQuerySysInfo(QSV_VERSION_MAJOR, QSV_VERSION_MINOR, Versions,
  2120.       sizeof(Versions));
  2121.   sprintf(retstr->strptr, "%lu.%02lu", Versions[0]/10, Versions[1]);
  2122.   retstr->strlength = strlen(retstr->strptr);
  2123.   return VALID_ROUTINE;
  2124. }
  2125.  
  2126. /*************************************************************************
  2127. * Function:  SysRmDir                                                    *
  2128. *                                                                        *
  2129. * Syntax:    call SysRmDir dir                                           *
  2130. *                                                                        *
  2131. * Params:    dir - Directory to be removed.                              *
  2132. *                                                                        *
  2133. * Return:    NO_UTIL_ERROR                                               *
  2134. *            Return code from DosRmDir()                                 *
  2135. *************************************************************************/
  2136.  
  2137. ULONG SysRmDir(PUCHAR name, ULONG numargs, RXSTRING args[],
  2138.                        PSZ queuename, RXSTRING *retstr)
  2139. {
  2140.   ULONG  rc;                           /* Ret code of func           */
  2141.  
  2142.   if (numargs != 1)
  2143.                                        /* If no args, then its an    */
  2144.                                        /* incorrect call             */
  2145.     return INVALID_ROUTINE;
  2146.                                        /* remove the directory       */
  2147.   rc = DosRmDir(args[0].strptr);
  2148.   sprintf(retstr->strptr, "%d", rc);
  2149.   retstr->strlength = strlen(retstr->strptr);
  2150.   return VALID_ROUTINE;
  2151. }
  2152.  
  2153.  
  2154. /*************************************************************************
  2155. * Function:  SysSearchPath                                               *
  2156. *                                                                        *
  2157. * Syntax:    call SysSearchPath path, file                               *
  2158. *                                                                        *
  2159. * Params:    path - Environment variable name which specifies a path     *
  2160. *                    to be searched (ie 'PATH', 'DPATH', etc).           *
  2161. *            file - The file to search for.                              *
  2162. *                                                                        *
  2163. * Return:    other  - Full path and filespec of found file.              *
  2164. *            ''     - Specified file not found along path.               *
  2165. *************************************************************************/
  2166.  
  2167. ULONG SysSearchPath(PUCHAR name, ULONG numargs, RXSTRING args[],
  2168.                             PSZ queuename, RXSTRING *retstr)
  2169. {
  2170.   UCHAR    buf[MAX];                   /* returned file name         */
  2171.  
  2172.                                        /* validate arguments         */
  2173.   if (numargs != 2 ||
  2174.       !RXVALIDSTRING(args[0]) ||
  2175.       !RXVALIDSTRING(args[1]))
  2176.     return INVALID_ROUTINE;
  2177.  
  2178.                                        /* use DosSearchPath          */
  2179.   DosSearchPath(7, args[0].strptr, args[1].strptr,
  2180.       buf, sizeof(buf));
  2181.  
  2182.   BUILDRXSTRING(retstr, (const char *)buf);          /* pass back result           */
  2183.   return VALID_ROUTINE;
  2184. }
  2185.  
  2186.  
  2187. /*************************************************************************
  2188. * Function:  SysSleep                                                    *
  2189. *                                                                        *
  2190. * Syntax:    call SysSleep secs                                          *
  2191. *                                                                        *
  2192. * Params:    secs - Number of seconds to sleep.                          *
  2193. *                                                                        *
  2194. * Return:    NO_UTIL_ERROR                                               *
  2195. *************************************************************************/
  2196.  
  2197. ULONG SysSleep(PUCHAR name, ULONG numargs, RXSTRING args[],
  2198.                        PSZ queuename, RXSTRING *retstr)
  2199. {
  2200.   LONG secs;                           /* Time to sleep in secs      */
  2201.  
  2202.   if (numargs != 1)                    /* Must have one argument     */
  2203.     return INVALID_ROUTINE;
  2204.                                        /* get number of seconds      */
  2205.   if (!string2long(args[0].strptr, &secs) || secs < 0)
  2206.     return INVALID_ROUTINE;            /* raise error if bad         */
  2207.  
  2208.   DosSleep(secs *1000);
  2209.   BUILDRXSTRING(retstr, NO_UTIL_ERROR);
  2210.   return VALID_ROUTINE;
  2211. }
  2212.  
  2213.  
  2214. /*************************************************************************
  2215. * Function:  SysTempFileName                                             *
  2216. *                                                                        *
  2217. * Syntax:    call SysTempFileName template [,filler]                     *
  2218. *                                                                        *
  2219. * Params:    template - Description of filespec desired.  For example:   *
  2220. *                        C:\TEMP\FILE.???                                *
  2221. *            filler   - A character which when found in template will be *
  2222. *                        replaced with random digits until a unique file *
  2223. *                        or directory is found.  The default character   *
  2224. *                        is '?'.                                         *
  2225. *                                                                        *
  2226. * Return:    other - Unique file/directory name.                         *
  2227. *            ''    - No more files exist given specified template.       *
  2228. *************************************************************************/
  2229.  
  2230. ULONG SysTempFileName(PUCHAR name, ULONG numargs, RXSTRING args[],
  2231.                               PSZ queuename, RXSTRING *retstr)
  2232. {
  2233.   CHAR   filler;                       /* filler character           */
  2234.  
  2235.   if (numargs < 1 ||                   /* validate arguments         */
  2236.       numargs > 2 ||
  2237.       !RXVALIDSTRING(args[0]) ||
  2238.       args[0].strlength > 512)
  2239.     return INVALID_ROUTINE;
  2240.  
  2241.   if (numargs == 2 &&                  /* get filler character       */
  2242.       !RXNULLSTRING(args[1])) {
  2243.     if (args[1].strlength != 1)        /* must be one character      */
  2244.       return INVALID_ROUTINE;
  2245.     filler = args[1].strptr[0];
  2246.   }
  2247.   else
  2248.     filler = '?';
  2249.                                        /* get the file id            */
  2250.   GetUniqueFileName(args[0].strptr, filler, retstr->strptr);
  2251.   retstr->strlength = strlen(retstr->strptr);
  2252.   return VALID_ROUTINE;
  2253. }
  2254.  
  2255.  
  2256. /*************************************************************************
  2257. * Function:  SysTextScreenRead                                           *
  2258. *                                                                        *
  2259. * Syntax:    call SysTextScreenRead row, col [,len]                      *
  2260. *                                                                        *
  2261. * Params:    row - Horizontal row on the screen to start reading from.   *
  2262. *                   The row at the top of the screen is 0.               *
  2263. *            col - Vertical column on the screen to start reading from.  *
  2264. *                   The column at the left of the screen is 0.           *
  2265. *            len - The number of characters to read.  The default is the *
  2266. *                   rest of the screen.                                  *
  2267. *                                                                        *
  2268. * Return:    Characters read from text screen.                           *
  2269. *************************************************************************/
  2270.  
  2271. ULONG SysTextScreenRead(PUCHAR name, ULONG numargs, RXSTRING args[],
  2272.                                 PSZ queuename, RXSTRING *retstr)
  2273. {
  2274.   LONG  row;                           /* Row from which to start    */
  2275.                                        /* read                       */
  2276.   LONG  col;                           /* Column from which to start */
  2277.                                        /* read                       */
  2278.   LONG len = 8160;                     /* Max length of string,      */
  2279.                                        /* default is 8160 (80x102)   */
  2280.   CHAR  temp[8160];                    /* Array of CHARs, aka PCH    */
  2281.  
  2282.   if (numargs < 2 ||                   /* validate arguments         */
  2283.       numargs > 3 ||
  2284.       !RXVALIDSTRING(args[0]) ||
  2285.       !RXVALIDSTRING(args[1]) ||
  2286.       !string2long(args[0].strptr, &row) || row < 0 ||
  2287.       !string2long(args[1].strptr, &col) || col < 0)
  2288.     return INVALID_ROUTINE;
  2289.  
  2290.   if (numargs == 3) {                  /* check the length           */
  2291.     if (!RXVALIDSTRING(args[2]) ||     /* bad string?                */
  2292.         !string2long(args[2].strptr, &len) || len < 0)
  2293.       return INVALID_ROUTINE;          /* error                      */
  2294.   }
  2295.                                        /* read the screen            */
  2296.   VioReadCharStr( temp, (PUSHORT)&len, row, col, (HVIO) 0);
  2297.  
  2298.   if (len > retstr->strlength)         /* default too short?         */
  2299.                                        /* allocate a new one         */
  2300.     if (DosAllocMem((PPVOID)&retstr->strptr, len, AllocFlag)) {
  2301.       BUILDRXSTRING(retstr, ERROR_NOMEM);
  2302.       return VALID_ROUTINE;
  2303.     }
  2304.   memcpy(retstr->strptr, temp, len);
  2305.   retstr->strlength = len;
  2306.  
  2307.   return VALID_ROUTINE;
  2308. }
  2309.  
  2310.  
  2311. /*************************************************************************
  2312. * Function:  SysTextScreenSize                                           *
  2313. *                                                                        *
  2314. * Syntax:    call SysTextScreenSize                                      *
  2315. *                                                                        *
  2316. * Return:    Size of screen in row and columns returned as:  row, col    *
  2317. *************************************************************************/
  2318.  
  2319. ULONG SysTextScreenSize(PUCHAR name, ULONG numargs, RXSTRING args[],
  2320.                                 PSZ queuename, RXSTRING *retstr)
  2321. {
  2322.   VIOMODEINFO  ModeData;               /* screen info structure      */
  2323.  
  2324.   if (numargs != 0)                    /* no arguments on this func. */
  2325.     return INVALID_ROUTINE;
  2326.  
  2327.   ModeData.cb = sizeof(ModeData);      /* find out screen size       */
  2328.   VioGetMode(&ModeData, (HVIO) 0);
  2329.   sprintf(retstr->strptr, "%d %d",(int)ModeData.row,(int)ModeData.col);
  2330.   retstr->strlength = strlen(retstr->strptr);
  2331.   return VALID_ROUTINE;
  2332. }
  2333.  
  2334. /*************************************************************************
  2335. * Function:  SysGetEA                                                    *
  2336. *                                                                        *
  2337. * Syntax:    call SysGetEA file, EA_name, variable                       *
  2338. *                                                                        *
  2339. * Params:    file - file containing EA.                                  *
  2340. *            EA_name - name of EA to be retrieved                        *
  2341. *            name of variable EA is placed in                            *
  2342. *                                                                        *
  2343. * Return:    Return code from DosQueryFileInfo.                          *
  2344. *************************************************************************/
  2345.  
  2346. ULONG SysGetEA(PUCHAR name, ULONG numargs, RXSTRING args[],
  2347.                        PSZ queuename, RXSTRING *retstr)
  2348. {
  2349.   LONG rc;                             /* Ret code                   */
  2350.   UCHAR       geabuff[300];            /* buffer for GEA             */
  2351.   PVOID       fealist;                 /* fealist buffer             */
  2352.   EAOP2       eaop;                    /* eaop structure             */
  2353.   PGEA2       pgea;                    /* pgea structure             */
  2354.   PFEA2       pfea;                    /* pfea structure             */
  2355.   HFILE       handle;                  /* file handle                */
  2356.   ULONG       act;                     /* open action                */
  2357.   RXSTEMDATA  ldp;                     /* stem data                  */
  2358.  
  2359.  
  2360.   if (numargs != 3 ||                  /* wrong number of arguments? */
  2361.       !RXVALIDSTRING(args[0]) ||
  2362.       !RXVALIDSTRING(args[1]) ||
  2363.       !RXVALIDSTRING(args[2]))
  2364.     return INVALID_ROUTINE;            /* raise error condition      */
  2365.  
  2366.   ldp.count = 0;                       /* get the stem variable name */
  2367.   strcpy(ldp.varname, args[2].strptr);
  2368.   ldp.stemlen = args[2].strlength;
  2369.   strupr(ldp.varname);                 /* uppercase the name         */
  2370.  
  2371.   if (rc = DosOpen(args[0].strptr, &handle, &act,
  2372.       0L, 0, OPEN_ACTION_OPEN_IF_EXISTS,
  2373.       OPEN_ACCESS_READONLY + OPEN_SHARE_DENYREADWRITE +
  2374.       OPEN_FLAGS_FAIL_ON_ERROR + OPEN_FLAGS_WRITE_THROUGH,NULL)) {
  2375.     sprintf(retstr->strptr, "%d", rc);
  2376.     retstr->strlength = strlen(retstr->strptr);
  2377.     return VALID_ROUTINE;
  2378.   }                                    /* get the file status info   */
  2379.  
  2380.   if (DosAllocMem((PPVOID)&fealist, 0x00010000L, AllocFlag)) {
  2381.     BUILDRXSTRING(retstr, ERROR_NOMEM);
  2382.     return VALID_ROUTINE;
  2383.   }
  2384.                                        /* FEA and GEA lists          */
  2385.   eaop.fpGEA2List = (PGEA2LIST)geabuff;
  2386.   eaop.fpFEA2List = (PFEA2LIST)fealist;
  2387.   eaop.oError = 0;                     /* no error occurred yet      */
  2388.   pgea = &eaop.fpGEA2List->list[0];    /* point to first GEA         */
  2389.   eaop.fpGEA2List->cbList = sizeof(ULONG) + sizeof(GEA2) +
  2390.       args[1].strlength;
  2391.   eaop.fpFEA2List->cbList = (ULONG)0xffff;
  2392.  
  2393.                                        /* fill in the EA name length */
  2394.   pgea->cbName = (BYTE)args[1].strlength;
  2395.   strcpy(pgea->szName, args[1].strptr);/* fill in the name           */
  2396.   pgea->oNextEntryOffset = 0;          /* fill in the next offset    */
  2397.                                        /* read the extended attribute*/
  2398.   rc = DosQueryFileInfo(handle, 3, (PSZ)&eaop, sizeof(EAOP2));
  2399.   DosClose(handle);                    /* close the file             */
  2400.   if (eaop.fpFEA2List->cbList <= sizeof(ULONG))
  2401.     rc = ERROR_EAS_NOT_SUPPORTED;      /* this is error also         */
  2402.  
  2403.   sprintf(retstr->strptr, "%d", rc);   /* format return code         */
  2404.   retstr->strlength = strlen(retstr->strptr);
  2405.  
  2406.   if (rc) {                            /* failure?                   */
  2407.     DosFreeMem(fealist);               /* error, get out             */
  2408.     return VALID_ROUTINE;
  2409.   }
  2410.  
  2411.   pfea = &(eaop.fpFEA2List->list[0]);  /* point to the first FEA     */
  2412.   ldp.shvb.shvnext = NULL;
  2413.   ldp.shvb.shvname.strptr = ldp.varname;
  2414.   ldp.shvb.shvname.strlength = ldp.stemlen;
  2415.   ldp.shvb.shvnamelen = ldp.stemlen;
  2416.   ldp.shvb.shvvalue.strptr = ((PSZ)pfea->szName+(pfea->cbName+1));
  2417.   ldp.shvb.shvvalue.strlength = pfea->cbValue;
  2418.   ldp.shvb.shvvaluelen = ldp.shvb.shvvalue.strlength;
  2419.   ldp.shvb.shvcode = RXSHV_SET;
  2420.   ldp.shvb.shvret = 0;
  2421.   if (RexxVariablePool(&ldp.shvb) == RXSHV_BADN) {
  2422.     DosFreeMem(fealist);               /* free our buffer            */
  2423.     return INVALID_ROUTINE;            /* error on non-zero          */
  2424.   }
  2425.  
  2426.   DosFreeMem(fealist);                 /* free our buffer            */
  2427.   return VALID_ROUTINE;
  2428. }
  2429.  
  2430. /*************************************************************************
  2431. * Function:  SysPutEA                                                    *
  2432. *                                                                        *
  2433. * Syntax:    call SysPutEA file, EA_name, value                          *
  2434. *                                                                        *
  2435. * Params:    file - file containing EA.                                  *
  2436. *            EA_name - name of EA to be written                          *
  2437. *            new value for the EA                                        *
  2438. *                                                                        *
  2439. * Return:    Return code from DosQueryFileInfo.                          *
  2440. *************************************************************************/
  2441.  
  2442. ULONG SysPutEA(PUCHAR name, ULONG numargs, RXSTRING args[],
  2443.                        PSZ queuename, RXSTRING *retstr)
  2444. {
  2445.   LONG rc;                             /* Ret code                   */
  2446.   PVOID       fealist;                 /* fealist buffer             */
  2447.   EAOP2       eaop;                    /* eaop structure             */
  2448.   PFEA2       pfea;                    /* pfea structure             */
  2449.   HFILE       handle;                  /* file handle                */
  2450.   ULONG       act;                     /* open action                */
  2451.  
  2452.  
  2453.   if (numargs != 3 ||                  /* wrong number of arguments? */
  2454.       !RXVALIDSTRING(args[0]) ||
  2455.       !RXVALIDSTRING(args[1]))
  2456.     return INVALID_ROUTINE;            /* raise error condition      */
  2457.  
  2458.   if (rc = DosOpen2(args[0].strptr, &handle, &act,
  2459.       0L, 0, OPEN_ACTION_OPEN_IF_EXISTS,
  2460.       OPEN_ACCESS_READWRITE + OPEN_SHARE_DENYWRITE +
  2461.       OPEN_FLAGS_FAIL_ON_ERROR + OPEN_FLAGS_WRITE_THROUGH, NULL)) {
  2462.     sprintf(retstr->strptr, "%d", rc);
  2463.     retstr->strlength = strlen(retstr->strptr);
  2464.     return VALID_ROUTINE;
  2465.   }
  2466.  
  2467.   if (DosAllocMem((PPVOID)&fealist, 0x00010000L, AllocFlag)) {
  2468.     BUILDRXSTRING(retstr, ERROR_NOMEM);
  2469.     return VALID_ROUTINE;
  2470.   }
  2471.  
  2472.   eaop.fpFEA2List = (PFEA2LIST)fealist;/* Set memory for the FEA     */
  2473.   eaop.fpGEA2List = NULL;              /* GEA is unused              */
  2474.   pfea = &eaop.fpFEA2List->list[0];    /* point to first FEA         */
  2475.   pfea->fEA = '\0';                    /* set the flags              */
  2476.                                        /* Size of FEA name field     */
  2477.   pfea->cbName = (BYTE)args[1].strlength;
  2478.                                        /* Size of Value for this one */
  2479.   pfea->cbValue = (SHORT)args[2].strlength;
  2480.                                        /* Set the name of this FEA   */
  2481.   strcpy((PSZ)pfea->szName, args[1].strptr);
  2482.                                        /* Set the EA value           */
  2483.   memcpy((PSZ)pfea->szName+(pfea->cbName+1), args[2].strptr,
  2484.       args[2].strlength);
  2485.   pfea->oNextEntryOffset = 0;          /* no next entry              */
  2486.   eaop.fpFEA2List->cbList =            /* Set the total size var     */
  2487.       sizeof(ULONG) + sizeof(FEA2) + pfea->cbName + pfea->cbValue;
  2488.  
  2489.                                        /* set the file info          */
  2490.   rc = DosSetFileInfo(handle, 2, (PSZ)&eaop, sizeof(EAOP2));
  2491.   DosClose(handle);                    /* Close the File             */
  2492.   DosFreeMem(fealist);                 /* Free the memory            */
  2493.   sprintf(retstr->strptr, "%d", rc);   /* format return code         */
  2494.   retstr->strlength = strlen(retstr->strptr);
  2495.   return VALID_ROUTINE;
  2496. }
  2497.  
  2498. /*************************************************************************
  2499. * Function:  SysWaitNamedPipe                                            *
  2500. *                                                                        *
  2501. * Syntax:    result = SysWaitNamedPipe(name, timeout)                    *
  2502. *                                                                        *
  2503. * Params:    name - name of the pipe                                     *
  2504. *            timeout - amount of time to wait.                           *
  2505. *                                                                        *
  2506. * Return:    Return code from DosWaitNPipe                               *
  2507. *************************************************************************/
  2508.  
  2509. ULONG SysWaitNamedPipe(PUCHAR name, ULONG numargs, RXSTRING args[],
  2510.                        PSZ queuename, RXSTRING *retstr)
  2511. {
  2512.   LONG        rc;                      /* Ret code                   */
  2513.   LONG        timeout;                 /* timeout value              */
  2514.  
  2515.  
  2516.   if (numargs < 1 ||                   /* wrong number of arguments? */
  2517.       numargs > 2 ||
  2518.       !RXVALIDSTRING(args[0]))
  2519.     return INVALID_ROUTINE;            /* raise error condition      */
  2520.  
  2521.   if (numargs == 2) {                  /* have a timeout value?      */
  2522.     if (!string2long(args[1].strptr, &timeout) ||
  2523.         (timeout < 0 && timeout != -1))
  2524.       return INVALID_ROUTINE;          /* raise error condition      */
  2525.   }
  2526.  
  2527.   rc = DosWaitNPipe(args[0].strptr, timeout);
  2528.   sprintf(retstr->strptr, "%d", rc);
  2529.   retstr->strlength = strlen(retstr->strptr);
  2530.   return VALID_ROUTINE;
  2531. }
  2532.