home *** CD-ROM | disk | FTP | other *** search
/ C!T ROM 5 / ctrom5b.zip / ctrom5b / PROGRAM / ASM / ALIB30B / DBASE.ASM < prev    next >
Assembly Source File  |  1994-12-03  |  34KB  |  1,240 lines

  1.     page    66,132
  2. ;****************************** DBASE.ASM **********************************
  3. ;upper case routine names are available.
  4. ; DBASE_INIT     -setup                     DBASE_REPLACE   -replace record
  5. ; DBASE_READ -read record                   DBASE_REMOVE-delete record
  6. ; DBASE_READ_NEXT-read next record          DBASE_CLOSE - close & write
  7. ; DBASE_READ_PREV-read previous rec.        DBASE_KILL - delete database
  8. ; DBASE_RENAME    -change dbase name
  9. ; DBASE_APPEND   -write rec at end 
  10. ; DBASE_INSERT   -write rec at loc.                                         
  11. ;----------------------------------------------------------------------------
  12.  
  13. LIBSEG           segment byte public "LIB"
  14.         assume cs:LIBSEG , ds:nothing
  15. ;----------------------------------------------------------------------------
  16. .xlist
  17.     include  mac.inc
  18.     include  common.inc
  19. .list
  20. ;----------------------------------------------------------------------------
  21.     extrn    lib_info:byte
  22.     extrn    dos_mem_allocate:far
  23.     extrn    dos_mem_release:far
  24.     extrn    strlen1:far
  25. ;----------------------------------------------------------------------------
  26. ;------------------------------ data section --------------------------------
  27. ;----------------------------------------------------------------------------
  28. buf_size    equ    16384
  29. index_size    equ    512
  30. ;-----------
  31. work_area    struc
  32. buf        db     buf_size dup (?)
  33. buf_end        dw       ?
  34. index        db    index_size    dup (?)
  35. index_end    dw    ?
  36.  
  37. temp_buf    db     buf_size dup (?)            ;used by DBASE_CLOSE
  38. temp_buf_end    dw       ?                ;  and $born_again
  39. temp_index    db    index_size    dup (?)
  40. temp_index_end    dw    ?
  41.  
  42. f_key           dw      ?       ;set to 'JO' to allow verification of selector
  43. f_handle    dw    ?    ;file handle
  44. f_asciiz    db    40 dup (?)
  45. f_flags        db    ?    ;see below
  46.   created    equ    01h    ;file was created or zero length initially.
  47.   at_top    equ    02h    ;file is at start, top of file in buffers.
  48.   at_eof    equ    04h    ;file is at eof, end of file in buffers.
  49.   fdirty    equ    08h    ;current block in memory has been modified
  50.  
  51. f_rec_bak    dw    ?    ;rec# for next block towards front of file
  52. f_seek_bak    dd    ?    ;seek for next block towards front of file
  53.  
  54. f_rec        dw    ?    ;rec# for top of current block in mem
  55. f_seek        dd    ?    ;seek for top of current block in memory
  56.  
  57. f_rec_fwd    dw    ?    ;rec# for next block towards end of file
  58. f_seek_fwd    dd    ?    ;seek for next block towards end of file
  59.  
  60. buf_avail_ptr    dw    ?    ;offset of next avail. buf entry
  61. index_avail_ptr dw    ?    ;offset of index next avail. free space
  62.  
  63. active_index    dw    ?    ;index ptr for last rec# read/written
  64. active_block_size dw    ?    ;size of block in memory
  65. record_count    dw    ?    ;number of records read from disk
  66.  
  67. work_area_end    db    ?
  68. work_area    ends
  69. ;--------------
  70. ;
  71. ; index structure
  72. ;
  73. index_struc    struc
  74. rec_no        dw    ?    ;modification rec# (-1 if record removed)
  75. file_rec_no    dw    ?    ;origional file record number (-1 if insert)
  76. buf_ptr        dw    ?    ;
  77. index_struc    ends
  78. ;---------------
  79. ; error codes -> 0 = success
  80. ;                1 = database empty
  81. ;                2 = selector bad or database buffers damaged
  82. ;                3 = insuffficient memory
  83. ;                4 = disk read/write error, possibly file at eof or top
  84. ;                5 = illegal record number
  85. ;                6 = file open error, or disk full
  86. ;                7 = record length exceeds size of buffers
  87. ;                8 = unknown code error
  88. ;
  89. comment 
  90. ;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -(DATABASE )
  91. DBASE_INIT - open and initialize an existing or new database
  92. ;
  93. ; inputs:  ds:dx = ptr to asciiz file name
  94. ;           
  95. ; output:  no carry + al = 0 (sucessfully opened an existing database)
  96. ;             carry + al = 1 (new data base created)
  97. ;             carry + al = 3 (insufficient memory to open database)
  98. ;             carry + al = 4 (disk error)
  99. ;            bx = selector needed to access database (segment)
  100. ;            cx = number of records read initially, if zero this is null file.
  101. ;            
  102. ; processing: 1. allocate memory to handle database information
  103. ;             2. open the file or create it if necessary
  104. ;             3. initialize the data area
  105. ;             4. read the first block of data
  106. ;
  107. ; Notes:  The database routines are usually called in the following
  108. ;      order:        1. DBASE_INIT
  109. ;                2. database read/write routines
  110. ;            3. dbase_close
  111. ;                      
  112. ;* * * * * * * * * * * * * *
  113. 
  114.     public    DBASE_INIT
  115. DBASE_INIT    proc    far
  116.     apush    dx,si,di,ds,es
  117.     cld
  118.     mov    bx,dx            ;save file asciiz ptr
  119. ;
  120. ;  try to allocate more memory
  121. ;
  122.     mov    dx,0
  123.     mov    ax,offset work_area_end        ;get amount of space needed
  124.     call    dos_mem_allocate
  125.     mov    al,03h                ;preload out of memory err
  126.     jc    di_error              ;jmp if out of memory
  127. ;
  128. ; A free file control block has been found and the segment is in -ax- and -es-
  129. ;    ds:dx = file asciiz name
  130. ; Setup the control block
  131. ;
  132. dinit2:        mov    cx,offset work_area_end
  133.         shr    cx,1
  134.         mov    di,offset buf
  135.         mov    ax,0
  136.         rep    stosw            ;clear the database
  137. ;
  138. ; set the individual fields in the file_control block.
  139. ;
  140.                 mov     word ptr es:[f_key],'JO' ;set check word
  141.  
  142. dinit3:        mov    ax,offset buf
  143.         mov    word ptr es:[buf_avail_ptr],ax
  144.         
  145.         mov    ax,offset index
  146.         mov    word ptr es:[index_avail_ptr],ax
  147. ;
  148. ; move the file asciiz name to file_control
  149. ;
  150.         apush    cx,si,di
  151.         mov    si,bx        ;from offset
  152.         mov    di,offset f_asciiz
  153.         mov    cx,40
  154.         rep    movsb
  155.         apop    di,si,cx
  156. ;
  157. ; attempth to open the file
  158. ;  ds:dx point to asciiz name of file
  159. ;
  160.         mov    dx,bx
  161.         mov    cx,2        ;open for write
  162.         mov    ah,3dh        ;open code
  163.         mov    al,2
  164.         int    21h
  165.         jc    open_failed
  166.         mov    word ptr es:[f_handle],ax
  167. ;
  168. ;  read first record
  169. ;
  170.         mov    al,1        ;select forward read
  171.         call    $disk_read    ;read database
  172.         jnc    di_rd_ok
  173.         cmp    al,4        ;check if eof or disk error
  174.         jne    di_error    ;jmp if bad error
  175. di_rd_ok:    mov    cx,es:record_count
  176. di_cont1:
  177.         mov    al,0
  178.         jcxz    di_e            ;jmp if file of zero length
  179.         jmp    dinit_exit
  180. ;
  181. ; the open failed, try to create the file
  182. ;
  183. open_failed:
  184.     mov    ah,3ch
  185.     mov    cx,0
  186.     int    21h        ;file create
  187.     jc    di_dsk_error
  188.     mov    word ptr es:[f_handle],ax
  189.     mov    al,1
  190. di_e:    or    es:[f_flags],created+at_top+at_eof
  191.     jmp    di_error
  192.  
  193. di_dsk_error:
  194.     mov    al,4
  195. di_error:
  196.     stc
  197. dinit_exit:
  198.     mov    bx,es        ;get database selector
  199.     apop    es,ds,di,si,dx
  200.     retf
  201. DBASE_INIT    endp
  202.  
  203. comment 
  204. ;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -(DATABASE )
  205. DBASE_READ - read specific record from the database.
  206. ;
  207. ; inputs: es = selector from DBASE_INIT
  208. ;         dx = record# to read
  209. ;
  210. ; output: no carry + al = 00 - if successful, cx=read amount
  211. ;            carry + al = 04 - record not here, could be no records are present
  212. ;            carry + al = 02 - selector bad or database corrupted.
  213. ;            carry + al = 07 - record was too big to fit in memory
  214. ;            carry + al = 08 - unknown error
  215. ;      es:si = ptr to record read (valid only if al=0)
  216. ;      cx = record length including separator character. (present if al=0)
  217. ;
  218. ;* * * * * * * * * * * * * *
  219. 
  220.     public    DBASE_READ
  221. DBASE_READ    proc    far
  222.     apush    bx,dx,di,bp,ds
  223.     call    verify1
  224.     jc    drr_exit            ;jmp if error type 1 or 2
  225.     mov    al,0                ;request search of all buffers
  226. drr_retry_entry:
  227.     call    $is_record_in_buf        ;scan buffers
  228. ;
  229. ; is_record_in_buf returns 0 - got record , cx=size
  230. ;                          1 - try reading forward
  231. ;                          2 - try reading backwards
  232.     cmp    al,0
  233.     je    drr_got_record    
  234.     test    es:[f_flags],fdirty
  235.     jz    drr_do_disk
  236.     call    $born_again            ;write out changes
  237.     jc    drr_exit
  238.     jmp    drr_retry_entry
  239. drr_do_disk:    
  240.     call    $disk_read            ;al=1 for forward  al=2 for bak
  241.     jc    drr_exit                 ;jmp if file at eof or top
  242.     jmp    drr_retry_entry            ;go see if we have read rec
  243. ;
  244. ; es:[bx] points at index structure for the requested record.
  245. ; set es:si pointing to rec data  or cx to length
  246. ;
  247. drr_got_record:
  248.     mov    es:[active_index],bx
  249.     mov    si,es:[bx.buf_ptr]    ;get ptr to record
  250.     call    $compute_record_length
  251.     mov    al,0
  252.     clc
  253. drr_exit:
  254.     apop    ds,bp,di,dx,bx
  255.     retf
  256. DBASE_READ    endp
  257.  
  258. comment 
  259. ;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -(DATABASE )
  260. dbase_read_next - read next sequential record.
  261. ;
  262. ; inputs:    es = selector from DBASE_INIT
  263. ;
  264. ; output: no carry or al = 00 - success
  265. ;            carry or al = 01 - record not here, could be no records are present
  266. ;            carry or al = 02 - selector bad or database corrupted.
  267. ;      es:si = ptr to record read (valid only if al=0)
  268. ;      cx = record length including separator character. (present if al=0)
  269. ;         dx = record number
  270. ;
  271. ;* * * * * * * * * * * * * *
  272. 
  273.     public    dbase_read_next
  274. dbase_read_next proc    far
  275.     apush    bx,di,ds
  276.     call    verify1
  277.     jc    drn_exit            ;jmp if error
  278.     mov    bx,es:[active_index]        ;get last record accessed
  279. drn_01: mov    dx,es:[bx.rec_no]
  280.     cmp    dx,-1                ;check if removed record
  281.     jne    drn_03
  282. ;
  283. ; the current record has been removed.    scan forward for record
  284. ;
  285.     sub    bx,size index_struc
  286.     cmp    bx,es:[index_avail_ptr]        ;check if at end of index
  287.     jne    drn_01                ; jmp if not at end of index
  288. ;
  289. ; we have scanned to the end of the index and all records have been removed
  290. ; scan back till a vaild record# found
  291. ;
  292.     mov    bx,es:[active_index]
  293. drn_02: cmp    bx,offset index
  294.     je    drn_04                ;jmp if all records removed
  295.     cmp    es:[bx.rec_no],-1
  296.     jne    drn_03                ;jmp if valid rec# found
  297.     sub    bx,size index_struc
  298.     jmp    drn_02
  299.  
  300. drn_04: mov    dx,es:[f_rec]
  301.     jmp    drn_03
  302.  
  303. drn_03: inc    dx
  304.     call    dbase_read            ;read next record
  305. drn_exit:
  306.     apop    ds,di,bx
  307.     retf
  308. dbase_read_next    endp
  309.  
  310. comment 
  311. ;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -(DATABASE )
  312. dbase_read_prev - read previous record. (write operations do not affect)
  313. ;
  314. ; inputs:     es = selector from DBASE_INIT
  315. ;
  316. ; output: no carry or al = 00 - success
  317. ;            carry or al = 01 - record not here, could be no records are present
  318. ;            carry or al = 02 - selector bad or database corrupted.
  319. ;      es:si = ptr to record read (valid only if al=0)
  320. ;      cx = record length including separator character. (present if al=0)
  321. ;         dx = record number
  322. ;
  323. ;* * * * * * * * * * * * * *
  324. 
  325. drp_temp    dw    0
  326.  
  327.     public    dbase_read_prev
  328. dbase_read_prev proc    far
  329.     apush    bx,di,ds
  330.     call    verify1
  331.     jc    drp_ex
  332.     mov    bx,es:[active_index]
  333.     mov    dx,es:[bx.rec_no]
  334.     cmp    dx,1
  335.     jbe    drp_xx
  336.     cmp    dx,-1
  337.     jne    drp_01            ;jmp if normal record
  338. ;
  339. ; this record has been deleted.
  340. ;
  341. drp_00: mov    dx,es:[f_rec]        ;get initial rec#
  342.     cmp    bx,offset index        ;check if at top of index
  343.     je    drp_01            ; jmp if deleted rec at top
  344.     sub    bx,size index_struc
  345.     cmp    bx,offset index
  346.     je    drp_00            ;jmp if at top of index
  347.     mov    dx,es:[bx.rec_no]    ;get previous rec#
  348.     cmp    dx,-1            ;check if removed record
  349.     je    drp_00
  350.  
  351. drp_01: dec    dx
  352.     call    dbase_read
  353.     jmp    drp_ex
  354. drp_xx:    mov    al,1
  355. drp_ex:    apop    ds,di,bx
  356.     retf
  357. ;
  358. dbase_read_prev endp
  359.  
  360. ;----------------------------------------------------------------------------
  361. ;------------------------------ dbase write ---------------------------------
  362. ;----------------------------------------------------------------------------
  363. comment 
  364. ;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -(DATABASE )
  365. dbase_append - append this record to end of databse
  366. ;
  367. ; inputs:     es = selector from DBASE_INIT
  368. ;          ds:di = source data buffer
  369. ;          cx = length of record excluding the separator character
  370. ;          
  371. ; output:  no carry,  al = 0 (success)
  372. ;            carry or al = 02 - selector bad or database corrupted.
  373. ;                     dx = record # assigned
  374. ;
  375. ;* * * * * * * * * * * * * *
  376. 
  377.     public    dbase_append
  378. dbase_append    proc    far
  379.     apush    bx,cx,bp,si,di,ds,es
  380.     call    verify2
  381.     jc    da_exit                ;jmp if error type 1 or 2
  382. da_lp1:    test    es:[f_flags],at_eof
  383.     jnz    da_at_eof            ;jmp if at end of file
  384.     mov    bx,es:[index_avail_ptr]
  385. da_lp2:    sub    bx,size index_struc
  386.     mov    dx,es:[bx.file_rec_no]
  387.     inc    dx
  388.     call    dbase_read            ;read next block
  389.     jmp    da_lp1
  390. ;
  391. ; we are at the end of file
  392. ;
  393. da_at_eof:
  394.     call    $check_if_room
  395.     jnc    da_append            ;jmp if room for this record
  396.     call    $born_again            ;assume we need to save mods
  397.     jc    da_exit                ;jmp if error
  398.     jmp    da_lp1                ;go scan to eof again
  399. ;
  400. ; append record to end of current block
  401. ;
  402. da_append:
  403.     mov    bx,es:[index_avail_ptr]
  404.     call    $build_index_entry        ;bx=index ptr  ds:si=data
  405.     mov    es:[bx.file_rec_no],-1        ;flag this record as insert
  406.     mov    dx,es:[bx.rec_no]        ;get append record#
  407.     mov    es:[active_index],bx        ;set new active index
  408.     
  409.     add    bx,size index_struc
  410.     mov    es:[index_avail_ptr],bx        ;update available index loc
  411.     mov    al,0
  412.     or    es:[f_flags],fdirty
  413.     clc
  414. da_exit:
  415.     apop    es,ds,di,si,bp,cx,bx
  416.     retf
  417. dbase_append    endp
  418. comment 
  419. ;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -(DATABASE )
  420. dbase_insert - insert this record before specific record
  421. ;
  422. ; inputs:      es = selector from DBASE_INIT
  423. ;        ds:di = source data buffer
  424. ;           cx = length of record excluding the separator char if present
  425. ;              dx = record number to insert before
  426. ;
  427. ; output:  no carry,  al = 0 (success)
  428. ;            carry or al = 01 - record not here, could be no records are present
  429. ;            carry or al = 02 - selector bad or database corrupted.
  430. ;                     dx = record number assigned
  431. ;          
  432. ; Note: Inserts are placed in front of the record number input. 
  433. ;* * * * * * * * * * * * * *
  434. 
  435.     public    dbase_insert
  436. dbase_insert    proc    far
  437.     apush    bx,cx,si,di,bp,ds,es
  438.     call    verify1
  439.     jc    dii_exit
  440.     call    dbase_read            ;read the record
  441.     jc    dii_exit
  442.     call    $is_record_in_buf        ;get index ptr
  443.     call    $make_index_hole
  444.     mov    si,di                ;get buffer ptr -> ds:si
  445.     call    $build_index_entry
  446.     mov    es:[bx.file_rec_no],-1        ;flag this record as insert
  447.     call    $resequence
  448.     mov    al,0
  449.     or    es:[f_flags],fdirty
  450.     clc
  451. dii_exit:
  452.     apop    es,ds,bp,di,si,cx,bx
  453.     retf
  454.  
  455. dbase_insert    endp
  456. comment 
  457. ;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -(DATABASE )
  458. dbase_replace - replace data for a specific record
  459. ;
  460. ; inputs:     es = selector from DBASE_INIT
  461. ;          ds:di = source data buffer
  462. ;          cx = length of record excluding the separator char if present
  463. ;             dx = record number to insert before
  464. ;
  465. ; output:  no carry,  al = 0 (success)
  466. ;            carry or al = 01 - record not here, could be no records are present
  467. ;            carry or al = 02 - selector bad or database corrupted.
  468. ;
  469. ;* * * * * * * * * * * * * *
  470. 
  471. dr_rec_size    dw    0    ;size of replacement record
  472. dr_file_rec    dw    0    ;record #
  473.  
  474.     public    dbase_replace
  475. dbase_replace    proc    far
  476.     apush    bx,cx,dx,si,di,bp,ds,es
  477.     call    verify1
  478.     jc    dr_exit            ;jmp if error type 1 or 2
  479.     call    dbase_read        ;read the correct record
  480.     jc    dr_exit
  481.     call    $is_record_in_buf        ;get index ptr
  482.     mov    si,di            ;get buffer ptr -> si
  483.     call    $build_index_entry
  484.     mov    al,0
  485.     or    es:[f_flags],fdirty
  486.     clc
  487. dr_exit:
  488.     apop    es,ds,bp,di,si,dx,cx,bx
  489.     retf
  490.  
  491. dbase_replace    endp
  492. comment 
  493. ;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -(DATABASE )
  494. DBASE_REMOVE - delete specific record
  495. ;
  496. ; inputs:      es = selector from DBASE_INIT
  497. ;           dx = record number to delete
  498. ;
  499. ; output:  no carry,  al = 0 (success)
  500. ;            carry or al = 01 - record not here, could be no records are present
  501. ;             
  502. ;* * * * * * * * * * * * * *
  503. 
  504.  
  505.     public    DBASE_REMOVE
  506. DBASE_REMOVE    proc    far
  507.     apush    bx,cx,dx,si,di
  508.     call    verify1
  509.     jc    ddr_exit
  510.     call    dbase_read        ;read the correct record
  511.     jc    ddr_exit        ;jmp if record not here
  512.     call    $is_record_in_buf        ;get index ptr
  513.     mov    es:[bx.rec_no],-1    ;flag this record as removed
  514.     call    $resequence
  515.     or    es:[f_flags],fdirty
  516.     mov    al,0
  517.     clc
  518. ddr_exit:
  519.     apop    di,si,dx,cx,bx
  520.     retf
  521.  
  522. DBASE_REMOVE    endp
  523. ;----------------------------------------------------------------------------
  524. ;------------------------------ dbase close ---------------------------------
  525. ;----------------------------------------------------------------------------
  526. comment 
  527. ;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -(DATABASE )
  528. dbase_close - close & write any pending data to file
  529. ;
  530. ; inputs:      es = database selector returned by DBASE_INIT
  531. ; output:  no carry,  al = 0 (success)
  532. ;            carry or al = 02 - selector bad or database corrupted.
  533. ;* * * * * * * * * * * * * *
  534. 
  535. dcc_temp_asciiz        db    'DBASE.$$$',0
  536. dcc_temp_handle        dw    0
  537.  
  538.     public    dbase_close
  539. dbase_close    proc    far
  540.     apush    bx,cx,dx,si,di,bp,ds,es
  541.     call    verify2
  542.     jc    dcc_exit
  543.     test    es:[f_flags],fdirty
  544.     jz    dc_release            ;jmp if disk still good
  545. ;
  546. ; save a copy of the buffers which contain the changes to temp buffers
  547. ;
  548.     cld
  549.     push    es
  550.     pop    ds
  551.     mov    si,offset buf
  552.     mov    di,offset temp_buf
  553.     mov    cx,offset index_end
  554.     rep    movsb
  555. ;
  556. ; open a temp output file
  557. ;
  558.     mov    ah,3ch
  559.     mov    cx,0                 ;create for write
  560.     mov    dx,offset dcc_temp_asciiz
  561.     push    cs                ;swap ds
  562.     pop    ds                ;  and cs
  563.     int    21h
  564.     jc    dcc_err2
  565.     mov    dcc_temp_handle,ax
  566. ;
  567. ; move to start of database file
  568. ;
  569. dc_lp1:    test    es:[f_flags],at_top
  570.     jnz    dc_merge        ;jmp if file at top
  571.     mov    al,2
  572.     call    $disk_read
  573.     jnc    dc_lp1            ;loop till top of file reached.
  574.     cmp    al,4            ;check if eof or disk error
  575.     jne    dcc_err            ;jmp if not possible eof
  576. ;
  577. ; merge database file and temp buffers -> temp file
  578. ;
  579. dc_merge:
  580.     call    $merge_and_write
  581. ;
  582. ; delete the database file, and rename the temp file to database file
  583. ;
  584.     mov    ah,3eh
  585.     mov    bx,dcc_temp_handle
  586.     int    21h
  587.     jc    dcc_err2
  588.  
  589.     mov    ah,3eh
  590.     mov    bx,es:[f_handle]
  591.     int    21h
  592.     jc    dcc_err2
  593. ;
  594. ; delete the origional dbase file
  595. ;
  596.     mov    ah,41h
  597.     push    es
  598.     pop    ds
  599.     mov    dx,offset f_asciiz
  600.     int    21h
  601.     jc    dcc_err2
  602. ;
  603. ; rename the temp file to origional dbase name
  604. ;
  605.     push    cs
  606.     pop    ds
  607.     mov    ah,56h            ;rename
  608.     mov    dx,offset dcc_temp_asciiz ;existing name
  609.     mov    di,offset f_asciiz
  610.     int    21h
  611.     jc    dcc_err2
  612. ;
  613. ;  release memory
  614. ;
  615. dc_release:
  616.     call    dos_mem_release
  617.     mov    al,0            ;preload success code
  618.     jnc    dcc_exit
  619.     mov    al,8            ;unknown error
  620.     jmp    dcc_err
  621.  
  622. dcc_err2:
  623.     mov    al,4            ;disk error    
  624. dcc_err:stc    
  625. dcc_exit:
  626.     apop    es,ds,bp,di,si,dx,cx,bx
  627.     retf
  628.  
  629. dbase_close    endp
  630. comment 
  631. ;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -(DATABASE )
  632. DBASE_KILL - delete dbase file
  633. ;
  634. ; inputs:       ds:dx = asciiz file name ptr
  635. ; output:    carry set if error, error code from DOS function 41h
  636. ;* * * * * * * * * * * * * *
  637. 
  638.     public    DBASE_KILL
  639. DBASE_KILL    proc    far
  640.     mov    ah,41h
  641.     int    21h
  642.     retf
  643. DBASE_KILL    endp
  644. ;-----------------------------------------------------------------------------
  645. ;------------------------------ local subroutines ----------------------------
  646. ;-----------------------------------------------------------------------------
  647. ; $disk_read - read block of data from the disk and create the index
  648. ;   inputs:  al = 1 - read next forward block
  649. ;                 2 - read back towards front of file
  650. ;   output:  no carry = success
  651. ;               carry & AL = 07 (record found exceeding buffer size)
  652. ;               carry & AL = 04 (disk read/write error or file at eof/top)
  653. ;               carry & AL = 08 (parameter error or unknown error)
  654. ;
  655. ;   processing: 1. update database of seek & record# depending upon direction
  656. ;               2. check if operation possible
  657. ;               3. read block, compute next block seek from seek_adjust,
  658. ;                  active_block_size
  659. ;               4. build index if valid read, check record_count
  660. ;               5. set f_flags to correct state
  661. ;
  662. dr_input    db    0
  663.                
  664. $disk_read:
  665.     apush    ax,bx,cx,dx,si,di,ds
  666.     mov    cs:dr_input,al
  667.     cmp    al,1
  668.     je    dr_forward
  669.     cmp    al,2
  670.     je    dr_back
  671.     mov    al,8
  672.     jmp    dr_err
  673.  
  674. dr_forward:
  675.     test    es:[f_flags],at_eof
  676.     jnz    dr_eof                ;jmp if at eof already
  677.     and    es:[f_flags],not at_top        ;clear at_top flag
  678.  
  679.     mov    dx,word ptr es:f_seek_fwd    ;setup seek low word
  680.     mov    cx,word ptr es:f_seek_fwd+2    ;setup seek high word
  681.     mov    ax,word ptr es:[f_rec_fwd]    ;get record#
  682.     jmp    do_seek
  683.     
  684. dr_back:
  685.     test    es:[f_flags],at_top
  686.     jnz    dr_err1             ;jmp if at top already
  687.     and    es:[f_flags],not at_eof        ;clear eof flag
  688.     
  689.     mov    dx,word ptr es:f_seek_bak    ;setup seek low word
  690.     mov    cx,word ptr es:f_seek_bak+2    ;setup seek high word
  691.     mov    ax,es:[f_rec_bak]        ;get record#
  692.  
  693. do_seek:
  694.     mov    word ptr es:[f_seek],dx
  695.     mov    word ptr es:[f_seek+2],cx
  696.     cmp    ax,0            ;check if record #1
  697.     jne    do_seek2        ;jmp if valid rec#
  698.     mov    ax,1
  699. do_seek2:
  700.     mov    es:[f_rec],ax        ;save record#        
  701.     mov    ah,42h            ;DOS seek code
  702.     mov    al,00h            ;seek relative to file start
  703.     mov    bx,es:[f_handle]     ;file handle
  704.     int    21h            ;
  705.     jc    dr_err1            ;jmp if seek error
  706. ;
  707. ; the file pointer has been positioned, now read block
  708. ;
  709.     mov    ah,3fh            ;DOS read code
  710.     mov    cx,buf_size/2        ;get size of read
  711.     mov    dx,offset buf        ;get buffer offset
  712.     push    ds            ;save ds
  713.     push    es            ;set ds to
  714.     pop    ds            ;  buffer segment
  715.     int    21h            ;returns ax=number of bytes read
  716.     pop    ds
  717.     jc    dr_err1            ;jmp if read error
  718.     cmp    ax,0
  719.     je    dr_eof            ;jmp if nothing read (EOF)
  720.     cmp    ax,buf_size/2
  721.     je    dr_build_index
  722.     or    es:[f_flags],at_eof    ;set eof flag
  723. ;
  724. ; the data has been read into the buffer, now build index, ax=amount read
  725. ;
  726. dr_build_index:
  727.     mov    dx,es:[f_rec]        ;get starting index#
  728.     call    $build_index
  729.     jc    dr_err            ;jmp if record exceeds buffer size
  730. ;;    cmp    es:[active_block_size],0
  731. ;;    je    dr_eof2            ;jmp if no data read
  732.     cmp    es:[record_count],0
  733.     jne    dr_compute_seeks
  734.     or    es:[f_flags],at_eof
  735. dr_compute_seeks:
  736.     cmp    es:[index.rec_no],1    ;check if at top
  737.     je    compute_fwd        ;jmp if next must be forward read
  738.     cmp    cs:dr_input,1
  739.     jne    compute_bak
  740. ;
  741. ; compute setting for f_rec_fwd, f_seek_fwd
  742. ;    
  743. compute_fwd:
  744.     mov    ax,es:[f_rec]
  745.     add    ax,es:[record_count]
  746.     mov    es:[f_rec_fwd],ax
  747.  
  748.     mov    ax,word ptr es:[f_seek]
  749.     mov    bx,word ptr es:[f_seek+2]
  750.     add    ax,es:active_block_size
  751.     adc    bx,0
  752.     mov    word ptr es:[f_seek_fwd],ax
  753.     mov    word ptr es:[f_seek_fwd+2],bx
  754.  
  755.     mov    word ptr es:[f_seek_bak],0
  756.     mov    word ptr es:[f_seek_bak+2],0
  757.     mov    es:[f_rec_bak],1
  758.     
  759.     clc
  760.     jmp    dr_quit
  761. ;
  762. ; compute setting for f_rec_bak, f_seek_bak
  763. ;
  764. compute_bak:
  765.     mov    es:f_rec_bak,1
  766.     mov    word ptr es:[f_seek_bak],0
  767.     mov    word ptr es:[f_seek_bak+2],0
  768.  
  769.     mov    es:f_rec_fwd,1
  770.     mov    word ptr es:[f_seek_fwd],0
  771.     mov    word ptr es:[f_seek_fwd+2],0
  772.     
  773.     clc
  774.     jmp    dr_quit
  775.     
  776. dr_eof: cmp    es:[index.rec_no],1
  777.     ja    dr_eof2                ;jmp if not at top
  778.     or    es:[f_flags],at_top
  779. dr_eof2:or    es:[f_flags],at_eof
  780.  
  781. dr_err1:mov    al,4                ;disk read/write error
  782. dr_err:    stc                    ;error code in AL here
  783.     jmp    dr_quit2
  784. dr_quit:
  785.     cmp    es:[index.rec_no],1
  786.     ja    dr_quit2
  787.     or    es:[f_flags],at_top
  788. dr_quit2:    
  789.     apop    ds,di,si,dx,cx,bx,ax
  790.     ret
  791. ;-----------------------------------------------------------------------------
  792. ; $is_record_in_buf - check if record in memory
  793. ;   inputs:  dx = record number
  794. ;   output:  al =          0 - got record
  795. ;                              bx=record index ptr
  796. ;                              cx=size
  797. ;                          1 - try reading forward
  798. ;                          2 - try reading backwards
  799. ;
  800. $is_record_in_buf:
  801.     apush    dx,si
  802.     cmp    dx,es:[f_rec]
  803.     jb    irib_back
  804.     mov    bx,es:[index_avail_ptr]
  805. irib_x: sub    bx,size index_struc
  806.     cmp    es:[bx.rec_no],-1        ;check if deleted record
  807.     je    irib_x
  808.     cmp    dx,es:[bx.rec_no]
  809.     ja    irib_forward
  810. ;
  811. ; record # falls somewhere in the block in memory.  scan for location
  812. ;    
  813.     mov    bx,offset index - size index_struc
  814. irib_lp:add    bx,size index_struc
  815.     cmp    dx,es:[bx.rec_no]
  816.     jne    irib_lp            ;loop till record found
  817.  
  818.     mov    si,es:[bx.buf_ptr]
  819.     call    $compute_record_length
  820.     mov    al,0
  821.     jmp    irib_exit
  822. irib_forward:
  823.     mov    al,1
  824.     jmp    irib_exit    
  825. irib_back:
  826.     mov    al,2
  827. irib_exit:
  828.     apop    si,dx
  829.     ret
  830. ;-----------------------------------------------------------------------------
  831. ;$build_index - build index for data in buf
  832. ; inputs: ax = amount of data in buffer
  833. ;         dx = starting record/sequience number
  834. ;
  835. ; output: no carry - index built ok
  836. ;            carry - al = 7 record too big
  837.  
  838. $build_index:
  839.     apush    ax,bx,cx,dx,si,di
  840. ;
  841. ; the data has been read into the buffer, now build index,
  842. ;
  843. bi_build_index:
  844.     mov    es:record_count,-1
  845.     mov    di,offset buf                   ;get buffer offset
  846.     mov    si,offset index                  ;get index top
  847.     mov    cx,ax                    ;get buffer length
  848. ;
  849. ; This file uses variable length records, registers are set as follows:
  850. ;  es:di = buffer ptr    es:si = index ptr  cx=buf len  dx=starting rec#
  851. ;
  852.     mov    al,0                     ;get record separator
  853.     sub    si,size index_struc        ;loop modification
  854.     dec    dx                ;loop modification for rec#
  855. bi_var_lp:
  856.     inc    es:record_count
  857.     add    si,size index_struc        ;move to next index
  858.     inc    dx                ;move to next rec#
  859.     cmp    si,index_end
  860.     jae    bi_var_zero_end            ;jmp if end of index buffer
  861.     mov    es:[si.file_rec_no],dx        ;store rec#
  862.     mov    es:[si.rec_no],dx
  863.     mov    es:[si.buf_ptr],di        ;store buffer ptr
  864.     jcxz    bi_var_zero_end            ;jmp if at end of disk data
  865.     repne    scasb                ;scan for next record separator
  866.     je    bi_var_lp            ;jmp if separator found
  867. ;
  868. ; the end of the buffer was reached
  869. ;
  870. bi_var_zero_end:
  871.     cmp    es:[record_count],0
  872.     je    bi_err                ;jmp if record too big
  873.     mov    es:[si.file_rec_no],0        ;mark index end
  874.     mov    es:[si.rec_no],0
  875.     mov    es:[index_avail_ptr],si
  876.  
  877.     mov    di,es:[si.buf_ptr]
  878.     mov    es:[buf_avail_ptr],di        ;set ptr past last valid rec
  879.     mov    es:[active_block_size],di    ;save size of this block
  880.     mov    es:[si.buf_ptr],0        ;zero residual buf_ptr
  881.     clc
  882.     jmp    bi_exit
  883.  
  884. bi_err:    mov    al,7                ;set record too big error
  885.     stc
  886.     jmp    bi_exit
  887.     
  888. bi_eof:    clc
  889.     or    es:[f_flags],at_eof    ;set eof flag
  890. bi_exit:
  891.     apop    di,si,dx,cx,bx,ax
  892.     ret
  893.  
  894. ;------------------------------------------------------------------------
  895. ; $build_index_entry - create index entry
  896. ;  inputs:  bx = pointer to index destination
  897. ;          ds:si = data ptr
  898. ;  output:  none
  899. ;  processing:  1. construct the index entry
  900. ;               2. move the data to database buffer
  901. ;
  902. $build_index_entry:
  903.     apush    ax,cx,si,di,ds
  904.     cmp    bx,offset index
  905.     jne    bie_cont2        ;jmp if not first index
  906.     test    es:[f_flags],at_top
  907.     jz    bie_cont1        ;jmp if not index #1
  908.     mov    ax,1
  909.     jmp    bie_cont3
  910. bie_cont1:
  911.     mov    ax,es:f_rec
  912.     jmp    bie_cont3
  913. bie_cont2:            
  914.     mov    ax,es:[bx.rec_no-size index_struc]    ;get previous rec #
  915.     inc    ax
  916. bie_cont3:
  917.     mov    es:[bx.rec_no],ax            ;store rec#
  918.     
  919.     mov    di,es:buf_avail_ptr
  920.     mov    es:[bx.buf_ptr],di            ;store buf ptr
  921.  
  922.     call    strlen1
  923.     cld
  924.     rep    movsb                    ;move data to buffer
  925.     movsb                        ;move zero at end
  926.     mov    es:[buf_avail_ptr],di
  927.     apop    ds,di,si,cx,ax
  928.     ret
  929. ;------------------------------------------------------------------------
  930. ;$make_index_hole - create space for new entry in mod indx
  931. ; inputs: es:bx points at mod index index to make hole in front of
  932. ;
  933. $make_index_hole:
  934.     apush    cx,si,di,ds
  935.     mov    di,offset index_end-1
  936.     mov    si,di
  937.     sub    si,size index_struc
  938.     mov    cx,si
  939.     sub    cx,bx
  940.     inc    cx
  941.     jcxz    maih_1        ;jmp if at end
  942.     std
  943.     push    es
  944.     pop    ds
  945.     rep    movsb
  946.     cld
  947. maih_1:
  948.     add    es:[index_avail_ptr],size index_struc
  949.     apop    ds,di,si,cx
  950.     ret
  951.     
  952. ;----------------------------------------------------------------------------
  953. ;$compute_record_length - compute size of modification record
  954. ; inputs:    es:si = pointer to modification record
  955. ; output:    cx = record size including separator character if present
  956. ;
  957. $compute_record_length:
  958.     push    ax
  959.     push    di
  960.     mov    al,0             
  961.     mov    di,si
  962.     mov    cx,-1
  963.     repne    scasb
  964.     not    cx
  965.     pop    di
  966. cars_exit:
  967.     pop    ax
  968.     ret
  969.  
  970. ;----------------------------------------------------------------------------
  971. ; $check_if_room - check if room for another operation
  972. ;   inputs:  cx = size of this record
  973. ;   output:  carry = no room
  974. ;
  975. $check_if_room:
  976.     mov    ax,es:[buf_avail_ptr]
  977.     add    ax,cx
  978.     cmp    ax,offset buf_end
  979.     ja    cir_nope
  980.     mov    ax,es:[index_avail_ptr]
  981.     cmp    ax,offset index_end -4
  982.     ja    cir_nope
  983.     clc
  984.     jmp    cir_exit
  985. cir_nope:
  986.     stc
  987. cir_exit:
  988.     ret
  989. ;----------------------------------------------------------------------------
  990. ; $born_again - close the database and reopen with a fresh copy
  991. ;   inputs:  dx = active record
  992. ;   outputs: no carry = success
  993. ;        carry = error, AL set to 1 (no records present)
  994. ;            registers  ax,bx,cx,si,di modified
  995. ;
  996. xasciiz        db    40 dup (0)
  997. target_record    dw    0        ;record location to restore
  998.  
  999. $born_again:
  1000.     mov    cs:target_record,dx
  1001.     push    es
  1002.     call    dbase_close
  1003.     jc    ba_exit
  1004.     pop    es
  1005. ;
  1006. ; move a copy of the database file name locally
  1007. ;
  1008.     push    es
  1009.     pop    ds
  1010.     mov    si,offset f_asciiz
  1011.     push    cs
  1012.     pop    es
  1013.     mov    di,offset xasciiz
  1014.     mov    cx,40
  1015.     rep    movsb
  1016. ;
  1017. ; setup parameters for dbase_init
  1018. ;
  1019.     mov    dx,offset xasciiz
  1020.     push    cs
  1021.     pop    ds
  1022.     call    dbase_init
  1023.     jc    ba_exit            ;jmp if error
  1024.     mov    es,bx            ;setup the selector
  1025.  
  1026. ba_loop:mov    dx,cs:target_record
  1027.     call    $is_record_in_buf
  1028.     cmp    al,0
  1029.     je    ba_got_it
  1030.     call    $disk_read        ;go and look in next block
  1031.     jnc    ba_loop
  1032.     cmp    dx,1            ;check if null database
  1033.     je    ba_got_it
  1034. ;
  1035. ; we could not find this record
  1036. ;
  1037.     cmp    es:[record_count],0    ;check if null database
  1038.     je    ba_null
  1039. ;
  1040. ; the last record of a database was deleted, so use the previous record.
  1041. ;
  1042.     mov    bx,es:[index_avail_ptr]
  1043.     sub    bx,size index_struc
  1044.     jmp    ba_got_it
  1045.  
  1046. ba_null:
  1047.     mov    al,8
  1048.     stc
  1049.     jmp    ba_exit
  1050.         
  1051. ba_got_it:
  1052.     mov    es:[active_index],bx    
  1053.     clc
  1054. ba_exit:    
  1055.     ret
  1056. ;-----------------------------------------------------------------------------
  1057. ; $resequence - resequence the sequence numbers from current record
  1058. ;   inputs:  bx = current index ptr
  1059. ;            dx = sequence # for this record
  1060. ;   output: none
  1061. ;
  1062. $resequence:
  1063.     apush    bx,dx
  1064. res_lp:    cmp    es:[bx.rec_no],0
  1065.     je    res_done        ;jmp if end of index found
  1066.     cmp    es:[bx.rec_no],-1
  1067.     je    res_c            ;jmp if removed (deleted) record
  1068.     mov    es:[bx.rec_no],dx
  1069.     inc    dx
  1070. res_c:    add    bx,size index_struc
  1071.     jmp    res_lp
  1072. res_done:
  1073.     apop    dx,bx
  1074.     ret
  1075. ;-----------------------------------------------------------------------------
  1076. ; $merge_and_write - merge file data with modifications in memory
  1077. ;   inputs:  - file is at top
  1078. ;            - index built
  1079. ;            - temp_buf & temp_index have modificaton data
  1080. ;            - output file open & handle at dcc_temp_handle
  1081. ;
  1082. ;  output:  no carry = success
  1083. ;              carry = error
  1084. ;
  1085. ; processing:  1. write from file until disk rec# reaches first temp file rec#
  1086. ;              2. write temp data until exhausted
  1087. ;              3. read input file until it reaches last temp file rec#
  1088. ;              4. write remaining file data
  1089.  
  1090. $merge_and_write:
  1091.     mov    bx,offset temp_index
  1092.     test    es:[f_flags],created
  1093.     jnz    maw_write_temp        ;jmp if file is empty
  1094. ;
  1095. ; find first temp file rec#
  1096. ;
  1097. maw_lp1:cmp    es:[bx.file_rec_no],1    ;check if temp file at start
  1098.     je    maw_write_temp
  1099. ;
  1100. ; the modification data is not first block of file, copy file data until
  1101. ; modification block area reached.
  1102. ;
  1103. maw_copy_file:
  1104.     mov    bx,offset temp_index-size index_struc ;get first mod block rec#
  1105. maw_lpx:add    bx,size index_struc
  1106.     mov    ax,es:[bx.file_rec_no]
  1107.     cmp    ax,-1
  1108.     je    maw_lpx
  1109.     
  1110. maw_lp2:mov    bx,offset index
  1111. maw_lp3:call    write_file_record
  1112.     jc    maw_done            ;jmp if error
  1113.     add    bx,size index_struc
  1114.     cmp    ax,es:[bx.file_rec_no]
  1115.     je    maw_write_temp        ;jmp if start of modification data fnd
  1116.     cmp    es:[bx.rec_no],0    ;check if end of file block
  1117.     jne    maw_lp3            ;jmp if more data to copy
  1118.     push    ax
  1119.     mov    al,1
  1120.     call    $disk_read
  1121.     pop    ax
  1122.     jc    maw_write_temp        ;jmp if eof
  1123.     mov    bx,offset index        ;restart the index
  1124.     cmp    ax,es:[bx.file_rec_no]
  1125.     jne    maw_lp3            ;loop till modify block reached
  1126. ;
  1127. ; copy data from temp_file to disk
  1128. ;
  1129. maw_write_temp:
  1130.     mov    bx,offset temp_index - size index_struc
  1131. maw_lp4:add    bx,size index_struc
  1132.     cmp    es:[bx.rec_no],0
  1133.     je    maw_t1            ;jmp if end of temp index
  1134.     cmp    es:[bx.rec_no],-1
  1135.     je    maw_lp4            ;jmp if removed record (deleted)
  1136.     call    write_file_record
  1137.     jc    maw_done        ;jmp if error
  1138.     jmp    maw_lp4
  1139. ;
  1140. ; write data following modification block
  1141. ;
  1142. maw_t1:    mov    ax,es:[bx.file_rec_no - size index_struc]    ;find
  1143.     inc    ax                        ; next file rec
  1144.     
  1145. maw_t2:    mov    bx,offset index                
  1146. maw_lp6:cmp    es:[bx.file_rec_no],ax
  1147.     je    maw_write_tail
  1148.     cmp    es:[bx.rec_no],0
  1149.     je    maw_get_more
  1150.     add    bx,size index_struc
  1151.     jmp    maw_lp6                
  1152. maw_get_more:
  1153.     push    ax
  1154.     mov    al,1
  1155.     call    $disk_read
  1156.     pop    ax
  1157.     jnc    maw_t2
  1158.     jmp    maw_done        ;jmp if input file at eof
  1159. ;
  1160. ; copy data remaining
  1161. ;
  1162. maw_write_tail:    
  1163. maw_lp7:cmp    es:[bx.file_rec_no],0
  1164.     je    maw_more_ck        ;jmp if out of data in memory
  1165.     call    write_file_record
  1166.     jc    maw_done        ;jmp if error
  1167.     add    bx,size index_struc
  1168.     jmp    maw_lp7            ;jmp if more data to copy
  1169. maw_more_ck:
  1170.     push    ax
  1171.     mov    al,1
  1172.     call    $disk_read
  1173.     pop    ax
  1174.     jc    maw_success    ;jmp if eof
  1175.     mov    bx,offset index
  1176.     jmp    maw_lp7
  1177. maw_success:
  1178.     clc    
  1179. maw_done:
  1180.     ret
  1181. ;-----------------------------------------------------------------------------
  1182. ; write_file_record - copy data from index file to output file
  1183. ;  input:  es:bx = pointer to index for input data
  1184. ;  output:  carry set if error
  1185. ;
  1186. write_file_record:
  1187.     apush    ax,bx,cx,dx
  1188.     push    es
  1189.     pop    ds
  1190.     mov    si,es:[bx.buf_ptr]
  1191.     call    $compute_record_length
  1192.     mov    dx,si
  1193.     mov    bx,cs:dcc_temp_handle
  1194.     mov    ah,40h
  1195.     int    21h
  1196.     apop    dx,cx,bx,ax
  1197.     ret
  1198. ;-----------------------------------------------------------------------------
  1199. ; verify1 - check if database valid and has data in it
  1200. ;  inputs:    es: setup
  1201. ;  outputs:   no carry - al = 0 (success)
  1202. ;                carry - al = 1 database empty
  1203. ;                carry - al = 2 selector bad or database corrupted
  1204. ;           registers bx,cx modified
  1205. ;
  1206. verify1:test    es:[f_flags],at_top
  1207.     jz    verify2            ;jmp if database has data
  1208.     test    es:[f_flags],at_eof
  1209.     jz    verify2            ;jmp if database has data
  1210.     mov    cx,0            ;record count
  1211.     mov    bx,offset index - size index_struc
  1212. v_lp:    add    bx,size index_struc
  1213.     cmp    es:[bx.rec_no],0
  1214.     je    v_check            ;jmp if end of index
  1215.     cmp    es:[bx.rec_no],-1
  1216.     je    v_lp            ;jmp if removed record
  1217.     inc    cx
  1218.     jmp    v_lp
  1219. v_check:jcxz    verify_bad1        ;jmp if no records found
  1220. verify2:cmp     es:[f_key],'JO'
  1221.     mov    al,2            ;preload error code for bad ES:
  1222.     jne    verify_bad
  1223.     clc
  1224.     mov    al,0
  1225.     jmp    verify_end
  1226. verify_bad1:
  1227.     mov    al,1            ;signal database empty    
  1228. verify_bad:
  1229.     stc
  1230. verify_end:
  1231.     ret        
  1232.     
  1233. ;-----------------------------------------------------------------------------
  1234.  
  1235. LIBSEG    ENDS
  1236. ;;    end
  1237.