MMCC MASTHEAD
Mid-Michigan Computer Consultants, Inc.
509 Center
Bay City, Michigan
NOTE TO OUR READERS
This web resource is written for our own use. But we feel strongly that the PL/B language should be shared with the software community. So feel free to use this at will! BUT PLEASE... if you find errors or omissions or have a better way to do something. TELL US! Dialog helps us all. Send e-mail to: support@mmcctech.com

ANSI Standard PL/B Language

FILE HANDLING NOTES

#PLB_0310_Rev#
This section discusses various file handling techniques and tools. Topics on this page include:

DEFINING FILES:

Use the FILE, IFILE, or AFILE to define a file. These are well defined in the Sunbelt manuals.

MMCC Typically uses IFILE (indexed) and FILE (sequential).

Sequential FILE are typically defined as {name} FILE BUFFER=nnnn. The understanding is that larger buffer sizes help performance. With modern Windows systems having huge amounts of RAM, we'll frequently just make this size 8000. It's hard to prove if it really helps.

IFILE index files are typically defined as {name} IFILE BUFFER=nnn,NODUP. In this case the BUFFER size is the defined record size desired for the file. It is not clear that the buffer size is still needed, but MMCC does it as a rule.

OPENING FILES:

Files may be OPENed or PREPed.
    OPEN is for a pre-existing file,
    PREP is used to create a new file.

There are quite a few variations on OPEN. But OPEN us usually as simple as:
    OPEN {filename}
        or
    PREP {filename}.

There are quite a few variations on OPEN. But OPEN us usually as simple as:
    OPEN {filename}
        or
    PREP {filename}.

OPEN MODE:
  • The most common variation to the OPEN is to add a sharing mode qualifier such as:
        OPEN {filename},READ

  • The most common sharing mode choices are READ, SHARE, and EXCLUSIVE,

  • The default mode is SHARE.

  • There are other opening modes documented in the SUNBELT manuals.

  • NOTE: Indexed files can have multiple indexes. If you're doing that then you must open all of the related files in SHARE mode if you plan to update any of the indexes.


There are quite a few variations on OPEN. But OPEN us usually as simple as:
    OPEN {filename}
        or
    PREP {filename}.

OPENING BINARY FILES:

As a general rule PL/B makes no distinction concerning binary files. Declare the file using the standard sequential FILE statement. The trick comes when reading the file since it may contain standard end of record characters. Most people would read it using the "absolute" (*ABSON / *ABSOFF) list controls. This allows you to read a block or a byte without regard to it being a control character.

The following note was from Sunbelt's Steve White in March 2009 in response to a question about why a very large binary file took a long time to open.
You are correct in your suspicion that the binary file without record delimiters is causing the problem. Since Sunbelt supports multiple data formats transparently we must know what format the file is in. So we start at the end of file and work backwards looking for CR/LF or LF sequences. If the file does not have either anywhere in it, then we will eventually get to the beginning of file and give up. So a gigabyte size file will take a while before getting to the beginning.

We have had a method for the programmer telling the compiler what type the file is and avoiding this searching. It is the FORMAT option on the FILE statement. If you set FORMAT=BINARY, then NO searching is done. This has been a documented option, but unfortunately in the wrong place. The current documentation says it is for RMSRAS from Datapoint only. This is not correct and the documentation will be corrected for the next release.

USEFUL TOOLS and TECHNIQUES
  • OPEN/PREP {nul file name}
    When you use a file name that's
    NUL (empty), the open instruction will present the standard Windows open dialog window. The user can browse to the file of their choice.

    To do this, the file name string must be completely nul. You can NOT include a partial file name like "*.JPG". If that's what you want to do, look at the next item: OPENDEFAULT.

  • OPENDEFAULT and PREPDEFAULT
    These two don't actually perform any opening actions. Instead they set the default PROMPT and FILE MASK that will be used in other open methods. For example you could say
         OPENDEFAULT "Select a picture file","*.jpg"
    The next OPEN which gets Windows' open dialog will have that prompt and will only allow files with extension ".jpg".

    You can also include a PATH in this opening method:
         OPENDEFAULT "Select a picture file","\pictures\condos\*.jpg"

  • GETFILE
    This will just retreive information about an open file. If you open a file using a NUL name, which means that the user browses to the file of choice, you can use the GETFILE to find the name of the file.

    This is a simple instruction and it's well documented in the Sunbelt manuals. We've added more information under: GETFILE


