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