home *** CD-ROM | disk | FTP | other *** search
/ Programming Languages Suite / ProgramD2.iso / Database / CLIPR503.W96 / FILEIO.PR_ / FILEIO.PR
Text File  |  1995-06-20  |  9KB  |  369 lines

  1. /***
  2. *
  3. *  Fileio.prg
  4. *
  5. *  Sample user-defined functions to process binary files
  6. *
  7. *  Copyright (c) 1993-1995, Computer Associates International Inc.
  8. *  All rights reserved.
  9. *
  10. *  NOTE: Compile with /a /m /n /w
  11. */
  12.  
  13. #include "Common.ch"
  14. #include "Fileio.ch"
  15.  
  16.  
  17. /***
  18. *
  19. *  FGets( <nHandle>, [<nLines>], [<nLineLength>], [<cDelim>] ) --> cBuffer
  20. *
  21. *  Read one or more lines from a text file
  22. *
  23. */
  24. FUNCTION FGets( nHandle, nLines, nLineLength, cDelim )
  25.    RETURN ( FReadLn( nHandle, nLines, nLineLength, cDelim ) )
  26.  
  27.  
  28.  
  29. /***
  30. *
  31. *  FPuts( <nHandle>, <cString>, [<nLength>], [<cDelim>] ) --> nBytes
  32. *
  33. *  Write a line to a text file
  34. *
  35. */
  36. FUNCTION FPuts( nHandle, cString, nLength, cDelim )
  37.    RETURN ( FWriteLn( nHandle, cString, nLength, cDelim ) )
  38.  
  39.  
  40.  
  41. /***
  42. *
  43. *  DirEval( <cMask>, <bAction> ) --> aArray
  44. *
  45. *  Apply a code block to each file matching a skeleton
  46. *
  47. */
  48. FUNCTION DirEval( cMask, bAction )
  49.    RETURN ( AEVAL( DIRECTORY( cMask ), bAction ) )
  50.  
  51.  
  52.  
  53. /***
  54. *
  55. *  FileTop( <nHandle> ) --> nPos
  56. *
  57. *  Position the file pointer to the first byte in a binary file and return
  58. *  the new file position (i.e., 0).
  59. *
  60. */
  61. FUNCTION FileTop( nHandle )
  62.    RETURN ( FSEEK( nHandle, 0 ) )
  63.  
  64.  
  65.  
  66. /***
  67. *
  68. *  FileBottom( <nHandle> ) --> nPos
  69. *
  70. *  Position the file pointer to the last byte in a binary file and return
  71. *  the new file position
  72. *
  73. */
  74. FUNCTION FileBottom( nHandle )
  75.    RETURN ( FSEEK( nHandle, 0, FS_END ) )
  76.  
  77.  
  78.  
  79. /***
  80. *
  81. *  FilePos( <nHandle> ) --> nPos
  82. *
  83. *  Report the current position of the file pointer in a binary file
  84. *
  85. */
  86. FUNCTION FilePos( nHandle )
  87.    RETURN ( FSEEK( nHandle, 0, FS_RELATIVE ) )
  88.  
  89.  
  90.  
  91. /***
  92. *
  93. *  FileSize( <nHandle> ) --> nBytes
  94. *
  95. *  Return the size of a binary file
  96. *
  97. */
  98. FUNCTION FileSize( nHandle )
  99.  
  100.    LOCAL nCurrent
  101.    LOCAL nLength
  102.  
  103.    // Get file position
  104.    nCurrent := FilePos( nHandle )
  105.  
  106.    // Get file length
  107.    nLength := FSEEK( nHandle, 0, FS_END )
  108.  
  109.    // Reset file position
  110.    FSEEK( nHandle, nCurrent )
  111.  
  112.    RETURN ( nLength )
  113.  
  114.  
  115.  
  116. /***
  117. *
  118. *  FReadLn( <nHandle>, [<nLines>], [<nLineLength>], [<cDelim>] ) --> cLines
  119. *
  120. *  Read one or more lines from a text file
  121. *
  122. *  NOTES:
  123. *     Line length includes delimiter, so max line read is
  124. *     (nLineLength - LEN( cDelim ))
  125. *
  126. *     Return value includes delimiters, if delimiter was read
  127. *
  128. *     nLines defaults to 1, nLineLength to 80 and cDelim to CRLF
  129. *
  130. *     FERROR() must be checked to see if FReadLn() was successful
  131. *
  132. *     FReadLn() returns "" when EOF is reached
  133. *
  134. */
  135. FUNCTION FReadLn( nHandle, nLines, nLineLength, cDelim )
  136.  
  137.    LOCAL nCurPos        // Current position in file
  138.    LOCAL nFileSize      // The size of the file
  139.    LOCAL nChrsToRead    // Number of character to read
  140.    LOCAL nChrsRead      // Number of characters actually read
  141.    LOCAL cBuffer        // File read buffer
  142.    LOCAL cLines         // Return value, the lines read
  143.    LOCAL nCount         // Counts number of lines read
  144.    LOCAL nEOLPos        // Position of EOL in cBuffer
  145.  
  146.    DEFAULT nLines      TO 1
  147.    DEFAULT nLineLength TO 80
  148.    DEFAULT cDelim      TO ( CHR(13) + CHR(10) )
  149.  
  150.    nCurPos   := FilePos( nHandle )
  151.    nFileSize := FileSize( nHandle )
  152.  
  153.    // Make sure no attempt is made to read past EOF
  154.    nChrsToRead := MIN( nLineLength, nFileSize - nCurPos )
  155.  
  156.    cLines  := ''
  157.    nCount  := 1
  158.    DO WHILE (( nCount <= nLines ) .AND. ( nChrsToRead != 0 ))
  159.  
  160.       cBuffer   := SPACE( nChrsToRead )
  161.       nChrsRead := FREAD( nHandle, @cBuffer, nChrsToRead )
  162.  
  163.       // Check for error condition
  164.       IF !(nChrsRead == nChrsToRead)
  165.          // Error!
  166.          // In order to stay conceptually compatible with the other
  167.          // low-level file functions, force the user to check FERROR()
  168.          // (which was set by the FREAD() above) to discover this fact
  169.          //
  170.          nChrsToRead := 0
  171.       ENDIF
  172.  
  173.       nEOLPos := AT( cDelim, cBuffer )
  174.  
  175.       // Update buffer and current file position
  176.       IF ( nEOLPos == 0 )
  177.          cLines  += LEFT( cBuffer, nChrsRead )
  178.          nCurPos += nChrsRead
  179.       ELSE
  180.          cLines  += LEFT( cBuffer, ( nEOLPos + LEN( cDelim ) ) - 1 )
  181.          nCurPos += ( nEOLPos + LEN( cDelim ) ) - 1
  182.          FSEEK( nHandle, nCurPos, FS_SET )
  183.       ENDIF
  184.  
  185.       // Make sure we don't try to read past EOF
  186.       IF (( nFileSize - nCurPos ) < nLineLength )
  187.          nChrsToRead := ( nFileSize - nCurPos )
  188.       ENDIF
  189.  
  190.       nCount++
  191.  
  192.    ENDDO
  193.  
  194.    RETURN ( cLines )
  195.  
  196.  
  197.  
  198. /***
  199. *
  200. *  FileEval( <nHandle>, [<nLineLength>], [<cDelim>], ;
  201. *            <bBlock>, 
  202. *            [<bForCondition>], 
  203. *            [<bWhileCondition>],
  204. *            [<nNextLines>],
  205. *            [<nLine>],
  206. *            [<lRest>] )   --> NIL
  207. *
  208. *  Apply a code block to lines in a binary file using DBEVAL() as a model.
  209. *  If the intent is to modify the file, the output must be written to a
  210. *  temporary file and copied over the original when done.
  211. *
  212. *  NOTES:
  213. *     <bBlock>, <bForCondition> and <bWhileCondition> are passed a
  214. *     line of the file
  215. *
  216. *     The defaults for nLineLength and cDelim are the same as those
  217. *     for FReadLn()
  218. *
  219. *     The default for the rest of the parameters is that same as for
  220. *     DBEVAL().
  221. *
  222. *     Any past EOF requests (nLine > last line in file, etc.) are ignored
  223. *     and no error is generated.  The file pointer will be left at EOF.
  224. *
  225. *     Check FERROR() to see if it was successful
  226. *
  227. */
  228. PROCEDURE FileEval( nHandle, nLineLength, cDelim, bBlock, bFor, bWhile, ;
  229.                     nNextLines, nLine, lRest )
  230.  
  231.    LOCAL cLine          // Contains current line being acted on
  232.    LOCAL lEOF := .F.    // EOF status
  233.    LOCAL nPrevPos       // Previous file position
  234.  
  235.    DEFAULT bWhile TO {|| .T. }
  236.    DEFAULT bFor   TO {|| .T. }
  237.  
  238.    // lRest == .T. means stay where I am.  Anything else means start from
  239.    // the top of the file
  240.    IF ! ( ( VALTYPE(lRest) == 'L' ) .AND. ( lRest == .T. ) )
  241.       FileTop( nHandle )
  242.    ENDIF
  243.  
  244.    BEGIN SEQUENCE
  245.       
  246.       IF nLine != NIL
  247.          
  248.          // Process only that one record
  249.          nNextLines := 1
  250.  
  251.          FileTop( nHandle )
  252.  
  253.          IF nLine > 1
  254.             cLine := FReadLn( nHandle, 1, nLineLength, cDelim )
  255.             IF FERROR() != 0
  256.                BREAK    // An error occurred, jump out of the SEQUENCE
  257.             ENDIF
  258.  
  259.             // If cLine is a null string, we're at end of file
  260.             lEOF := ( cLine == "" )
  261.             nLine--
  262.          ENDIF
  263.  
  264.          // Move to that record (nLine will equal 1 when we are there)
  265.          DO WHILE ( ! lEOF  ) .AND. (nLine > 1)
  266.             cLine := FReadLn( nHandle, 1, nLineLength, cDelim )
  267.             IF FERROR() != 0
  268.                BREAK          // NOTE: will break out of SEQUENCE
  269.             ENDIF
  270.  
  271.             lEOF := ( cLine == "" )
  272.             nLine--
  273.          ENDDO
  274.  
  275.       ENDIF
  276.  
  277.       // Save starting position
  278.       nPrevPos := FilePos( nHandle)
  279.  
  280.       // If there is more to read from here, get the first line for
  281.       // comparison and potential processing 
  282.       IF ( ! lEOF ) .AND. (nNextLines == NIL .OR. nNextLines > 0)
  283.          cLine := FReadLn( nHandle, 1, nLineLength, cDelim )
  284.          IF FERROR() != 0
  285.             BREAK             // NOTE
  286.          ENDIF
  287.  
  288.          lEOF := ( cLine == "" )
  289.       ENDIF
  290.  
  291.       DO WHILE ( ! lEOF ) .AND. EVAL( bWhile, cLine )      ;
  292.                .AND. (nNextLines == NIL .OR. nNextLines > 0)
  293.  
  294.          IF EVAL( bFor, cLine )
  295.             EVAL( bBlock, cLine )
  296.          ENDIF
  297.  
  298.          // Save start of line
  299.          nPrevPos := FilePos( nHandle )
  300.  
  301.          // Read next line
  302.          cLine    := FReadLn( nHandle, 1, nLineLength, cDelim )
  303.          IF FERROR() != 0
  304.             BREAK
  305.          ENDIF
  306.  
  307.          lEOF := ( cLine == "" )
  308.  
  309.          IF nNextLines != NIL
  310.             nNextLines--
  311.          ENDIF
  312.  
  313.       ENDDO
  314.  
  315.       // If the reason for ending was that I ran past the WHILE or the number
  316.       // of lines specified, back up to the beginning of the line that failed
  317.       // so that there is no gap in processing
  318.       //
  319.       IF ( ! EVAL( bWhile, cLine ) ) .OR. ;
  320.          ( (nNextLines != NIL) .AND. (nNextLines == 0) )
  321.  
  322.          FSEEK( nHandle, nPrevPos, FS_SET )
  323.  
  324.       ENDIF
  325.  
  326.    END SEQUENCE
  327.  
  328.    RETURN
  329.  
  330.  
  331.  
  332. /***
  333. *
  334. *  FEof( <nHandle> ) --> lBoundary
  335. *
  336. *  Determine if the current file pointer position is the last
  337. *  byte in the file
  338. *
  339. */
  340. FUNCTION FEof( nHandle )
  341.    RETURN ( IF( FileSize( nHandle ) == FilePos( nHandle ), .T., .F. ))
  342.  
  343.  
  344.  
  345. /***
  346. *
  347. *  FWriteLn( <nHandle>, <cString>, [<nLength>], [<cDelim>] ) --> nBytes
  348. *
  349. *  Write a line to a text file at the current file pointer position. 
  350. *  
  351. *  NOTES:
  352. *     Check FERROR() for the error
  353. *
  354. *     nLength defaults to length of entire string + delim, cDelim
  355. *     defaults to CHR(13) + CHR(10)
  356. *
  357. *     Return value includes length of delimiter
  358. *
  359. */
  360. FUNCTION FWriteLn( nHandle, cString, nLength, cDelim )
  361.  
  362.    IF cDelim == NIL
  363.       cString += CHR(13) + CHR(10)
  364.    ELSE
  365.       cString += cDelim
  366.    ENDIF
  367.  
  368.    RETURN ( FWRITE( nHandle, cString, nLength ) )
  369.