home *** CD-ROM | disk | FTP | other *** search
/ Liren Large Software Subsidy 9 / 09.iso / l / l196 / 3.ddi / INDEX.BA$ / INDEX.bin
Encoding:
Text File  |  1990-06-24  |  9.0 KB  |  305 lines

  1. DEFINT A-Z
  2.  
  3. ' Define the symbolic constants used globally in the program:
  4. CONST FALSE = 0, TRUE = NOT FALSE
  5.  
  6. ' Define a record structure for random-file records:
  7. TYPE StockItem
  8.     PartNumber AS STRING * 6
  9.     Description AS STRING * 20
  10.     UnitPrice AS SINGLE
  11.     Quantity AS INTEGER
  12. END TYPE
  13.  
  14. ' Define a record structure for each element of the index:
  15. TYPE IndexType
  16.     RecordNumber AS INTEGER
  17.     PartNumber AS STRING * 6
  18. END TYPE
  19.  
  20. ' Declare procedures that will be called:
  21. DECLARE FUNCTION Filter$ (Prompt$)
  22. DECLARE FUNCTION FindRecord% (PartNumber$, RecordVar AS StockItem)
  23.  
  24. DECLARE SUB AddRecord (RecordVar AS StockItem)
  25. DECLARE SUB InputRecord (RecordVar AS StockItem)
  26. DECLARE SUB PrintRecord (RecordVar AS StockItem)
  27. DECLARE SUB SortIndex ()
  28. DECLARE SUB ShowPartNumbers ()
  29. ' Define a buffer (using the StockItem type)
  30. ' and define and dimension the index array:
  31. DIM StockRecord AS StockItem, index(1 TO 100) AS IndexType
  32.  
  33. ' Open the random-access file:
  34. OPEN "STOCK.DAT" FOR RANDOM AS #1 LEN = LEN(StockRecord)
  35.  
  36. ' Calculate number of records in the file:
  37. NumberOfRecords = LOF(1) \ LEN(StockRecord)
  38.  
  39. ' If there are records, read them and build the index:
  40. IF NumberOfRecords <> 0 THEN
  41.     FOR RecordNumber = 1 TO NumberOfRecords
  42.  
  43.         ' Read the data from a new record in the file:
  44.         GET #1, RecordNumber, StockRecord
  45.  
  46.         ' Place part number and record number in index:
  47.         index(RecordNumber).RecordNumber = RecordNumber
  48.         index(RecordNumber).PartNumber = StockRecord.PartNumber
  49.     NEXT
  50.  
  51.     SortIndex            ' Sort index in part-number order.
  52. END IF
  53.  
  54. DO                      ' Main-menu loop.
  55.     CLS
  56.     PRINT "(A)dd records."
  57.     PRINT "(L)ook up records."
  58.     PRINT "(Q)uit program."
  59.     PRINT
  60.     LOCATE , , 1
  61.     PRINT "Type your choice (A, L, or Q) here: ";
  62.  
  63.     ' Loop until user presses, A, L, or Q:
  64.     DO
  65.         Choice$ = UCASE$(INPUT$(1))
  66.     LOOP WHILE INSTR("ALQ", Choice$) = 0
  67.  
  68.     ' Branch according to choice:
  69.     SELECT CASE Choice$
  70.         CASE "A"
  71.      AddRecord StockRecord
  72.         CASE "L"
  73.      IF NumberOfRecords = 0 THEN
  74.          PRINT : PRINT "No records in file yet. ";
  75.          PRINT "Press any key to continue.";
  76.          Pause$ = INPUT$(1)
  77.      ELSE
  78.          InputRecord StockRecord
  79.      END IF
  80.         CASE "Q"          ' End program.
  81.     END SELECT
  82. LOOP UNTIL Choice$ = "Q"
  83.  
  84. CLOSE #1                ' All done, close file and end.
  85. END
  86.  
  87. ' ======================== ADDRECORD ======================
  88. ' Adds records to the file from input typed at the keyboard
  89. ' =========================================================
  90. SUB AddRecord (RecordVar AS StockItem) STATIC
  91.     SHARED index() AS IndexType, NumberOfRecords
  92.     DO
  93.         CLS
  94.         INPUT "Part Number: ", RecordVar.PartNumber
  95.         INPUT "Description: ", RecordVar.Description
  96.  
  97.         ' Call the Filter$ FUNCTION to input price & quantity:
  98.         RecordVar.UnitPrice = VAL(Filter$("Unit Price : "))
  99.         RecordVar.Quantity = VAL(Filter$("Quantity   : "))
  100.  
  101.         NumberOfRecords = NumberOfRecords + 1
  102.  
  103.         PUT #1, NumberOfRecords, RecordVar
  104.  
  105.         index(NumberOfRecords).RecordNumber = NumberOfRecords
  106.         index(NumberOfRecords).PartNumber = RecordVar.PartNumber
  107.         PRINT : PRINT "Add another? ";
  108.         OK$ = UCASE$(INPUT$(1))
  109.     LOOP WHILE OK$ = "Y"
  110.  
  111.     SortIndex            ' Sort index file again.
  112. END SUB
  113.  
  114. ' ========================= FILTER ========================
  115. '       Filters all non-numeric characters from a string
  116. '       and returns the filtered string
  117. ' =========================================================
  118. FUNCTION Filter$ (Prompt$) STATIC
  119.     ValTemp2$ = ""
  120.     PRINT Prompt$;                    ' Print the prompt passed.
  121.     INPUT "", ValTemp1$               ' Input a number as
  122.                                                  ' a string.
  123.     StringLength = LEN(ValTemp1$)     ' Get the string's length.
  124.     FOR I% = 1 TO StringLength        ' Go through the string,
  125.         Char$ = MID$(ValTemp1$, I%, 1) ' one character at a time.
  126.  
  127.         ' Is the character a valid part of a number (i.e.,
  128.         ' a digit or a decimal point)?  If yes, add it to
  129.         ' the end of a new string:
  130.         IF INSTR(".0123456789", Char$) > 0 THEN
  131.             ValTemp2$ = ValTemp2$ + Char$
  132.  
  133.         ' Otherwise, check to see if it's a lowercase "l",
  134.         ' since typewriter users may enter a one that way:
  135.         ELSEIF Char$ = "l" THEN
  136.             ValTemp2$ = ValTemp2$ + "1" ' Change the "l" to a "1".
  137.         END IF
  138.     NEXT I%
  139.  
  140.     Filter$ = ValTemp2$               ' Return filtered string.
  141.  
  142. END FUNCTION
  143.  
  144. ' ======================= FINDRECORD ===================
  145. '  Uses a binary search to locate a record in the index
  146. ' ======================================================
  147. FUNCTION FindRecord% (Part$, RecordVar AS StockItem) STATIC
  148.     SHARED index() AS IndexType, NumberOfRecords
  149.  
  150.     ' Set top and bottom bounds of search:
  151.     TopRecord = NumberOfRecords
  152.     BottomRecord = 1
  153.  
  154.     ' Search until top of range is less than bottom:
  155.     DO UNTIL (TopRecord < BottomRecord)
  156.  
  157.         ' Choose midpoint:
  158.         Midpoint = (TopRecord + BottomRecord) \ 2
  159.  
  160.         ' Test to see if it's the one wanted (RTRIM$()
  161.         ' trims trailing blanks from a fixed string):
  162.         Test$ = RTRIM$(index(Midpoint).PartNumber)
  163.  
  164.         ' If it is, exit loop:
  165.         IF Test$ = Part$ THEN
  166.      EXIT DO
  167.  
  168.         ' Otherwise, if what we're looking for is greater,
  169.         ' move bottom up:
  170.         ELSEIF Part$ > Test$ THEN
  171.      BottomRecord = Midpoint + 1
  172.  
  173.         ' Otherwise, move the top down:
  174.         ELSE
  175.      TopRecord = Midpoint - 1
  176.         END IF
  177.     LOOP
  178.  
  179.     ' If part was found, input record from file using
  180.     ' pointer in index and set FindRecord% to TRUE:
  181.     IF Test$ = Part$ THEN
  182.         GET #1, index(Midpoint).RecordNumber, RecordVar
  183.         FindRecord% = TRUE
  184.  
  185.     ' Otherwise, if part was not found, set FindRecord%
  186.     ' to FALSE:
  187.     ELSE
  188.         FindRecord% = FALSE
  189.     END IF
  190. END FUNCTION
  191.  
  192. ' ======================= INPUTRECORD =====================
  193. '    First, INPUTRECORD calls SHOWPARTNUMBERS, which prints
  194. '    a menu of part numbers on the top of the screen. Next,
  195. '    INPUTRECORD prompts the user to enter a part number.
  196. '    Finally, it calls the FINDRECORD and PRINTRECORD
  197. '    procedures to find and print the given record.
  198. ' =========================================================
  199. SUB InputRecord (RecordVar AS StockItem) STATIC
  200.     CLS
  201.     ShowPartNumbers      ' Call the ShowPartNumbers SUB.
  202.  
  203.     ' Print data from specified records
  204.     ' on the bottom part of the screen:
  205.     DO
  206.         PRINT "Type a part number listed above ";
  207.         INPUT "(or Q to quit) and press <ENTER>: ", Part$
  208.         IF UCASE$(Part$) <> "Q" THEN
  209.      IF FindRecord(Part$, RecordVar) THEN
  210.          PrintRecord RecordVar
  211.      ELSE
  212.          PRINT "Part not found."
  213.      END IF
  214.         END IF
  215.         PRINT STRING$(40, "_")
  216.     LOOP WHILE UCASE$(Part$) <> "Q"
  217.  
  218.     VIEW PRINT   ' Restore the text viewport to entire screen.
  219. END SUB
  220.  
  221. ' ======================= PRINTRECORD =====================
  222. '                Prints a record on the screen
  223. ' =========================================================
  224. SUB PrintRecord (RecordVar AS StockItem) STATIC
  225.     PRINT "Part Number: "; RecordVar.PartNumber
  226.     PRINT "Description: "; RecordVar.Description
  227.     PRINT USING "Unit Price :$$###.##"; RecordVar.UnitPrice
  228.     PRINT "Quantity   :"; RecordVar.Quantity
  229. END SUB
  230.  
  231. ' ===================== SHOWPARTNUMBERS ===================
  232. ' Prints an index of all the part numbers in the upper part
  233. ' of the screen
  234. ' =========================================================
  235. SUB ShowPartNumbers STATIC
  236.     SHARED index() AS IndexType, NumberOfRecords
  237.  
  238.     CONST NUMCOLS = 8, COLWIDTH = 80 \ NUMCOLS
  239.  
  240.     ' At the top of the screen, print a menu indexing all
  241.     ' the part numbers for records in the file. This menu is
  242.     ' printed in columns of equal length (except possibly the
  243.     ' last column, which may be shorter than the others):
  244.     ColumnLength = NumberOfRecords
  245.     DO WHILE ColumnLength MOD NUMCOLS
  246.         ColumnLength = ColumnLength + 1
  247.     LOOP
  248.     ColumnLength = ColumnLength \ NUMCOLS
  249.     Column = 1
  250.     RecordNumber = 1
  251. DO UNTIL RecordNumber > NumberOfRecords
  252.         FOR Row = 1 TO ColumnLength
  253.      LOCATE Row, Column
  254.      PRINT index(RecordNumber).PartNumber
  255.      RecordNumber = RecordNumber + 1
  256.      IF RecordNumber > NumberOfRecords THEN EXIT FOR
  257.         NEXT Row
  258.         Column = Column + COLWIDTH
  259.     LOOP
  260.  
  261.     LOCATE ColumnLength + 1, 1
  262.     PRINT STRING$(80, "_")       ' Print separator line.
  263.  
  264.     ' Scroll information about records below the part-number
  265.     ' menu (this way, the part numbers are not erased):
  266.     VIEW PRINT ColumnLength + 2 TO 24
  267. END SUB
  268.  
  269. ' ========================= SORTINDEX =====================
  270. '                Sorts the index by part number
  271. ' =========================================================
  272. SUB SortIndex STATIC
  273.     SHARED index() AS IndexType, NumberOfRecords
  274.  
  275.     ' Set comparison offset to half the number of records
  276.     ' in index:
  277.     Offset = NumberOfRecords \ 2
  278.  
  279.     ' Loop until offset gets to zero:
  280.     DO WHILE Offset > 0
  281.         Limit = NumberOfRecords - Offset
  282.         DO
  283.  
  284.      ' Assume no switches at this offset:
  285.      Switch = FALSE
  286.  
  287.      ' Compare elements and switch ones out of order:
  288.      FOR I = 1 TO Limit
  289.          IF index(I).PartNumber > index(I + Offset).PartNumber THEN
  290.              SWAP index(I), index(I + Offset)
  291.              Switch = I
  292.          END IF
  293.      NEXT I
  294.  
  295.      ' Sort on next pass only to where
  296.      ' last switch was made:
  297.      Limit = Switch
  298.         LOOP WHILE Switch
  299.  
  300.         ' No switches at last offset, try one half as big:
  301.         Offset = Offset \ 2
  302.     LOOP
  303. END SUB
  304.  
  305.