home *** CD-ROM | disk | FTP | other *** search
- DEFINT A-Z
-
- ' Define the symbolic constants used globally in the program:
- CONST FALSE = 0, TRUE = NOT FALSE
-
- ' Define a record structure for random-file records:
- TYPE StockItem
- PartNumber AS STRING * 6
- Description AS STRING * 20
- UnitPrice AS SINGLE
- Quantity AS INTEGER
- END TYPE
-
- ' Define a record structure for each element of the index:
- TYPE IndexType
- RecordNumber AS INTEGER
- PartNumber AS STRING * 6
- END TYPE
-
- ' Declare procedures that will be called:
- DECLARE FUNCTION Filter$ (Prompt$)
- DECLARE FUNCTION FindRecord% (PartNumber$, RecordVar AS StockItem)
-
- DECLARE SUB AddRecord (RecordVar AS StockItem)
- DECLARE SUB InputRecord (RecordVar AS StockItem)
- DECLARE SUB PrintRecord (RecordVar AS StockItem)
- DECLARE SUB SortIndex ()
- DECLARE SUB ShowPartNumbers ()
-
- ' Define a buffer (using the StockItem type) and
- ' define & dimension the index array:
- DIM StockRecord AS StockItem, Index(1 TO 100) AS IndexType
-
- ' Open the random-access file:
- OPEN "STOCK.DAT" FOR RANDOM AS #1 LEN = LEN(StockRecord)
-
- ' Calculate number of records in the file:
- NumberOfRecords = LOF(1) \ LEN(StockRecord)
-
- ' If there are records, read them and build the index:
- IF NumberOfRecords <> 0 THEN
- FOR RecordNumber = 1 TO NumberOfRecords
-
- ' Read the data from a new record in the file:
- GET #1, RecordNumber, StockRecord
-
- ' Place part number and record number in index:
- Index(RecordNumber).RecordNumber = RecordNumber
- Index(RecordNumber).PartNumber = StockRecord.PartNumber
- NEXT
-
- SortIndex ' Sort index in part-number order.
- END IF
-
- DO ' Main-menu loop.
- CLS
- PRINT "(A)dd records."
- PRINT "(L)ook up records."
- PRINT "(Q)uit program."
- PRINT
- LOCATE , , 1
- PRINT "Type your choice (A, L, or Q) here: ";
-
- ' Loop until user presses, A, L, or Q:
- DO
- Choice$ = UCASE$(INPUT$(1))
- LOOP WHILE INSTR("ALQ", Choice$) = 0
-
- ' Branch according to choice:
- SELECT CASE Choice$
- CASE "A"
- AddRecord StockRecord
- CASE "L"
- IF NumberOfRecords = 0 THEN
- PRINT : PRINT "No records in file yet. ";
- PRINT "Press any key to continue.";
- Pause$ = INPUT$(1)
- ELSE
- InputRecord StockRecord
- END IF
- CASE "Q" ' End program
- END SELECT
- LOOP UNTIL Choice$ = "Q"
-
- CLOSE #1 ' All done, close file and end.
- END
- '
- ' ======================== ADDRECORD =========================
- ' Adds records to the file from input typed at the keyboard.
- ' ============================================================
- '
- SUB AddRecord (RecordVar AS StockItem) STATIC
- SHARED Index() AS IndexType, NumberOfRecords
- DO
- CLS
- INPUT "Part Number: ", RecordVar.PartNumber
- INPUT "Description: ", RecordVar.Description
- RecordVar.UnitPrice = VAL(Filter$("Unit Price : "))
- RecordVar.Quantity = VAL(Filter$("Quantity : "))
-
- NumberOfRecords = NumberOfRecords + 1
-
- PUT #1, NumberOfRecords, RecordVar
-
- Index(NumberOfRecords).RecordNumber = NumberOfRecords
- Index(NumberOfRecords).PartNumber = RecordVar.PartNumber
- PRINT : PRINT "Add another? ";
- OK$ = UCASE$(INPUT$(1))
- LOOP WHILE OK$ = "Y"
-
- SortIndex ' Re-sort index file.
- END SUB
- '
- ' ========================= FILTER ===========================
- ' Filters all non-numeric characters from a string
- ' and returns the filtered string.
- ' ============================================================
- '
- FUNCTION Filter$ (Prompt$) STATIC
- ValTemp2$ = ""
- PRINT Prompt$; ' Print the prompt passed.
- INPUT "", ValTemp1$ ' Input a number as
- ' a string.
- StringLength = LEN(ValTemp1$) ' Get the string's length.
- FOR I% = 1 TO StringLength ' Go through the string,
- Char$ = MID$(ValTemp1$, I%, 1) ' one character at a time.
-
- ' Is the character a valid part of a number (i.e.,
- ' a digit or a decimal point)? If yes, add it to
- ' the end of a new string:
- IF INSTR(".0123456789", Char$) > 0 THEN
- ValTemp2$ = ValTemp2$ + Char$
-
- ' Otherwise, check to see if it's a lowercase "l",
- ' since users used to typewriters may enter a one
- ' value that way:
- ELSEIF Char$ = "l" THEN
- ValTemp2$ = ValTemp2$ + "1" ' Change the "l" to a "1".
- END IF
- NEXT I%
-
- Filter$ = ValTemp2$ ' Return filtered string.
-
- END FUNCTION
- '
- ' ======================= FINDRECORD =========================
- ' Uses a binary search to locate a record in the index.
- ' ============================================================
- '
- FUNCTION FindRecord% (Part$, RecordVar AS StockItem) STATIC
- SHARED Index() AS IndexType, NumberOfRecords
-
- ' Set top and bottom bounds of search:
- TopRecord = NumberOfRecords
- BottomRecord = 1
-
- ' Search until top of range is less than bottom:
- DO UNTIL (TopRecord < BottomRecord)
-
- ' Choose midpoint:
- Midpoint = (TopRecord + BottomRecord) \ 2
-
- ' Test to see if it's the one wanted (RTRIM$() trims
- ' trailing blanks from a fixed string):
- Test$ = RTRIM$(Index(Midpoint).PartNumber)
-
- ' If it is, exit loop:
- IF Test$ = Part$ THEN
- EXIT DO
-
- ' Otherwise, if what we're looking for is greater,
- ' move bottom up:
- ELSEIF Part$ > Test$ THEN
- BottomRecord = Midpoint + 1
-
- ' Otherwise, move the top down:
- ELSE
- TopRecord = Midpoint - 1
- END IF
- LOOP
-
- ' If part was found, get record from file using
- ' pointer in index and set FindRecord% to TRUE:
- IF Test$ = Part$ THEN
- GET #1, Index(Midpoint).RecordNumber, RecordVar
- FindRecord% = TRUE
-
- ' Otherwise, if part was not found, set FindRecord%
- ' to FALSE:
- ELSE
- FindRecord% = FALSE
- END IF
- END FUNCTION
- '
- ' ======================= INPUTRECORD ========================
- ' First, INPUTRECORD calls SHOWPARTNUMBERS, which
- ' prints a menu of part numbers on the top of the screen.
- ' Next, INPUTRECORD prompts the user to enter a part
- ' number. Finally, it calls the FINDRECORD and PRINTRECORD
- ' procedures to find and print the given record.
- ' ============================================================
- '
- SUB InputRecord (RecordVar AS StockItem) STATIC
- CLS
- ShowPartNumbers ' Call the ShowPartNumbers SUB.
-
- ' Print data from specified records on the bottom
- ' part of the screen:
- DO
- PRINT "Type a part number listed above ";
- INPUT "(or Q to quit) and press <ENTER>: ", Part$
- IF UCASE$(Part$) <> "Q" THEN
- IF FindRecord(Part$, RecordVar) THEN
- PrintRecord RecordVar
- ELSE
- PRINT "Part not found."
- END IF
- END IF
- PRINT STRING$(40, "_")
- LOOP WHILE UCASE$(Part$) <> "Q"
-
- VIEW PRINT ' Restore the text viewport to entire screen.
- END SUB
- '
- ' ======================= PRINTRECORD ========================
- ' Prints a record on the screen
- ' ============================================================
- '
- SUB PrintRecord (RecordVar AS StockItem) STATIC
- PRINT "Part Number: "; RecordVar.PartNumber
- PRINT "Description: "; RecordVar.Description
- PRINT USING "Unit Price :$$###.##"; RecordVar.UnitPrice
- PRINT "Quantity :"; RecordVar.Quantity
- END SUB
- '
- ' ===================== SHOWPARTNUMBERS ======================
- ' Prints an index of all the part numbers in the upper part
- ' of the screen.
- ' ============================================================
- '
- SUB ShowPartNumbers STATIC
- SHARED Index() AS IndexType, NumberOfRecords
-
- CONST NUMCOLS = 8, COLWIDTH = 80 \ NUMCOLS
-
- ' At the top of the screen, print a menu indexing all
- ' the part numbers for records in the file. This menu is
- ' printed in columns of equal length (except possibly the
- ' last column, which may be shorter than the others):
- ColumnLength = NumberOfRecords
- DO WHILE ColumnLength MOD NUMCOLS
- ColumnLength = ColumnLength + 1
- LOOP
- ColumnLength = ColumnLength \ NUMCOLS
- Column = 1
- RecordNumber = 1
- DO UNTIL RecordNumber > NumberOfRecords
- FOR Row = 1 TO ColumnLength
- LOCATE Row, Column
- PRINT Index(RecordNumber).PartNumber
- RecordNumber = RecordNumber + 1
- IF RecordNumber > NumberOfRecords THEN EXIT FOR
- NEXT Row
- Column = Column + COLWIDTH
- LOOP
-
- LOCATE ColumnLength + 1, 1
- PRINT STRING$(80, "_") ' Print separator line.
-
- ' Scroll information about records below the part-number
- ' menu (this way, the part numbers are not erased):
- VIEW PRINT ColumnLength + 2 TO 24
- END SUB
- '
- ' ========================= SORTINDEX ========================
- ' Sorts the index by part number
- ' ============================================================
- '
- SUB SortIndex STATIC
- SHARED Index() AS IndexType, NumberOfRecords
-
- ' Set comparison offset to half the number of records
- ' in index:
- Offset = NumberOfRecords \ 2
-
- ' Loop until offset gets to zero:
- DO WHILE Offset > 0
- Limit = NumberOfRecords - Offset
- DO
-
- ' Assume no switches at this offset:
- Switch = FALSE
-
- ' Compare elements and switch ones out of order:
- FOR I = 1 TO Limit
- IF Index(I).PartNumber > Index(I + Offset).PartNumber THEN
- SWAP Index(I), Index(I + Offset)
- Switch = I
- END IF
- NEXT I
-
- ' Sort on next pass only to where last
- ' switch was made:
- Limit = Switch
- LOOP WHILE Switch
-
- ' No switches at last offset, try one half as big:
- Offset = Offset \ 2
- LOOP
- END SUB
-