Datalist.DIR method
  • {datalist object}.DIR [GIVING {return}] USING [*FileSpec=]{filespec},[*Flags=]{flags}

    This is a great method for filling a datalist with the files in a given path.

    Here are a few notes from experimentation:
    • The *FILESPEC seems to require the full path. To get the path that you're running from we usually start with:
             PATH  CURRENT,CURR_PATH
             PACK  WORK_PATH,CURR_PATH,"\*.txt"
             MY_DataList.DIR USING *FileSpec=WORK_PATH:
                                   *Flags=DDL_READWRITE
      

    • The method requires the SHORT filename in the path. If you're starting with a long path, i.e. My_Documents, you can use a FINDFILE to get the ALTPATH which is the short filename MYDOCU~1.

    • The method also RETURNS SHORT filenames. Our practice is to do the .DIR, then come back and pull each line out of the datalist and use FINDFILE to get the full details. We then put those back into the list.

    • The *FLAGs shown below are defined in the Sunbelt supplied PLBMETH.INC source file.

    • The *FLAGs defined by Sunbelt are INTEGER 4. It looks like they could also be INTEGER 2, but that's not confirmed.

    • The *FLAGs seem to be a 16 wide bitmask. By implication it seems that you could add flags together to get multiple properties. We've not tried that.


    The PLBWIN manual can give the basics. Here's an extract which we'll add to later:


      Value Keyword Includes ...       Defined in PLBMETH.inc
      0x0000 DDL_READWRITE Files that can be read or written.
      0x0001 DDL_READONLY Files that can be read but not written.
      0x0002 DDL_HIDDEN Hidden files.
      0x0004 DDL_SYSTEM System files.
      0x0010 DDL_DIRECTORY Directories.
      0x0020 DDL_ARCHIVE File has been archived.
      0x4000 DDL_DRIVES Include all drives.
      0x8000 DDL_EXCLUSIVE Exclusive flag. If the exclusive flag is set, only files of the specified type are listed. Otherwise, files of the specified type are listed in addition to normal files.
      3. Upon completion, {return} will contain the zero-based index of the last filename in the list or -1 if the method fails.
      4. If the value returned is zero, the ZERO (or EQUAL) Condition Flag is set (TRUE).
      5. If {return} is too small to contain the string index, the OVER Condition Flag is set (TRUE).
      6. The EOS Condition Flag is always cleared (FALSE).

  • GETFILE     Get information about a file after it's open.

    This is really handy when you let the user enter the file name and they enter a blank which causes Windows to let them broswe for the file. You need some way to know which file they chose. Use GETFILE after the file is open, then you can use
    FINDFILE to get even more information about the file.

    [label] GETFILE {file},{keyword}={value}[,{keyword=value}...]
    • If the file is NOT OPEN, the ZERO flag is cleared and the variables remain unchanged.
    • If the file is OPEN, the ZERO flag is set.
    • The EOS flag is set if any variable overflows.
       ...........................
       .   Example
       .
       MYFILE     FILE
       FILENAME   DIM   250
           OPEN        MYFILE, "ZZDATA"
           GETFILE     MYFILE, TXTNAME=FILENAME
           IF ZERO
               DISPLAY "File name is ",*HON,*LL,FILENAME,*PL,*HOFF
             ELSE
               DISPLAY "File is NOT OPEN"
           ENDIF
    
    Selected Keywords from the Sunbelt Visual PL/B manual. (There are lots more)
       ISINAME={svar} qualified (with path) ISI file name.
       MODE={nva} opened: 0=Not Defined, 1=EXCLUSIVE, 2=SHARE, 3=READ, 4=SHARENF.
       PRTNAME={svar} name stored for a PFILE.
       TXTNAME={svar} qualified (with path) text file name.
    
    Check the manual for information relating to COMFILEs, PFILEs, etc.

    Fillow this with a FINDFILE to get even more information about the file

    VERSION 9.x FILEFORMAT

    Version 9 added a FILEFORMAT flag to the GETFILE. This gives some useful information about an ISI file. The basic usage would be something like:
        OPEN    ISIFILE,"NAME"
        GETFILE FILEFORMAT=NWK03
    
    The language ref says the FILEFORMAT value contains bits with the following meaning
    0x1  0000 0001  IFILE
    0x2  0000 0010  AFILE
    0x10 0001 0000  version 9.0x format
    0x20 0010 0000  version 8.7x format
    0x40 0100 0000  the ISI file supports file larger than 4BG.
    
    The GETFILE FILEFORMAT should be given a 3 digit FORM field for the return value. That's because you're going to get a decimal number which could range from 0 to 255 (8 bit binary value).

    Move that number to an INTEGER 1 to get the binary value in a single byte.

    Move the INTEGER 1 to a DIM 1 so that you can do a logical AND against it.

    Now test with the AND. If the ZERO flag is not set then the bit position you're testing has a 1. (1 AND 1 = 1 . . . 1 AND 0 = 0)

    If you test multiple flags, be sure to move the integer to the DIM 1 again because the AND is destructive.

     
    TEST_ISI_FILE  IFILE
    NWK03          FORM     3
    INT1           INTEGER 1
    WORK01         DIM        1
    .
        OPEN      TEST_ISI_FILE,"TESTFILE"
        GETFILE   TEST_ISI_FILE, FILEFORMAT=NWK03
        MOVE      NWK03, INT1
    .
        MOVE      INT1,    WORK01
        AND       0x1,      WORK01
        IF NOT ZERO
            ..... I file
        ENDIF
    .
        MOVE      INT1,    WORK01
        AND       0x2,      WORK01
        IF NOT ZERO
            ..... A file
        ENDIF
    .
        MOVE      INT1,     WORK01
        AND       0x10,      WORK01
        IF NOT ZERO
            ..... 9.x ISI
        ENDIF
    .
        MOVE      INT1,     WORK01
        AND       0x20,      WORK01
        IF NOT ZERO
            ..... 8.7 ISI
        ENDIF
    .
        MOVE      INT1,     WORK01
        AND       0x40,      WORK01
        IF NOT ZERO
            ..... allows 4GB files
        ENDIF
    

  • GETFNAME      THIS ONE IS POWERFUL

    This instruction does everything that an OPEN or a PREP would do except to actually open or prep the files. Basically it will present the Windows OPEN dialog to let the user select the file they want. On exit it returns the selected filename and path. You can then use that name in a subsequent OPEN or PREP.

    This is very powerful, but the syntax in the manual can be a bit difficult to follow.
    Here's what we've learned:

    The basic format for the instruction is:
           GETFNAME    TYPE=OPEN_MODE:
                       PROMPT_STRING:
                       FILE_NAME:
                       FILE_PATH:
                       FILTER_STRING
    
    • The TYPE parameter defines the "mode" and the "dialog type". That is, it tells Windows how to handle the interaction with the user. We'll defened that below.

    • The PROMPT_STRING will appear in the title of the Windows open dialog box. You can use a literal or a string variable for this one.

    • The FILE_NAME is just that. If you pre-load the name, even with a mask like *.TXT, then only files matching that name or mask will be shown. On return you get the file name that the user clicked.

    • The FILE_PATH is just that. You can enter any path that you want and that's where the open dialog starts. The user can still navigate to other paths as you'd expect. On return you get the final path to the file that the user selected.

    • FILTER_STRING is a special case and only goes with certain open dialog types. We'll talk about those next.

    RETURNS
    • If user CANCELs, OVER is set.

    • If NOT OVER:
      • File name is stored in the name variable
      • The path is stored in the path variable.
        (Path ends with a backslash).

    GETFNAME: The TYPE parameter:

    The TYPE parameter defines the "mode" and the "dialog type". That is, it tells Windows how to handle the interaction with the user.

    TYPE allows two basic MODES: Open and Prep. There are several variations of each.

    All that this particular MODE does is to tell windows it it should ask "do you want to overwrite" if the file already exits. That is:
    • In OPEN mode the user selects a file and control immediately returns to your program.
    • In PREP mode Windows will see if the selected filename already exists and, if so, it will ask the "overwrite" question. If the user answers NO to "overwrite" then control stays in the open dialog so the user can try again.

    You can actually code the GETFNAME using the word OPEN or PREP in that first parameter. But there are other, more useful modes which are identified numerically using by saying TYPE=nn. The nn is a number representing the mode.

    Both the plain OPEN and PREP are included in the numbered type list so you can really just always use the TYPE=nn. For example the following two opens are equivalent to each other:
         GETFNAME TYPE=OPEN
         GETFNAME TYPE=1


    That numeric TYPE can be a variable as well. So you can easily set it from your program and use a single GETFNAME to do several different things.
        OPEN_TYPE  FORM        2
                   MOVE        "1" to OPEN_TYPE
                   GETFNAME    TYPE=OPEN_TYPE
    
    The GETFNAME open TYPE table is as follows:
    MODE DIALOG TYPE
    OPEN Standard open dialog
    PREP Standard prep dialog
    TYPE=1 Standard open dialog
    TYPE=2 Standard prep dialog
    TYPE=17 Open dialog with user filter
    TYPE=18 Prep dialog with user filter.
    TYPE=33 Open dialog with multi-select feature.
    TYPE=34 Prep dialog with multi-select feature.
    TYPE=49 Open dialog with filter and multi-select.
    TYPE=50 Prep dialog with filter and multi-select.

    Here's what the Sunbelt manual says about TYPE and FILTERS:
    3. When {mode} identifies employment of a user filter, the string format requires {info} and {filter} pairs to follow the extension which are then passed to the Open or Prep dialogs. The {type} string format is as follows:
          {ext}[,{info1},{filter1}[,{info2},{filter2}]...]
    Where:
    • {ext} Identifies the default extension used when no name filtering is provided.
    • {info1} First information/comment string presented and associated with the file filter which follows it.
    • {filter1} First file filter which can be one or more files separated by the semicolon character. The file names can be specific or partial names and include wildcard characters. When a user selects the {info1} identifier, only those files which conform to the filter appear in the dialog presentation window.
    Here's what that translates to in real-world usage:

    TYPE:

    • You can use a variable or a literlal numeric parameter for the GETFNAME. For type 1 you can use the literal OPEN and for type 2 you can use PREP. Example code might include:
      OPEN_TYPE  FORM   2
                 MOVE    "1",OPEN_TYPE
                 GETFNAME  TYPE=OPEN_TYPE ....
                    or
                 GETFNAME  TYPE=1 ....
                    or
                 GETFNAME  TYPE=OPEN ....
      

    • The numeric types are grouped in pairs for OPEN and PREP dialogs:
           1 = open      2 = prep
          17 = open     18 = prep
          33 = open     34 = prep
          49 = open     50 = prep
      
    • The numeric types are grouped broadly by MULTI-SELECT capability.

      What multi-select does is to allow the user to click more than one file, drag a box around a group of files, use CTRL-click and SHIFT-click. When the GETFNAME operation returns, multi selected files are returned as a comma-delimited list of files (without path) in FILE_NAME.
           1,  2, 17 and 18   do NOT allow multi-select
          33, 34, 49 and 50   DO allow multi-select
      
    • Two groups of the numeric types allow FILTERS to be used. (Filters are described below)
          17  Open with filter
          18  Prep with filter
          49  Open with filter and multi-select
          50  Prep with filter and multi-select
      
    FILTERS:

    Here's how I describe the "filter" string.
    First, the general form is:
          {ext} [,{info1},{filter1}] [,{info2},{filter2}] ...
    I call this entire thing a FILTER STRING although the official definition refers to just those elements within the string as "filters".

    Note:
    • This entire filter string can be a literal or can be a string variable.
    • The values are comma delimited and don't need any quotes within the string.
    • There can be multiple "filters" elements in the string but they're delimited by semi-colons.
    The breakdown of the filter string is this:

    • {ext} Identifies the default extension used when no name filtering is provided. That means that if you don't give any other information in the filter string, this is the file extent ion that will be displayed. If you are going to use filter pairs, you can just ignore this parameter and use a "," as a place holder. For example:
            ,pictures,*.jpg;*.tif

    • {info1},{filter} work in pairs. The info string is just text describing what the filter represents. For example the pair could be
            picture types allowed,*.jpg;*.tif;*.bmp
      In that example, the description will be the entire string picture types allowed. Note that there are no quotes.

      The actual filter is *.jpg;*.tif;*.bmp. Again, these are not in quotes... they're just a string. Note that the three types are separated by semi-colons.

      The actual filters may be wild card masks such as CWV*.TXT.

    • SPECIAL NOTE:
      To make the filter work, you MUST provide a default value in the FILENAME field of the GETFNAME. That doesn't sound reasonable, but if you don't the filter will be ignored and you'll get everything. Interestingly, the value can be a SPACE. What it can NOT be is NUL.

      If you include an actual name in the FILENAME field, that will be shown as the default filename in the dialog box... even if it is a non-existant file!
    Now here's how the filter string works. For this example we're using filter elements so we do not need the opening {ext} parameter. Our example GETFNAME is as follows. (We'll show a screen shot of the results a bit farther down)
           PACK        FILTER_STRING WITH "":
                          ",Picture Files,*.tif;*.jpg;*.bmp":
                          ",BGT Text File,*.txt":
                          ",Source code,*.pls;*.plf":
                          ",Programs,*.plc;*.exe"
    					  
           MOVE        " ",FILE_NAME             ;Insure it's not NUL
    	  
           GETFNAME    TYPE=17:                  ;open dialog, with filter
                       "Select a file":          ;prompt
                       FILE_NAME:                ;file name return string
                       "C:\MMCC-WWW\BARGAINT":   ;starting path to look in          
                       FILTER_STRING
    
    The effect of the filter strings is to give the user a collection of views to the folders. Each of your filter strings will be added to a combo box at the bottom of the OPEN dialog screen. Look at the example below. You'll see the Files of type combo is expanded and it shows the description of each of our filters.

    The combo box does not show the actual filter elements. You could put that into your filter definition if you want; just don't use any commas. For example, this would work in our example PACK above:
         ",Picture Files: *.tif *.jpg *.bmp,*.tif;*.jpg;*.bmp"
    There are no commas within the actual "info" string.



    OTHER USEFUL ROUTINES
    MMCC Staff : Don't forget that we have several routines in the UTIL-PLB folder that deal with directories. These use Windows API calls to access the directory structure.
    • WWW-ANLZ was started as a file chaser to find all HTML files in a given directory structure.
    • GET-TREE is an external routine to chase all folders within a given path.
    • GET-DIR is an external routine which gets the list of files within a directory.



  • CONTENTS
    Home

    v1.10
    Send e-mail to MMCC.
    Write to MMCC Technical Support at:
          MMCC, Inc.
          600 W. Midland
          Bay City, MI 48708
          (989) 686-8860
    © 1997 - present MMCC, Inc. All Rights Reserved.
    Report problems or suggestions to support@mmcctech.com
    Originally Written 09/14/1998