home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 18 REXX / 18-REXX.zip / filerx11.zip / filerexx.INF (.txt) < prev    next >
OS/2 Help File  |  1995-09-22  |  87KB  |  2,865 lines

  1.  
  2. ΓòÉΓòÉΓòÉ 1. Introduction ΓòÉΓòÉΓòÉ
  3.  
  4. Please read this document in entirety.  I took the time to make it explicit, 
  5. clear, and very useful.  It took me longer to write it than it will ever take 
  6. you to read it.  Therefore, you owe it to both of us to read it.  OK? 
  7.  
  8. FILEREXX.DLL is a REXX Function Library.  It adds "commands" to the REXX 
  9. language, which a REXX script (ie, program) can call.  These commands offer 
  10. alternatives to the REXX file reading/writing routines which make it possible 
  11. to access the same files from multiple running scripts (ie, allow file 
  12. sharing). FileRexx also makes it much easier to read/write files containing 
  13. binary values.  There are also routines which vastly simplify device (ie, 
  14. driver) I/O, and make some driver control possible which standard REXX doesn't 
  15. allow.  Finally, FileRexx offers a lot more parsing options when reading a 
  16. line, thus eliminating the need to parse a line into separate pieces, or using 
  17. TRANSLATE to change the case. 
  18.  
  19. REXX has standard functions for opening files and reading/writing to those 
  20. files.  The STREAM command is used to open a file.  Then, data is read from 
  21. and/or written to the file via other standard functions such as CHAROUT, 
  22. CHARIN, LINEOUT, etc. 
  23.  
  24. The STREAM command opens a file without allowing READ or WRITE sharing.  What 
  25. this means is that another program cannot have that file open simultaneously. 
  26. Normally, you don't want two programs to be simultaneously writing to a file 
  27. under a true multi-tasking OS, since data that one program is writing may be 
  28. overwritten by the other program when a task switch occurs.  If the programs 
  29. are appending data to the end of the file, the result could be an arbitrary 
  30. intermixing of data from the two programs.  So, preventing WRITE access is a 
  31. foolproof way to make sure that this situation doesn't happen, and this is 
  32. completely implemented by the OS (ie, it's transparent to the program). 
  33. Likewise, a program that is writing to a file may wish to prevent READ sharing, 
  34. so that other programs don't open and read from the file while its contents are 
  35. changing.  (A program that only reads from a file, and doesn't write to that 
  36. file, doesn't need to worry about sharing access.  After all, the contents of 
  37. the file will be in a static state unless some program writes to that file. 
  38. Normally, only a program that writes to a file specifies that sharing is to be 
  39. prevented.  Usually, such a program will open the file, write data to it, and 
  40. then close that file as soon as possible so that other programs can 
  41. subsequently open and access the file). 
  42.  
  43. The REXX STREAM command prevents both READ and WRITE sharing because REXX 
  44. doesn't know whether your program is going to read from or write to that 
  45. stream.  The STREAM command can be used both with functions that read from the 
  46. file (ie, CHARIN) and functions that write to the file (ie, CHAROUT).  So, REXX 
  47. assumes that preventing READ and WRITE sharing is the safest approach with the 
  48. STREAM command.  Unfortunately, this means that if any other program has a 
  49. particular file open, a REXX script can't open that file, even if the other 
  50. program is allowing sharing, because the STREAM command itself doesn't allow 
  51. that. 
  52.  
  53. A situation arose where a sysop wanted to write a REXX script that read the 
  54. contents of a "configuration" file that some BBS software created.  The BBS 
  55. software kept this file open all of the time that the software was running. 
  56. Unfortunately, this meant that the STREAM command could not open that file 
  57. while the BBS was running.  This sysop asked me to write a REXX Function 
  58. Library that contained new REXX commands for opening, reading, and writing 
  59. files, allowing shared access.  (Actually, he BEGGED me.  He whimpered and 
  60. sobbed and offered his family pet for sexual favors.  After all, he's a sysop). 
  61. Being the nice guy that I am (and also his french poodle is quite attractive), 
  62. I did so. 
  63.  
  64. Furthermore, these configuration files contained binary values (ie, not just 
  65. ascii text).  Because REXX needs to express all numeric variables as strings of 
  66. ascii digits (ie, a REXX variable with the value 147 is actually stored 
  67. internally as the string "147"), his REXX script had to read in each character 
  68. and convert it to an ascii digit.  To avoid all of this hassle, I added two 
  69. functions to the DLL to make it easy to read or write a binary CHAR (8-bit), 
  70. SHORT (16-bit), or LONG (32-bit) value, signed or unsigned, to/from a file. 
  71.  
  72. Finally, REXX has no facilities for controlling a device via DosDevIOCtl() (ie, 
  73. the device specific commands, such as the ASYNC RS232-C Control functions, 
  74. which can control a COM driver).  So, I added FileDevIOCtl(), a function that 
  75. allows you to create a generic call to DosDevIOCtl(), thereby doing driver 
  76. specific operations with most any driver.  In fact, you could even use FILEREXX 
  77. to create a REXX script to fully test the IOCTL interface of any driver that 
  78. you may be developing, or to develop applications which use that driver. 
  79. (Along with RXDLG.DLL, my Presentation Manager Interface for REXX, you could 
  80. even develop PM apps for your driver). 
  81.  
  82. In conclusion, FILEREXX offers a more direct interface to OS/2's file system 
  83. than standard commands such as STREAM, LINEIN, LINEOUT, etc, and therefore 
  84. offers more control over such things as file sharing and device I/O, plus it 
  85. has a few functions that make it easy to read/write binary files and 
  86. send/receive binary values to device drivers, and some extra line parsing 
  87. features that LINEIN doesn't have. 
  88.  
  89. This is version 1.  Don't worry.  It shouldn't kill you. 
  90.  
  91. Some of the words in this manual are highlighted in bold text, such as STREAM. 
  92. These refer to REXX commands, either standard ones, or new commands that the 
  93. FILEREXX DLL makes available to a REXX program.  Other words are in italics 
  94. such as FileHandle.  These refer to REXX variable names (ie, data within a REXX 
  95. program).  Words that are in colored text such as Read This are meant to be 
  96. emphasized. 
  97.  
  98.  
  99. ΓòÉΓòÉΓòÉ 2. Copyright ΓòÉΓòÉΓòÉ
  100.  
  101. This OS/2 Online Book and the related files FILEREXX.DLL, and REXX scripts 
  102. written by Jeff Glatt are all copyright 1995 by Jeff Glatt.  These files are 
  103. freely redistributable, and may be used by and distributed along with any 
  104. software, be it commercial or otherwise, provided that these files are not 
  105. internally modified, nor specifically sold as a complete product by themselves. 
  106. The only price that you have to pay is the one that you're already paying by 
  107. spending all of your time in front of a computer instead of developing 
  108. healthier outlets. 
  109.  
  110. NOT SO STANDARD DISCLAIMER: 
  111.  
  112. These programs are provided "as is" without warranty of any kind either 
  113. expressed or implied or tatooed in a place that only a few people have ever 
  114. seen, including but not limited to the implied warranties of merchantability, 
  115. fitness for a particular purpose, and the dubious assumption that the software 
  116. has been created by a sane individual who would never do anything that may hurt 
  117. you. The entire risk as to the results and performance of the programs is 
  118. assumed by you or someone who looks exactly like you.  Jeff Glatt does not 
  119. guarantee that the functions in these programs will meet your requirements, 
  120. especially if your requirements involve lots of latex and some docile, 
  121. domesticated animal.  Nor does Jeff Glatt warranty the programs to be 
  122. uninterruptable or error-free, although mercifully free of "General Protection 
  123. Faults".  If you use said programs, you can not say anything nasty about the 
  124. author, even if the programs inadvertently cause the erasure of your collection 
  125. of X-rated GIFs of a conservative, overweight and overrated TV "personality" 
  126. plooking himself vigorously with his royalty checks from some rancid paperback. 
  127. Jeff Glatt is not responsible for any damages as a result of anything that he 
  128. has done, or hasn't done, or was supposed to do but never got around to it, and 
  129. furthermore, he doesn't even care so leave him alone, ratface.  You may have 
  130. more or less protections in certain states of the union, depending upon how far 
  131. your local politician is willing to bend over for some bribe from a business 
  132. lobbyist.  Just remember that Jeff Glatt has no money, so don't bother suing 
  133. him as a result of any damages caused by this OS/2 program.  Tell your greasy 
  134. lawyer to go after IBM, and make sure that you pick 12 really stupid pinheads 
  135. for the jury.  If swallowed, induce vomiting immediately by contemplating the 
  136. asthetics of Microsoft Windows. 
  137.  
  138. OS/2 is a trademark of International Business Machines Corporation. 
  139.  
  140. Windows is a trademark of Microsoft Incorporated, and furthermore, Bill Gates 
  141. is to blame for it. 
  142.  
  143. If you have unreasonably presumptuous suggestions (ie, an enduser who expects 
  144. outrageous amounts of free support), snide comments, criticisms, and anything 
  145. else other than dollar bills, then send them to someone else because you got it 
  146. for free, and you know what you get for nothing?  On the other hand, any type 
  147. of positive contribution from other programmers is very much welcome and 
  148. encouraged as these are the only folks who can made things happen for OS/2. 
  149. IBM ain't gonna do it.  If you do need to contact the author, then either phone 
  150. some of the more prominent psychiatrict clinics in central New York state, or 
  151. try this: 
  152.  
  153. Jeff Glatt 
  154. 6 Sycamore Drive East 
  155. New Hartford, NY 13413 
  156. (315) 735-5350 
  157.  
  158. Sure, this copyright notice has attitude.  Get used to it, or kill yourself. 
  159.  
  160.  
  161. ΓòÉΓòÉΓòÉ 3. Installing and initializing FILEREXX ΓòÉΓòÉΓòÉ
  162.  
  163. FILEREXX.DLL should be copied to some directory along the LIBPATH specified in 
  164. your config.sys file.  That way, REXX will be able to find it when your REXX 
  165. script references it. 
  166.  
  167. In order to be able to call a given function in FILEREXX, your script must 
  168. first register that DLL function with REXX.  You do this using the standard 
  169. REXX command RXFUNCADD.  That function takes the name of the DLL which contains 
  170. the function (minus the .DLL extension), in this case FILEREXX, the name of the 
  171. function that you wish to call within the DLL (a list of available functions 
  172. will follow in this document), and the name that you'd like to assign to that 
  173. function (ie, so that your script can call it using a name different than its 
  174. real name). 
  175.  
  176. FILEREXX has a special function called FILELOADFUNCS.  A call to this one 
  177. function causes it to register all of the other functions in the DLL.  This 
  178. means that you don't have to do a separate RXFUNCADD for every FILEREXX 
  179. function that you wish to call.  Of course, you do have to initially call 
  180. RXFUNCADD for FILELOADFUNCS, so that you can call this one FILEREXX function 
  181. initially.  Here's an example REXX script that does a RXFUNCADD on 
  182. FILELOADFUNCS, and then calls FILELOADFUNCS.  After this, the REXX script may 
  183. call any other functions in FILEREXX. 
  184.  
  185. CALL RxFuncAdd 'FileLoadFuncs', 'FILEREXX', 'FileLoadFuncs' 
  186. CALL FileLoadFuncs 
  187.  
  188.  
  189. ΓòÉΓòÉΓòÉ 4. FILEREXX Functions ΓòÉΓòÉΓòÉ
  190.  
  191. Here are the FILEREXX functions that you can call.  Each function is on its own 
  192. page.  The name of the function is in the title bar of the window.  Listed on 
  193. the page below is its syntax (ie, what parameters you pass to it and what it 
  194. returns), as well as an example of its use.  You'll note that all functions 
  195. begin with the letters File. 
  196.  
  197. The functions are broken up into subsections.  From example, all of the 
  198. functions that concern writing data to a file or device (as opposed to, for 
  199. example, listing or processing the name of a file) are under the heading 
  200. Writing Data to a File/Device. 
  201.  
  202. If any of the functions are passed a zero handle (ie, an error return from 
  203. FileOpen), then they usually perform no work upon that handle.  Always do error 
  204. checking upon the returns from FILEREXX functions.  Failure to supply required 
  205. arguments (or invalid arguments) cause a REXX error condition.  Other file 
  206. system errors do not cause a REXX error condition, but return an appropriate 
  207. error number to your script.  For example, if a device returns some error to 
  208. FileDevIOCtl(), then that error number is returned by FileDevIOCtl(), but the 
  209. REXX ERROR or FAILURE Flags aren't set.  It's up to the script to check 
  210. returned values for any errors in performing an operation. 
  211.  
  212.  
  213. ΓòÉΓòÉΓòÉ 4.1. DLL Setup and Cleanup ΓòÉΓòÉΓòÉ
  214.  
  215. These functions are used at the beginning and end of your REXX script, to 
  216. perform setup and cleanup of resources associated with using FILEREXX. 
  217.  
  218.  
  219. ΓòÉΓòÉΓòÉ 4.1.1. FileAddFuncs ΓòÉΓòÉΓòÉ
  220.  
  221. Syntax         Call FileLoadFuncs 
  222.  
  223. Args           None 
  224.  
  225. Returns        None 
  226.  
  227. Purpose        Registers all of the REXX functions in FILEREXX.DLL, so that a 
  228.                REXX script can subsequently call them without having to do a 
  229.                separate RXFUNCADD for each desired function. 
  230.  
  231. Examples       CALL FileLoadFuncs 
  232.  
  233.  
  234. ΓòÉΓòÉΓòÉ 4.1.2. FileDropFuncs ΓòÉΓòÉΓòÉ
  235.  
  236. Syntax         Call FileDropFuncs 
  237.  
  238. Args           None 
  239.  
  240. Returns        None 
  241.  
  242. Purpose        DeRegisters all of the REXX functions in FILEREXX.DLL.  A REXX 
  243.                script cannot subsequently call them, until it registers those 
  244.                functions again.  Normally, this is only used at the end of a 
  245.                script to allow REXX to purge the DLL from memory after it is no 
  246.                longer needed. 
  247.  
  248. Examples       CALL FileDropFuncs 
  249.  
  250.  
  251. ΓòÉΓòÉΓòÉ 4.2. Open/Close a File/Device ΓòÉΓòÉΓòÉ
  252.  
  253. FileOpen is used to open a file or device.  You must open a file/device before 
  254. you use any functions that read or write data to that file/device, such as 
  255. FilePuts or FileGets, or other functions that require a file handle argument. 
  256. FileClose is used to close a file or device.  You must close a file/device 
  257. after you're done writing or reading however much data that you desire from it. 
  258.  
  259. Definitely close all (successfully) open files before your program ends.  That 
  260. is to say, every time that FileOpen returns a non-zero handle to you, make sure 
  261. that you later pass that handle to FileClose once.  A good approach is to have 
  262. separate "handle" variables for each file/device that you ever intend to open. 
  263. Set them all to 0 at the start of your program.  Whenever you finally close the 
  264. handle, reset it to 0.  Right before your program ends, check all of those 
  265. handle variables, and if any one isn't 0, pass it to FileClose.  Example: 
  266.  
  267. /* I intend to open 2 files and 1 device. So I have 3 handle variables. 
  268. Initially set them to 0 */ 
  269. handle.1 = 0 
  270. handle.2 = 0 
  271. handle.3 = 0 
  272.  
  273. Label: 
  274.  
  275. /* Here you maybe open a file */ 
  276. handle.1 = FileOpen('myfile') 
  277. IF handle.1 <> 0 THEN DO 
  278.  
  279.   /* Here you probably do something with that file */ 
  280.  
  281.   /* Let's say that you're done using the file now. Close it, and reset the 
  282. handle variable */ 
  283.   IF FileClose(handle.1) = 0 THEN handle.1 = 0 
  284.  
  285. END 
  286.  
  287. /* OK, maybe you want to loop around for some reason */ 
  288. SIGNAL Label 
  289.  
  290. /* Here's where we end the program. Check all of the handles to make sure that 
  291. they're 0 */ 
  292. DO i = 1 to 3 /* I had 3 handles */ 
  293.   IF handle.i <> 0 THEN CALL FileClose(handle.i) 
  294. END 
  295.  
  296. Note:  Handles returned by FileMatchFile should be closed by using 
  297.        FileMatchFile rather than FileClose.
  298.  
  299.  
  300. ΓòÉΓòÉΓòÉ 4.2.1. FileOpen ΓòÉΓòÉΓòÉ
  301.  
  302. Syntax         handle = FileOpen(filename, mode, Flags, attributes) 
  303.  
  304. Purpose        Opens a file (or device driver) for reading and writing, 
  305.                returning a file handle which the REXX script uses for calls to 
  306.                other DLL functions.  FileOpen is an alternative to using 
  307.                STREAM. 
  308.  
  309. Args           filename is the complete filename (ie, with path, if desired) to 
  310.                open.  For example: 'c:\mydir\myfile'.  This can also be the 
  311.                name of a device driver, but you must use the internal name of 
  312.                the driver, which may not necessarily be the same as its 
  313.                filename on disk.  (Usually, the internal name is simply the 
  314.                driver's filename minus the .SYS extension). 
  315.  
  316.                mode is a string of characters where each character may be one 
  317.                of the following: 
  318.                   'r'    Allows reading from the file or driver (with FileRead, 
  319.                FileGets, and FileReadValue).  'w' can be specified also if 
  320.                writing is desired. 
  321.                   'w'   Allows writing to the file or driver (with FileWrite, 
  322.                FilePuts, and FileWriteValue).  'r' can be specified also if 
  323.                reading is desired. 
  324.                   's'   Sharing.  Two characters may follow the 's'.  These two 
  325.                characters indicate the sharing status for READ and WRITE 
  326.                respectively.  Sharing is enabled if the character is '+', and 
  327.                denied if the character is '-'.  So, if you want READ sharing 
  328.                with no WRITE sharing, you specify 's+-'.  If you want no READ 
  329.                sharing but with WRITE sharing, you specify 's-+'.  If you want 
  330.                no READ or WRITE sharing (ie, deny both), then you specify, 
  331.                's--'.  If you want both READ and WRITE sharing, you specify 
  332.                's++', or simply 's' since that is considered the same as 's++'. 
  333.                Sharing works like this.  If you deny WRITE sharing, no other 
  334.                program can have that file (or driver) open for writing, 
  335.                although reading is OK, in order for your open to succeed, and 
  336.                afterward, no other program can open the file for writing until 
  337.                you close it, although another program can open it for reading. 
  338.                If you deny READ sharing, no other program can have that file 
  339.                open for reading, although writing is OK, in order for your open 
  340.                to succeed, and afterward, no other program can open the file 
  341.                for reading until you close it, although another program can 
  342.                open it for writing.  If you deny READ and WRITE sharing, no 
  343.                other program can have that file open in order for your open to 
  344.                succeed, and afterward, no other program can open that file 
  345.                until you close it.  If you don't deny READ and WRITE sharing 
  346.                (and no other program has either), then any other program can 
  347.                open the file. 
  348.                   'c'   The opened file handle isn't passed on to child 
  349.                processes. 
  350.                   'a'   Sequential or Random Access.  A '+' or '-' character 
  351.                may follow the 'a'.  If a '+', then Random Access is selected. 
  352.                If a '-', then Sequential access is selected.  'a' is the same 
  353.                as 'a-'. 
  354.                   'b'   Output (ie, FileWrite, FileWriteValue, FilePuts) is not 
  355.                put in the hardware cache. 
  356.                   'e'   Report errors to caller.  This is with the OS, not 
  357.                between your script and FILEREXX. 
  358.                   'v'    Do not return until output is written to the device. 
  359.                   If the mode arg is not supplied, it defaults to 'rs+-'.  The 
  360.                order of mode parameters is irrelevant. 
  361.  
  362.                Flags is a string of characters where each character may be one 
  363.                of the following: 
  364.                   'v'    Fail if the file/driver already exists.  This can't be 
  365.                specified along with any of the other 3 options. 
  366.                   'e'    Open the file/driver if it exists, otherwise fail if 
  367.                it does not. 
  368.                   'o'    Overwrite any file that exists with the same name. 
  369.                   'n'    Create a new file if one with this name doesn't 
  370.                already exist. 
  371.                   If the Flags arg is not supplied, it defaults to 'e'.  The 
  372.                order of Flags is irrelevant. 
  373.  
  374.                attributes is the desired file attributes of the file, if 
  375.                creating it.  These can be any sensible combination of the 
  376.                following (where you simply add the values that you desire): 
  377.                   0    Normal File or Driver 
  378.                   1    Read-Only 
  379.                   2    Hidden 
  380.                   4    System 
  381.                  16    Directory 
  382.                  32    Archived 
  383.                   If the attributes arg is not supplied, it defaults to 0 
  384.                (Normal File). 
  385.  
  386. Returns        If this function was successful, the handle of the opened file 
  387.                or driver is returned, and this will not be 0.  This handle is 
  388.                passed to other FILEREXX functions.  The REXX variable, FileErr 
  389.                is also set to the action taken by FileOpen, and can be one of 
  390.                the following values: 
  391.  
  392.                1   file/driver existed 
  393.                2   file was created 
  394.                3   file length was truncated 
  395.  
  396.                If an error, a 0 is returned, and the REXX variable, FileErr is 
  397.                set to 0. 
  398.  
  399. Examples       /* Open a file named 'c:\blort' for reading/writing.  Specify 
  400.                Flags as 'on' to overwrite any existing file with the same name, 
  401.                or create a new file if it doesn't exist.  Specify mode as 'rws' 
  402.                in order to read and write to the file, and allow READ and WRITE 
  403.                sharing.  Specify attributes as 0 for normal file, although we 
  404.                don't need to supply this arg as that's the default. 
  405.                */ 
  406.                handle = FileOpen('c:\blort', 'rws', 'on', 0) 
  407.                IF handle = 0 THEN SAY 'error' 
  408.  
  409.                /* Open a file named 'myfile' for reading.  Specify Flags as 'e' 
  410.                to only open the file if it already exists. Specify mode as 'r' 
  411.                in order to read from the file.  Since we didn't specify 
  412.                sharing, we accept the default of allowing READ sharing but no 
  413.                WRITE sharing.  Since the attributes arg is omitted, it defaults 
  414.                to 0 for normal file. This could also be used to check if a file 
  415.                exists before writing to that filename; if the returned handle 
  416.                is 0, then you can open the file again for writing and create a 
  417.                new file. 
  418.                */ 
  419.                handle = FileOpen('myfile', 'r', 'e') 
  420.                IF handle = 0 THEN SAY 'error' 
  421.  
  422.                /* Same as above, since the default for mode is 'rs+-' and 
  423.                default for Flags is 'e'. 
  424.                */ 
  425.                handle = FileOpen('myfile') 
  426.                IF handle = 0 THEN SAY 'error' 
  427.  
  428.                /* Open a file named 'c:\blort' for writing.  Specify Flags as 
  429.                'n' to create a new file if it doesn't exist, but we aren't 
  430.                going to overwrite any existing file.  Specify mode as 'ws--' in 
  431.                order to write to the file, and prevent READ and WRITE sharing. 
  432.                */ 
  433.                handle = FileOpen('c:\blort', 'ws--', 'n') 
  434.                IF handle = 0 THEN SAY 'error' 
  435.  
  436.                /* Open the COM1 device driver for reading/writing.  Allow both 
  437.                read and write sharing. 
  438.                */ 
  439.                handle = FileOpen('COM1', 'rws') 
  440.                IF handle = 0 THEN SAY 'error' 
  441.  
  442.  
  443. ΓòÉΓòÉΓòÉ 4.2.2. FileClose ΓòÉΓòÉΓòÉ
  444.  
  445. Syntax         err = FileClose(handle) 
  446.  
  447. Purpose        Closes a file or driver that was opened with FileOpen.  A 
  448.                file/driver that is successfully opened with FileOpen must 
  449.                always be closed after the REXX script is finished accessing the 
  450.                file/driver. 
  451.  
  452. Args           handle is the opened handle as returned by FileOpen. 
  453.  
  454. Returns        If successful, a 0 is returned. 
  455.  
  456.                If an error, a non-zero value is returned which represents the 
  457.                error number from DosClose. 
  458.  
  459. Examples       /* Open a file named 'myfile' for reading. */ 
  460.                handle = FileOpen('myfile', 'r', 'e') 
  461.                IF handle = 0 THEN SAY 'error opening file' 
  462.                err = FileClose(handle) 
  463.                IF err <> 0 THEN SAY 'error closing file' 
  464.  
  465.  
  466. ΓòÉΓòÉΓòÉ 4.3. Read data from a File/Device ΓòÉΓòÉΓòÉ
  467.  
  468. These functions are used to read data from a file or device.  You must open a 
  469. file/device with FileOpen before you use these functions.  FileRead is used to 
  470. read individual (8-bit) characters, or a specific number of characters from a 
  471. file/device.  It's essentially an equivalent to CHARIN.  No translation is 
  472. performed upon the data.  So if you happen to read a text file (ie, containing 
  473. ascii characters), you get ascii characters back.  All REXX variables, even 
  474. numeric ones, are stored internally as ascii strings.  So as long as you read 
  475. ascii data, you can perform math on any numeric values.  But if you need to 
  476. read binary data (and most non-REXX programs and device drivers read/write 
  477. numeric data in binary), you should use FileReadValue.  This automatically 
  478. reads a binary LONG (32-bit value), SHORT (16-bit value), or CHAR (8-bit) 
  479. value, translating it to an equivalent REXX ascii string.  Finally, FileGets is 
  480. essentially an alternative to LINEIN, but with built-in parsing options. 
  481.  
  482.  
  483. ΓòÉΓòÉΓòÉ 4.3.1. FileRead ΓòÉΓòÉΓòÉ
  484.  
  485. Syntax         contents = FileRead(handle, count) 
  486.  
  487. Purpose        Reads in 8-bit characters from an open file or driver, and 
  488.                returns them to the REXX script.  No translation is performed 
  489.                upon the characters.  So, if you read in a binary character of 
  490.                6, then that's what is returned to your script.  Remember that 
  491.                REXX internally stores all variables as ascii strings, including 
  492.                numeric variables, so if you want the returned string to be the 
  493.                value 6, you'll have to convert the returned character into hex 
  494.                36 (ie, an ascii '6'), or use FileReadValue instead.  FileRead 
  495.                is an alternative to using CHARIN for reading ascii text 
  496.                characters from a file or driver. 
  497.  
  498.                Note:  This function can be used in combination with FileGets, 
  499.                       FileReadBlock, or FileReadValue upon the same handle.
  500.  
  501. Args           handle is the opened handle as returned by FileOpen. 
  502.  
  503.                count is the number of 8-bit characters to read.  If not 
  504.                supplied, this defaults to 1 (ie, for reading the next character 
  505.                in the file/driver). 
  506.  
  507. Returns        If success, the requested number of characters are read from the 
  508.                file/driver and returned to the REXX script.  Note that some 
  509.                drivers may cause the REXX script to be suspended if the driver 
  510.                doesn't have as many characters as you've requested, until such 
  511.                time as the requested number of characters are received by the 
  512.                driver (by its device).  Other drivers may do some sort of 
  513.                timeout if it is necessary to wait for more characters, after 
  514.                which the driver will return however many characters it could 
  515.                fill of your request.  Furthermore, if you try to read more 
  516.                characters from a file than are remaining in the file, you'll 
  517.                only get as characters as are remaining.  So, it's possible to 
  518.                get less characters back than you requested. 
  519.  
  520.                If an error or the end of file, a null string is returned. 
  521.                Also, some drivers that have no characters ready to be read, but 
  522.                which don't suspend the REXX script until the requested 
  523.                characters are received, may return a null string. 
  524.  
  525. Examples       /* Open 'myfile' for reading */ 
  526.                handle = FileOpen('myfile') 
  527.                IF handle <> 0 THEN DO 
  528.                   /* Read 10 characters and print them */ 
  529.                   contents = FileRead(handle, 10) 
  530.                   IF contents <> "" THEN SAY contents 
  531.                   /* Read 1 more character */ 
  532.                   contents = FileRead(handle) 
  533.                   IF contents <> "" THEN SAY contents 
  534.                   err = FileClose(handle) 
  535.                END 
  536.  
  537.  
  538. ΓòÉΓòÉΓòÉ 4.3.2. FileGets ΓòÉΓòÉΓòÉ
  539.  
  540. Syntax         line = FileGets(handle, Flags, rightseparators, leftseparators) 
  541.  
  542. Purpose        Reads in one line of text from an open file/driver, returning 
  543.                that to the REXX script.  No translation is done on any of the 
  544.                characters of the line (so this should be used merely as an 
  545.                alternative to the standard REXX command LINEIN). 
  546.  
  547.                For parsing, this can break up the line into several pieces and 
  548.                place those pieces in a stem variable for easy processing. 
  549.  
  550.                Note:  A line limit of 256 characters is imposed.  Trying to 
  551.                       read a longer line will result in the first 255 
  552.                       characters being returned as if that was the next line in 
  553.                       the file, and a subsequent call to FileGets will begin 
  554.                       reading on the 256th character of the oversized line.  If 
  555.                       parsing, the 256 character limit applies to each arg, but 
  556.                       not the entire line.
  557.  
  558.                Note:  This function can be used in combination with FileRead, 
  559.                       FileReadBlock, or FileReadValue upon the same handle.
  560.  
  561. Args           handle is the opened handle as returned by FileOpen. 
  562.  
  563.                Flags is a string containing any of the following: 
  564.                   't'  Trim off spaces at the head and tail of the line (or 
  565.                each arg if parsing the line). 
  566.                   's'  Compress spaces (ie, replace all instances of more than 
  567.                one space in a row, with one space). 
  568.                   'c'  Make all letters (ie, A to Z) in the line (or each arg 
  569.                if parsing the line) upper or lower case.  If a '-' sign appears 
  570.                after the 'c', that means lower case.  If a '+' appears (or no 
  571.                sign is specified), that's upper case. 
  572.                   'r'  Step match rightseparators.  Search for only the first 
  573.                separator when parsing the first arg, search for only the second 
  574.                separator when parsing the second arg, etc.  If a '+' appears 
  575.                after the 'r', then if there are more args in the line than 
  576.                rightseparator characters, use the last separator character to 
  577.                parse the extra args. 
  578.                   'l'  Step match leftseparators.  Search for only the first 
  579.                separator when parsing the last arg, search for only the second 
  580.                separator when parsing the next to last arg, etc.  If a '+' 
  581.                appears after the 'l', then if there are more args in the line 
  582.                than leftseparator characters, use the last separator character 
  583.                to parse the extra args. 
  584.                   If Flags is omitted (or a null string), the default is none 
  585.                of the above.  The order of Flags is irrelevant. 
  586.  
  587.                rightseparators is a string of characters where any one of those 
  588.                characters causes the line to be parsed into a separate arg at 
  589.                that point.  This can cause the line to be broken up into many 
  590.                args, and each arg is stored in the REXX stem variable FILEARG. 
  591.                So, the first parsed arg is in FILEARG.1, the second arg is 
  592.                FILEARG.2, etc, and the number of args parsed is stored in 
  593.                FILEARG.0.  If rightseparators is a null string (ie, ""), then 
  594.                that is the same as omitting the rightseparators arg. 
  595.  
  596.                leftseparators is a string of characters where any one of those 
  597.                characters causes the line to be parsed into a separate arg at 
  598.                that point.  This can cause the line to be broken up into many 
  599.                args, and each arg is stored in the REXX stem variable FILEARG. 
  600.                The difference between rightseparators and leftseparators is 
  601.                that the latter breaks off args from the end of the line, 
  602.                whereas the former breaks off args from the front of the line. 
  603.                So, the last parsed arg for leftseparators is placed in 
  604.                FILEARG.1, the second to last arg is placed in FILEARG.2, etc, 
  605.                and the number of args parsed is stored in FILEARG.0.  If 
  606.                leftseparators is a null string (ie, ""), then that is the same 
  607.                as omitting the leftseparators arg.  If both rightseparators and 
  608.                leftseparators are specified, then the rightseparators args are 
  609.                broken off first, and then leftseparators breaks args off of any 
  610.                remaining text on the line. 
  611.  
  612.                Note:  If rightseparators and/or leftseparators are omitted (or 
  613.                       both are null strings), then the line isn't broken up 
  614.                       into separate args (ie, it's returned as one string) and 
  615.                       FILEARG is not used.
  616.  
  617. Returns        The return depends upon whether you are parsing the line into 
  618.                separate args (ie, you have specified a string of separators), 
  619.                or whether you are reading the line as one string. 
  620.  
  621.                For reading the line as one string: 
  622.                   If successful, the entire line contents are returned (ie, all 
  623.                of the characters from the current position in the file up to 
  624.                the newline character).  The final newline and any line feeds 
  625.                are stripped from the line.  The REXX variable, FileErr is set 
  626.                to the number of characters in the line, plus 1. 
  627.                   If an error or end of the file, a null string (ie, "") is 
  628.                returned, and the REXX variable, FileErr is set to 0. 
  629.  
  630.                Note:  A blank line in the file will return a null string, but FileErr=1.
  631.  
  632.                For parsing the line into separate args: 
  633.                   If successful, each arg is returned in the REXX stem variable 
  634.                FILEARG.  So, the first parsed arg is in FILEARG.1, the second 
  635.                arg is FILEARG.2, etc.  The number of args parsed is stored in 
  636.                FILEARG.0. 
  637.                   If an error or end of the file, the REXX stem variable 
  638.                FILEARG.0 is set to 0. 
  639.  
  640.                Note:  A blank line in the file will return FileArg.0=1 and FileArg.1="".
  641.  
  642. Examples       /* Open 'myfile' for reading */ 
  643.                handle = FileOpen('myfile') 
  644.                IF handle <> 0 THEN DO 
  645.                   /* Read the next line and print it.  If no more lines, exit 
  646.                */ 
  647.                   contents = FileGets(handle) 
  648.                   IF FileErr = 0 THEN LEAVE 
  649.                   SAY contents 
  650.                END 
  651.                err = FileClose(handle) 
  652.  
  653.                /* Open 'myfile' for reading */ 
  654.                handle = FileOpen('myfile') 
  655.                linenum=1 
  656.                IF handle <> 0 THEN DO 
  657.                   /* Read the next line, separating each arg by a blank space 
  658.                   between them.  Also, trim leading and trailing spaces off 
  659.                   of each arg.  Print the args.  If no more lines, exit 
  660.                   */ 
  661.                   FileGets(handle, 't', ' ') 
  662.                   IF FileArg.0 = 0 THEN LEAVE 
  663.                   DO i = 1 to FileArg.0 
  664.                     SAY "line #"linenum": Arg #"i"="FileArg.i 
  665.                   END 
  666.                   linenum = linenum+1 
  667.                END 
  668.                err = FileClose(handle) 
  669.  
  670.  
  671. ΓòÉΓòÉΓòÉ 4.3.3. FileReadValue ΓòÉΓòÉΓòÉ
  672.  
  673. Syntax         value = FileReadValue(handle, size, sign, Flags) 
  674.  
  675. Purpose        Reads in the next 1, 2, or 4 bytes (ie, 8-bit values) from an 
  676.                open file/driver (depending upon whether size is 1, 2 or 4), and 
  677.                returns a numeric value to the REXX script representing such. 
  678.                This allows a REXX script to read binary CHAR, UCHAR, SHORT, 
  679.                USHORT, LONG, and ULONG values from a file, and have them 
  680.                returned in REXX form (ie, as a string of ascii digits 
  681.                representing that number). 
  682.  
  683.                Note:  This function can be used in combination with FileRead, 
  684.                       FileReadBlock, or FileGets upon the same handle.
  685.  
  686. Args           handle is the opened handle as returned by FileOpen. 
  687.  
  688.                size is the size of the value to read; char, short, or long (ie, 
  689.                1, 2, or 4).  A char is 8-bits (ie, the next byte in the 
  690.                file/driver).  A short is 16-bits (ie, the next 2 bytes in the 
  691.                file/driver).  A long is 32-bits (ie, the next 4 bytes in the 
  692.                file/driver).  If this arg is not supplied, then char is 
  693.                assumed. 
  694.  
  695.                sign determines whether the value is expressed as an unsigned 
  696.                ('+') or signed ('-') quantity.  For unsigned char, the range is 
  697.                0 to 255.  For signed char, the range is -128 to 127.  For 
  698.                unsigned short, the range is 0 to 65,535.  For signed short, the 
  699.                range is -32,768 to 32,767.  For unsigned long, the range is 0 
  700.                to 4,294,947,295.  For signed long, the range is -2,147,483,648 
  701.                to 2,147,483,647.  If sign is omitted, unsigned ('+') is 
  702.                assumed. 
  703.  
  704.                Flags is any of the following: 
  705.                   'm'  Read short or long values that are stored in Motorola 
  706.                format (ie, MSB comes first, and LSB is last, versus Intel 
  707.                format where LSB comes first, and MSB is last). 
  708.                   'h'  Return the value expressed in hexadecimal format.  A X 
  709.                is not appended after the value, so it is up to your script to 
  710.                convert the value to decimal using REXX's X2D is you wish to 
  711.                perform any mathematical operations upon it.  For example, if 
  712.                you set this flag and read a USHORT hexidecimal value of F001, 
  713.                'F001' is returned. 
  714.                   'b'  Return the value expressed in binary format (ie, each 
  715.                bit is its own digit; a 0 or 1).  It is up to your script to 
  716.                convert the value to decimal using REXX's B2X and X2D is you 
  717.                wish to perform any mathematical operations upon it.  For 
  718.                example, if you set this flag and read a USHORT binary value of 
  719.                0110 1111 0000 0001 (ie, hexadecimal 6F01), then 
  720.                '0110111100000001' is returned. 
  721.                   If Flags is omitted, then it defaults to none of the above. 
  722.                The order of Flags is irrelevant. 
  723.  
  724. Returns        If success, the binary char, short, or long, is read from the 
  725.                file/driver and returned to the REXX script (ie, expressed as an 
  726.                ascii string of digits -- the way that REXX internally expresses 
  727.                numeric variables). 
  728.  
  729.                If an error or the end of file, a null string is returned. 
  730.  
  731. Examples       /* Open 'myfile' for reading */ 
  732.                handle = FileOpen('myfile') 
  733.                IF handle <> 0 THEN DO 
  734.                   /* Read a signed char and print it */ 
  735.                   contents = FileReadValue(handle, 1, '-') 
  736.                   IF contents <> "" THEN SAY contents 
  737.                   /* Read a signed short (Intel format) and print it */ 
  738.                   contents = FileReadValue(handle, 2, '-') 
  739.                   IF contents <> "" THEN SAY contents 
  740.                   /* Read a unsigned short and print it */ 
  741.                   contents = FileReadValue(handle, 2) 
  742.                   IF contents <> "" THEN SAY contents 
  743.                   /* Read an unsigned char and print it */ 
  744.                   contents = FileReadValue(handle) 
  745.                   IF contents <> "" THEN SAY contents 
  746.                   /* Read a signed long and print it */ 
  747.                   contents = FileReadValue(handle, 4, '-') 
  748.                   IF contents <> "" THEN SAY contents 
  749.                   /* Read an unsigned short (in Motorola format), expressed in 
  750.                binary, and print it */ 
  751.                   contents = FileReadValue(handle, 2, '+', 'mb') 
  752.                   IF contents <> "" THEN SAY contents 
  753.                   err = FileClose(handle) 
  754.                END 
  755.  
  756.  
  757. ΓòÉΓòÉΓòÉ 4.3.4. FileReadBlock ΓòÉΓòÉΓòÉ
  758.  
  759. Syntax         contents = FileReadBlock(handle, variable count) 
  760.  
  761. Purpose        Reads in 8-bit characters from an open file or driver, converts 
  762.                each byte to its REXX numeric value and stores that in the 
  763.                specified stem variable.  FileReadBlock is an alternative to 
  764.                using FileRead for reading in numerous binary characters from a 
  765.                file or driver which you want converted to REXX numeric values. 
  766.  
  767.                Note:  This function can be used in combination with FileGets, 
  768.                       FileRead, or FileReadValue upon the same handle.
  769.  
  770. Args           handle is the opened handle as returned by FileOpen. 
  771.  
  772.                variable is the name of the stem variable where you want the 
  773.                values to be stored. 
  774.  
  775.                count is the number of 8-bit characters to read.  If not 
  776.                supplied, this defaults to 1 (ie, for reading the next character 
  777.                in the file/driver). 
  778.  
  779. Returns        If success, the requested number of characters are read from the 
  780.                file/driver, stored in the stem variable, and the total number 
  781.                of values read is returned to the REXX script. Note that some 
  782.                drivers may cause the REXX script to be suspended if the driver 
  783.                doesn't have as many characters as you've requested, until such 
  784.                time as the requested number of characters are received by the 
  785.                driver (by its device).  Other drivers may do some sort of 
  786.                timeout if it is necessary to wait for more characters, after 
  787.                which the driver will return however many characters it could 
  788.                fill of your request.  Furthermore, if you try to read more 
  789.                characters from a file than are remaining in the file, you'll 
  790.                only get as characters as are remaining.  So, it's possible to 
  791.                get less values back than you requested, including even 0, if 
  792.                the end of file is reached, or if a driver has no characters 
  793.                ready to be read, but doesn't suspend the REXX script waiting 
  794.                for characters to be received. 
  795.  
  796.                If an error, a null string is returned.  Also, some drivers that 
  797.                have no characters ready to be read, but which don't suspend the 
  798.                REXX script until the requested characters are received, may 
  799.                return a null string. 
  800.  
  801. Examples       /* Open 'myfile' for reading */ 
  802.                handle = FileOpen('myfile') 
  803.                IF handle <> 0 THEN DO 
  804.                   /* Read upto 10 values into BLORT.X and print them */ 
  805.                   count = FileReadBlock(handle, 'blort', 10) 
  806.                   IF count <> "" THEN DO 
  807.                     DO i = 1 TO count 
  808.                       SAY blort.count 
  809.                     END 
  810.                   END 
  811.                   err = FileClose(handle) 
  812.                END 
  813.  
  814.  
  815. ΓòÉΓòÉΓòÉ 4.4. Write data to a File/Device ΓòÉΓòÉΓòÉ
  816.  
  817. These functions are used to write data to a file or device.  You must open a 
  818. file/device with FileOpen before you use these functions.  FileWrite is used to 
  819. write individual (8-bit) characters, or a specific number of characters to a 
  820. file/device.  It's essentially an equivalent to CHAROUT.  No translation is 
  821. performed upon the data.  All REXX variables, even numeric ones, are stored 
  822. internally as ascii strings.  So whatever you write to a file/device is seen by 
  823. the file system or device as ascii text.  But if you need to write out binary 
  824. data (and most non-REXX programs and device drivers expect to deal with numeric 
  825. data in binary), you should use FileWriteValue.  This automatically translates 
  826. some REXX numeric value to its respecitve binary LONG (32-bit value), SHORT 
  827. (16-bit value), or CHAR (8-bit) value, before writing it to disk or sending it 
  828. to a device.  Finally, FilePuts is essentially an alternative to LINEOUT. 
  829.  
  830.  
  831. ΓòÉΓòÉΓòÉ 4.4.1. FileWrite ΓòÉΓòÉΓòÉ
  832.  
  833. Syntax         actual = FileWrite(handle, contents, count) 
  834.  
  835. Purpose        Writes out characters (ie, 8-bit bytes) to an open file or 
  836.                driver.  No translation is performed upon the characters. 
  837.                Remember that REXX internally stores all variables as ascii 
  838.                strings, including numeric variables, so if you want to write 
  839.                out binary values, use FileWriteValue instead.  FileWrite is an 
  840.                alternative to using CHAROUT for writing ascii text characters 
  841.                to a file. 
  842.  
  843.                Note:  This function can be used in combination with FilePuts or 
  844.                       FileWriteValue upon the same handle.
  845.  
  846. Args           handle is the opened handle as returned by FileOpen. 
  847.  
  848.                contents is the string of characters to write to the 
  849.                file/driver. 
  850.  
  851.                count is the number of bytes to write to the file/driver (ie, 
  852.                number of characters in the passed contents).  If not supplied, 
  853.                this defaults to 1 (ie, for writing one passed character to the 
  854.                file/driver). 
  855.  
  856. Returns        This returns the number of bytes (ie, characters) actually 
  857.                written out.  So, if successful, this will return the same value 
  858.                as count. 
  859.  
  860.                If an error, it will return 0 or a mismatch with count. 
  861.  
  862. Examples       /* Open 'myfile' for writing */ 
  863.                handle = FileOpen('myfile', 'ws--', 'on') 
  864.                IF handle <> 0 THEN DO 
  865.                   /* Write 10 characters (ie, 0123456789) */ 
  866.                   err = FileWrite(handle, '0123456789', 10) 
  867.                   IF err <> 10 THEN SAY 'error' 
  868.                   /* Write 1 more character */ 
  869.                   mychar = '*'  /* Just for the hell of it, store in a variable 
  870.                */ 
  871.                   err = FileWrite(handle, mychar) 
  872.                   IF err <> 1 THEN SAY 'error' 
  873.                   err = FileClose(handle) 
  874.                END 
  875.  
  876.  
  877. ΓòÉΓòÉΓòÉ 4.4.2. FilePuts ΓòÉΓòÉΓòÉ
  878.  
  879. Syntax         actual = FilePuts(handle, line) 
  880.  
  881. Purpose        Writes out one line of text to an open file or driver.  No 
  882.                translation is done on any of the characters of the line (so 
  883.                this should be used merely as an alternative to the standard 
  884.                REXX command LINEOUT).  There is no limit on the line length. 
  885.  
  886.                Note:  This function can be used in combination with FileWrite 
  887.                       or FileWriteValue upon the same handle.
  888.  
  889. Args           handle is the opened handle as returned by FileOpen. 
  890.  
  891.                line are the characters to write to the file/driver as a line of 
  892.                text.  FILEREXX automatically appends a line feed and newline 
  893.                character to the end of the line written out. 
  894.  
  895.                Note:  If no line arg is supplied (or a null string), then only 
  896.                       a line feed and newline character are written out.  So, 
  897.                       this can be used to "close" a line after numerous calls 
  898.                       to FileWrite to write out separate characters of a line.
  899.  
  900. Returns        If successful, this returns the number of characters written 
  901.                out, including the line feed and newline characters appended to 
  902.                the line. 
  903.  
  904.                If an error, it returns 0 or a mismatch with the number of 
  905.                characters that you attempted to write (plus 2). 
  906.  
  907. Examples       /* Open 'myfile' for writing */ 
  908.                handle = FileOpen('myfile', 'ws--', 'on') 
  909.                IF handle <> 0 THEN DO 
  910.                   /* Write the characters 0123456789 as a line */ 
  911.                   err = FilePuts(handle, '0123456789') 
  912.                   IF err <> 12 THEN SAY 'error' 
  913.                   err = FileClose(handle) 
  914.                END 
  915.  
  916.  
  917. ΓòÉΓòÉΓòÉ 4.4.3. FileWriteValue ΓòÉΓòÉΓòÉ
  918.  
  919. Syntax         actual = FileWriteValue(handle, values, size, Flags) 
  920.  
  921. Purpose        Writes out one or more numeric values as expressed by REXX (ie, 
  922.                in the form of an ascii string of digits) to an open file or 
  923.                driver as a binary char, short, or long (depending upon whether 
  924.                size is 1, 2 or 4).  This allows a REXX script to write binary 
  925.                CHAR, UCHAR, SHORT, USHORT, LONG, and ULONG values to a 
  926.                file/driver. 
  927.  
  928.                Note:  This function can be used in combination with FileWrite 
  929.                       or FilePuts upon the same handle.
  930.  
  931. Args           handle is the opened handle as returned by FileOpen. 
  932.  
  933.                values are the values that you wish to write out in binary.  For 
  934.                example, if you pass a value of 6, it gets written out as a six, 
  935.                rather than as the ascii digit for six which is hex 36.  You can 
  936.                specify more than one value if desired.  Simply leave a space 
  937.                between each value.  One caveat with negative numbers is that 
  938.                the number must be enclosed within quotes if you specify it as a 
  939.                literal string rather than a variable (or REXX will think that 
  940.                you wish to subtract that value from the value preceding it). 
  941.                You are limited to writing 64 values at a time if size is 4, 128 
  942.                values if size is 2, or 256 values if size is 1. 
  943.  
  944.                size is the size of the value to write; char, short, or long 
  945.                (ie, 1, 2, or 4).  A char is 8-bits (ie, write 1 byte to the 
  946.                file/driver).  A short is 16-bits (ie, write 2 bytes to the 
  947.                file).  A long is 32-bits (ie, write 4 bytes to the file).  If 
  948.                this arg is not supplied, then char is assumed. 
  949.  
  950.                Flags is any of the following: 
  951.                   'm'  Write short or long values in Motorola format (ie, MSB 
  952.                comes first, and LSB is last, versus Intel format where LSB 
  953.                comes first, and MSB is last).  Of course, you always supply the 
  954.                value in Intel format, but choosing Motorola format causes the 
  955.                value to be converted to Motorola format when written to the 
  956.                file. 
  957.                   'h'  The value that you supplied is in hexadecimal format. 
  958.                Do not put a X after the value.  Simply express it in 
  959.                hexidecimal.  For example, if you wish to write out a USHORT 
  960.                hexidecimal value of F001, then simply pass 'F001' and set this 
  961.                flag. 
  962.                   'b'  The value that you supplied is in binary format.  For 
  963.                example, if you wish to write out a UCHAR (ie, 8-bits) binary 
  964.                value of 10001000 (ie, hexidecimal 88), then simply pass 
  965.                '10001000' and set this flag. 
  966.                   If Flags is omitted, then it defaults to none of the above. 
  967.                The order of Flags is irrelevant. 
  968.  
  969. Returns        This returns the number of bytes (ie, characters) actually 
  970.                written out.  So, if successful, this will return the same value 
  971.                as size * the number of values that you specified. 
  972.  
  973.                If an error, it will return 0 or a mismatch with size * the 
  974.                number of values that you specified. 
  975.  
  976. Examples       /* Open 'myfile' for writing */ 
  977.                handle = FileOpen('myfile', 'ws--', 'on') 
  978.                IF handle <> 0 THEN DO 
  979.                   /* Write the value -30 as a char */ 
  980.                   err = FileWriteValue(handle, -30, 1) 
  981.                   IF err <> 1 THEN SAY 'error' 
  982.                   /* Write the value -45 as a short */ 
  983.                   myval = -45  /* Just for the hell of it, store in a variable 
  984.                */ 
  985.                   err = FileWriteValue(handle, mychar, 2) 
  986.                   IF err <> 2 THEN SAY 'error' 
  987.                   /* Write the value 10000 as a long in Motorola format */ 
  988.                   err = FileWriteValue(handle, 10000, 4, 'm') 
  989.                   IF err <> 4 THEN SAY 'error' 
  990.                   err = FileClose(handle) 
  991.                END 
  992.  
  993.                This writes out 3 values with one call to FileWriteValue(). All 
  994.                of the values must be the same size, and any negative values, 
  995.                expressed as a literal string, must be enclosed in quotes. It's 
  996.                more efficient to write out several values with one call to 
  997.                FileWriteValue rather than a separate call for each value. 
  998.  
  999.                /* Open 'myfile' for writing */ 
  1000.                handle = FileOpen('myfile', 'ws--', 'on') 
  1001.                IF handle <> 0 THEN DO 
  1002.                   myval = -3  /* Just for the hell of it, store in a variable 
  1003.                */ 
  1004.                   /* Write the values 4, -30, and -3 as chars */ 
  1005.                   err = FileWriteValue(handle, 4 '-30' myval, 1) 
  1006.                   IF err <> 3 THEN SAY 'error'  /* Note: size*number of values 
  1007.                written = 3 */ 
  1008.                   err = FileClose(handle) 
  1009.                END 
  1010.  
  1011.  
  1012. ΓòÉΓòÉΓòÉ 4.5. Setting/Querying the file position for read/write ΓòÉΓòÉΓòÉ
  1013.  
  1014. You must open a file/device with FileOpen before you use FileSeek.  A file on 
  1015. disk contains lots of "bytes" of information.  You can skip around the file, 
  1016. reading only certain data (ie, with FileRead, FileGets, or FileReadValue), and 
  1017. skipping over other data by using FileSeek to do the skipping.  Also, you can 
  1018. use FileSeek to set a position where you wish to overwrite certain bytes (ie, 
  1019. change the data to new values). 
  1020.  
  1021.  
  1022. ΓòÉΓòÉΓòÉ 4.5.1. FileSeek ΓòÉΓòÉΓòÉ
  1023.  
  1024. Syntax         newpos = FileSeek(handle, amount, origin) 
  1025.  
  1026. Purpose        This allows a script to skip over bytes or go back to bytes that 
  1027.                were already moved past.  A subsequent FileRead, FileReadValue, 
  1028.                or FileGets will start reading at that position.  A subsequent 
  1029.                FileWrite, FileWriteValue, or FilePuts will start writing at 
  1030.                that position.  Note that specifying an amount of 0 and an 
  1031.                origin of 1 will return the current position without changing 
  1032.                that position. 
  1033.  
  1034.                Note:  Many devices do not support the concept of "seek"ing, and 
  1035.                       this function will always return an error from such a 
  1036.                       device's driver.
  1037.  
  1038. Args           handle is the opened handle as returned by FileOpen. 
  1039.  
  1040.                amount is the number of bytes to move forward or backward in the 
  1041.                file.  A negative value moves backward, and a positive value 
  1042.                moves forward. 
  1043.  
  1044.                origin tells from where to start the move (ie, where to 
  1045.                reference your amount from).  It can be one of the following: 
  1046.                   0   Beginning of the file 
  1047.                   1   Current position in the file 
  1048.                   2   End of the file 
  1049.                   If the origin arg is not supplied, the current position is 
  1050.                assumed to be the origin. 
  1051.  
  1052. Returns        If successful, this returns the new, "current file position" 
  1053.                which is the offset in bytes from the head (ie, start) of the 
  1054.                file (after the seek).  (0 is the head of the file). 
  1055.  
  1056.                If an error, a null string is returned (ie, ""). 
  1057.  
  1058. Examples       /* Open 'myfile' for writing and seek to the end of the file */ 
  1059.                handle = FileOpen('myfile', 'ws--', 'on') 
  1060.                IF handle <> 0 THEN DO 
  1061.                   err = FileSeek(handle, 0, 2) 
  1062.                   IF err = "" THEN SAY 'error seeking' 
  1063.                   err = FileClose(handle) 
  1064.                END 
  1065.  
  1066.  
  1067. ΓòÉΓòÉΓòÉ 4.6. Setup/Control a Device or query its settings ΓòÉΓòÉΓòÉ
  1068.  
  1069. You must open a device driver with FileOpen before you use this function.  This 
  1070. function allows you to send commands to the device driver to operate its 
  1071. device.  For certain commands, you may define a "request block" which sends 
  1072. data to the device to control it or receives data back from a device that 
  1073. indicates something about its operation.  Each device driver gets to define 
  1074. what commands it supports and whatever request blocks are associated with those 
  1075. commands, so you must consult the documentation for a device driver that you 
  1076. wish to control.  Nevertheless, IBM has established certain standardized "sets 
  1077. of commands" for some devices.  For example, nearly everyone who makes a driver 
  1078. that controls a modem follows IBM's set of commands for the COM driver, such as 
  1079. setting baud rate, setting handshaking, etc. 
  1080.  
  1081. Typically, you'll open a device driver by passing the driver name to FileOpen. 
  1082. Then, you'll use FileDevIOCtl to setup or obtain information about the device 
  1083. associated with that driver.  Then, you'll use FileWriteValue (or FileWrite or 
  1084. FilePuts if the device expects ascii data, such as a modem) to send data to 
  1085. that device, and FileReadValue (or FileRead or FileGets to receive data from 
  1086. the device.  When done, you'll close the driver with FileClose. 
  1087.  
  1088.  
  1089. ΓòÉΓòÉΓòÉ 4.6.1. FileDevIOCtl ΓòÉΓòÉΓòÉ
  1090.  
  1091. Syntax         error = FileDevIOCtl(handle, catagory, function, paramvar, 
  1092.                datavar, Flags) 
  1093.  
  1094. Purpose        Lets a REXX script perform operations specific to a particular 
  1095.                device, such as setting the baud rate of a modem. 
  1096.  
  1097. Args           handle is the opened handle as returned by FileOpen. 
  1098.  
  1099.                catagory is the catagory number for the IOCTL.  For example, the 
  1100.                functions for an ASYNC RS232-C Control driver (ie, COM driver) 
  1101.                all come under catagory number 1.  Check the literature for the 
  1102.                device driver (ie, under the section that describes its IOCTL 
  1103.                interface -- how OS/2's DosDevIOCtl() is used with it) for the 
  1104.                catagory numbers that the driver supports.  IBM's book Physical 
  1105.                Device Driver Reference lists IOCTL interfaces for standard 
  1106.                drivers such as COM, KEYBOARD, MOUSE, etc. 
  1107.  
  1108.                Note:  The catagory must be expressed in decimal, not hexadecimal.
  1109.  
  1110.                If the catagory arg is omitted, it defaults to 128 (80 hex), 
  1111.                which is typically used for driver specific catagories. 
  1112.  
  1113.                function is the function number for the IOCTL.  For example, if 
  1114.                you want to set the bit rate of an ASYNC RS232-C Control driver 
  1115.                (ie, COM driver), then this is function 65.  Check the 
  1116.                literature for the device driver for the function numbers that 
  1117.                the driver supports. 
  1118.  
  1119.                Note:  The function must be expressed in decimal, not hexadecimal.
  1120.  
  1121.                paramvar is the REXX stem variable name that describes and 
  1122.                initializes any Parameters Block sent to the driver.  It also 
  1123.                describes any Parameters Block that will be received from the 
  1124.                driver, and the returned values are placed into this REXX stem 
  1125.                variable.  If this arg is omitted, then no Parameter Block is 
  1126.                sent to nor received from the driver.  For example, if you want 
  1127.                to set the bit rate (ie, Catagory 1, Function 65) of an ASYNC 
  1128.                RS232-C Control driver (ie, COM driver), then you must describe 
  1129.                and initialize a Parameters Block that contains the desired bit 
  1130.                rate. 
  1131.  
  1132.                datavar is the REXX stem variable name that describes and 
  1133.                initializes any Data Block sent to the driver.  It also 
  1134.                describes any Data Block that will be received from the driver, 
  1135.                and the returned values are placed into this REXX stem variable. 
  1136.                If this arg is omitted, then no Data Block is sent to nor 
  1137.                received from the driver.  For example, if you want to find out 
  1138.                the bit rate (ie, Catagory 1, Function 97) of an ASYNC RS232-C 
  1139.                Control driver (ie, COM driver), then you must describe a Data 
  1140.                Block so that the driver can return its current bit rate. 
  1141.  
  1142.                Flags is any of the following: 
  1143.                   'p'  The Parameters Block returned by the driver is to be 
  1144.                copied into the REXX stem variable that described that Block. 
  1145.                   'd'  The Data Block returned by the driver is to be copied 
  1146.                into the REXX stem variable that described that Block. 
  1147.  
  1148. Returns        If successful, a 0 is returned.  Also, FILEREXX may fill in the 
  1149.                REXX stem variables for the Parameters and/or Data Block if the 
  1150.                appropriate Flags were set to have the driver return those 
  1151.                Blocks. 
  1152.  
  1153.                If an error, a non-zero number is returned, which represents the 
  1154.                error number from the driver, or REXX, or FILEREXX.  Here are 
  1155.                some possible error numbers, and their meanings: 
  1156.  
  1157.                1     Invalid Function (driver doesn't support that function 
  1158.                number) 
  1159.                6     Invalid (non-zero) Handle 
  1160.                15     Invalid drive specified to a driver 
  1161.                31     General driver failure (could be lots of reasons why) 
  1162.                87     Invalid parameter (ie, the Data or Parameters Block was 
  1163.                described incorrectly) 
  1164.                111    Buffer overflow in the driver 
  1165.                115    Protection violation in the driver 
  1166.                117    Invalid Catagory (driver doesn't support that catagory 
  1167.                number) 
  1168.                119    Bad driver level (ie, need an updated version of the 
  1169.                driver) 
  1170.                163    Uncertain media (driver having trouble accessing its 
  1171.                device) 
  1172.                165    Monitors not supported 
  1173.                 -1    Rexx Variable (for Parameters or Data Block) can't be 
  1174.                found. (Check that you spelled it correctly, and got all of stem 
  1175.                numbers in order) 
  1176.                -2     More values/fields than specified Block size 
  1177.                -3     Out of memory for Parameters or Data Block 
  1178.                -4     Truncation occurred.  Your description/initialization for 
  1179.                a field was longer than 255 characters. 
  1180.                -8     Invalid REXX variable name 
  1181.                -16    Out of memory for REXX variables 
  1182.  
  1183. Discussion     FileDevIOCtl() is passed the name of the REXX stem variable that 
  1184.                describes the (Parameters or Data) Block sent to or received 
  1185.                from the driver.  For example, you may pass 'REQUEST' as the 
  1186.                name of the REXX variable that describes the Parameters Block. 
  1187.  
  1188.                When describing a Block, you need to know how many total bytes 
  1189.                (ie, 8-bit characters) are in the Block.  This is the size of 
  1190.                the Block.  You set the first stem variable (ie, with an 
  1191.                extension of 0) to this number.  For example, assume that our 
  1192.                Block will have a size of 16.  Then, REQUEST.0 = 16. 
  1193.  
  1194.                Variables with extensions of .1 and more describe each "field" 
  1195.                of the Block.  For example, REQUEST.1 would describe the first 
  1196.                field.  REQUEST.2 would describe the second field.  Etc. 
  1197.  
  1198.                Each field can contain one or more values.  A field begins with 
  1199.                a "Type".  This is a 1, 2, 4, -1, -2, or -4 to indicate whether 
  1200.                the field's value(s) are expressed as unsigned char (8-bits), 
  1201.                unsigned short (16-bits), unsigned long (32-bits), signed char 
  1202.                (8-bits), signed short (16-bits), or signed long (32-bits) 
  1203.                value(s) respectively.  Then the field's value(s) follow.  If 
  1204.                the "Type" is 0, then the value string is used verbatim without 
  1205.                any translation to binary values. The Type can have an 
  1206.                extension, which I'll refer to as the "Count".  This will be how 
  1207.                many values of that type follow.  If the Count arg is omitted, 
  1208.                then the field's size is ultimately determined by however many 
  1209.                values follow.  For example, if you had a field that consisted 
  1210.                of 32 unsigned chars, you could define the Type and Count as 
  1211.                1.32 and then list the 32 values after that.  If you don't 
  1212.                supply as many values as "Count", then null bytes are used to 
  1213.                pad out to Count.  There can be an additional extension after 
  1214.                the Count, which I'll refer to as an "Initialization".  This 
  1215.                will be either a numeric value that it is to be duplicated for 
  1216.                Count times, or a (non-numeric) character that it is to be 
  1217.                duplicated Count times.  For example, if you wanted to specify 
  1218.                32 unsigned chars and set them all to the value 16, the Type, 
  1219.                Count, and Initialization would be 1.32.16 with no need to 
  1220.                specify any values after that.  If you wanted to specify 4 'A' 
  1221.                chars, the Type, Count, and Initialization would be 0.4.A with 
  1222.                no need to specify any chars after that. 
  1223.  
  1224.                Placing a 'H' before a Type means that you're expressing the 
  1225.                values (or Initialization) in hexadecimal.  Placing a 'B' before 
  1226.                a Type means that you're expressing the values in binary.  This 
  1227.                is not applicable to Type 0. 
  1228.  
  1229.                Say that you want a block that is composed of 5 fields.  The 
  1230.                first field is 1 unsigned char with a value of 16.  The second 
  1231.                field is 3 signed shorts with the values -400, 20, and 0.  The 
  1232.                third field is the string "Hello".  The fourth field is 4 signed 
  1233.                chars with the values 1 2 0 0.  The fifth field will be 6 
  1234.                unsigned chars, initialized to 0.  Here's an example of that: 
  1235.  
  1236.                /* Size of REQUEST block.  Add up the absolute value of each 
  1237.                field's Types (multipled by any Counts, or by the number of 
  1238.                values supplied if no Count).  For a Type of 0 (String), simply 
  1239.                add Count, or the number of values specified.  So, for this 
  1240.                Block's 4 fields, we have (1*1)+(2*3)+5+(1*4)+(1*6) */ 
  1241.                REQUEST.0 = 22 
  1242.  
  1243.                /* First field of REQUEST. Unsigned char. Value is 16 */ 
  1244.                REQUEST.1 = '1 16' 
  1245.  
  1246.                /* Second field of REQUEST. Signed short. There are 3 Values of 
  1247.                -400, 20, and 0 */ 
  1248.                REQUEST.2 = '-2 -400 20 0' 
  1249.  
  1250.                /* Third field of REQUEST. A string */ 
  1251.                REQUEST.3 = '0 Hello' 
  1252.  
  1253.                /* Fourth field of REQUEST. Signed char. Count is 4 (although 
  1254.                only the first two values are supplied) */ 
  1255.                REQUEST.4 = '-1.4 1 2' 
  1256.  
  1257.                /* Fifth field of REQUEST. Unsigned char. Count is 6. 
  1258.                Initialization is 0 */ 
  1259.                REQUEST.5 = '1.6.0' 
  1260.  
  1261.                It's also permissible to have more than one Type, Count, and 
  1262.                values (or Initialization) per field.  But, all of the Types 
  1263.                must also have a Count, except for the last Type (which may or 
  1264.                may not have a Count).  For example, say that you want to make 
  1265.                "Hello" a null-terminated string: 
  1266.  
  1267.                REQUEST.3 = '0.5 Hello 1 0' 
  1268.  
  1269.                When you're describing a Block which is going to be filled in by 
  1270.                the driver and returned to your script, you don't need to 
  1271.                initialize the fields as long as you provide Counts for each 
  1272.                Type.  For example, the above Block would be described as so: 
  1273.  
  1274.                /* Size of REQUEST block.  Add up the absolute value of each 
  1275.                field's Types (multipled by any Counts, or by the number of 
  1276.                values supplied if no Count).  For a Type of 0 (String), simply 
  1277.                add Count, or the number of values specified.  So, for this 
  1278.                Block's 4 fields, we have (1*1)+(2*3)+5+(1*4)+(1*6) */ 
  1279.                REQUEST.0 = 22 
  1280.  
  1281.                /* First field of REQUEST. 1 unsigned char */ 
  1282.                REQUEST.1 = '1.1' 
  1283.  
  1284.                /* Second field of REQUEST. 3 signed shorts */ 
  1285.                REQUEST.2 = '-2.3' 
  1286.  
  1287.                /* Third field of REQUEST. A string of 5 characters */ 
  1288.                REQUEST.3 = '0.5' 
  1289.  
  1290.                /* Fourth field of REQUEST. 4 signed chars */ 
  1291.                REQUEST.4 = '-1.4' 
  1292.  
  1293.                /* Fifth field of REQUEST. 6 unsigned chars */ 
  1294.                REQUEST.5 = '1.6' 
  1295.  
  1296.                The driver returns the values for the respective fields in those 
  1297.                same REXX variables.  For example, let's say that the driver is 
  1298.                going to return the values 30, 4, and -6 for the second field. 
  1299.                It would set REQUEST.2 to the string '30 4 -6'.  You would need 
  1300.                to parse this variable to extract the individual values (which 
  1301.                is why it's better to only have one value per field -- then the 
  1302.                variable ends up being set to that one value, and there's no 
  1303.                need for any parsing). 
  1304.  
  1305.                Of course, if the driver wanted a fully initialized Block 
  1306.                despite the fact that it may also be returning new values for 
  1307.                the Block, you would then initialize it as in the first example. 
  1308.                Remember to set the Flags arg to 'p' if the driver is to return 
  1309.                a filled-in Parameters Block.  Set the Flags arg to 'd' if the 
  1310.                driver is to return a filled-in Data Block.  Set the Flags arg 
  1311.                to 'pd' if the driver is to return filled-in Parameters and Data 
  1312.                Blocks. 
  1313.  
  1314.                Say that you wanted to describe a field that contained an 8-bit 
  1315.                char, but you wish to express it in binary (ie, each bit is a 0 
  1316.                or 1) rather than decimal or hexadecimal.  Let's say that the 
  1317.                bits 0 to 3, and bit 7 are going to be set (ie, 1) and the 
  1318.                remaining bits are going to be clear (ie, 0). 
  1319.  
  1320.                REQUEST.1 = 'B1 10000111' 
  1321.  
  1322.                Say that you wanted to describe that same field expressed in 
  1323.                hexadecimal.  That would be 87. 
  1324.  
  1325.                REQUEST.1 = 'H1 87' 
  1326.  
  1327.                If you mix different Types in a field, and the driver is 
  1328.                returning a filled in Block, the driver returns the field with 
  1329.                all values set to the last Type of that field.  For example, say 
  1330.                that you initialized that null-terminated string as so: 
  1331.  
  1332.                REQUEST.1 = '0.5 Hello 1 0' 
  1333.  
  1334.                When the driver returns the Block, it would set this field to 6 
  1335.                numeric values (ie, unsigned char).  For example, if it returned 
  1336.                the same value(s), you would see each character of "Hello" 
  1337.                expressed as an ascii value.  The result would be '72 101 108 
  1338.                108 111 0'. 
  1339.  
  1340.                Note:  Never describe a field to be returned that will result in 
  1341.                       a line length greater than 255 characters.  This is no 
  1342.                       problem if each field only contains one value, or a (Type 
  1343.                       0) string that is less than 255 characters.
  1344.  
  1345.                A field that contains a pointer (ie, a field that points to some 
  1346.                memory area) can't be initialized (although you could declare it 
  1347.                as an unsigned long and set it to 0 perhaps).  Because IBM's 
  1348.                Device Driver Team simply haven't gotten on the 32-bit bandwagon 
  1349.                like the rest of OS/2's developers, and created a new 32-bit PDD 
  1350.                model that standardized on all addresses expressed as 0:32 
  1351.                (instead of the current mixture of 16:16 and 0:32), it's simply 
  1352.                not worth having FileDevIOCtl() try to hassle with setting up 
  1353.                various types of pointers.  Scream at IBM if you want 32-bit 
  1354.                PDDs. 
  1355.  
  1356. Examples       See com.cmd 
  1357.  
  1358.  
  1359. ΓòÉΓòÉΓòÉ 4.7. Querying information about a File/Device ΓòÉΓòÉΓòÉ
  1360.  
  1361. You must open a file/device with FileOpen before you use these functions.  They 
  1362. are used to obtain information about files such as the file size, the date that 
  1363. it was last modified, and its attributes (ie, is it read-only, or hidden, or a 
  1364. system file, etc).  You can also use FileGetInfo to get information about a 
  1365. device if the handle (returned by FileOpen) is for some device driver. 
  1366.  
  1367.  
  1368. ΓòÉΓòÉΓòÉ 4.7.1. FileGetInfo ΓòÉΓòÉΓòÉ
  1369.  
  1370. Syntax         err = FileGetInfo(filehandle, VarName, infotype) 
  1371.  
  1372. Purpose        Lets a REXX script get information about an open file, such as 
  1373.                its size, last write date and time (ie, date and time that it 
  1374.                was last modified), size of its extended attributes, and its 
  1375.                attribute bits. 
  1376.  
  1377.                Note:  Many devices do not support the concept of a "size", and 
  1378.                       this function will always return an error from such a 
  1379.                       device's driver.
  1380.  
  1381. Args           handle is the opened handle as returned by FileOpen. 
  1382.  
  1383.                VarName is the REXX stem variable where info is returned.  The 
  1384.                file's size is returned in the variable name with a .0 
  1385.                extension.  If a directory, then the size is a null string.  The 
  1386.                Last Write Date/Time is returned in the variable name with a .1 
  1387.                extension.  The month, day, and year are first, each separated 
  1388.                by a space, then the hour, minute, and second follow.  The hour 
  1389.                goes from 1 to 24, where 13 to 24 are for 1PM to 12PM.  The file 
  1390.                attributes are returned in the variable name with a .2 
  1391.                extension.  This is expressed in binary (ie, 32 numeric digits, 
  1392.                where each digit is a 0 or 1, meaning that the respective bit is 
  1393.                clear or set).  The first bit (ie, rightmost digit) is a 1 if 
  1394.                the file is read-only.  The second bit is a 1 if the file is 
  1395.                hidden.  The third bit is a 1 if the file is a system file.  The 
  1396.                fifth bit is a 1 if you're dealing with a directory rather than 
  1397.                a file.  The sixth bit is a 1 if the file is archived.  The 
  1398.                extended attributes size is returned in the variable name with a 
  1399.                .3 extension.  Note that the return is twice what the size 
  1400.                really is, and reflects how much memory would be needed to load 
  1401.                the EA.  The file's Type is returned in the variable name with a 
  1402.                .4 extension (see below under TYPE flag). 
  1403.  
  1404.                infotype determines which information you want returned, and can 
  1405.                be any of the following, each separated by a | character, and 
  1406.                all enclosed in quotes: 
  1407.  
  1408.                SIZE    Return file/dir size (size for a dir is always a null 
  1409.                string) 
  1410.                DATE    Return last written date and time 
  1411.                ATTR    Return attribute bits 
  1412.                EASIZE   Return size of extended attributes 
  1413.                TYPE      Return a string that contains several numbers 
  1414.                identifying the type of file.  The first number is 0 if the file 
  1415.                is local; otherwise 1 if the file is on a remote server.  The 
  1416.                second number is 0 if this is a file, 1 is this is a driver (ie, 
  1417.                device), or 2 if this is a pipe.  The third number will only be 
  1418.                present if you're dealing with a local driver.  This will be 
  1419.                expressed as a 32-bit (ie, 32 digits, with each digit being 0 or 
  1420.                1) value, and represents the driver's attributes word.  If 
  1421.                you're dealing with a driver, then the returned size, EA size, 
  1422.                and attribute bits will all be zero, and the file date will be 
  1423.                '0 0 1980 0 0 0'. 
  1424.  
  1425.                If infotype is omitted, only SIZE information is returned.  The 
  1426.                order of infotype parameters is irrelevant. 
  1427.  
  1428. Returns        If successful, a 0 is returned.  Also, FILEREXX may fill in the 
  1429.                REXX stem variables described above. 
  1430.  
  1431.                If an error, a non-zero number is returned, which represents the 
  1432.                error number from OS/2 or FILEREXX.  Here are some possible 
  1433.                error numbers, and their meanings: 
  1434.  
  1435.                5     Access denied 
  1436.                6     Invalid handle 
  1437.                111    Buffer overflow 
  1438.                124    Invalid level 
  1439.                130    Direct access handle 
  1440.                254    Invalid EA name 
  1441.                255    EA list inconsistent 
  1442.                1     Rexx Variable (for VarName) can't be found. (Check that 
  1443.                you spelled it correctly) 
  1444.                4     Truncation occurred 
  1445.                8     Invalid REXX variable name 
  1446.                16    Out of memory for returning REXX variables 
  1447.  
  1448. Examples       /* Open 'myfile' for reading and get its size and attribute bits 
  1449.                */ 
  1450.                handle = FileOpen('myfile', 'r', 'e') 
  1451.                IF handle <> 0 THEN DO 
  1452.                   err = FileGetInfo(handle, 'Info', 'SIZE|ATTR') 
  1453.                   IF err = 0 THEN DO 
  1454.                     SAY 'size of file =' Info.0 'bytes' 
  1455.                     SAY 'file attribute bits =' Info.2 
  1456.                   END 
  1457.                   err = FileClose(handle) 
  1458.                END 
  1459.  
  1460.  
  1461. ΓòÉΓòÉΓòÉ 4.8. Delete/Copy/Move Files ΓòÉΓòÉΓòÉ
  1462.  
  1463. These functions can work on just one file, or because they support wildcards, 
  1464. can be used to copy, move, or delete groups of files. 
  1465.  
  1466.  
  1467. ΓòÉΓòÉΓòÉ 4.8.1. FileDeleteFile ΓòÉΓòÉΓòÉ
  1468.  
  1469. Syntax         err = FileDeleteFile(filename) 
  1470.  
  1471. Purpose        Deletes a file (or multiple files if wildcards are used in 
  1472.                filename). 
  1473.  
  1474. Args           filename is the name of the file(s) to delete.  This can be 
  1475.                fully qualified with a drive and path.  If filename is omitted, 
  1476.                "*.*" is assumed (ie, delete all files in the current 
  1477.                directory).  FileDeleteFile does not delete directories.  You 
  1478.                need to use FileRmDir to delete a directory. 
  1479.  
  1480.                The wildcards * and ? can be used when specifying the filename. 
  1481.                This makes it possible to delete more than one file with a 
  1482.                single call to FileDeleteFile().  * matches any amount of 
  1483.                characters up to a ..  ? matches any one character, except for 
  1484.                .. 
  1485.  
  1486.                When the filename is a directory (as opposed to a single file), 
  1487.                you must end the arg with a \ character, or \*.*, or some other 
  1488.                string containing wildcards. 
  1489.  
  1490.                Note:  FileDeleteFile is not recursive.  That is, it won't 
  1491.                       delete the files in any subdirectories that match some 
  1492.                       wildcard pattern.  For example, even if you specify *.* 
  1493.                       as the source string, FileDeleteFile won't delete the 
  1494.                       contents of any subdirectories within the current 
  1495.                       directory (nor the contents of any subdirectories inside 
  1496.                       of those subdirectories).  If you want recursive action, 
  1497.                       you have to use FileDeleteFile to get a listing of all of 
  1498.                       the directories (ie, Flags = DIRONLY) in the desired 
  1499.                       directory, and then do a FileDeleteFile on each 
  1500.                       subdirectory.  You'll also have to use FileMatchFile on 
  1501.                       each subdirectory to see if it has subdirectories too. 
  1502.                       Finally, you'll have to use FileRmDir to remove the directories.
  1503.  
  1504. Returns        If successful, a 0 is returned. 
  1505.  
  1506.                If an error, a non-zero number is returned, which represents the 
  1507.                error number from OS/2 or FILEREXX.  Here are some possible 
  1508.                error numbers, and their meanings: 
  1509.  
  1510.                2     File not found 
  1511.                3     Path not found 
  1512.                5     Access denied 
  1513.                26     Not DOS disk 
  1514.                32     Sharing violation 
  1515.                36     Sharing buffer exceeded 
  1516.                87     Invalid parameter 
  1517.                108    Drive locked 
  1518.                111    Buffer overflow 
  1519.                112    Destination disk is full 
  1520.                113    No more search handles. Perhaps too many nested calls to 
  1521.                FileMatchFile() while doing this FileDeleteFile() FileMatchFile 
  1522.                with a 0 for the VarName arg. 
  1523.                206    Filename exceeded character limit 
  1524.                208    Meta expansion too long 
  1525.  
  1526. Examples       /* Delete 'myfile' */ 
  1527.                err = FileDeleteFile('myfile') 
  1528.                IF err = 0 THEN SAY 'File is deleted' 
  1529.  
  1530.                /* Delete all files in C:\temp */ 
  1531.                err = FileDeleteFile('C:\temp\') 
  1532.                IF err = 0 THEN SAY 'Files are deleted' 
  1533.  
  1534.                /* Delete all files in C:\temp that end in with a .bak extension 
  1535.                */ 
  1536.                err = FileDeleteFile('C:\temp\*.bak') 
  1537.                IF err = 0 THEN SAY 'Files are deleted' 
  1538.  
  1539.  
  1540. ΓòÉΓòÉΓòÉ 4.8.2. FileMoveFile ΓòÉΓòÉΓòÉ
  1541.  
  1542. Syntax         err = FileMoveFile(source, destination) 
  1543.  
  1544. Purpose        Moves and/or renames a file (or multiple files if wildcards are 
  1545.                used in the source and destination). 
  1546.  
  1547. Args           source is the name of the file(s) to move.  This can be fully 
  1548.                qualified with a drive and path.  If source is omitted, "*.*" is 
  1549.                assumed (ie, move all files in the current directory). 
  1550.  
  1551.                destination is the new name and/or destination for the file(s). 
  1552.                This can be fully qualified with a drive and path, as well as a 
  1553.                new name for the file(s).  If destination points to a drive or 
  1554.                directory, then the file is moved to that directory or drive 
  1555.                (which must already exist -- FileMoveFile does not create new 
  1556.                directories) with the same name.  If destination is omitted, 
  1557.                "*.*" is assumed (ie, move all source files to the current 
  1558.                directory). 
  1559.  
  1560.                A file can be moved across devices, as long as you specify the 
  1561.                drive for both the source and destination. 
  1562.  
  1563.                When the source or destination is a directory (as opposed to a 
  1564.                single file), you must end the arg with a \ character, or \*.*, 
  1565.                or some other string containing wildcards. 
  1566.  
  1567.                The wildcards * and ? can be used when specifying the source or 
  1568.                destination.  This makes it possible to move more than one file 
  1569.                with a single call to FileMoveFile(), and also give the files 
  1570.                new names.  * matches any amount of characters up to a ..  ? 
  1571.                matches any one character, except for .. 
  1572.  
  1573.                Note:  FileMoveFile is not recursive.  That is, it won't move 
  1574.                       the files in any subdirectories that match some wildcard 
  1575.                       pattern.  For example, even if you specify *.* as the 
  1576.                       source string, FileMoveFile won't move the contents of 
  1577.                       any subdirectories within the current directory (nor the 
  1578.                       contents of any subdirectories inside of those 
  1579.                       subdirectories).  If you want recursive action, you have 
  1580.                       to use FileMatchFile to get a listing of all of the 
  1581.                       directories (ie, Flags = DIRONLY) in the desired 
  1582.                       directory, and then do a FileMoveFile on each 
  1583.                       subdirectory.  You'll also have to use FileMatchFile on 
  1584.                       each subdirectory to see if it has subdirectories too.
  1585.  
  1586. Returns        If successful, a 0 is returned. 
  1587.  
  1588.                If an error, a non-zero number is returned, which represents the 
  1589.                error number from OS/2 or FILEREXX.  Here are some possible 
  1590.                error numbers, and their meanings: 
  1591.  
  1592.                2     File (ie, source) not found 
  1593.                3     Path not found 
  1594.                5     Access denied 
  1595.                17     Not same device. (Use FileCopyFile and FileDeleteFile 
  1596.                instead) 
  1597.                26     Not DOS disk 
  1598.                32     Sharing violation 
  1599.                36     Sharing buffer exceeded 
  1600.                87     Invalid parameter 
  1601.                108    Drive locked 
  1602.                112    Destination disk is full 
  1603.                206    Filename exceeded character limit 
  1604.                250    Circularity requested 
  1605.                251    Directory in cds 
  1606.                267    Directory error 
  1607.                282    EAs not supported on destination 
  1608.                283    Need EAs found 
  1609.  
  1610. Examples       /* Move 'myfile' to 'mydir' */ 
  1611.                err = FileMoveFile('myfile', 'mydir\') 
  1612.                IF err = 0 THEN SAY 'File is moved' 
  1613.  
  1614.                /* Move 'myfile' to 'mydir', renaming it to myfile2 */ 
  1615.                err = FileMoveFile('myfile', 'mydir\myfile2') 
  1616.                IF err = 0 THEN SAY 'File is moved and renamed' 
  1617.  
  1618.                /* Move 'myfile.c' in the C:\OS2 directory to 'mydir', renaming 
  1619.                it with a .bak extension */ 
  1620.                err = FileMoveFile('C:\os2\myfile.c', 'mydir\*.bak') 
  1621.                IF err = 0 THEN SAY 'File is moved and renamed' 
  1622.  
  1623.                /* Move all files in 'mydir' to 'C:\' */ 
  1624.                err = FileMoveFile('mydir\', 'C:\') 
  1625.                IF err = 0 THEN SAY 'Files are moved' 
  1626.  
  1627.                /* Move all files in 'mydir' that end in .cmd to 'C:\' */ 
  1628.                err = FileMoveFile('mydir\*.cmd', 'C:\') 
  1629.                IF err = 0 THEN SAY 'Files are moved' 
  1630.  
  1631.                /* Move all files in the current directory that end in .cmd to 
  1632.                'C:\' */ 
  1633.                err = FileMoveFile('*.cmd', 'C:\') 
  1634.                IF err = 0 THEN SAY 'Files are moved' 
  1635.  
  1636.                /* Move all files in 'mydir' to the current directory */ 
  1637.                err = FileMoveFile('mydir\') 
  1638.                IF err = 0 THEN SAY 'Files are moved' 
  1639.  
  1640.                /* Move all files in 'mydir' to the current directory, renaming 
  1641.                them with a .bak extension */ 
  1642.                err = FileMoveFile('mydir\', '*.bak') 
  1643.                IF err = 0 THEN SAY 'Files are moved' 
  1644.  
  1645.                /* Move all files in 'mydir' that have a .c extension to the 
  1646.                C:\OS2 directory, renaming them with a .bak extension */ 
  1647.                err = FileMoveFile('MYDIR\*.C', 'c:\OS2\*.bak') 
  1648.                IF err = 0 THEN SAY 'Files are moved' 
  1649.  
  1650.  
  1651. ΓòÉΓòÉΓòÉ 4.8.3. FileCopyFile ΓòÉΓòÉΓòÉ
  1652.  
  1653. Syntax         err = FileCopyFile(source, destination, Flags) 
  1654.  
  1655. Purpose        Copies a file (or multiple files if wildcards are used in the 
  1656.                source and destination). 
  1657.  
  1658. Args           source is the name of the file(s) to copy.  This can be fully 
  1659.                qualified with a drive and path.  If source is omitted, "*.*" is 
  1660.                assumed (ie, copy all files in the current directory). 
  1661.  
  1662.                destination is the new name and/or destination for the file(s). 
  1663.                This can be fully qualified with a drive and path, as well as a 
  1664.                new name for the file(s).  If destination points to a drive or 
  1665.                directory, then the file is copied to that directory or drive 
  1666.                (which must already exist -- FileCopyFile does not create new 
  1667.                directories) with the same name, perhaps overwriting any 
  1668.                previous file with that name (depending upon the REPLACE flag). 
  1669.                If destination is omitted, "*.*" is assumed (ie, copy all files 
  1670.                to the current directory). 
  1671.  
  1672.                The wildcards * and ? can be used when specifying the source or 
  1673.                destination.  This makes it possible to copy more than one file 
  1674.                with a single call to FileCopyFile(), and also give the files 
  1675.                new names.  * matches any amount of characters up to a ..  ? 
  1676.                matches any one character, except for .. 
  1677.  
  1678.                When the source is a directory (as opposed to a single file), 
  1679.                you must end the arg with a \ character, or \*.*, or some other 
  1680.                string containing wildcards.  Unlike with FileMoveFile(), if the 
  1681.                destination is a directory, you don't need to end it with a \ 
  1682.                (although you can). 
  1683.  
  1684.                Flags can be any of the following, each separated by a | 
  1685.                character, and all enclosed in quotes: 
  1686.  
  1687.                REPLACE   If there is already a destination file with the same 
  1688.                name existing, overwrite it. 
  1689.                APPEND    Append source file to the end of destination file. 
  1690.                FAILEA     If source has Extended Attributes, and if the 
  1691.                destination's media doesn't support EA's, then fail. 
  1692.  
  1693.                If Flags is omitted, it defaults to none of the above.  The 
  1694.                order of Flags is irrelevant. 
  1695.  
  1696.                Note:  FileCopyFile is not recursive.  That is, it won't copy 
  1697.                       the files in any subdirectories that match some wildcard 
  1698.                       pattern.  For example, even if you specify *.* as the 
  1699.                       source string, FileCopyFile won't copy the contents of 
  1700.                       any subdirectories within the current directory (nor the 
  1701.                       contents of any subdirectories inside of those 
  1702.                       subdirectories).  If you want recursive action, you have 
  1703.                       to use FileMatchFile to get a listing of all of the 
  1704.                       directories (ie, Flags = DIRONLY) in the desired 
  1705.                       directory, and then do a FileCopyFile on each 
  1706.                       subdirectory.  You'll also have to use FileMatchFile on 
  1707.                       each subdirectory to see if it has subdirectories too.
  1708.  
  1709. Returns        If successful, a 0 is returned. 
  1710.  
  1711.                If an error, a non-zero number is returned, which represents the 
  1712.                error number from OS/2 or FILEREXX.  Here are some possible 
  1713.                error numbers, and their meanings: 
  1714.  
  1715.                2     File (ie, source) not found 
  1716.                3     Path not found 
  1717.                5     Access denied 
  1718.                26     Not DOS disk 
  1719.                32     Sharing violation 
  1720.                36     Sharing buffer exceeded 
  1721.                87     Invalid parameter 
  1722.                108    Drive locked 
  1723.                112    Destination disk is full 
  1724.                206    Filename exceeded character limit 
  1725.                267    Directory error 
  1726.                282    EAs not supported on destination 
  1727.                283    Need EAs found 
  1728.  
  1729. Examples       /* Copy 'myfile' to c:\mydir\myfile2 */ 
  1730.                err = FileCopyFile('myfile', 'c:\mydir\myfile2') 
  1731.                IF err = 0 THEN SAY 'File is copied' 
  1732.  
  1733.                /* Copy all .exe files in C:\OS2 dir to C:\MYDIR, replacing any 
  1734.                files with the same names */ 
  1735.                err = FileCopyFile('C:\OS2\*.exe', 'c:\mydir', "REPLACE') 
  1736.                IF err = 0 THEN SAY 'Files are copied' 
  1737.  
  1738.                Also look at the examples for FileMoveFile().  The way that you 
  1739.                specify the source and destination are applicable to 
  1740.                FileCopyFile(). 
  1741.  
  1742.  
  1743. ΓòÉΓòÉΓòÉ 4.9. Create/Delete Directories ΓòÉΓòÉΓòÉ
  1744.  
  1745.  
  1746. ΓòÉΓòÉΓòÉ 4.9.1. FileMkDir ΓòÉΓòÉΓòÉ
  1747.  
  1748. Syntax         err = FileMkDir(dirname) 
  1749.  
  1750. Purpose        Creates a directory. 
  1751.  
  1752. Args           dirname is the name of the directory to create. 
  1753.  
  1754. Returns        If successful, a 0 is returned. 
  1755.  
  1756.                If an error, a non-zero number is returned, which represents the 
  1757.                error number from OS/2 or FILEREXX.  Here are some possible 
  1758.                error numbers, and their meanings: 
  1759.  
  1760.                3     Path not found 
  1761.                5     Access denied 
  1762.                26     Not DOS disk 
  1763.                87     Invalid parameter 
  1764.                108    Drive locked 
  1765.                206    Filename exceeded character limit 
  1766.                254    Invalid EA name 
  1767.                255    EA list inconsistent 
  1768.  
  1769. Examples       /* Create C:\temp */ 
  1770.                err = FileMkDir('C:\temp') 
  1771.                IF err = 0 THEN SAY "Created it" 
  1772.  
  1773.  
  1774. ΓòÉΓòÉΓòÉ 4.9.2. FileRmDir ΓòÉΓòÉΓòÉ
  1775.  
  1776. Syntax         err = FileRmDir(dirname) 
  1777.  
  1778. Purpose        Deletes a directory. 
  1779.  
  1780. Args           dirname is the name of the directory to delete.  The directory 
  1781.                must be empty; that is, it cannot have hidden files nor 
  1782.                directory entries other than the "." and ".." entries.  To 
  1783.                delete files, use FileDeleteFile.  The root directory and 
  1784.                current directory cannot be deleted.  (To delete the current 
  1785.                directory, change to another directory using REXX's DIRECTORY 
  1786.                command, and then call FileRmDir). 
  1787.  
  1788. Returns        If successful, a 0 is returned. 
  1789.  
  1790.                If an error, a non-zero number is returned, which represents the 
  1791.                error number from OS/2 or FILEREXX.  Here are some possible 
  1792.                error numbers, and their meanings: 
  1793.  
  1794.                2     File not found 
  1795.                3     Path not found 
  1796.                5     Access denied 
  1797.                6     Invalid handle 
  1798.                16     Current directory. Change your directory, and then delete 
  1799.                it. 
  1800.                26     Not DOS disk 
  1801.                87     Invalid parameter 
  1802.                108    Drive locked 
  1803.                206    Filename exceeded character limit 
  1804.  
  1805. Examples       /* Delete C:\temp */ 
  1806.                err = FileRmDir('C:\temp') 
  1807.                IF err = 0 THEN SAY "Deleted it" 
  1808.  
  1809.  
  1810. ΓòÉΓòÉΓòÉ 4.10. List/Search Files/Directories ΓòÉΓòÉΓòÉ
  1811.  
  1812. FileMatchFile is used to list all of the filenames and/or subdirectories in a 
  1813. specific directory (and obtain information about each file and subdirectory). 
  1814. FileSearchPath can be used to locate a specific file or directory.  It also can 
  1815. be used to obtain the value of an environment variable (typically used to set 
  1816. default paths). 
  1817.  
  1818.  
  1819. ΓòÉΓòÉΓòÉ 4.10.1. FileMatchFile ΓòÉΓòÉΓòÉ
  1820.  
  1821. Syntax         err = FileMatchFile(VarName, handle, pattern, attributes, 
  1822.                infotype) 
  1823.  
  1824. Purpose        To find the first/next file in the specified directory that 
  1825.                matches the specified pattern.  FileMatchFile may be called many 
  1826.                times in a row to enumerate each matching item.  Each time that 
  1827.                FileMatchFile is called, it either matches one more item, or 
  1828.                indicates that there are no more matching items.  FileMatchFile 
  1829.                should either be called until it finds no more matches, or you 
  1830.                should make a call to specifically abort the search. 
  1831.  
  1832. Args           VarName is the name of the REXX stem variable where info is 
  1833.                returned.  If you pass a 0 instead, then you are indicating that 
  1834.                you want to abort a search in progress and close the handle. 
  1835.  
  1836.                handle is the name of the REXX stem variable where FileMatchFile 
  1837.                returns the handle that you use on subsequent calls to 
  1838.                FileMatchFile.  Before calling FileMatchFile for the first time, 
  1839.                you should initialize this variable to zero.  After each call to 
  1840.                FileMatchFile, you'll check this variable.  As long as it's not 
  1841.                zero, FileMatchFile has returned another match.  When 
  1842.                FileMatchFile can't find any more matching items, it 
  1843.                automatically sets this variable to 0.  (Also, FileMatchFile 
  1844.                returns error number 18 when it can't find any more matches). 
  1845.  
  1846.                pattern is the FileSpec to match.  This can be fully qualified 
  1847.                with the drive and path.  The wildcards * and ? can be used.  * 
  1848.                matches any amount of characters up to a \, :, or ..  ? matches 
  1849.                any one character.  If pattern is omitted, "*.*" is assumed (ie, 
  1850.                search the current directory). 
  1851.  
  1852.                attributes determines which files/dirs are scanned and which are 
  1853.                skipped.  It can be any of the following, each separated by a | 
  1854.                character, and all enclosed in quotes: 
  1855.  
  1856.                RDO       include readonly files 
  1857.                RDOONLY     only readonly (exclude everything else) 
  1858.                HID       include hidden files 
  1859.                HIDONLY     only hidden files (exclude everything else) 
  1860.                SYS       include system files 
  1861.                SYSONLY     only system files (exclude everything else) 
  1862.                DIR       include subdirectories (ie, but not the contents of 
  1863.                such) 
  1864.                DIRONLY     only directories (exclude everything else) 
  1865.                ARC       include files with archive bit set 
  1866.                ARCONLY     only files with archive bit set (exclude everything 
  1867.                else) 
  1868.  
  1869.                If attributes is omitted, it defaults to none of the above (ie, 
  1870.                matches only files that are read/write).  The order of match 
  1871.                parameters is irrelevant. 
  1872.  
  1873.                infotype determines what info is returned along with the name of 
  1874.                the matching file/dir.  It can be any of the following, each 
  1875.                separated by a | character, and all enclosed in quotes: 
  1876.  
  1877.                SIZE      Return file/dir size (size for a dir is always a null 
  1878.                string) 
  1879.                DATE      Return last written date and time 
  1880.                ATTR      Return attribute bits 
  1881.  
  1882.                If infotype is omitted, it defaults to none of the above (ie, 
  1883.                only returns file/dir name).  The order of infotype parameters 
  1884.                is irrelevant. 
  1885.  
  1886. Returns        If a match is found, a 0 is returned.  Also, the name of the 
  1887.                matching file/dir is returned in your specified VarName.  The 
  1888.                size is returned in the variable name with a .0 extension.  If a 
  1889.                directory, then the size is a null string.  The Last Write 
  1890.                Date/Time is returned in the variable name with a .1 extension. 
  1891.                The month, day, and year are first, each separated by a space, 
  1892.                then the hour, minute, and second follow.  The hour goes from 1 
  1893.                to 24, where 13 to 24 are for 1PM to 12PM.  The file attributes 
  1894.                are returned in the variable name with a .2 extension.  This is 
  1895.                expressed in binary (ie, 32 numeric digits, where each digit is 
  1896.                a 0 or 1, meaning that the respective bit is clear or set).  The 
  1897.                first bit (ie, rightmost digit) is a 1 if the file is read-only. 
  1898.                The second bit is a 1 if the file is hidden.  The third bit is a 
  1899.                1 if the file is a system file.  The fifth bit is a 1 if you're 
  1900.                dealing with a directory rather than a file.  The sixth bit is a 
  1901.                1 if the file is archived.  The extended attributes size is 
  1902.                returned in the variable name with a . 3 extension.  Note that 
  1903.                the return is twice what the size really is, and reflects how 
  1904.                much memory would be needed to load the EA.  The file's Type is 
  1905.                returned in the variable name with a .4 extension. 
  1906.  
  1907.                When there are no more matching files/dirs, then FileMatchFile 
  1908.                sets your handle variable to 0, and also returns an error number 
  1909.                of 18. 
  1910.  
  1911.                If an error, a non-zero number is returned, which represents the 
  1912.                error number from OS/2 or FILEREXX.  Here are some possible 
  1913.                error numbers, and their meanings: 
  1914.  
  1915.                2     File not found (ie, can't locate the initial file, 
  1916.                Varname, that you supplied, assuming that it's not a directory). 
  1917.                3     Path not found (ie, a problem with Varname's path) 
  1918.                5     Access denied 
  1919.                6     Invalid handle 
  1920.                18     No more matching files found 
  1921.                26     Not DOS disk 
  1922.                32     Sharing violation 
  1923.                36     Sharing buffer exceeded 
  1924.                87     Invalid parameter 
  1925.                108    Drive locked 
  1926.                111    Buffer overflow 
  1927.                112    Destination disk is full 
  1928.                113    No more search handles. Make sure that you always call 
  1929.                FileMatchFile until your handle variable is 0, or call 
  1930.                FileMatchFile with a 0 for the VarName arg. 
  1931.                206    Filename exceeded character limit 
  1932.                208    Meta expansion too long 
  1933.                254    Invalid EA name 
  1934.                255    EA list inconsistent 
  1935.                275    EAs didn't fit 
  1936.  
  1937. Examples       /* Search for all matches to '*.cmd' in current directory. Only 
  1938.                check read/write files */ 
  1939.  
  1940.                /* Initially set handle to 0 */ 
  1941.                Handle = 0 
  1942.  
  1943.                DO UNTIL Handle = 0 
  1944.  
  1945.                  err = FileMatchFile('File', 'Handle', '*.cmd',, 'SIZE|DATE') 
  1946.  
  1947.                  /* No error? (ie, another match) */ 
  1948.                  IF err = 0 THEN DO 
  1949.  
  1950.                    /* Print matching filename (and its size and date) */ 
  1951.                      SAY File '|' File.0 '|' File.1 
  1952.  
  1953.                  END 
  1954.  
  1955.                  /* An error occurred (unless it was "no more files" -- we 
  1956.                ignore that since it only means that our loop is going to end, 
  1957.                being that Handle is now 0) */ 
  1958.                  ELSE IF err <> 18 THEN SAY  "FileMatchFile('File', 'Handle', 
  1959.                '*.cmd',, 'SIZE|DATE') =" err 
  1960.  
  1961.                END 
  1962.  
  1963.                /* Collect all of the subdirectory names (and their attributes 
  1964.                bits) in the current directory. Note that we pass a variable 
  1965.                name of 'File.X' where the X is incremented. That means that the 
  1966.                first directory's name is stored in File.0 and its attributes 
  1967.                bits are stored in File.0.2. */ 
  1968.  
  1969.                /* Initially set handle and count to 0 */ 
  1970.                Handle = 0 
  1971.                Count = 0 
  1972.  
  1973.                DO UNTIL Handle = 0 
  1974.  
  1975.                  err = FileMatchFile('File.'Count, 'Handle',, 'DIRONLY', 
  1976.                'ATTR') 
  1977.  
  1978.                  /* No error? (ie, another match) */ 
  1979.                  IF err = 0 THEN DO 
  1980.  
  1981.                    /* Increment Count */ 
  1982.                    Count = Count + 1 
  1983.  
  1984.                  END 
  1985.  
  1986.                  /* An error occurred? */ 
  1987.                  ELSE IF err <> 18 THEN SAY  "Error collecting directories:" 
  1988.                err 
  1989.  
  1990.                If you wish to abort a loop in which you're making calls to 
  1991.                FileMatchFile (ie, you want to stop searching the directory 
  1992.                before you've exhausted all possible matches), you should make 
  1993.                sure that you call FileMatchFile one more time with a Varname 
  1994.                arg of 0, and passing Handle. 
  1995.  
  1996.                /* Initially set handle 0 */ 
  1997.                Handle = 0 
  1998.  
  1999.                DO UNTIL Handle = 0 
  2000.  
  2001.                  err = FileMatchFile('File', 'Handle', '*.exe') 
  2002.  
  2003.                  /* No error? (ie, another match) */ 
  2004.                  IF err = 0 THEN DO 
  2005.  
  2006.                    /* Let's say that you want to leave the loop right now. 
  2007.                First clean up with one more call to FileMatchFile */ 
  2008.                    CALL FileMatchFile(0,'Handle') 
  2009.                    LEAVE 
  2010.  
  2011.                  END 
  2012.  
  2013.                  /* An error occurred? */ 
  2014.                  ELSE IF err <> 18 THEN SAY  "Error:" err 
  2015.  
  2016.                Or, you could do the cleanup afterward, by checking Handle for 
  2017.                0. 
  2018.  
  2019.                /* Initially set handle to 0 */ 
  2020.                Handle = 0 
  2021.  
  2022.                DO UNTIL Handle = 0 
  2023.  
  2024.                  err = FileMatchFile('File', 'Handle', '*.exe') 
  2025.  
  2026.                  /* No error? (ie, another match) */ 
  2027.                  IF err = 0 THEN DO 
  2028.  
  2029.                    /* Let's say that you want to leave the loop right now */ 
  2030.                    LEAVE 
  2031.  
  2032.                  END 
  2033.  
  2034.                  /* An error occurred? */ 
  2035.                  ELSE IF err <> 18 THEN SAY  "Error collecting directories:" 
  2036.                err 
  2037.  
  2038.                /* Do any cleanup now */ 
  2039.                IF Handle <> 0 THEN CALL FileMatchFile(0,'Handle') 
  2040.  
  2041.  
  2042. ΓòÉΓòÉΓòÉ 4.10.2. FileSearchPath ΓòÉΓòÉΓòÉ
  2043.  
  2044. Syntax         FileSpec = FileSearchPath(path, filename) 
  2045.  
  2046. Purpose        Searches the specified path for the specified file/directory and 
  2047.                returns the full FileSpec of the file/dir if found.  Also can be 
  2048.                used to get the value of an environment variable. 
  2049.  
  2050. Args           path is any environment variable that resembles a path, such as 
  2051.                'PATH', 'DPATH', etc. 
  2052.  
  2053.                filename is the file to search for within that path.  The 
  2054.                wildcards * and ? can be used.  * matches any amount of 
  2055.                characters up to a \, :, or ..  ? matches any one character.  If 
  2056.                wildcards are used, they appear in the returned FileSpec.  If 
  2057.                the filename arg is not supplied, then the value of the 
  2058.                environment variable is returned.  In this case, the environment 
  2059.                variable can be other than one assigned to some path. 
  2060.  
  2061. Returns        If successful, the full FileSpec is returned.  If the filename 
  2062.                arg is not supplied, then the value of the environment variable 
  2063.                is returned. 
  2064.  
  2065.                If the file can't be found along the specified path, a null 
  2066.                string is returned. 
  2067.  
  2068. Examples       /* Search for a 'filerexx.dll' along LIBPATH */ 
  2069.                name = FileSearchPath('LIBPATH', 'filerexx.dll') 
  2070.  
  2071.                /* found it? */ 
  2072.                IF name <> '' THEN SAY "Found it" 
  2073.  
  2074.                /* Get the value of the environment variable VIDEO_DEVICES */ 
  2075.                dev = FileSearchPath('VIDEO_DEVICES') 
  2076.  
  2077.                /* found it? */ 
  2078.                IF dev <> '' THEN SAY "VIDEO_DEVICES =" dev 
  2079.  
  2080.  
  2081. ΓòÉΓòÉΓòÉ 4.11. Query information about Drives/Devices ΓòÉΓòÉΓòÉ
  2082.  
  2083. FileDriveMap can list all of the drives on the system, as well as remote (ie, 
  2084. LAN) drives.  FileDevInfo can get information about a specific drive, such as 
  2085. the total free space on it, its size, and the serial number and label of any 
  2086. media in that drive.  FileDevInfo can also be used to get the (internal) names 
  2087. of drivers mounted upon the system, or check that a certain driver is mounted. 
  2088.  
  2089.  
  2090. ΓòÉΓòÉΓòÉ 4.11.1. FileDriveMap ΓòÉΓòÉΓòÉ
  2091.  
  2092. Syntax         map = FileDriveMap(startdrive, Flags) 
  2093.  
  2094. Purpose        Lists all of the drives with the specified attributes. 
  2095.  
  2096. Args           startdrive is the name of the drive at which to start listing. 
  2097.                For example, 'C:' skips the A and B drives.  If startdrive is a 
  2098.                full FileSpec, the drive letter is extracted from it.  If 
  2099.                startdrive is omitted, then the drives are listed from A. 
  2100.  
  2101.                Flags may be any one of the following, each separated by a | 
  2102.                character, and all enclosed in quotes: 
  2103.  
  2104.                FREE     Lists drives which are free or not in use. 
  2105.                USED     Lists drives which are accessible or in use.  This 
  2106.                includes all local and remote drives. 
  2107.                LOCAL     Lists only those drives which are local drives. 
  2108.                REMOTE    Lists only those drives which are remote drives such 
  2109.                as redirected LAN resources, IFS attached drives, etc. 
  2110.                DETACHED   Lists drives which are detached LAN resources. 
  2111.                NUMS     Lists drives as numbers instead of letters, where '1' 
  2112.                is drive 'A'.  For example, '1 2 3' is 'A:\ B:\ C:\'. 
  2113.  
  2114.                If Flags is omitted, it defaults to USED.  The FREE flag is 
  2115.                mutually exclusive with the following 4, ie, if you set USED, 
  2116.                then it overrides FREE.  The order of Flags is irrelevant. 
  2117.  
  2118. Returns        If successful, a string containing all of the drives with the 
  2119.                specified attributes is returned, each separated by a space. 
  2120.                For example, 'A:\ B:\ C:\'. 
  2121.  
  2122.                If an error (or no drives with those matching Flags are found), 
  2123.                a null string is returned. 
  2124.  
  2125. Examples       /* List all drives after C: */ 
  2126.                map = FileDriveMap('C:\temp') 
  2127.                SAY map 
  2128.  
  2129.  
  2130. ΓòÉΓòÉΓòÉ 4.11.2. FileDevInfo ΓòÉΓòÉΓòÉ
  2131.  
  2132. Syntax         err = FileDevInfo(VarName, Device) 
  2133.  
  2134. Purpose        Gets information about a particular drive or device driver. 
  2135.  
  2136. Args           Device is either the name of the drive to query, for example, 
  2137.                'C:', or a device driver name to query, for example 'COM2', or 
  2138.                if a number is specified, then that driver is looked up in 
  2139.                OS/2's list of mounted drivers, for example, a 1 would return 
  2140.                information about the first mounted driver, and a 2 would return 
  2141.                information about the second mounted driver.  If Device is a 
  2142.                drive, then you can specify a full filespec, for example, 
  2143.                'C:\OS2\DLL' would return info about C:.  If Device is omitted, 
  2144.                then the current drive is queried. 
  2145.  
  2146.                VarName is the REXX stem variable where info is returned. 
  2147.  
  2148.                For a drive, the drive name (separated from any filespec, for 
  2149.                example, 'C:\OS2\DLL' returns 'C:\' and a \ character always 
  2150.                ends the drive name), is returned in the variable name without 
  2151.                any extension.  If the Device arg was omitted, this will be the 
  2152.                current drive.  The Free Bytes is returned in the variable name 
  2153.                with a .0 extension.  The Drive Size is returned in the variable 
  2154.                name with a .1 extension.  The Volume Serial Number is returned 
  2155.                in the variable with a .2 extension.  The Volume Label is 
  2156.                returned in the variable name with a .3 extension. 
  2157.  
  2158.                For a device driver, it's name is returned in the variable name 
  2159.                without any extension.  This will have the subdirectory '\DEV\' 
  2160.                prepended to the device's name.  The driver's type is returned 
  2161.                in the variable name with a .0 extension.  This will be 1 for a 
  2162.                Resident character device, a 2 for a Pseudocharacter device, a 3 
  2163.                for a Local Drive, or a 4 for a Remote drive attached to the 
  2164.                file-system driver.  The variable name with a .1 extension will 
  2165.                always be a null string.  This corresponds to the Drive Size 
  2166.                when querying a drive.  Of course, a drive would never have a 
  2167.                null size, so you could use this variable when you aren't 
  2168.                certain if the Device arg that you're passing to FileDevInfo is 
  2169.                the name of a drive or a device driver. 
  2170.  
  2171. Returns        If successful, a 0 is returned.  Also, FILEREXX will fill in the 
  2172.                REXX stem variables described above. 
  2173.  
  2174.                If an error, a non-zero number is returned, which represents the 
  2175.                error number from OS/2 or FILEREXX.  Here are some possible 
  2176.                error numbers, and their meanings: 
  2177.  
  2178.                15     Invalid drive 
  2179.                111    Buffer overflow 
  2180.                124    Invalid level 
  2181.                1     Rexx Variable (for VarName) can't be found. (Check that 
  2182.                you spelled it correctly) 
  2183.                4     Truncation occurred 
  2184.                8     Invalid REXX variable name 
  2185.                16    Out of memory for returning REXX variables 
  2186.                253   Device driver not found. The name that you supplied is not 
  2187.                a mounted driver. 
  2188.                259   No driver matching this number. The device driver number 
  2189.                that you supplied is greater than the number of drivers in the 
  2190.                list of mounted drivers. 
  2191.  
  2192. Examples       /* Get info about current drive */ 
  2193.                err = FileDevInfo('Info') 
  2194.                IF err = 0 THEN DO 
  2195.                  SAY 'Bytes Free =' Info.0 
  2196.                  SAY 'Bytes Used =' Info.1 
  2197.                  SAY 'Serial Number =' Info.2 
  2198.                  SAY 'Volume Label =' Info.3 
  2199.                  SAY 'Current drive =' Info 
  2200.                END 
  2201.                ELSE SAY  "FileDevInfo('Info') =" err 
  2202.  
  2203.                /* List the names of all mounted device drivers */ 
  2204.                drvnum = 1 
  2205.                err = 0 
  2206.                DO WHILE err = 0 
  2207.                  /* Get the next driver in the list */ 
  2208.                  err = FileDevInfo('Info', drvnum) 
  2209.                  IF err = 0 THEN DO 
  2210.                    /* Chop off the \DEV\ subdirectory, and only display the 
  2211.                driver name */ 
  2212.                    err = FileGetPath('File', Info) 
  2213.                    SAY File.2||File.3   END 
  2214.                  drvnum = drvnum+1 
  2215.                END 
  2216.                IF err <> 259 THEN SAY  "FileDevInfo('Info', drvnum) =" err 
  2217.  
  2218.                /* Check if COM2 driver is mounted */ 
  2219.                err = FileDevInfo('Info', 'COM2') 
  2220.                IF err = 0 THEN SAY "COM2 is mounted." 
  2221.                ELSE IF err = 253 THEN SAY "COM2 is not mounted." 
  2222.                ELSE SAY  "FileDevInfo('Info', 'COM2') =" err 
  2223.  
  2224.  
  2225. ΓòÉΓòÉΓòÉ 4.12. Parse/Edit File/Directory/Drive names, Change/Query current Drive/Directory ΓòÉΓòÉΓòÉ
  2226.  
  2227. FileGetPath can split up a variable containing the full path name of some file 
  2228. or directory into its separate components of drive, path (ie, parent 
  2229. directories), file (or subdir) name, and extension.  Also, it can be used to 
  2230. obtain the name of the current drive and path (ie, directories).  FileEditName 
  2231. can be used to transform a file/directory name into a new name by using 
  2232. wildcard pattern matching and replacing. 
  2233.  
  2234.  
  2235. ΓòÉΓòÉΓòÉ 4.12.1. FileGetPath ΓòÉΓòÉΓòÉ
  2236.  
  2237. Syntax         err = FileGetPath(VarName, FileSpec, Flags) 
  2238.  
  2239. Purpose        Splits the FileSpec into its separate components of drive, path 
  2240.                (ie, parent directories), file (or subdir) name, and extension. 
  2241.                It also can be used to obtain the current drive and path (split 
  2242.                into separate variables).  It also can be used to change the 
  2243.                current drive and directory. 
  2244.  
  2245. Args           VarName is the REXX stem variable where info is returned.  The 
  2246.                Drive is returned in the variable name with a .0 extension, for 
  2247.                example 'C:\'.  This will be a null string if there was no drive 
  2248.                specified in the FileSpec.  The Path (ie, parent directories) is 
  2249.                returned in the variable name with a .1 extension.  This will be 
  2250.                a null string if there was no path specified in the FileSpec. 
  2251.                The Filename is returned in the variable with a .2 extension. 
  2252.                This will be a null string if the FileSpec arg is omitted.  The 
  2253.                Extension is returned in the variable name with a .3 extension. 
  2254.                This will be a null string if there was no extension specified 
  2255.                in the FileSpec, or the FileSpec arg is omitted. 
  2256.  
  2257.                FileSpec is the full pathname to parse, for example, 
  2258.                'C:\os2\dll\pmwin.dll'.  If FileSpec is omitted, then the 
  2259.                current drive and path are returned (and the Filename and 
  2260.                Extension variables are nulled).  If FileSpec is only a drive 
  2261.                letter, then it need not have a \ at the end, for example, C: or 
  2262.                C:\ are both identical. 
  2263.  
  2264.                If the VarName arg is omitted, then the current drive and/or 
  2265.                directory is changed to the drive/directory specified FileSpec. 
  2266.                For example, 'C:\os2' changes the current drive to 'C:' and the 
  2267.                current directory to 'os2'.  Passing 'os2\dll' would change the 
  2268.                current directory to '?:\os2\dll' where ? is whatever the 
  2269.                current drive already is (ie, the current drive isn't changed). 
  2270.                The FileSpec itself does not have to a directory.  For example, 
  2271.                if you pass 'C:\os2\cmd.exe' and cmd.exe happens to be a file 
  2272.                (rather than a directory), the current drive is changed to 'C:' 
  2273.                and the current directory is changed to 'os2'. 
  2274.  
  2275.                Flags may be any one of the following, each separated by a | 
  2276.                character, and all enclosed in quotes: 
  2277.  
  2278.                CHK     Check whether the FileSpec (if specified) is a directory 
  2279.                or file before parsing.  For example, assume that you pass the 
  2280.                FileSpec 'C:\os2\dll'.  Without the CHK flag, this would be 
  2281.                broken up with a drive of 'C:\', a directory of 'os2\', a 
  2282.                filename of 'dll', and a null string for extension.  But if you 
  2283.                specify the CHK flag and dll happens to be a directory, then 
  2284.                this would be broken up with a drive of 'C:\', a directory of 
  2285.                'os2\dll\', and a null filename and extension.  A way to force 
  2286.                FileGetPath to regard your FileSpec as pointing to a directory 
  2287.                rather than a file, is to make sure that the FileSpec ends with 
  2288.                a \.  For example, even without the CHK flag, a FileSpec of 
  2289.                'C:\os2\dll\' would be broken up with a drive of 'C:\', a 
  2290.                directory of 'os2\dll\', and a null filename and extension. 
  2291.  
  2292.                If Flags is omitted, it defaults to none of the above.  The 
  2293.                order of Flags is irrelevant. 
  2294.  
  2295. Returns        If successful, a 0 is returned.  Also, FILEREXX will fill in the 
  2296.                REXX stem variables described above. 
  2297.  
  2298.                If an error, a non-zero number is returned, which represents the 
  2299.                error number from OS/2 or FILEREXX.  Here are some possible 
  2300.                error numbers, and their meanings: 
  2301.  
  2302.                2     File not found 
  2303.                3     Path not found 
  2304.                5     Access denied 
  2305.                8     Not enough memory 
  2306.                15     Invalid drive 
  2307.                26     Not DOS disk 
  2308.                87     Invalid parameter 
  2309.                108    Drive locked 
  2310.                111    Buffer overflow 
  2311.                206    Path name too long 
  2312.                1     Rexx Variable (for VarName) can't be found. (Check that 
  2313.                you spelled it correctly) 
  2314.                4     Truncation occurred 
  2315.                8     Invalid REXX variable name 
  2316.                16    Out of memory for returning REXX variables 
  2317.  
  2318. Examples       /* Get current drive and path */ 
  2319.                err = FileGetPath('Info') 
  2320.                IF err = 0 THEN DO 
  2321.                  SAY 'Current drive =' Info.0 
  2322.                  SAY 'Current path =' Info.1 
  2323.                END 
  2324.                ELSE SAY  "FileGetPath('Info') =" err 
  2325.  
  2326.                /* Split up 'C:\os2\dll\pmwin.dll' */ 
  2327.                err = FileGetPath('Info', 'C:\os2\dll\pmwin.dll') 
  2328.                IF err = 0 THEN DO 
  2329.                  SAY 'Drive =' Info.0 
  2330.                  SAY 'Path =' Info.1 
  2331.                  SAY 'Filename =' Info.2 
  2332.                  SAY 'Extension =' Info.3 
  2333.                END 
  2334.                ELSE SAY  "FileGetPath('Info', 'C:\os2\dll\pmwin.dll') =" err 
  2335.  
  2336.                /* Change current drive to C: and current directory to 'os2' */ 
  2337.                err = FileGetPath(, 'C:\os2') 
  2338.                IF err = 0 THEN SAY 'Current directory and drive is changed' 
  2339.                ELSE SAY  "FileGetPath(, 'C:\os2') =" err 
  2340.  
  2341.  
  2342. ΓòÉΓòÉΓòÉ 4.12.2. FileEditName ΓòÉΓòÉΓòÉ
  2343.  
  2344. Syntax         NewName = FileEditName(Source, Template, Flags) 
  2345.  
  2346. Purpose        Transforms a filename into a new name by applying a template 
  2347.                perhaps containing wildcard characters.  FileEditName can be 
  2348.                used to easily resolve filenames containing the wildcard 
  2349.                characters * and ?.  In this way, your script can support 
  2350.                "filename global pattern matching", allowing the user to easily 
  2351.                specify many files that your script must act upon, without 
  2352.                forcing the user to type the name of every single file that he 
  2353.                wants processed.  FileEditName will typically be used in 
  2354.                conjunction with FileMatchFile.  FileMatchFile will be used to 
  2355.                search for "source files" (ie, to load and modify) and 
  2356.                FileEditName will be used to create new filenames based upon 
  2357.                those source names (ie, so that data can be saved in new files, 
  2358.                rather than overwriting the originals). 
  2359.  
  2360. Args           Source is the filename to be transformed.  This can be fully 
  2361.                qualified with a drive and path (but doing so means that you'll 
  2362.                have to specify the USEDIR or SKIPDIR Flags).  If this points to 
  2363.                a drive or directory, you should end the arg with a \ character 
  2364.                (unless you're transforming the name of a directory in order to 
  2365.                create a new directory name). 
  2366.  
  2367.                Template is the filename that is used to transform the Source 
  2368.                filename.  This can be fully qualified with a drive and path 
  2369.                (but doing so means that you need to specify the RESTRICT, 
  2370.                SKIPDIR, and/or USEDIR Flags).  If Template is omitted, "*.*" is 
  2371.                assumed (ie, the transformed name has the same filename and 
  2372.                extension pieces as the Source, although the drive and directory 
  2373.                may be different if you set the SKIPDIR flag).  When the 
  2374.                Template is a directory (as opposed to a single file), you must 
  2375.                end the arg with a \ character, or \*.* (unless the source is 
  2376.                also a directory, and you wish to transform that directory 
  2377.                name).  In this case, the transformed name 
  2378.  
  2379.                Flags is any of the following: 
  2380.                USEDIR    Use any drive and directory of the source verbatim, 
  2381.                and ignore any drive and directory of the template. 
  2382.                SKIPDIR   Ignore any drive and directory of the source, and 
  2383.                instead use any drive and directory on the template verbatim 
  2384.                (unless the RESTRICT flag is also set). 
  2385.                RESTRICT  Ignore any drive and directory on the template. 
  2386.  
  2387.                If Flags is omitted, then it defaults to none of the above.  In 
  2388.                this case, you should make sure that neither the Source nor 
  2389.                Template are fully qualified (ie, only the Filename and 
  2390.                Extension pieces are supplied). 
  2391.  
  2392.                The wildcards * and ? can be used when specifying the Template. 
  2393.                * matches any amount of characters in the Source up to a ..  ? 
  2394.                matches any one character in the Source, except for .. 
  2395.  
  2396. Returns        If successful, the transformed name is returned. 
  2397.  
  2398.                If an error, a null string is returned.  This will happen if the 
  2399.                Source and/or Template are fully qualified, but the proper Flags 
  2400.                aren't set to ignore the drive and directory of one while using 
  2401.                the other's drive and directory (or ignoring both args' drive 
  2402.                and directories by specifying both the SKIPDIR and RESTRICT 
  2403.                Flags). 
  2404.  
  2405. Examples       /* This creates a NewName of "hi" */ 
  2406.                NewName = FileEditName('hello', 'hi') 
  2407.                IF NewName = '' THEN SAY 'ERROR' 
  2408.  
  2409.                /* This creates a NewName of "hello.exe" */ 
  2410.                NewName = FileEditName('hello.cmd', '*.exe') 
  2411.                IF NewName = '' THEN SAY 'ERROR' 
  2412.  
  2413.                /* This creates a NewName of "hi.cmd" */ 
  2414.                NewName = FileEditName('hello.cmd', 'hi.*') 
  2415.                IF NewName = '' THEN SAY 'ERROR' 
  2416.  
  2417.                /* This creates a NewName of "hello.cmd" */ 
  2418.                NewName = FileEditName('hello.cmd', '*.*') 
  2419.                IF NewName = '' THEN SAY 'ERROR' 
  2420.  
  2421.                /* This creates a NewName of "c:\mydir\hello.bak" */ 
  2422.                NewName = FileEditName('c:\mydir\hello.cmd', '*.bak', 'USEDIR') 
  2423.                IF NewName = '' THEN SAY 'ERROR' 
  2424.  
  2425.                /* This creates a NewName of "c:\hello.cmd" */ 
  2426.                NewName = FileEditName('c:\mydir\hello.cmd', 'c:\', 'SKIPDIR') 
  2427.                IF NewName = '' THEN SAY 'ERROR' 
  2428.  
  2429.                /* This creates a NewName of "c:\hello2.cmd" */ 
  2430.                NewName = FileEditName('mydir\mydir2\hello.cmd', 'c:\*2.*', 
  2431.                'SKIPDIR') 
  2432.                IF NewName = '' THEN SAY 'ERROR' 
  2433.  
  2434.                /* This creates a NewName of "hello.cmd" */ 
  2435.                NewName = FileEditName('c:\mydir\hello.cmd', 'c:\', 
  2436.                'SKIPDIR|RESTRICT') 
  2437.                IF NewName = '' THEN SAY 'ERROR' 
  2438.  
  2439.                /* This creates a NewName of "c:\mydir\hi.bak" */ 
  2440.                NewName = FileEditName('c:\mydir\', 'd:\mydir2\hi.bak', 
  2441.                'USEDIR') 
  2442.                IF NewName = '' THEN SAY 'ERROR' 
  2443.  
  2444.  
  2445. ΓòÉΓòÉΓòÉ 4.13. FileSysInfo ΓòÉΓòÉΓòÉ
  2446.  
  2447. Syntax         err = FileSysInfo(VarName, FirstItem, LastItem) 
  2448.  
  2449. Purpose        Gets information about the operating system. 
  2450.  
  2451. Args           VarName is the REXX stem variable where info is returned. 
  2452.  
  2453.                FirstItem is the item number of the first piece of information 
  2454.                that you desire.  FirstItem is the item number of the last piece 
  2455.                of information that you desire.  If you only want one piece of 
  2456.                information, simply omit the LastItem arg. 
  2457.  
  2458.                Each piece of information about the OS has a number associated 
  2459.                with it.  Here are all of the numbers that you can specify, and 
  2460.                what piece of information each number returns. 
  2461.  
  2462.                0    Version number of FILEREXX (currently 1) 
  2463.                1    Maximum length, in bytes, of a path name. 
  2464.                2    Maximum number of text sessions. 
  2465.                3   Maximum number of PM sessions. 
  2466.                4   Maximum number of DOS sessions. 
  2467.                5   The drive from which the system was started (1 means drive 
  2468.                A, 2 means drive B, and so on). 
  2469.                6   Dynamic priority variation flag (0 means absolute priority, 
  2470.                1 means dynamic priority). 
  2471.                7   Maximum wait in seconds. 
  2472.                8   Minimum time slice in milliseconds. 
  2473.                9   Maximum time slice in milliseconds. 
  2474.                10   Memory page size in bytes.  This value is 4096 for the 
  2475.                80386 processor. 
  2476.                11   Major OS version number. 
  2477.                12   Minor OS version number. 
  2478.                13   OS Revision letter. 
  2479.                14   Value of a 32-bit, free-running millisecond counter.  This 
  2480.                value is zero when the system is started. This is useful as a 
  2481.                seed for a random number generator. 
  2482.                15   Low-order 32 bits of the time in seconds since January 1, 
  2483.                1970 at 0:00:00. 
  2484.                16   High-order 32 bits of the time in seconds since January 1, 
  2485.                1970 at 0:00:00. 
  2486.                17   Total number of bytes of physical memory in the system. 
  2487.                One page is 4KB. 
  2488.                18   Total number of bytes of resident memory in the system. 
  2489.                19   Maximum number of bytes of memory that can be allocated by 
  2490.                all processes in the system.  This number is advisory and is not 
  2491.                guaranteed, since system conditions change constantly. 
  2492.                20   Maximum number of bytes of memory that this process can 
  2493.                allocate in its private arena.  This number is advisory. 
  2494.                21   Maximum number of bytes of memory that a process can 
  2495.                allocate in the shared arena.  This number is advisory. 
  2496.                22   Timer interval in tenths of a millisecond. 
  2497.                23   Maximum length, in bytes, of one component in a path name. 
  2498.                24   Session ID of the current foreground full-screen session. 
  2499.                Note that this only applies to full-screen sessions.  The 
  2500.                Presentation Manager session (which displays Vio-windowed, PM, 
  2501.                and Windowed VDM sessions) is full-screen session ID 1. 
  2502.                25   Process ID of the current foreground process. 
  2503.  
  2504.                In order to obtain a piece of info, you pass the desired number 
  2505.                above as the FirstItem arg.  The value of that item is returned 
  2506.                in the REXX variable with an extension that is the same as the 
  2507.                information number.  For example, passing a FirstItem number of 
  2508.                5, and a VarName of 'Info' to FileSysInfo returns the drive 
  2509.                number from which the system was booted, in the REXX variable 
  2510.                Info.5. 
  2511.  
  2512.                You can obtain several pieces of information with one call by 
  2513.                supplying a LastItem arg.  All of the pieces of info from the 
  2514.                FirstItem up to and including the last item are returned, in 
  2515.                their respective REXX variables. 
  2516.  
  2517.                If you omit the FirstItem arg, it defaults to 14 (ie, obtaining 
  2518.                the free-running counter value). 
  2519.  
  2520. Returns        If successful, a 0 is returned.  Also, FILEREXX will fill in the 
  2521.                REXX stem variables described above. 
  2522.  
  2523.                If an error, a non-zero number is returned, which represents the 
  2524.                error number from OS/2 or FILEREXX.  Here are some possible 
  2525.                error numbers, and their meanings: 
  2526.  
  2527.                87     Invalid parameter. Don't specify an Item number of 0 or 
  2528.                greater than 25 (although future versions of the OS may support 
  2529.                item numbers greater than 25). 
  2530.                111    Buffer overflow 
  2531.                1     Rexx Variable (for VarName) can't be found. (Check that 
  2532.                you spelled it correctly) 
  2533.                4     Truncation occurred 
  2534.                8     Invalid REXX variable name 
  2535.                16    Out of memory for returning REXX variables 
  2536.  
  2537. Examples       /* Get the free running millisecond counter's value. Use it to 
  2538.                generate a random number from 0 to 2 (ie, 0, 1, or 2) */ 
  2539.                err = FileSysInfo('Info') 
  2540.                IF err = 0 THEN SAY 'Random =' Info.14 // 3 
  2541.                ELSE SAY  "FileSysInfo('Info') =" err 
  2542.  
  2543.                /* Get the OS major and minor version numbers, and revision 
  2544.                letter */ 
  2545.                err = FileSysInfo('Info', 11, 13) 
  2546.                IF err = 0 THEN DO 
  2547.                  SAY 'OS Version =' Info.11/10'.'Info.12 
  2548.                  SAY 'OS Revision =' Info.13 
  2549.                END 
  2550.                ELSE SAY  "FileSysInfo('Info', 11, 13) =" err 
  2551.  
  2552.                /* Get the total number of physical memory bytes */ 
  2553.                err = FileSysInfo('Info', 17) 
  2554.                IF err = 0 THEN SAY "Total bytes =" Info.17 
  2555.                ELSE SAY  "FileSysInfo('Info', 17) =" err 
  2556.  
  2557.  
  2558. ΓòÉΓòÉΓòÉ 4.14. FileIterateExe ΓòÉΓòÉΓòÉ
  2559.  
  2560. Syntax         err = FileIterateExe(program, source, destination, before, 
  2561.                after) 
  2562.  
  2563. Purpose        Calls another program a multiple number of times, passing it new 
  2564.                args each time.  The source and destination filenames can 
  2565.                contain wildcards, and these are automatically resolved upon 
  2566.                each call to the other program.  The net result is that 
  2567.                FileIterateExe can be used to specify filename args which 
  2568.                contain wildcards to programs that themselves can't deal with 
  2569.                wildcards.  FileIterateExe implements a "filename global pattern 
  2570.                matching" frontend for any program that accepts a filename 
  2571.                argument. 
  2572.  
  2573.                Note:  One limitation of FileIterateExe is that it can only 
  2574.                       invoke a program that is the same type as the program 
  2575.                       that launched your REXX script.  For example, if you 
  2576.                       launch your script from an OS/2 command prompt window, 
  2577.                       that you can invoke windowed apps, but not a Presentation 
  2578.                       Manager app.  If your script was launched from PMREXX, or 
  2579.                       my REXX Windowing Utility RX.EXE, or was launched by some 
  2580.                       PM app, then you can invoke a PM program, but not an OS/2 
  2581.                       full screen or windowed app.
  2582.  
  2583. Args           program is the name of the program to run.  This can be fully 
  2584.                qualified with a drive and path.  You should also specify an 
  2585.                extension if the program has one (ie, .exe or .cmd).  If program 
  2586.                is omitted, it defaults to the OS/2 command line shell.  (This 
  2587.                is useful if you wish to execute built-in commands of the shell, 
  2588.                such as DIR.  You'll omit the program arg, and pass 'DIR' as the 
  2589.                before arg). 
  2590.  
  2591.                source is the name of the file to supply as the source filename 
  2592.                to the program.  This can be fully qualified with a drive and 
  2593.                path.  If source is omitted, "*.*" is assumed (ie, invoke the 
  2594.                program upon each file in the current directory).  When the 
  2595.                source is a directory (as opposed to a single file), you must 
  2596.                end the arg with a \ character, or \*.*.  In this case, the 
  2597.                program is invoked upon all files in that directory. 
  2598.                FileIterateExe() never passes a program the name of any 
  2599.                directory, so it is only used for programs that operate upon 
  2600.                files, not directories themselves. 
  2601.  
  2602.                destination is the name of the file to supply as the destination 
  2603.                filename to the program.  This can be fully qualified with a 
  2604.                drive and path, as well as a new name for the file(s).  If 
  2605.                destination points to a drive or directory, then the source arg 
  2606.                is appended to that directory or drive name, and that becomes 
  2607.                the destination filename passed to the program.  If you want the 
  2608.                exact same destination as source name, then pass '*.*' for the 
  2609.                destination arg.  If the program doesn't require a destination 
  2610.                filename, or you don't wish to pass one, then omit the 
  2611.                destination arg. 
  2612.  
  2613.                The wildcards * and ? can be used when specifying the source or 
  2614.                destination.  This makes it possible to invoke the program upon 
  2615.                more than one file with a single call to FileIterateExe(), and 
  2616.                also supply new names for destination files.  * matches any 
  2617.                amount of characters up to a ..  ? matches any one character, 
  2618.                except for .. 
  2619.  
  2620.                before is any string of characters that should be placed before 
  2621.                the source and destination filenames (ie, at the start of the 
  2622.                line) when the args are passed to the program upon each 
  2623.                invocation.  Typically, these might be program "options" that 
  2624.                are required before any filenames. 
  2625.  
  2626.                after is any string of characters that should be placed after 
  2627.                the source and destination filenames (ie, at the end of the 
  2628.                line) when the args are passed to the program upon each 
  2629.                invocation.  Typically, these might be program "options" that 
  2630.                are required after any filenames. 
  2631.  
  2632.                Note:  FileIterateExe is not recursive.  That is, it won't 
  2633.                       invoke the program upon the files in any subdirectories 
  2634.                       that match some wildcard pattern.  For example, even if 
  2635.                       you specify *.* as the source string, FileIterateExe 
  2636.                       won't invoke the program upon the contents of any 
  2637.                       subdirectories within the current directory (nor the 
  2638.                       contents of any subdirectories inside of those 
  2639.                       subdirectories).  If you want recursive action, you have 
  2640.                       to use FileMatchFile to get a listing of all of the 
  2641.                       directories (ie, Flags = DIRONLY) in the desired 
  2642.                       directory, and then do a FileIterateExe on each 
  2643.                       subdirectory.  You'll also have to use FileMatchFile on 
  2644.                       each subdirectory to see if it has subdirectories too.
  2645.  
  2646.                The source filename is always specified before the destination 
  2647.                filename when passed to the program.  This means that programs 
  2648.                which require a source and destination filename must expect the 
  2649.                source first. 
  2650.  
  2651. Returns        If successful, a 0 is returned. 
  2652.  
  2653.                Note:  In order for FileIterateExe to work properly, the program 
  2654.                       must exit with a 0 for success.  Otherwise, you'll get an 
  2655.                       error back after the program is invoked with the first 
  2656.                       set of args.
  2657.  
  2658.                If an error, a non-zero number is returned, which represents the 
  2659.                error number from OS/2 or FILEREXX or the program being invoked. 
  2660.                Here are some possible error numbers, and their meanings (but if 
  2661.                the program also passes back some of these same numbers, then it 
  2662.                may be impossible to determine what the exact cause of the error 
  2663.                is): 
  2664.  
  2665.                2     File (ie, source) not found 
  2666.                3     Path not found 
  2667.                5     Access denied 
  2668.                26     Not DOS disk 
  2669.                32     Sharing violation 
  2670.                36     Sharing buffer exceeded 
  2671.                87     Invalid parameter 
  2672.                108    Drive locked 
  2673.                112    Destination disk is full 
  2674.                206    Filename exceeded character limit 
  2675.                267    Directory error 
  2676.                282    EAs not supported on destination 
  2677.                283    Need EAs found 
  2678.  
  2679. Examples       /* Invoke the program 'test.exe', specifying 'myfile' as the 
  2680.                source arg */ 
  2681.                err = FileIterateExe('test.exe', 'myfile') 
  2682.                IF err <> 0 THEN SAY 'ERROR:' err 
  2683.  
  2684.                /* Invoke the program 'test.exe' upon all files in the C:\OS2 
  2685.                directory */ 
  2686.                err = FileIterateExe('test.exe', 'C:\OS2\') 
  2687.                IF err <> 0 THEN SAY 'ERROR:' err 
  2688.  
  2689.                /* Invoke the program 'test.exe' upon all files in the C:\OS2 
  2690.                directory that end in .exe extension */ 
  2691.                err = FileIterateExe('test.exe', 'C:\OS2\*.exe') 
  2692.                IF err <> 0 THEN SAY 'ERROR:' err 
  2693.  
  2694.                /* Invoke the program 'test.exe' upon all files in the C:\ 
  2695.                directory that end in .bat extension, and also supply a 
  2696.                destination arg that consists of the filename with a .bak 
  2697.                extension instead of the .bat */ 
  2698.                err = FileIterateExe('test.exe', 'C:\*.bat', '*.bak') 
  2699.                IF err <> 0 THEN SAY 'ERROR:' err 
  2700.  
  2701.                /* Do a DIR on all of the files that end with the extension .c 
  2702.                in the current directory. Supply the option '/W' at the end of 
  2703.                the line */ 
  2704.                err = FileIterateExe(, '*.c', ,'DIR','/W') 
  2705.                IF err <> 0 THEN SAY 'ERROR:' err 
  2706.  
  2707.                /* Do a DIR on all of the files that end with the extension .c 
  2708.                in the current directory. Supply the option '/W' at the start of 
  2709.                the line (so we include it as part of the before arg) */ 
  2710.                err = FileIterateExe(, '*.c', ,'DIR /W') 
  2711.                IF err <> 0 THEN SAY 'ERROR:' err 
  2712.  
  2713.                Also look at the examples for FileMoveFile().  The way that you 
  2714.                specify the source and destination are applicable to 
  2715.                FileIterateExe(). 
  2716.  
  2717.                Note:  An OS/2 command line app is included, called TEST.EXE, 
  2718.                       which simply prints out the args that it receives upon 
  2719.                       each invocation.  You can use this to test out your call 
  2720.                       to FileIterateExe, to ensure that the arguments are being 
  2721.                       passed properly to a program.
  2722.  
  2723.                #define INCL_DOSPROCESS 
  2724.                #include <os2.h> 
  2725.                #include <stdio.h> 
  2726.                #include <conio.h> 
  2727.  
  2728.                main(int argc, char *argv[], char *envp[]) 
  2729.                { 
  2730.                  ULONG i; 
  2731.  
  2732.                  printf("================== %s has been invoked! 
  2733.                ===================\n\r", argv[0]); 
  2734.  
  2735.                  for (i=1; i<argc; i++) 
  2736.                  { 
  2737.                    printf("Arg #%d = %s\n\r", i, argv[i]); 
  2738.                  } 
  2739.  
  2740.                  printf("====================== All Done! 
  2741.                =======================\n\r"); 
  2742.  
  2743.                  DosExit(EXIT_PROCESS,0); 
  2744.                } 
  2745.  
  2746.  
  2747. ΓòÉΓòÉΓòÉ 4.15. FileBit ΓòÉΓòÉΓòÉ
  2748.  
  2749. Syntax         value = FileBit(Value, AdditionalArg, Operation) 
  2750.  
  2751. Purpose        Performs operations upon values expressed in binary.  A value 
  2752.                expressed in binary has digits that are '1's or '0's.  For 
  2753.                example, the hexadecimal byte (ie, 8 bits) of 71 is expressed in 
  2754.                binary as '01110001'. 
  2755.  
  2756.                Note:  Be careful not to use REXX's ARG command to parse binary 
  2757.                       expressions out of a string.  ARG automatically chops off 
  2758.                       any leading zeros on strings of digits.  For example, if 
  2759.                       you run the following: 
  2760.  
  2761.                /* */ 
  2762.                arg val 
  2763.                SAY val 
  2764.  
  2765.                and supply 00110101 as the argument when invoking the script, 
  2766.                you'll notice that val is '110101'.
  2767.  
  2768. Args           Value is the binary value to operation upon.  Binary values are 
  2769.                limited to 32 bits (ie, digits). 
  2770.  
  2771.                AdditionalArg is interpreted differently depending upon the 
  2772.                Operation.  For ROR, ROL, SHR, and SHL, this is the number of 
  2773.                bits to shift/rotate.  For AND, OR, or XOR, AdditionalArg is the 
  2774.                other binary value to AND/OR/XOR with.  For TEST, SET, CLR, or 
  2775.                FLIP, AdditionalArg is the bit number to operate upon, where 0 
  2776.                is the first (leftmost bit).  For XTRT, AdditionalArg will be 2 
  2777.                numbers.  The first number indicates which bit position to start 
  2778.                extracting at.  The second number is how many bits to be 
  2779.                extracted.  If AdditionalArg is omitted, it defaults to 0 (ie, 
  2780.                all 32 bits), except for XTRT, it defaults to 0 1 (ie, extract 
  2781.                the first bit). 
  2782.  
  2783.                Operation is one of the following: 
  2784.                  TEST  Test a specific bit (ie, return '0' if it's clear, or 
  2785.                '1' if it's set) 
  2786.                  CLR  Clear a specific bit (ie, change it to a '0') 
  2787.                  SET  Set a specific bit (ie, change it to a '1') 
  2788.                  FLIP  Toggle a specific bit (ie, if it was '0', change it to a 
  2789.                '1', and vice versa) 
  2790.                  AND  Mathematically AND the Value with the Additional Arg 
  2791.                  OOR  Mathematically OR the Value with the Additional Arg 
  2792.                  XOR  Mathematically Exclusive OR the Value with the Additional 
  2793.                Arg 
  2794.                  XTRT  Extract several bits. 
  2795.                  SHR  Shift all bits to the right. (Toss away bits that get 
  2796.                "shifted out" on the right, and replace them with 0 bits on the 
  2797.                left) 
  2798.                  SHL  Shift all bits to the left. (Toss away bits that get 
  2799.                "shifted out" on the left, and replace them with 0 bits on the 
  2800.                right) 
  2801.                  ROR  Rotate all bits to the right. 
  2802.                  ROL  Rotate all bits to the left. 
  2803.  
  2804.                If Operation is omitted, it defaults to TEST. 
  2805.  
  2806.                Note:  The value that you pass to FileBit is not padded out to 
  2807.                       8, 16, or 32 bits.  The returned value will be the same 
  2808.                       number of bits as the value you pass (with the exception 
  2809.                       of TEST and XTRT).  For example, if you pass '011' and do 
  2810.                       a ROR for 1 bit, the return is '101'.
  2811.  
  2812. Returns        The new value is returned for operations AND, OR, XOR, ROR, ROL, 
  2813.                SHR, SHL, SET, CLR, or FLIP.  For TEST, a '0' is returned if the 
  2814.                bit is clear, or a '1' is returned if the bit is set.  For XTRT, 
  2815.                only the number of bits that were requested to be extracted are 
  2816.                returned. 
  2817.  
  2818. Examples       /* AND '01010101' with '11110000'. The result is '01010000' */ 
  2819.                value = FileBit('01010101', '11110000', 'AND') 
  2820.                SAY value 
  2821.  
  2822.                /* Set bit 0 (ie, leftmost bit) of '1111000001110000'. The 
  2823.                result is '1111000001110001' */ 
  2824.                value = FileBit('1111000001110000', 0, 'SET') 
  2825.                SAY value 
  2826.  
  2827.                /* Extract 4 bits starting at bit 2. The result is '1100' */ 
  2828.                value = FileBit('11110000', 2 4, 'XTRT') 
  2829.                SAY value 
  2830.  
  2831.                /* Test bit 7. The result is '1' */ 
  2832.                value = FileBit('11110000', 7) 
  2833.                SAY value 
  2834.  
  2835.  
  2836. ΓòÉΓòÉΓòÉ 4.16. FileDoSleep ΓòÉΓòÉΓòÉ
  2837.  
  2838. Syntax         err = FileDoSleep(Milliseconds) 
  2839.  
  2840. Purpose        Allows a script to perform a delay in a manner which allows 
  2841.                other OS/2 programs to multi-task while your script is 
  2842.                "sleeping". 
  2843.  
  2844.                Note:  FileDoSleep cannot be called from a script launched by a 
  2845.                       PM application (unless that app launches the script from 
  2846.                       a secondary thread).  If FileDoSleep causes the script to 
  2847.                       lockup when launched by PMREXX, VXREXX, VREXX, and other 
  2848.                       visual REXX packages, that would be the problem. 
  2849.                       (Definitely don't call FileDoSleep in a script that uses 
  2850.                       my own visual REXX package, Rexx Dialog, also freely 
  2851.                       available).  You'll need to find some other means to do a 
  2852.                       delay in your script.
  2853.  
  2854. Args           Milliseconds is the amount of time to sleep, in milliseconds 
  2855.                (ie, 1000 milliseconds = 1 second).  If you omit this arg, it 
  2856.                defaults to 1 second delay. 
  2857.  
  2858. Returns        If successful, a 0 is returned. 
  2859.  
  2860.                If an error, a non-zero number is returned, indicating that the 
  2861.                function has already timed out upon return. 
  2862.  
  2863. Examples       /* Sleep for 5000 milliseconds (ie, 5 seconds) */ 
  2864.                err = FileDoSleep(5000) 
  2865.