Navigation:  Reference > Commands >

Scan Records in File

Print this Topic Previous pageReturn to chapter overviewNext page


This command combines the work of a WHILE/ENDW loop and the FINDV (Find Record) command into one super command.  This is actually the starting point of a control structure.


SCAN file_num Required - The number/handle of the file to be used.  If you do not include this option, the program will look for a default search file set in the SRCH (Search File) command.  If that hasn't been previously set, the program will report an error and the command will be skipped.  This entry will override any default value set in the SRCH command.


       NOTE:  You must enter something here as a place marker, so put '' (double single quotes) for this option if you want to use the SRCH file.


KEY key_expr Set this to the appropriate value to read the records in the file in the correct order.  If you do not include this option, the program will look for a default key set in the SRCH command.  If a default key hasn't been previously set the program will report an error and the command will be skipped.  This entry will override any default value set in the SRCH command.


START f/c/e1,f/c/e2,...,f/c/ex The value to use as the beginning record.  This is similar to doing a FINDV (Find Record) before the command.  If the index you're searching on has multiple segments you may list the proper value for each segment, separating them with commas.  This will allow you to specify the exact type for each of the segments.  For example, suppose you're searching on an index that has two segments:  a 5 character alpha and an I type field.  Each record you want has the same alpha but the I field will change, and is in order.  In the first record the I type field has a value of 0.  The following would find the first record for that group, if it exists:


               start 'ABCDE',0!


       Notice that we separate the values with a comma.  The only requirement is that the values be of the same type (and size) as the segments in the key.  In this case we put the I type constant specifier (!) after the 0 to make sure that it is passed as an I type field.



       scope - This option may help determine how many records are read.  The options are:  A (All), F (First), N (Next) and R (Rest).  For more information about the scope specifier please see the general information at the beginning of this chapter.


       f/c/e - If scope is set to N or F this is the number of records to read.


       An example of this would be:


               ... SCOPE A...                //all records in the file.  This is the default scope value.


               ... SCOPE N 20 ...        //the next 20 records in the file


FOR lexpr You would use this option to restrict the records read in this command.  If the expression did not resolve to .TRUE. the record would not be read.    In this option, the search continues until the program reaches the end of file and then will quit.  Any legal expression that resolves to .TRUE. or .FALSE. can be used.


       An example of this would be:


               ... FOR (x=100) .and. (y=200) ...

                            Note : You can use the FOR to help you display the progress bar. example for ChkFilter() don't forget to set the min                 and max values on the progress bar.


                        func ChkFilter

                                              '@pbRecCount.Position' = RecCntr   // This updates my progress bar

                                                (x=100) .and. (y=200) ...

                                        Ret .t.


WHILE lexpr This option also restricts the records read.  However, the first time the expression resolves to .FALSE., the program stops reading records and continues to the next command.  Here's the benefit of this option:  if the program is reading records in a certain order (by a specific key) and the expression returns .FALSE. then the program knows that all the appropriate records have been read and there is no need to continue.  For example:  You want to read all the invoice records for a specific customer.  The first record for that customer is found in the invoice file either by using the start_value option within this command, or through the FINDV (Find Record) command before executing this command.  Then the WHILE expression would be:




       (This assumes that there is a field called INV_CUST_CODE in the invoice file and a like field in the customer file called CUSTOMER_CODE.  The KEY option must be set to the proper value so that the records are read in CUSTOMER_CODE order, or you must have set the SRCH command previous to this command.)  When the first invoice record for the next customer is read the program will stop reading records.


       NOTE:  If there is no START value you must set the scope value to R or N xxx.  If you do not do this, the program will find the first record in the file and the WHILE expression will probably fail the first time.  However, if the START option is used you can ignore this requirement.


DISPEach time a record is read the program will redisplay the screen fields, if you specify this option.  This will slow down the operation of this command, depending on how many fields are displayed on the screen.


NLOCK If this option is included in the command the program will NOT lock the record upon finding it as it would normally do in a multi-user situation.  The default operation is to place a lock on the record upon reading it.


REVIf this option is included, the SCAN will be performed in reverse order.




This command, together with the other parts of the control structure, could easily become your most used command when accessing records in any file.  With just two commands, SCAN and ENDS (Endscan) you can create a loop that will automatically provide to the commands within that loop just the records necessary for the operation and no others.  When the last record in the file, or the last appropriate record, has been read, the program will automatically transfer control to the line after the appropriate ENDS command and continue with the program.  The SLOOP, and SLOOP_IF commands will transfer control back to the beginning of the loop and the next record will be found without any other Find command!  This single structure can replace many lines of code in your programs.

The SEXIT, and SEXIT_IF[****]commands will exit the loop. This single structure can replace many lines of code in your programs.


For more information on the different structured programming commands, and the SCAN command in particular, please see Structured Programming Commands.






This example would scan the bkarinvl_hndl file and link up records in three other files by using the findv command. Then sending data to a report.   When it finished it would print the report. This also shows how to create a function that can be used to filter the data for you. // the event

      scan @bkarinvl_hndl key bkar.invl.invnm start fromso //Scan the records

                findv m fnum bkarinv_hndl key BKAR.INV.SONUM value bkar.invl.invnm // find the inv header

                findv m fnum bkicmstr_hndl key value bkar.inv.pcode

                findv M fnum bkicloc_hndl key bkic.loc.key value bkar.invl.pcode,BKAR.INV.LOC

              sloop_if bkar.invl.invnm = 0 // Loop back if true if you used a sexit or sexit_if you would ends

                sloop_if .n. filter1()

               output_report_data rb_num 1 // send data to report

              '@progressbar1.position' = REC_PERCENTAGE(bkarinvl_hndl) //update the progress bar

      ends // Stop scanning

      print_report //Print the report


you could also use this scan line and take out the sloop_if using a for or a while

scan @bkarinvl_hndl key bkar.invl.invnm start fromso for filter1()


scan @bkarinvl_hndl key bkar.invl.invnm start fromso while filter1()


func filter1

      '@pbRecCount.Position' = RecCntr   // This updates my progress bar      

       if  fromso <> 0

          if  fromso < bkar.invl.invnm

             ret .f.



      ret .t.

      if thruso <> 0

          if bkar.invl.invnm > thruso

              ret .f.



      // you could add more filters if needed for your application here.

    ret .t.

Note : If using this type filter in a scan fields in this checking have to be in file your scanning.

Example Using scan and  xfer in codebase where we have two files sharing same schema and rec_buf

openv 'myfile1' fnum file1_hndl lock N
openv 'myfile2' fnum file2_hndl lock N

scan @File1_hndl key @0   //read all records using natural order
  clr @file2_hndl buff   // This has to be on the loop
  xfer from file1_hndl to file2_hndl Rec_Buff
  save @file2_hndl nocnf //save the history


More on codebase

   scan @boxcount_hndl key MACHINE_ID

          sloop_if OPENED = .t.

          EXCEPTION = .t.

          if exnote = ''

            EXNOTE = exnote_error

            OPENDATE = date()

            OPENETIME = time()

            USR_CODE = user


          save @boxcount_hndl nocnf noclr 

          //in codebase we have to use the noclr in the save in a scan.

          // otherwise the scan looses the record to get the next record..

          // and we get a codebase error -910








Page url: