home *** CD-ROM | disk | FTP | other *** search
/ 8bitfiles.net/archives / archives.tar / archives / genie-commodore-file-library / Information / RELATIVE-FILES < prev    next >
Encoding:
Text File  |  2019-04-13  |  28.0 KB  |  598 lines

  1. *********************************************************************
  2. This article is being presented through the *StarBoard* Journal of
  3. the FlagShip/StarShip, SIGS (Special Interest Groups) on the
  4. Delphi and GEnie telecommunications networks.  Permission is
  5. hereby granted to non-profit organizations only to reprint this
  6. article or pass it along electronically as long as proper credit
  7. is given to both the author and the *StarBoard* Journal.
  8. *********************************************************************
  9.  
  10.        RELATIVE FILES MADE RELATIVELY EASY (Epilogue 1)
  11.  
  12.                        by Bill Brier
  13.  
  14.                   (TROUBLESOME on DELPHI)
  15.  
  16. I.  RECORD INDEXING
  17.  
  18. RELative files operate by assigning each record a number.  The record
  19. number tells the disk operating system (DOS) where to look in the
  20. file for the desired data.  As a result, searches can be rapidly
  21. performed without a lot of overhead in the program.
  22.  
  23. While the technique of assigning numbers to records is quite
  24. efficient from the disk drive's point of view, it is quite annoying
  25. from the user's point of view.  This is because human beings find
  26. numbers rather difficult to associate with other information.  Of
  27. course, the computer finds such association quite easy to deal with.
  28. Therefore, some sort of compromise must be worked out.  That
  29. compromise is the FILENAME INDEX.
  30.  
  31. In RELATIVE FILES MADE RELATIVELY EASY parts 1 and 2 we discussed the
  32. methods by which a mailing list could be implemented using a RELative
  33. file. So, let's see what it would take to index our mailing list.
  34.  
  35. Each record contains the person's or company's name, street address,
  36. city and so forth.  We can consider the person's or company's name to
  37. be the key field or element in the record.  So, why not construct a
  38. filename index using filenames derived from each person's name?
  39. Then, once we've made a filename, we can simply append the record
  40. number to that filename and store it along with other filenames in a
  41. SEQuential file on the same disk.  When the mailing list program is
  42. first RUN we would load the resulting filename index into memory and
  43. modify it each time a new record was added or removed from the
  44. RELative file.
  45.  
  46. About this time you are saying that this is a great idea, but how do
  47. I create the filename?  Let's do that right now.  We'll introduce
  48. some new variables to the small army of variables that we already
  49. have.  Here is how to create a name and a filename using simple
  50. string functions:
  51.  
  52.     100 INPUT"FIRST NAME";GN$:IF GN$=""THEN100:REM NO NULLS
  53.     110 INPUT"LAST NAME";NA$:IF NA$=""THEN110
  54.     120 NA$=LEFT$(NA$,18):REM TRUNCATE LAST NAME
  55.     130 NF$=NA$+LEFT$(GN$,1):REM CREATE FILENAME
  56.     140 NA$=LEFT$(GN$,13)+CHR$(32)+NA$
  57.  
  58. This will result in NA$ containing the first and last name separated
  59. by a space so that a first name of Steven and a last name of Smith
  60. would look like this:
  61.  
  62.     STEVEN SMITH
  63.  
  64. Notice how we truncated the first and last names so that the combined
  65. length of the two plus the space will not exceed the size of the name
  66. field in the record.  This is necessary to avoid corrupting the next
  67. field with an overflow.
  68.  
  69. In line 130 we create the filename by attaching the first letter of
  70. the first name to the end of the last name.  Steven Smith's file name
  71. would be:
  72.  
  73.     SMITHS
  74.  
  75. In order for our filename system to correctly operate, we must never
  76. allow a space in the filename and we may not duplicate filenames as
  77. the system will then be unable to distinguish one record from
  78. another.  Lastly, we must organize the filenames into an array, and
  79. we must have some means of extracting the record number from the
  80. filename.  In the process of accomplishing all of this, we will also
  81. incorporate a useful feature...filename PATTERN-MATCHING.
  82.  
  83. II.  FILENAME ARRAY STRUCTURE
  84.  
  85. In order to manipulate the filenames we need to set up an string
  86. array in memory and store all of the filenames in it.  This is
  87. initially accomplished with the DIMension statement.  We will now
  88. introduce a few more variables for this purpose.  The variable R will
  89. represent the number of the highest element in the array, and the
  90. variable N will represent the number of active filenames in the
  91. array.  The variable R, in our mailing list, would equal 499 (not
  92. 500, as one might presume).
  93.  
  94. The value of N could be anything from 0 (no names on file) to 500 (a
  95. full file).  As you will see, these two variables will assume
  96. considerable importance in our program.
  97.  
  98. First, let's DIMension our filename array:
  99.  
  100.     DIM NF$(R)
  101.  
  102. That was simple, wasn't it?  Remember that R has a value of 499.  The
  103. DIMension statement sets up an array starting with NF$(0) and ending
  104. with NF$(499).  Thus, the array actually has 500 elements.  Of
  105. course, right now all 500 elements are nulls.  For the sake of easy
  106. use we need to initialize the array, a task somewhat similar to the
  107. initializing of the RELative file when we first created it.
  108. Initializing the array will create 500 "dummy" filenames, complete
  109. with 500 record numbers.  Later, as you add records, the dummy
  110. filenames will be replaced with actual filenames, as derived in the
  111. previous chapter.
  112.  
  113. Here is how to initialize the index array:
  114.  
  115.     FOR I=0 TO R:NF$(I)=MID$(STR$(I+1),2):NEXT
  116.  
  117. When this loop is done each element will contain a number from 1 to
  118. 500 (which corresponds with the available records in the RELative
  119. file).  For example, NF$(212) would look like this:
  120.  
  121.     213
  122.  
  123. The MID$ function eliminates the leading space that all positive
  124. numbers are stored with.  The space is unnecessary and simply
  125. consumes more room in both the disk file and in memory.  Initializing
  126. of the index array should be performed only when the new RELative
  127. file is first created.  Thereafter, the index will be manipulated by
  128. the insertion or removal of filenames.
  129.  
  130. III.  APPENDING AND EXTRACTING RECORD NUMBERS
  131.  
  132. Once the dummy filenames have been created we can start to fill our
  133. RELative file with the actual records.  To do this requires that we
  134. know which records are available.  Assuming that the index is always
  135. kept in alphabetic order (we'll discuss later how to do this from
  136. BASIC without a lot of hassle), the variable N will always "point" to
  137. the next dummy filename and thus the next available record.
  138.  
  139. In our newly-created dummy filename index, variable N would initially
  140. have a value of zero.  So, if we "look" at NF$(N) we would find:
  141.  
  142.     1
  143.  
  144. The 1 is the unused and therefore available record number.
  145. Extracting the record number from a dummy filename is quite easy as
  146. the VAL function can be used:
  147.  
  148.     J = VAL(NF$(N))
  149.  
  150. Once we have extracted the unused record number we can then append it
  151. to the previously created filename with string functions.  Assuming
  152. that the record number is represented by the variable J, we would
  153. append this record number to Steven Smith's filename (SMITHS) as
  154. follows (SMITHS is contained in NF$):
  155.  
  156.     NF$=NF$+STR$(J)
  157.  
  158. This will result in NF$ containing:
  159.  
  160.     SMITHS 1
  161.  
  162. The space between the filename and the record number occurs because a
  163. string equivalent of a positive numeric variable takes the space as
  164. well as the number itself.  This works out very nicely for us as we
  165. need the space to separate the filename and record number for easy
  166. location and extraction of the number.
  167.  
  168. Obviously, we can't extract the record number of a "real" or ACTIVE
  169. filename with VAL as we did with the dummy filename as VAL will
  170. return a zero.  Extracting the record number from an active filename
  171. takes a bit of programming with string functions.  This is because
  172. the location of the record number depends on the length of the
  173. filename itself.  Therefore, to find the record number we have to
  174. PARSE the filename in a loop.  Parsing a filename successively looks
  175. at each character within the filename by taking repeated substrings
  176. of the filename.  When doing searches of the mailing list you will
  177. have to extract the record number from each active filename in order
  178. to look at all records.  This is best accomplished within a FOR-NEXT
  179. loop (or DO-LOOP in BASIC 7.0).  Assuming that the loop variable I is
  180. pointing to the filename, here is how you get the record number into
  181. J:
  182.  
  183.     8550 F=2
  184.     8555 IF MID$(NF$(I),F,1)<>CHR$(32)THEN F=F+1:GOTO 8555
  185.     8560 J = VAL(MID$(NF$(I),F)):RETURN
  186.  
  187. Line 8555 does the actual parsing of the filename.  It scans the
  188. filename until the space separating the name from the record number
  189. is located. When the space is found the routine falls through to 8560
  190. where the actual value of the record number is derived.  The reason
  191. for setting F to 2 is because that is the lowest position in the
  192. filename in which a space is to be found.  The routine will operate
  193. slightly faster.  In line 8560 we take advantage of a little-known
  194. function of Commodore BASIC...the REMAINDER STRING.  A MID$ function
  195. without the second value returns all of the characters remaining at
  196. the point determined by the first value.  The result of this in 8560
  197. is to extract the entire record number rather than just a character
  198. or two.
  199.  
  200. Let's see how this routine would work on Steven Smith's filename:
  201.  
  202.     SMITHS 1
  203.  
  204. When the routine is first entered, variable F will point at the M in
  205. SMITHS.  Since the PETASCII value of M is not 32, F would be
  206. incremented and would successively point at I, T, H and S.  Finally,
  207. F would point at the space between SMITHS and 1, and the loop would
  208. end.  We would exit the routine with the variable J equal to the
  209. record number (1 in this example).
  210.  
  211.     NOTE:  In BASIC 7.0 on the C-128 the INSTR function can be used
  212.     to locate the space.  The method used would be:
  213.     F=INSTR(NF$(I),CHR$(32)). This would replace lines 8550 and 8555
  214.     in the above example.
  215.  
  216. The reason for placing this sequence into a subroutine is so your
  217. program can easily extract the record number out of any filename in
  218. the index. This function will play great importance in searches.
  219.  
  220. IV.  MANIPULATING THE FILENAME INDEX
  221.  
  222. Up to this point we have seen how to create a filename and how to
  223. append a record number to it.  Additional examples will now be
  224. presented that scan the index for a duplicate filename, insert the
  225. new filename into the index at the proper point to keep the index in
  226. alphabetic order, and save the index on the file disk.
  227.  
  228. As previously mentioned the variables N and R are quite important to
  229. the manipulation of the index.  Variable N indicates the number of
  230. active filenames in the index and also "points" to the next dummy
  231. filename. Variable R is a constant of 499, which is the maximum
  232. number of records allowed in the mailing list.  Prior to actually
  233. accepting a new record and filename for inclusion in the mailing list
  234. it is necessary to determine if space is available for the new
  235. record.  This is easily accomplished by comparing N to R and setting
  236. a flag to indicate the result:
  237.  
  238.     F=0:IF N > R THEN F=1
  239.  
  240. If N is less than 500 then it is not greater than R (which is equal
  241. to 499) and flag F remains zero.  If the file is full, N will equal
  242. 500 and the flag F will be set to one, indicating that no more
  243. entries can be accommodated.  It is important to trap this condition
  244. as referencing NF$(N) when N=500 will cause a BAD SUBSCRIPT error
  245. (NF$ was DIMensioned to 499).
  246.  
  247. If the flag F equals one then we know that the file is full, and a
  248. suitable warning can be displayed to the user indicating this fact.
  249. If room exists for a new entry then the new filename can be inserted
  250. in the index, and the counter N can be increased by one to show that
  251. the index has also increased by one.  Insertion of a new name into
  252. the index should not be performed until after the record has been
  253. written into the RELative file.  This is to avoid modifying the index
  254. in the event a disk error aborts the writing of the record.
  255.  
  256. So, the procedure for adding a record to the mailing list is
  257. something like this:
  258.  
  259.     1.  Check variable N for space.  If no space exists then abort
  260.         the entry process.
  261.  
  262.     2.  Have the user type in the first and last name.
  263.  
  264.     3.  Construct the filename (SMITHS for example) and scan the
  265.         active index for a duplicate.
  266.  
  267.     4.  If a duplicate is found advise the user and abort.
  268.         Otherwise, have the user type in the remaining
  269.         information for the record (address, city, etc.).
  270.  
  271.     5.  Extract the next available record number from the index as
  272.         demonstrated above.  This is variable J.
  273.  
  274.     6.  Write the record to the disk using J for the record number.
  275.  
  276.     7.  Upon a successful write to the disk append the record number
  277.         in variable J to the filename and insert the filename into
  278.         the index.
  279.  
  280.     8.  When all entries have been made save the filename index to
  281.         the disk.
  282.  
  283. Steps 1,2, and part of 3 have already been described in the chapters
  284. on manipulating the filename.  We will now look at how to determine
  285. if a filename is a duplicate or is unique.  The technique of
  286. PATTERN-MATCHING will also be presented.
  287.  
  288. V.  SCANNING THE INDEX FOR A DUPLICATE FILENAME
  289.  
  290. Before we actually insert the new record into the mailing list and
  291. insert the new filename into the index, we must scan the existing
  292. filenames for a pattern match.  If two identical filenames were
  293. permitted to exist in the index, it would be impossible to
  294. differentiate one from the other.  To prevent such an occurrence we
  295. must scan the index from beginning to end and attempt to locate a
  296. duplicate filename.  In the process of doing this we can also
  297. determine at what point in the index we should insert the new
  298. filename to keep everything in alphabetic order.  Let's see how we
  299. can accomplish these operations.
  300.  
  301. We know from previous discussion that variable N points to the next
  302. dummy filename in the index.  This implies that the active index
  303. spans from NF$(0) up to NF$(N-1), containing all of the active
  304. filenames.  Therefore, what needs to be done is to compare the new
  305. filename against each of the active filenames using a loop.  If a
  306. duplicate is found we terminate the loop and set a flag to indicate
  307. the match.
  308.  
  309. Here's a method of accomplishing this:
  310.  
  311.     8570 I=0:F=0:L=LEN(NF$):IF N=0 THEN 8590
  312.     8575 IF LEFT$(NF$(I),L) = NF$ THEN F=1:GOTO 8590
  313.     8580 IF NF$ < NF$(I) THEN 8590
  314.     8585 I=I+1:IF I<N THEN 8575:REM CONTINUE SCANNING
  315.     8590 RETURN
  316.  
  317. Let's see how this operates.  Upon entering the routine we set the
  318. variables I and F to zero.  Variable I will be used to reference each
  319. of the filename index elements as we scan for a duplicate.  Variable
  320. F will act as the "duplicate" or match flag.  If we leave this
  321. routine with F set to one that means that a duplicate filename was
  322. located in the index.
  323.  
  324. Line 8575 attempts to pattern-match the filenames.  Using the LEFT$
  325. function and variable L (which is equal to the number of characters
  326. in the new filename), we compare the new filename to a portion of the
  327. filename pointed to in the index by variable I to see if an exact
  328. match exists.  If a match does occur, we set variable F to one and
  329. exit.  Variable I will be left pointing to the matched filename.
  330.  
  331. Assuming that a pattern-match does not occur in 8575, line 8580 will
  332. check the relationship between NF$ and NF$(I) to see which is higher
  333. in the alphabet.  If NF$ was SMITHS and NF$(I) was SMITHR then
  334. nothing would happen as NF$ would be greater (alphabetically
  335. speaking) than NF$(I).  If, on the other hand, NF$(I) was SMITHT then
  336. the comparison would work and variable I would be left pointing to
  337. the index position that SMITHT currently occupied.  This would be the
  338. location to which SMITHS would have to be inserted into the index to
  339. retain alphabetic order.  More on this later on.
  340.  
  341. If a match doesn't occur or if the new filename is alphabetically
  342. higher than the index filename just checked, variable I is increased
  343. by one and then checked against variable N.  If I is less than N a
  344. loop occurs, as there are more names to check.  If the entire index
  345. was scanned and no duplicate was found, variable I will equal N and F
  346. will equal zero, indicating the filename was not found.  This
  347. function is quite useful for searches, as will be seen later on.
  348.  
  349. Of course, I'm sure you are a bit puzzled as to how this system can
  350. pattern-match filenames.  Let's assume that NF$ is SMI and that
  351. NF$(I) is SMITHS.  The value of L as established in line 8570 would
  352. be 3, because the length of NF$ is 3 (SMI).  In 8575 we compare
  353. LEFT$(NF$(I),L) against NF$. In effect, the function becomes
  354. LEFT$("SMITHS",3) which would be "SMI". Because "SMI"="SMI" we have a
  355. pattern match.  A pattern match does not require that the entire
  356. filename be entered.  As long as the characters in the new filename
  357. are exactly equal to a substring of characters in an index filename a
  358. match will occur.
  359.  
  360. Upon exiting this routine, testing the variable F will establish
  361. whether a duplicate filename was located.  With variable I pointing
  362. at the matched element in the index, it is possible to either extract
  363. the record number from the filename or mark the filename for deletion
  364. from the index.  If the intent is to insert a new filename into the
  365. index, variable I (assuming that a match did not occur) will point to
  366. the location to which the new filename must be inserted to retain
  367. alphabetic order in the index.
  368.  
  369. VI.  INSERTING A FILENAME INTO THE INDEX
  370.  
  371. Once a new record has been written out to the RELative file the new
  372. filename must be inserted into the index and the variable N must be
  373. incremented by one to reflect the change.  Naturally, it is desirable
  374. to keep the index in alphabetic order so that searches and displays
  375. are also in alphabetic order.  Fortunately, the subroutine at line
  376. 8570 shown above takes care of some of the work required to
  377. accomplish alphabetic insertion of the new filename.  Upon exit from
  378. that subroutine (assuming the new filename didn't pattern-match an
  379. existing one) variable I was left pointing to the location in the
  380. index where the new filename has to be inserted. Thus to insert the
  381. new filename we need to move all of the active filenames starting at
  382. the spot pointed by variable I up one position in the index and then
  383. insert the new filename into the resulting gap.  Then with all of
  384. that accomplished the value of N is increased by one, and a flag is
  385. set to indicate to the program that the index has been modified and
  386. must be saved to the disk.
  387.  
  388. Here is a routine to accomplish these functions.  It is assumed that
  389. the new filename has already had the record number appended to it:
  390.  
  391.     500 FOR J = N TO I+1 STEP-1
  392.     510 NF$(J)=NF$(J-1)
  393.     520 NEXT:NF$(I)=NF$:N=N+1:FF=1
  394.  
  395. This routine starts at the top of the active index using variable J
  396. as a counter and successively shifts filenames up one position in the
  397. index until the filename at NF$(I) has been shifted.  At that point
  398. the new filename is used to replace the filename in NF$(I).
  399.  
  400. Let's suppose that N=20 and I=10 (from the subroutine at 8570).  In
  401. the first pass through, line 510 variable J would equal 20 and thus
  402. the filename in NF$(19) would be moved to NF$(20), which is the same
  403. as moving NF$(19) to NF$(N).  Then variable J is decreased by one due
  404. to the STEP-1 portion of the FOR-NEXT loop.  Since J-1 equals 19 in
  405. the first pass, the loop is executed once again.  Now we move NF$(18)
  406. to NF$(19).  Each iteration lowers J by one until it equals I, at
  407. which point the loop is terminated.
  408.  
  409. All filenames from I to N-1 have been shifted up in the index, and we
  410. can now insert the new filename into the slot formerly held by
  411. NF$(10), which is now in NF$(11).  Variable N is increased by one,
  412. and "file flag" FF is set to one, indicating that the index must be
  413. saved back to the disk because of a change.  The index has been
  414. "alphabetized" although no actual sort was performed.
  415.  
  416. VII.  SAVING AND LOADING THE FILENAME INDEX ON DISK
  417.  
  418. Once filename index manipulations have been completed, the index must
  419. be saved back to the disk.  Also, variable N must be likewise saved
  420. for future reference.  The following subroutine will save the index
  421. and will also report any disk errors that may have occurred:
  422.  
  423.     1500 OPEN1,8,15:OPEN2,8,2,"0:INDEX.TEMP,S,W"
  424.     1510 INPUT#1,X,X$:IF X > 19 THEN 1540
  425.     1520 X=0:PRINT#2,MID$(STR(N),2)
  426.     1530 FOR I = 0 TO R:PRINT#2,NF$(I):NEXT
  427.     1540 CLOSE2:IF X THEN 1580
  428.     1550 PRINT#1,"S0:INDEX":INPUT#1,X,X$
  429.     1560 IF X > 19 THEN 1580
  430.     1570 PRINT#1,"R0:INDEX=INDEX.TEMP":FF=0:INPUT#1,X,X$
  431.     1580 CLOSE1:RETURN
  432.  
  433. Lines 1500 and 1510 OPEN the required files and check for errors.
  434. Variable X will contain the DOS error number while X$ will contain
  435. the plain English error message.  If X is at least equal to 20 some
  436. type of DOS error has occurred and the routine aborts.  Otherwise the
  437. string equivalent of variable N is saved in the file along with the
  438. 500 filenames.  All of this data goes into temporary file INDEX.TEMP.
  439. Only after the save has been completed is the old index SCRATCHed
  440. from the disk.  Then INDEX.TEMP is RENAMEd to INDEX.  The purpose of
  441. this is to avoid the loss of the existing index in the event that
  442. power or hardware failure aborts the save of the new index.  This is
  443. similar to the SAVE with replace (@0:) DOS function but avoids the
  444. bug that the DOS equivalent contains.  Upon completion of the RENAME
  445. of the INDEX.TEMP file, the "file flag" FF is reset to zero.
  446.  
  447. If a DOS error occurs during the save of the index, the routine will
  448. abort and report the error in X$.
  449.  
  450.     NOTE:  In BASIC 3.5, 4.0 or 7.0 the DOS variables DS and DS$
  451.     perform the functions of reading the error channel and may be
  452.     used in place of X and X$.  The INPUT#1 routines can be likewise
  453.     removed and the SCRATCH and RENAME functions used in place of
  454.     lines 1560 and 1580 respectively.
  455.  
  456. To load the index into memory the following routine may be used:
  457.  
  458.     1600 DIM NF$(R):OPEN1,8,15:OPEN2,8,2,"0:INDEX"
  459.     1610 INPUT#1,X,X$:IF X > 19 THEN 1640
  460.     1620 INPUT#2,N$:N=VAL(N$):FOR I = 0 TO R
  461.     1630 INPUT#2,NF$(I):NEXT
  462.     1640 CLOSE2:CLOSE1:RETURN
  463.  
  464. Upon exit from this routine variables X and X$ will report any disk
  465. errors as above.  The error you would want to watch for is error 62
  466. (file not found) which would indicate that the file disk has no
  467. mailing list on it. You could then create the new RELative file and
  468. filename index as we have discussed.
  469.  
  470. VIII.  DELETING RECORDS FROM THE MAILING LIST
  471.  
  472. From time to time it may be necessary to remove a record from the
  473. mailing list.  This may be accomplished by simply removing the
  474. corresponding filename from the index and placing the corresponding
  475. record number back into the "pool" of available records.  To do this
  476. requires that you first locate the desired filename to be removed,
  477. noting its position in the index.  Then you would extract the record
  478. number from it, shift the rest of the index down one position to
  479. close the gap where the filename used to be located and then assign
  480. the record number to an unused filename in the index.  You would
  481. follow this by reducing the filename count (variable N) by one and
  482. setting the file flag FF for writing the revised index back to the
  483. disk.  Fortunately, some of the subroutines that we have already
  484. developed for other functions can be used for deleting filenames.
  485.  
  486. To delete a filename you need to know what that name is:
  487.  
  488.     1700 INPUT"FILENAME";NF$:IF NF$=""THEN 1700:REM NO NULLS
  489.  
  490. Following the input of the filename you should call the subroutine at
  491. 8570 (see above) and test the flag variable F.  If F is zero then
  492. nothing matching the input filename was located, and the user should
  493. be advised with a suitable error response from your program.
  494.  
  495. It is important to consider that if flag F is set to one upon exit
  496. from the subroutine at 8570, it means that the input filename
  497. patter-matched with an index filename.  Therefore the index filename,
  498. which will be the one that will be deleted, should be displayed to
  499. the user for confirmation before it is actually removed.  For
  500. example, the user may wish to delete Steven Smith's record.  In
  501. response to the input prompt the user types SMITH. However, let's
  502. suppose that in the index the filenames SMITHD, SMITHF, SMITHR,
  503. SMITHS (the filename that the user wishes to delete) and SMITHT all
  504. exist.
  505.  
  506. Because the index is scanned from bottom to top by the subroutine at
  507. 8570, and because the SMITH input filename will pattern-match with
  508. anything starting with SMITH, the program will flag SMITHD as the one
  509. to delete. Hence the need for confirmation.
  510.  
  511. Once the user has confirmed that the displayed filename is to be
  512. deleted you must extract the record number from the filename so that
  513. the record number can be returned to the index for reuse.  This of
  514. course may be performed by calling the subroutine at 8550 (see
  515. above).  Upon exit from this subroutine variable J will contain the
  516. record number of the filename to be deleted.
  517.  
  518. With these operations completed the next step would be to shift all
  519. index filenames down one position starting with the filename
  520. immediately above the one to be deleted.  Then, after the shift had
  521. been completed, the record number stored in variable J would be
  522. inserted at the top of the active index and the value of variable N
  523. would be reduced by one.  Here is a routine that would accomplish
  524. this
  525.  
  526. 1800 IF N=1 OR I=N-1 THEN 1820
  527. 1810 FOR F = I+1 TO N-1:NF$(F-1)=NF$(F):NEXT
  528. 1820 NF$(N-1)=MID$(STR$(J),2):N=N-1:FF=1
  529.  
  530. Line 1800 bypasses the shift routine in line 1810 if N equals 1 or if
  531. I equals N-1 because in those two cases a shift isn't required.  If N
  532. equals one this implies that the last filename remaining in the index
  533. is to be deleted, which of course obviates the need for a shift.  If
  534. variable I is the same as N-1 this implies that the filename being
  535. deleted is the last one in the active portion of the index and also
  536. obviates the need for a shift.  If neither one of these conditions
  537. exist then the index will be shifted down one position until the end
  538. of the active index (N-1) is reached.
  539.  
  540. Finally the value of N is reduced as there is one less filename in
  541. the index and the file flag FF is set to one indicating that the
  542. index must be written back to the disk.  With the filename deleted
  543. from the index there is no way to retrieve the corresponding record
  544. from the RELative file. Although the RELative file itself was not
  545. disturbed, as far as the mailing list is concerned, the record no
  546. longer exists and the record is now available for use by some other
  547. entry.
  548.  
  549. IX.  STRING MANIPULATION AND GARBAGE COLLECTION ON THE C-64
  550.  
  551. The foregoing routines all involve considerable string manipulation
  552. in order to structure and control the filename index.  In BASIC 2.0,
  553. as implemented on the C-64, this may result in garbage collection and
  554. program delays.  There is really no simple method of avoiding garbage
  555. collection from BASIC due to the manner in which BASIC stores strings
  556. in memory.
  557.  
  558. A good compiler can be of assistance in this case.  Not only will the
  559. compiler perform much more efficient garbage collection, it will also
  560. make the search and index shift routines execute much faster,
  561. resulting in a substantial improvement to the overall program speed.
  562. The main disadvantage of using a compiler is that the compiled
  563. program usually is quite large compared to the BASIC source program.
  564. This will reduce the available memory for variable storage and may
  565. cause the program to crash with an OUT OF MEMORY error.
  566.  
  567. The time required to locate a filename in the index and the time
  568. required to shift the index when inserting or removing filenames
  569. depends on the number of elements in the index and the relative
  570. position of the affect index entry in the entire array.  If the index
  571. is nearly full (500 entries) eight to ten seconds may be required to
  572. locate the desired index filename. A compiled version of the program
  573. can improve that by a factor of ten or more.  The same holds true for
  574. index shifting.  Therefore in the interest of speed, compiling is
  575. recommended.
  576.  
  577. X.  WRAP-UP
  578.  
  579. In the RELATIVE FILES MADE RELATIVELY EASY series we have seen how to
  580. create a RELative file, how to enter records into that file, how to
  581. do field searches and, with this article, how to construct and
  582. maintain a filename index of the records.  Although we used a mailing
  583. list as an example of how to perform these functions, the principles
  584. set forth in these articles may be applied to virtually any kind of
  585. database system that requires a RELative file and index approach.
  586. Whether the "filenames" are actually names, part numbers of a stock
  587. room inventory or a list of files on a disk, the essential elements
  588. of a successful program remain the same.
  589.  
  590. I hope that this series of articles has been beneficial and
  591. instructive.
  592.  
  593. If you have questions on anything that has not been covered in one of
  594. these articles, please direct it to me via the DELPHI FLAGSHIP FORUM.
  595.  
  596. W.J. Brier
  597. 7-86
  598.