home *** CD-ROM | disk | FTP | other *** search
/ Shareware Overload / ShartewareOverload.cdr / database / prntsay.zip / CUSTMIZE.DOC < prev    next >
Text File  |  1988-01-01  |  41KB  |  824 lines

  1.  
  2.                                  SECTION 5 
  3.                     - Exploring a PRINT-SAY* .PRG file -
  4.  
  5.  
  6.        [This section and the next are intended as reference material for 
  7.      later interactions with PRINT-SAY and should probably be skipped if 
  8.      you are reading through for the first time.] 
  9.  
  10.      5.1. FIRST THOUGHTS: 
  11.        As mentioned above, PRINT-SAY is primarily a programmer's tool. In 
  12.      a professional environment we expect our computers and software to 
  13.      adapt to our designs and not vice versa. 
  14.        A program which would generate virtually any possible report would 
  15.      be at least as large and complicated as dBASE itself and has yet to 
  16.      be written.  In the meantime the dBASE programming language provides 
  17.      the minimum necessary tools to create more sophisticated reports than 
  18.      LIST and REPORT FORM can provide.  PRINT-SAY is intended to alleviate 
  19.      most of the routine drudgery of such programming for the programmer. 
  20.      The programmer will take the .PRG output file created by PRINT-SAY 
  21.      and customize it to suit the demands of a more complicated report. 
  22.        Non-programmers with a modicum of dot-prompt expertise can also 
  23.      customize the PRINT-SAY .PRG files in many ways which require no 
  24.      understanding or experience with programming.  The reason for this 
  25.      is that a dBASE program is to a large degree simply a batch of dot- 
  26.      prompt commands grouped together to function as one task.  The pur- 
  27.      pose of this section of the manual, then, is to provide a second 
  28.      guided tour of a more advanced nature.  A tour which examines the 
  29.      details of the PRINT-SAY .PRG file and illustrates some customization 
  30.      changes you may want to use at some point in the future. 
  31.  
  32.      5.2. HOW TO PROCEED: 
  33.        I strongly recommend that the following material be read with 
  34.      your dBASE manual in hand.  It would also be highly useful for the 
  35.      novice programmer to read the really excellent chapters provided in 
  36.      the dBASE III Plus manual on how to program; or one of the many ex- 
  37.      cellent books on the subject, if you are still using non-Plus, such 
  38.      as Alan Simpson's Understanding dBASE III from SYBEX. 
  39.  
  40.      5.3. STEP-BY-STEP: 
  41.        I will presume you are using PRINT-SAY from within dBASE itself by 
  42.      using the RUN command explained in the first manual.  I will also 
  43.      presume (as an example) that you have already created the PRINT-SAY 
  44.      .PRG file called REPORT-A.PRG. from Section 3, A Guided Tour, in the 
  45.      first manual. 
  46.  
  47.      5.3.1. STEP ONE: 
  48.        The first step is to copy REPORT-A.PRG and work with the copy in 
  49.      case there are any mishaps: 
  50.  
  51.                1. Type  RUN COPY REPORT-A.PRG NEWREPRT.PRG 
  52.  
  53.      5.3.2. STEP TWO: 
  54.        Next, you need a way to view and change NEWREPRT.PRG.  (dBASE 
  55.      provides a primitive editor MODIFY COMMAND; many people use WordStar 
  56.      (tm); for my part, I find that the notepad of SideKick (tm) is by 
  57.      far the handiest tool for this task.)  However, for the sake of the 
  58.      example let's stick to the lowest common denominator. 
  59.  
  60.                2. Type  MODI COMM NEWREPRT.PRG 
  61.  
  62.        Now you should see a new screen filled with programmer-ese.  In 
  63.      fact, there is little mystery here.  Most lines of a program are 
  64.      dBASE commands, which could be typed in at the dot-prompt: 'set 
  65.      margin to 0', 'set device to print', 'PageNo = 1', etc.  Some lines, 
  66.      such as: 'do while .not. eof()', however, are valid only in programs. 
  67.        To see more of the program the [PgDn], [PgUp], arrow keys, etc. of 
  68.      the numeric keypad will move you through the file.  The key combin- 
  69.      ations [Ctrl-A] and [Ctrl-F] move left and right from one blank space 
  70.      to the next to speed up left/right motion.  (To exit use the [Esc] 
  71.      key.) 
  72.       [Note that you can also get a print-out of NEWREPRT.PRG (or any .PRG 
  73.      file) with the dBASE command 
  74.  
  75.                        TYPE NEWREPRT.PRG TO PRINT 
  76.  
  77.      This allows you to see more of the code at a glance, which in turn 
  78.      to clarify relations between various parts of a program.  (To see even 
  79.      more of the code at a glance use the Cotton-Ware utility, Prim - with 
  80.      which, incidentally, you can also print this manual.)] 
  81.        Let's read through the program - whether via screen or print-out - 
  82.      to see what some of the more cryptic lines do: 
  83.  
  84.      ***  Program: REPORT-A.PRG 
  85.      ***  Called from: 
  86.      ***  Property of: MOOSE FALLS CLUB OF VERY IMPORTANT PERSONS 
  87.      ***  Programmer: A. PROGRAMMER 
  88.      ***  Created on: 10/11/87 
  89.      ***  Last Update: 
  90.      ***  Purpose: 
  91.      *** 
  92.      ***               (This report is in Compressed pitch) 
  93.      *** 
  94.  
  95.        5.3.3. THE TITLE BLOCK: 
  96.        '***  Program: REPORT-A.PRG' -  This is the program title. Every 
  97.        line in a dBASE program which starts with an asterisk is ignored 
  98.        by the computer and is purely for human consumption.  These lines 
  99.        are called comments or documentation; the computer has no need 
  100.        for a title. 
  101.  
  102.        '***  Called from:' you may insert the name of another .PRG file 
  103.        if it calls this file in the course of its execution. 
  104.  
  105.        '***  Programmer: A. PROGRAMMER' this line identifies you as the 
  106.        author. 
  107.  
  108.        '***  Purpose:' insert a brief explanation of exactly what this 
  109.        report is supposed to report on.  It may be obvious to you now; 
  110.        6 months from now this brief statement will save you some aggra- 
  111.        vation. 
  112.  
  113.  
  114.      ** --------------------- Initialize Environment --------------------- ** 
  115.      set talk off 
  116.      set echo off 
  117.      use CLIQUE 
  118.      set index to CLIQNAME 
  119.  
  120.  
  121.        5.3.4. INITIALIZE ENVIRONMENT: 
  122.        '** --- Initialize Environment --- **' - since this line starts 
  123.        with an asterisk it is ignored by the computer.  This is what is 
  124.        technically known as a comment, and its purpose it both to explain 
  125.        the code which follows it and to section off that code into a 
  126.        logical group to make program reading easier.  All the in-code 
  127.        comments created by PRINT-SAY take this form of two asterisks fol- 
  128.        lowed by dashes, but this is purely an arbitrary artifact. 
  129.  
  130.        'set talk off' and 'set echo off' are commands which tell dBASE 
  131.        not to send anything to the monitor which isn't specifically re- 
  132.        quested by the programmer.  Note: if your report is intended to 
  133.        be called from another .PRG program, be sure to delete these two 
  134.        lines and both other pairs of 'set talk on' and 'set echo on' lines 
  135.        farther down in the code. 
  136.  
  137.        'use CLIQUE' and 'set index to CLIQNAME' - these lines are the 
  138.        familiar dot-prompt commands you are hopefully accustomed to 
  139.        using every day. 
  140.  
  141.  
  142.      ** ---------------------- Initialize Variables ---------------------- ** 
  143.      ResetCode = chr(27)+chr(64) 
  144.      PicaCode = chr(27)+chr(80) 
  145.      CompCode = chr(15) 
  146.      CompOffCode = chr(18) 
  147.      DbleOnCode = chr(27)+chr(71) 
  148.      DbleOffCode = chr(27)+chr(72) 
  149.      Bar = "=============================================================; 
  150.      ====================================================" 
  151.      PageNo = 1 
  152.      store 0 to Sub_1, Sub_2 
  153.  
  154.  
  155.        5.3.5. INITIALIZE VARIABLES: 
  156.        'ResetCode = chr(27)+chr(64)' - "ResetCode" is NOT a dBASE func- 
  157.        tion or command.  Instead it is a dBASE MemVar (memory variable), 
  158.        which is a way of getting the computer to store a certain number, 
  159.        letter, or phrase and recall it each time the MemVar name is used. 
  160.        This is exactly like saying X = 1 in algebra; it's just that 
  161.        programmers prefer to use more descriptive variable names than 
  162.        X, Y, and Z.  In this case, however, ResetCode is not even being 
  163.        assigned a numerical value but that of a group of characters 
  164.        treated as a whole - a "string".  Once a MemVar has been assigned 
  165.        a value, the programmer may change that value at whim but dBASE 
  166.        won't let him change the TYPE of that value.  In this case Reset- 
  167.        Code may become any single character or group of characters, as 
  168.        long as they are bunched together between quotes, but never a 
  169.        numeric (non-quoted digit) type. 
  170.          The 'chr(27)+chr(64)' phrase is what is being stored for future 
  171.        use.  More on MemVars below at PageNo. 
  172.          Almost all printer manuals explain these chr() codes in more 
  173.        detail than I care to go into here.  The dBASE chr() function sends 
  174.        a (hopefully) non-printable instruction to the printer which modi- 
  175.        fies all further activities of the printer in a specific fashion. 
  176.        Most of these instructions start with the character chr(27) 
  177.        (Escape) which tells Epson printers that what follows is a command 
  178.        and not for printing.  (Incidentally, if your non-Epson printer 
  179.        starts each PRINT-SAY report with an unwanted '@' character, 
  180.        remove this line.) 
  181.          If your printer is totally non-Epson compatible, as for example 
  182.        a Hewlett-Packard LaserJet, you will have to change each of these 
  183.        codes to the 'escape sequences' in your manual which perform the 
  184.        equivalent task. 
  185.  
  186.        - Let's skip down a few past the rest of the printer codes: 
  187.  
  188.        'Bar = "======...==' - this MemVar will be used further along to 
  189.        create the double line which separates the header of the printed 
  190.        report from its body.  The long row of characters repeats whatever 
  191.        character you entered as the answer to Question 8 in the Re-Usables 
  192.        Mode. 
  193.  
  194.        'PageNo = 1' Reading this line a programmer knows that the value 
  195.        stored under the name of the MemVar 'PageNo' will only be used 
  196.        for assigning a page number to the report, and that the variable 
  197.        will stay at the value '1' until the next time the MemVar is as- 
  198.        signed a value.  Because the 1 is not in quotes we know it is a 
  199.        numeric variable and arithmetic may be performed with it. 
  200.  
  201.        'store 0 to Sub_1, Sub_2' - this line creates two new MemVars 
  202.        in one stroke using the dBASE STORE x TO command.  Obviously, 
  203.        one could create as many MemVars as wanted with one command - 
  204.        as long as you wanted them all to have the same value. 
  205.  
  206.  
  207.     ** ---------------------- Create Screen Display --------------------- ** 
  208.     clear 
  209.     Begin = " " 
  210.     @ 5,19 say "MOOSE FALLS CLUB OF VERY IMPORTANT PERSONS" 
  211.     @ 7,26 say "STATEMENT OF BALANCE OF DUES" 
  212.     @ 16,34 say "To proceed:" 
  213.     @ 18,17 say '1. Start printer  2. Insert 8 1/2"-wide paper' 
  214.     @ 20,17 say "3. Scroll to start of new page or perforation" 
  215.     @ 22,17 say "4. Press A to Abandon; any other key to begin. . ." get Begin 
  216.     read 
  217.     if Begin = "A" 
  218.       set talk on 
  219.       set echo on 
  220.       return 
  221.     endif 
  222.     @ 12,35 say "PRINTING..." 
  223.  
  224.  
  225.        5.3.6. CREATING THE SCREEN DISPLAY: 
  226.        @ 5,19 say "MOOSE FALLS CLUB OF VERY IMPORTANT PERSONS" - 
  227.        - this line is an example from this group of messages to the 
  228.        monitor.  The '@ say' combination is explained in detail in 
  229.        each dBASE manual.  In brief, '@ say' says: 
  230.  
  231.                    'at row X, column Y say the following'. 
  232.  
  233.        X and Y are the addresses of a point on the monitor screen (or 
  234.        the printed page) exactly like the X,Y co-ordinates on graphs we 
  235.        so tediously studied in algebra many years ago.  Normally, you
  236.        may be used to using the "?" character to write a message to the 
  237.        screen; @ SAY allows more control of message placement. 
  238.  
  239.  
  240.     ** ----------------------- Set-up For Printing ---------------------- ** 
  241.     set device to print 
  242.     set console off 
  243.     @ prow(),pcol() say ResetCode 
  244.     do while .not. eof() 
  245.  
  246.  
  247.        5.3.7. SETTING-UP FOR PRINTING: 
  248.        'set device to print' sends all following commands to the printer 
  249.        instead of the monitor. 
  250.  
  251.        'set console off' tells dBASE not to send any further messages to 
  252.        the monitor or repeat out-put there. 
  253.  
  254.        '@ prow(),pcol() say ResetCode' this cryptic line sends the 
  255.        printer code defined in the MemVar command described above to 
  256.        the printer which tells it to clear all previous format settings 
  257.        from its memory. 
  258.          As in the monitor '@ say' commands above, the formula is also: 
  259.        at row X, column Y say the following.  But in this line X and Y 
  260.        are not directly specified as numbers; instead two dBASE FUNCTIONS 
  261.        are used which tell dBASE to ask the printer for the present row 
  262.        address [prow()] and the present column address [pcol()] and to 
  263.        substitute whatever numbers it receives from the printer into the 
  264.        program at this point. (See the Functions section of your manual.) 
  265.        When the computer is forced to look up an address like this, 
  266.        we are said to be using RELATIVE ADDRESSING. 
  267.          Now that was a pretty technical discussion: you should be pleas- 
  268.        antly surprised that you nearly understood it the first time 
  269.        through. 
  270.  
  271.        5.3.8. CONTROL STRUCTURES: 
  272.        'do while .not. eof()' - this is the beginning of what programmers 
  273.        call a LOOP.  Loops are the most powerful tool in the programmer's 
  274.        arsenal.  Near the end of the program you will see another command: 
  275.        'enddo'.  Everything between the words 'do while' and 'enddo' are 
  276.        repeated over and over by the computer.   
  277.          Notice that all the lines which are enclosed between each pair 
  278.        of 'do while' and 'enddo' commands are indented by two characters. 
  279.        The indentation makes the program hugely more understandable for 
  280.        human beings (the computer ignores it).  Because of the indentation 
  281.        we can see at a glance all the lines which are part of the loop and 
  282.        which are therefore to be repeated. 
  283.          The '.not. eof()' part of the line is the CONDITION which deter- 
  284.        mines when the computer will STOP repeating the loop.  In this case  
  285.        the condition reads: "DO what follows, WHILE you are NOT at the end  
  286.        of the database file which is currently opened".  Eof() is another  
  287.        dBASE function, which returns a True or a False, depending on whether  
  288.        or not the database has been opened to the point just after the last  
  289.        record - the END-OF-FILE point.  This end-of-file point is reached 
  290.        after every SUM or TOTAL and after every LOCATE, SEEK, or FIND which  
  291.        fails to find its target.  The SKIP command below will also finally  
  292.        reach the eof() point.  Eof() is also True if the file is completely  
  293.        empty - contains zero records. 
  294.          After reading this line the computer will first check to see if 
  295.        eof() is true or false.  If true (hopefully not) it has nothing to 
  296.        do and skips down to the matching 'enddo' and proceeds from there. 
  297.        If false (in other words, the record pointer is pointing to a 
  298.        record) it proceeds to execute each of the following commands 
  299.        until it reaches a matching 'enddo'.  When it reaches the 'enddo' 
  300.        it then LOOPS up to the beginning of the 'do while' loop, checks 
  301.        on eof() and repeats the same steps over and over, as long as the 
  302.        function eof() does not return a true. 
  303.          The periods around the not in '.not.' tell dBASE that the word 
  304.        enclosed is a CONDITIONAL word and not a MemVar.  '.and.', '.or.', 
  305.        and '.not.' are the three logic conditional words.  While '.t.' 
  306.        and '.f.' mean True and False to dBASE. 
  307.  
  308.  
  309.   ** ---------------- Code For Printing Page Header ----------------- ** 
  310.   set margin to 0 
  311.   @ 2,0 say CompOffCode+PicaCode+DbleOnCode 
  312.   @ prow()+1,21 say "MOOSE FALLS CLUB OF VERY IMPORTANT PERSONS" 
  313.   @ prow()+2,6 say date() 
  314.   @ prow(),28 say "STATEMENT OF BALANCE OF DUES" 
  315.   @ prow(),71 say "Page" + ltrim(str(PageNo)) 
  316.  
  317.  
  318.        5.3.9. PRINTING THE HEADER LINES: 
  319.        'set margin to 0' - set margin is a normal dBASE command which is 
  320.        often issued from the dot-prompt.  This is also the first of the 
  321.        repeated commands in this 'do while' loop. 
  322.  
  323.        '@ 2,0 say CompOffCode+PicaCode+DbleOnCode' - for this report, 
  324.        PRINT-SAY has chosen to use Compressed pitch to squeeze all the 
  325.        fields in we asked for; in other reports this may be PicaCode or 
  326.        EliteCode. However, in every report PRINT-SAY starts with PICA pitch 
  327.        so that the banner lines of each report will have the same visual 
  328.        format and since compression simply isn't needed at this point in 
  329.        the printout. 
  330.          Note also that this the one of the few lines in which the X,Y 
  331.        co-ordinates in an '@ say' command are simply given straight 
  332.        out - without forcing the computer to perform a prow() or pcol() 
  333.        calculation.  The technical term for sending actual numbers as an 
  334.        address is ABSOLUTE ADDRESSING.  This line tells the printer to 
  335.        move its print head to the first character of the 2nd row down 
  336.        from its initial position; the chr() values mean: switch to pica 
  337.        pitch. 
  338.  
  339.        '@ prow()+2,6 say date()' - this @ SAY uses the other type of 
  340.        addressing, relative, again for the row value, and an absolute 
  341.        (non-look-up) value for the column.  When it gets there it is 
  342.        commanded by the 'date()' function to ask the computer for the 
  343.        current date from its clock and put the answer at this location 
  344.        on the printed page. 
  345.          More importantly, the '+2' phrase tells the computer it is time 
  346.        to cease printing on the previous line and skip down to rows to 
  347.        start a new line of print. 
  348.  
  349.          Two more mixed-address commands list your report title (if any) 
  350.        and the page number, completing the banner or header portion of 
  351.        the printed page. 
  352.          Because these commands are all inside the initial 'do while' 
  353.        loop, they will be executed as many times as dBASE fills a page 
  354.        with records and starts a new one.  Towards the end of the code we  
  355.        see another statement containing PageNo which reads: 'PageNo =  
  356.        PageNo + 1'.  This happens when a full page is printed, causing 
  357.        the value '1' to be added to the memory variable called PageNo, 
  358.        so that the next page will have one higher number than the one 
  359.        previous.  This sort of formula, X = X + 1, is called a COUNTER 
  360.        by programmers and is used frequently. 
  361.  
  362.  
  363.   ** ---------------- Code For Printing Column-Titles --------------- ** 
  364.   set margin to 9 
  365.   @ prow()+1,0 say CompCode 
  366.   @ prow()+1,0 say "Title" 
  367.   @ prow(),12 say "Last Name" 
  368.   @ prow(),31 say "First Name" 
  369.   @ prow(),54 say "Street Address" 
  370.   @ prow(),78 say "Phone No." 
  371.   @ prow(),89 say "Dues Paid" 
  372.   @ prow(),99 say "Dues Owing" 
  373.   @ prow(),111 say "Date Rec'd" 
  374.   @ prow()+1,0 say Bar + DbleOffCode 
  375.  
  376.  
  377.        5.3.10. PRINTING THE FIELD TITLES: 
  378.          This group of code, all starting with '@ prow()' change the 
  379.        print style to Compressed pitch and list the field titles across 
  380.        the paper.  Because each of these commands starts with a plain 
  381.        'prow()' they are all sent to the same row on the page. 
  382.  
  383.  
  384.   ** ------------------- Code For Printing Records ------------------ ** 
  385.   do while .not. eof() .and. prow() < 60 
  386.     @ prow()+1,0 say TITLE 
  387.     @ prow(),7 say SURNAME 
  388.     @ prow(),29 say FIRST 
  389.     @ prow(),46 say STREET 
  390.     @ prow(),78 say PHONE 
  391.     @ prow(),89 say DUES_PAID picture "999.99" 
  392.     Sub_1 = Sub_1 + DUES_PAID 
  393.     @ prow(),101 say 100 - DUES_PAID picture "999.99" 
  394.     Sub_2 = Sub_2 + 100 - DUES_PAID 
  395.     @ prow(),113 say DATE_PAID 
  396.     skip 
  397.   enddo 
  398.   PageNo = PageNo + 1 
  399.   @ prow()+1,0 say DbleOnCode + Bar 
  400.  
  401.  
  402.        5.3.11. THE WORK-HORSE LOOP: 
  403.        'do while .not. eof() .and. prow() < 60'.  The code lines fol- 
  404.        lowing this one until the "enddo" line all work together to write 
  405.        a single line of field-data across the page then they skip down 
  406.        and repeat the process until either the end of the file or the 
  407.        end of the current page is reached.  The result of all this is a 
  408.        loop within a loop!  This is a very powerful tool in the pro- 
  409.        grammer's repertoire; and it is by no means unheard of to have 
  410.        a loop within a loop within a loop, etc.  When loops come inside 
  411.        other loops they are called nested; with the first loop being 
  412.        referred to as the outer and the second the inner loop. 
  413.          While this may seem a bit mind-boggling, it becomes easy to fol- 
  414.        low if you simply keep in mind that each line of the outer loop is 
  415.        executed once. . .until the first line of an inner loop is up to 
  416.        bat.  At that point the inner loop is executed over and over again 
  417.        as long as its condition holds true.  This may be zero times, once, 
  418.        or ten thousand - but eventually something changes which makes its 
  419.        condition (not end-of-file and not printing past row 61 in this 
  420.        example) untrue.  When that happens the outer loop takes control 
  421.        back, any further of its lines are executed until the last line when 
  422.        an 'enddo' line is reached.  At that point control is looped back to 
  423.        the start of the loop; its condition (not end-of-file, in this case) 
  424.        is checked for true and false again; and, if eof() says false, the 
  425.        loop is run through a second time.  Eventually, the beginning of the 
  426.        inner loop is reached - its condition is checked for true or false, 
  427.        and, if true, it is executed any of number of times again. 
  428.          What happens when we apply this theory to the particular case 
  429.        in this program is that the outer loop prints a banner section 
  430.        at the top of a page.  Then it prints the underlined field-titles. 
  431.        Then it meets the inner loop which goes to database, grabs a 
  432.        handful of fields from that file, and spreads them across the 
  433.        next row on the printed page under the field-titles.  Then the 
  434.        program comes to the single word 'skip'.  This DOESN'T mean 'skip 
  435.        a line on the page'; it means 'skip' down to the next record in 
  436.        the database.  It is entirely because of this line that the con- 
  437.        dition at the start of the outer loop can ever come to the answer 
  438.        'false' - and therefore end the print job.  The inner loop is more 
  439.        touchy: it will knock-off whenever end-of-file is reached, like the 
  440.        outer loop, but also whenever the bottom of a page of paper is 
  441.        reached. 
  442.          We might think of the computer as bouncing frantically back and 
  443.        forth between two walls - 'do while' and 'enddo' for each loop it 
  444.        gets snared into by the program.  Each bounce moves a little farther 
  445.        along the walls between the entrance and the exit - though frequent- 
  446.        ly there may be an inner entrance in one of the walls into which the 
  447.        computer pops when it gets that far along the wall.  Then it finds 
  448.        itself in an inner room with an inner wall it must bounce its way 
  449.        along, hoping to avoid yet a deeper trap, before it can exit back to 
  450.        outer room to complete its work-out. . .and very likely be zapped 
  451.        right back to the beginning of the trap again. 
  452.  
  453.  
  454.        5.3.12. ACCUMULATING SUB-TOTALS: 
  455.          Also intermingled in the lines of code sandwiched into this do 
  456.        while loop are two lines using the Sub_1 and Sub_2 MemVars. Because 
  457.        of the "formula" used here, in both cases these MemVars act as ac- 
  458.        cumulators, successively accumulating each value of Dues_Paid and 
  459.        100 - Dues_Paid as the program writes each new line.  At the end of 
  460.        a page the total number accumulated into these MemVars is shown as 
  461.        a sub-total. 
  462.          Notice the single PageNo = PageNo + 1 line sandwiched between 
  463.        the two 'enddo' lines.  This is the only work the computer needs 
  464.        to do after completing the inner loop before bouncing back to 
  465.        the top of the outer loop. 
  466.          Next, the loop which draws a line of equal signs across the 
  467.        page is repeated. 
  468.  
  469.  
  470.     ** ----------------- Code For Printing Sub-Totals ----------------- ** 
  471.     @ prow()+1,86 say Sub_1 picture "99,999.99" 
  472.     @ prow(),98 say Sub_2 picture "99,999.99" 
  473.     @ prow(),pcol() say DbleOffCode 
  474.   enddo 
  475.   eject 
  476.  
  477.  
  478.        5.3.13. DISPLAYING THE SUB-TOTALS: 
  479.          Next, the sub-total MemVars are displayed at the appropriate rows 
  480.        and columns on the printed page.  After these four lines a lone 
  481.        'enddo' closes the largest, outside loop which started with 'do 
  482.        while .not. eof()'.  Therefore, all the lines which follow this line 
  483.        are outside all loops and will only be executed once. 
  484.  
  485.  
  486.   ** ----------------------- Restore Environment ---------------------- ** 
  487.   @ prow(),pcol() say ResetCode 
  488.   set console on 
  489.   set device to screen 
  490.   set talk on 
  491.   set echo on 
  492.   clear 
  493.   return 
  494.  
  495.  
  496.        5.3.14. RESTORING THE ENVIRONMENT: 
  497.        'eject' - the line following both loops - tells the printer to eject 
  498.        the final page of printout so you can tear it off. 
  499.  
  500.          The 'chr(27)+chr(64)' code sent by the second ResetCode MemVar, 
  501.        politely clears the printer of all the other chr() codes left 
  502.        over from the print job. 
  503.  
  504.          The remaining lines simply undo the work of the first several 
  505.        by restoring control of the monitor screen to dBASE and turning 
  506.        the printer back over to itself. 
  507.  
  508.  
  509.  
  510.  
  511.                                  SECTION 6 
  512.                              - Making Changes - 
  513.  
  514.  
  515.        [Note: as in Section 5, in Section 6 we will be using MODIFY 
  516.      COMMAND to examine and change REPORT-A.PRG.  See the beginning 
  517.      of Section 5 for details if you're unclear on how to proceed.] 
  518.  
  519.      6.1. HEADER BLOCK: 
  520.        Drop down a few lines from the top of REPORT-A to enter a sentence 
  521.      or two giving a general description of what this report does.  What 
  522.      may be obvious today may be mysterious next year.  Also the logo line 
  523.      which follows 'Property of:' may or may not be accurate.  To change 
  524.      it merely position the cursor at the beginning of the logo phrase then 
  525.      start typing, what you type will over-write what PRINT-SAY wrote.  To 
  526.      get rid of any excess hold down the space bar.  To delete this line 
  527.      altogether simply position the cursor anywhere on that line and press 
  528.      [Ctrl-Y]. 
  529.  
  530.      6.2. INITIALIZE ENVIRONMENT BLOCK: 
  531.        New lines further controlling the environment might be inserted 
  532.      here, such as 'set status off' for dBASE III Plus.  In that case, 
  533.      drop all the way down to the second-last line and insert a corre- 
  534.      sponding 'set status on'.  To insert a line press enter at the 
  535.      beginning of the following line or the end of the preceding line. 
  536.        If more than one database needs to be opened simultaneously to 
  537.      provide all the fields your report needs insert the appropriate 
  538.      "SELECT 1" (or "SELECT A"), "SELECT 2", etc. lines with appropriate 
  539.      USE and INDEX commands following each area.  For example, NEWREPRT 
  540.      currently reads: 
  541.  
  542.                 use CLIQUE 
  543.                 set index to CLIQNAME 
  544.  
  545.      But a different report might have needed the lines 
  546.  
  547.                 select 1 
  548.                 use CLIQUE 
  549.                 set index to CLIQNAMES 
  550.                 reindex 
  551.                 select 2 
  552.                 use OLMEMBRS 
  553.                 set index to OLDNAMES 
  554.                 reindex. 
  555.  
  556.  
  557.      6.3. INITIALIZE VARIABLES BLOCK: 
  558.        If your printer uses some non-Epson compatible codes, you would 
  559.      of course need to change those provided here accordingly.  In some 
  560.      cases it may be possible to enter a Near Letter Quality code as 
  561.      well.  Most printers will not allow simultaneous pitch control and 
  562.      draft/NLQ control but yours may.  In any case, it can't hurt to try 
  563.      adding a line such as "NLQCode = #27#110" in this group, then below 
  564.      (See 6.5.) another line to call the code. 
  565.        Technical users please note: Many printer manuals offer a detailed 
  566.      description of what Epson calls the Master Select command, chr(27)+ 
  567.      '!'+chr(x).  Unfortunately, you can write this off: dBASE makes  
  568.      mincemeat out of Master Select codes on any printer I've tried. 
  569.  
  570.      6.4. CREATE SCREEN DISPLAY BLOCK: 
  571.        Quite possibly you may want to delete this altogether or change 
  572.      the text it presents to the screen.  You can do no harm I can think 
  573.      of by changing any of the text between the double-quotes, changing 
  574.      the numbers which show which row and column each line will appear 
  575.      at, or even by inserting new lines.  The lines involving the MemVar 
  576.      `Begin' and the verb `read' illustrate only one way of gathering 
  577.      the all-important fact that the user has turned on the printer and 
  578.      gotten it adjusted for printing.  See the dBASE manual for an ex- 
  579.      lanation of the WAIT verb for another alternative. 
  580.  
  581.      6.5. SET-UP FOR PRINTING BLOCK: 
  582.        Neither the 'set console off' nor the '- say ResetCode' lines 
  583.      are absolutely necessary.  In particular if the ResetCode is missing 
  584.      from your printer's bag of tricks you may want to delete this line 
  585.      (position the cursor anywhere on its length then press [Ctrl-Y]) and 
  586.      change a line in the Screen Display section prompting the user to 
  587.      turn the printer off then on again before printing. 
  588.        The reset code clears the printer of any previous format commands 
  589.      such as a margin setting or a different pitch; simply turning the 
  590.      printer off then back on accomplishes the same function as the reset 
  591.      code used here. 
  592.        If you are attempting to use an NLQ code, tag your MemVar name on 
  593.      to the ResetCode line here to send your NLQ code to the printer. For 
  594.      example this line might become: 
  595.  
  596.                   '@ prow(),pcol() say ResetCode+NLQCode'. 
  597.  
  598.      6.6. PAGE HEADER BLOCK: 
  599.        Just about anything in this block is game for easy customization: 
  600.  
  601.      6.6.1. USING EXPANDED PRINT: 
  602.      One cute trick would be to add an expanded print code to the logo 
  603.      display line.  Chr(14) starts expanded print; chr(20) cancels it. 
  604.      Because each character between these commands will occupy twice the 
  605.      number of spaces as normal pica text, the number after the comma 
  606.      in the prow()+1,xx segment will have to be reduced accordingly. 
  607.      This number shown here by "xx" is the column address - the left-most 
  608.      point on the line at which the say portion of the command will be 
  609.      displayed. 
  610.        A typical expanded logo might be: 
  611.  
  612.            @ prow()+1,23 say chr(14)+"Metro Police Dept."+chr(20) 
  613.  
  614.        Since the logo is 17 characters long, it will consume 34 chars. 
  615.      of space in expanded print; presuming normal paper which gives us 
  616.      80 characters of space in Pica, we're left with 46 blanks: 23 on 
  617.      each side of the logo to centre it. 
  618.  
  619.      6.6.2. ADDING AN ADDITIONAL LOGO LINE: 
  620.        Nothing could be simpler.  Immediately after the logo line add 
  621.      a new line with exactly the same format, changing only the number 
  622.      after the comma and the string of characters in quotes.  An example: 
  623.  
  624.          @ prow()+1,20 say 'Homicide, Suicide, and Ax-Murders Division'. 
  625.  
  626.      Since this text is 41 characters long, centering it would require 
  627.      20 spaces on one side and 19 on the other, therefore, the number 
  628.      following the comma can be either 19 or 20. 
  629.  
  630.      6.6.3. OTHER CHANGES: 
  631.        The page number and date positions may be changed within the report 
  632.      title line to suit your taste by simply modifying the column number 
  633.      following the '@ prow(),' portion of these lines. 
  634.        A second report title line may be added above or beneath the one 
  635.      PRINT-SAY created simply by following the same procedure described 
  636.      above for adding a second logo line. 
  637.  
  638.      6.7. COLUMN-TITLES BLOCK: 
  639.        The whole body of the report may be moved left or right by chang- 
  640.      ing the margin numeral. 
  641.  
  642.      6.7.1. RE-LOCATING INDIVIDUAL TITLES: 
  643.        Any of the column titles may be moved are left or right of the 
  644.      centre of their fields by changing the column address numbers on 
  645.      their lines.  Often a field for a name of an address needs to be 
  646.      kept as long as the longest name or address, while the vast major- 
  647.      ity of the names or addresses are much shorter, leaving an unsightly 
  648.      gap in the report.  A further consequence of this situation is that 
  649.      the titles appear to be too far to the right of the names or addres- 
  650.      ses below them. 
  651.  
  652.      6.7.2. ADDING A SECOND TITLE LINE: 
  653.        Occasionally it is desirable to break a field title into two 
  654.      phrases one above the other, especially if the title needs to be 
  655.      significantly longer than the width of the field itself.  Perhaps 
  656.      this is a little more complicated than what we've done so far, but 
  657.      it is far from being difficult.  Let's use the titles section from 
  658.      REPORT-A.PRG, created in section 4 of this manual as an example. 
  659.  
  660.  Last Name  First Name  Street Address  Phone No. Received  Owing  Date Rec'd 
  661.  
  662.      Here again is the section of code which generated these titles 
  663.      (I had to leave the first title off, above): 
  664.  
  665.           @ prow()+1,0 say CompCode 
  666.           @ prow()+1,0 say 'Title' 
  667.           @ prow(),12 say 'Last Name' 
  668.           @ prow(),31 say 'First Name' 
  669.           @ prow(),54 say 'Street Address' 
  670.           @ prow(),78 say 'Phone No.' 
  671.           @ prow(),89 say 'Received' 
  672.           @ prow(),99 say 'Dues Owing' 
  673.           @ prow(),111 say "Date Rec'd" 
  674.  
  675.      The first one starts the ball rowing by turning on compressed pitch 
  676.      after dropping down one line (row) from the date/report title/page 
  677.      number line.  The second statement drops down yet another row and 
  678.      prints the first column title, 'Title'.  All the rest of the commands 
  679.      stay on the same line (whatever line number prow() refers to in this 
  680.      case) but move to a different COLUMN address: 0, 12, 31, 54, etc. When 
  681.      that much is clear read on: 
  682.        Now, suppose we wanted to change the field titles to look something 
  683.      like this: 
  684.                                                     Dues    Dues 
  685.  Last Name  First Name  Street Address  Phone No. Received  Owing  Date Rec'd 
  686.  
  687.      which is a fairly common practice.  What we need to do is to insert 
  688.      a row with three titles between the date/report title/page number 
  689.      line and the current titles line.  So, between the first two lines of 
  690.      the block of code shown above we need to insert a new line which 
  691.      will print the word "Dues", then a second new line which will also 
  692.      print the word "Dues" (but in a farther-right location).  We can 
  693.      steal a lot from the code PRINT-SAY generated to do this.  Since the 
  694.      first "Dues" is going above the word "Received" we can borrow "Re- 
  695.      ceived"'s address and add two to it to get the location for the first 
  696.      "Dues", and borrow the exact address from the word "Owing" for the 
  697.      second "Dues".  Like so: 
  698.  
  699.           @ prow()+1,0 say CompCode 
  700.           @ prow()+1,91 say 'Dues'    { - new line 
  701.           @ prow(),100 say 'Dues'     { - new line 
  702.           @ prow()+1,0 say 'Title' 
  703.           . 
  704.           . 
  705.           . 
  706.  
  707.      - It's as simple as that! 
  708.  
  709.      6.8. PRINTING RECORDS BLOCK: 
  710.        In the last fraction of the line `do while .not. eof() .and. prow() 
  711.      < 60' - the `60' is the last row of print the printer will write 
  712.      before starting a new page.  Change this to any value you like less 
  713.      that the maximum which will fit on one page. 
  714.        Any fields which you've entered as being numeric have a dBASE 
  715.      picture statement added to them.  Occasionally,  you may want to 
  716.      modify this picture in one of the multitude of variations shown in 
  717.      your dBASE manual. 
  718.  
  719.      6.9. CLOSING OFF: 
  720.        When using MODI COMM to edit a file, always remember to exit with 
  721.      [Ctrl-W] or [Ctrl-End]: NEVER use [Esc] unless you have consciously 
  722.      decided to abandon the changes you've made. 
  723.        A true programmer will possibly make countless other modifications 
  724.      to this code to handle any number of special situations.  The above 
  725.      represent changes which can be easily controlled by the average dot- 
  726.      prompt user. 
  727.        
  728.  
  729.                             - SECTION 7: INDEX - 
  730.  
  731.       @ say - 5.3.6 
  732.       APPSGEN - 1.2 
  733.       ASSIST - 1.2, 2.2 
  734.       Addressing, Absolute - 3.1.2, 4.2, 5.3.9 
  735.       Addressing, Relative - 3.1.2, 5.3.7 
  736.       Asterisk - 5.3.3 
  737.       Chr() - 5.3.5, 6.6.1 
  738.       Clique.dbf - 4.1 
  739.       Code generators - 1.1 
  740.       Column address - 5.3.6, 5.3.7 
  741.       Comments - 5.3.3, 5.3.4 
  742.       Compatibilities, Printer - 1.1, 1.2 
  743.       Compressed pitch - 3.1.3, 4.8 
  744.       Contents, field - 3.2.2, 4.5 
  745.       Ctrl-C - 2.3 
  746.       Ctrl-A - 5.3.2 
  747.       Ctrl-F - 5.3.2 
  748.       Ctrl-W - 5.3.5, 6.11 
  749.       Ctrl-End - 5.3.5, 6.11 
  750.       DO <PRG> - 2.2 
  751.       DO WHILE - 5.3.8, 5.3.11, 5.3.12 
  752.       Databases - 3.1.9 
  753.       Decimals - 3.2.5 
  754.       Default - 3.1.2 
  755.       DrawLineChr - 5.3.5 
  756.       Eject - 5.3.14 
  757.       Elite pitch - 3.1.3 
  758.       Enddo - 5.3.8, 5.3.12 
  759.       Eof() - 5.3.8 
  760.       Epson - 1.1 
  761.       Esc - 5.3.2, 6.11 
  762.       Exiting PRINT-SAY - 2.3; MODI COMM - 5.3.2 
  763.       Expanded print - 6.6.1 
  764.       Field titles - 3.2.1, 4.5, 5.3.10; re-locating - 6.7.1, adding - 6.7.2 
  765.       Field contents - 3.2.2, 4.5 
  766.       Field size - 3.2.4 
  767.       Generator, Code - 1.1, 1.2 
  768.       IF - 3.1.11 
  769.       Indexes - 3.1.10, 4.3 
  770.       Installation (of PRINT-SAY) - 2.1 
  771.       LIST - 1.1 
  772.       LIST STRUcture - 2.2, 3.2.2, 4.1 
  773.       Length of paper - 3.1.5 
  774.       Licensing, Site - 7.1 
  775.       Logo - 3.1.1, 6.1; additional - 6.6.2 
  776.       Loops - 5.3.8, 5.3.11, 5.3.12 
  777.       MEMO fields - 1.5 
  778.       MODIFY COMMAND - 4.8, 5.3.2 
  779.       MemVars - 5.3.5 
  780.       Memory Variables - 5.3.5 
  781.       NLQ - 6.3, 6.5 
  782.       Naming files - 3.1.7, 4.3 
  783.       Number of fields - 3.1.12 
  784.       Numeric, fields - 3.2.3, 4.7 
  785.       Out-put file - 3.1.7  
  786.       PageNo = 5.3.5 
  787.       PCOL() - 5.3.6, 5.3.7 
  788.       Pica pitch - 3.1.3 
  789.       Printers - 1.1
  790.       PRINTSAY.DAT - 3.3, 4.8 
  791.       PROW() - 5.3.6, 5.3.7  
  792.       PRNTCODE.PRG - 3.1.7 
  793.       REPORT FORM - 1.1 
  794.       RUN PRINTSAY - 2.2, 4.1 
  795.       RUN DEL <filename> - 4.1 
  796.       RUN COPY <Filename> <Filename> - 5.3.1 
  797.       Re-Usables - 3.1, 4.2 
  798.       Relative addressing - 3.1.2, 5.3.7 
  799.       ResetCode - 5.3.5, 6.5 
  800.       Revision Mode, Initial Questions - 4.4 
  801.       Revision Mode, Field Questions - 4.8 
  802.       Row address - 5.3.6, 5.3.7 
  803.       SELECT - 1.3, 6.2 
  804.       SET MARGIN TO - 5.3.9 
  805.       SET DEVICE TO PRINT - 5.3.7 
  806.       SET CONSOLE OFF/ON - 5.3.7, 6.5 
  807.       Separators - 3.1.6 
  808.       Size, fields - 3.2.4 
  809.       Skip - 5.3.12 
  810.       Sub-totals - 3.2.6, 5.3.13, 6.10 
  811.       TRIM() - 3.2.2 
  812.       Throw-aways - 3.1.7, 4.3 
  813.       Title, report - 3.1.8 
  814.       Titles, Field - 3.2.1, 4.5, 5.3.10; re-locating - 6.7.1, adding - 6.7.2 
  815.       USE <database> - 3.1.9 
  816.       Underline - 5.3.11 
  817.       Variables - 5.3.5 
  818.       Width of paper - 3.1.4
  819.  
  820.  
  821.        * PRINTSAY.COM, PRINTSAY.DOC and CUSTMIZE.DOC are (c) Copyright 
  822.                      1988, by Dale Cotton, Toronto, Canada.
  823.                               All Rights Reserved. 
  824.