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