; BUFFERS is copyright (c) 1986 by: ; C.B. Falconer, 680 Hartford Tpk, Hamden, Conn. 06517 ; all rights reserved. (203) 281-1438 ; ; BUFFERS is released to the public domain for non-profit private ; use only. It may be freely copied, distributed, and used for ; such purposes. It may not be sold, nor included in packages for ; sale, without the express written permission of C.B. Falconer. ; ; All components of BUFFERS.LBR are datestamped, and are protected ; by CCITCRC checksums (but not BUFFERS.LBR). "crunched" components ; (indicated by a middle 'Z' in the filetype) may be extracted or ; typed by LT (included). Execute LT with no parameters for help. ; "ccitcrc filename.typ" on any extracted component should yield ; a zero checksum. Version no. is displayed by "TYPE bufflib.slr". ; ; ------ General ------ ; ; BUFFERS provides a buffering mechanism for diskfiles, i/o devices, ; and others. It provides for byte by byte extraction and insertion, ; and full du addressing. A rich variety of utility routines are ; available. The searchable library is BUFFLIB.REL or .SLR. ; ; BUFFERS is designed to operate correctly when the default drive and ; or user is changed after the files have been opened. The code is ; re-entrant, 8080 executable, and need only appear once in any system. ; No data segment (except for an addressable end marker) is used, and ; the linked code may be mounted in ROM. Buffer sizes and allocation ; are entirely up to the caller. The procedures are also compatible ; with use in interrupt driven or polled i/o systems. ; ; NOTE: Various routines expect to operate with adequate stack space ; available. In general, SP should be set to the TOP of available ; memory, and altered with extreme care. This convention maximizes ; memory availablity by allowing dynamic assignment and release. ; ; Ver. 1.4 provides a cleaner user interface for file name parsing, ; adds tdzsf (type decimal right justified in field), and options ; (parse command line options). pfnm, pfnmdu, getdu, nextch, ; skipblks were affected. tdzsf, qwhite, lastch, options, blk, and ; blks (multiple blanks to console) were added. ; ; Ver. 1.3 up provide routines for dynamic stack frame allocation, ; deallocation, and access. "move" has different parameters than in ; Ver. 1.2 (de and hl registers exchanged). ; ; Ver. 1.2 up provide routines for expanding and processing wild ; card specifications. ; ; For modification history, see BVER.MAC ; ; Various utility routines are also available. ; ; After familiarization most users will only require one of ; BUFFLIB.SLR (in SLR format) or BUFFLIB.REL (in Microsoft format), ; depending on their linker, and BUFFERS.DOC, which summarizes all ; procedures available. The source can be examined if needed. ; ; Examination of the various TESTn.MAC files will demonstrate usage. ; Linking procedures can be checked by comparison with the pre-linked ; TESTn.OBJ files provided. ; ; The buffer storage space MUST be supplied by the main program, and ; appropriate pointers passed. Note that each buffer requires 12 ; bytes of overhead space, in addition to the buffer proper. Programs ; should use the external b.ohead rather than 12, to allow for ; future changes. System flags are kept in the first byte of the ; buffer. The second byte is (at present) available for user use. ; The buffers should only be manipulated by the procedures provided. ; ; The disk file linkages provide for full DU control. The default ; user (specified by a 0 byte) is that in effect when the file is ; opened. Any user can be specified by (user_no + 1). The file ; open primitives .FOPNR and .FOPNW are an exception in that they ; require the absolute user number. ; ; TESTn.MAC files are application examples. Simply declare the ; appropriate routines as EXTRN, and link the master module with ; BUFFERS using the /s option. However, you MUST control the DSEG ; allocation at link time for these examples. You can check your ; linkage procedures by comparing the final .COM file with the ; two TESTn.OBJ files provided. Differences in uninitialized data ; area (after the end of all code) do not matter. ; ; BUFFLIB.SLR is in SLR format, and 16 name characters are signifi- ; cant. BUFFLIB.REL is in Microsoft format, and all names are trun- ; cated to 6 characters. You should normally use the full routine ; names, and allow the linker and assembler to truncate. ; ; Any routine in the library may be over-ridden by linking a routine ; of the same name BEFORE the library search. This allows customized ; versions of .IOPOLL to be used. ; ; -------- ; ; Linking instructions: ; ; With l80 or SLRNK ; l80 /p:100,/d:8000,yourfile,bufflib/s,/u ; and note the next code byte free. Exit and repeat replacing the ; "8000" above by this address. (the 8000 is not a critical value) ; e.g. if the storage was shown as "100..cde" then enter ; l80 /p:100,/d:cde,yourfile,bufflib/s,yourfile/n,/e ; ; NOTE: SLRNK shows last byte used, L80 shows next byte free. Thus ; for SLRNK add 1 to the value displayed. ; ; NOTE: l80 will append unnecessary empty space to the output ; file for uninitialized data areas. Can be removed with DDT ; and save, or with DDTZ and "k first,last" command. ; ; With SLRNK+ ; slrnk+ /a:100,/j,yourfile,bufflib/s,yourfile/n,/e ; and the data area will automatically be placed at the end. ; ; CAUTION: When using SLRNK or SLRNK+ do not intermix SLR and REL ; format files, because all REL (Microsoft) format files truncate ; module and entry names to 6 chars. SLRNK and SLRNK+ use up to 16 ; char. names, and thus may not find some entries. SLRMAC and ; Z80ASM (from SLR) can create either format. ; ; ------ ENTRY POINTS ------- ; ; NOTE: In the following, the notation "hl^" means the memory to ; which register hl is pointing, and similarly for de^ and bc^. ; ; NOTE: Each routine description is followed by a "registers affected" ; comment, e.g. "a,f", which annotates all registers that the routine ; may alter. All others will not be changed. ; ; ; Standard i/o control bits, returned by BSTA. Alter in BUFFDEFN inrdy equ 1 ordy equ 4 ; ; Bits in b.flgs low order byte. Hi byte available for user b.usrm equ 01fh; Mask for user area storage b.spare equ 020h b.wrt equ 040h; {MUST be reset for read files. b.eof equ 080h; {MUST be set for write files. b.wflg equ b.eof+b.wrt ; ; structure of a buffer aseg org 0; offsets relative to buffer start b.flgs: ds 2; gp flags. eof/user in lo byte b.size: ds 2; allocated space b.fcb: ds 2; attached fcb, if any b.cnt: ds 2; bytes currently in buffer b.rptr: ds 2; NEXT byte to read from buffer (index) b.wptr: ds 2; NEXT byte to write to buffer (index) b.body: ds 0; Actually b.size bytes b.ohead equ b.body ; ; ------- Version control ------- ; ; return a=version of bufflib in use, de pointer to version msg. ; a,d,e ; ; ------- Buffered file i/o routines, byte and block -------- ; ; initialize buffer hl^, size bc, attached file de^, on user (a) ; (where a=0 for current, else 1 larger than user desired), ; for buffered file writes. Create/rewind the output file. ; The caller must make (bc) + b.ohead bytes of storage available. ; Buffer size (bc) is rounded down to a multiple of 128 ; a,f,(b,c) ; ; initialize buffer hl^, size bc, attached file de^, on user (a) ; (where a=0 for current user, else 1 larger than user desired), ; for buffered file reads. Carry if file not found. ; The caller must make (bc) + b.ohead bytes of storage available. ; Buffer size (bc) is rounded down to a multiple of 128 ; a,f,(b,c) ; ; Close buffered write file hl^. Carry for failure. ; Flush buffers to file. ; a,f ; ; Input (a) from buffered file via buffer hl^. ; Carry on eof or error. ; a,f ; ; Put byte c to buffered file hl^. Carry for write error ; a,f ; ; Read into buffer hl^ from attached disc file until less than ; 128 bytes free or eof. Carry for eof on entry or read error. ; This delays the eof signal until .bload cannot read further ; data. Reset pointers for any extra portion not read ; Assumes no other access via wptr, i.e. input only buffer ; This code assumes buffer size to be a multiple of 128 bytes, ; so that single reads never need to "wrap around" the buffer. ; a,f ; ; swap file de^, user/flags a, for the file presently attached ; to buffer hl^. Return de a pointer to the previous file, and ; a as the previous flags lo byte setting. ; This permits use of a single buffer for fast file transfers, ; using the .BLOAD and .BDUMP routines to control user access ; during file read/writes. ; a,f,d,e ; ; Write from buffer hl^ to attached disc file until less than ; 128 bytes stored. Carry for write error. ; Reset pointers for any extra portion not written. ; Assumes no other access via rptr, i.e. output only buffer ; This code assumes buffer size to be a multiple of 128 bytes, ; so that single writes never need to "wrap around" the buffer. ; a,f ; ; ------ Routines useful with interrupt or polled i/o ----- ; ; get byte from buffer hl^ when ready, else wait. Entry for ; interrupt driven systems. This enables interrupts. The .iopoll ; routine is called whenever no char. is ready in the buffer ; a,f ; ; get byte from buffer hl^, pause until ready. Also an entry for ; interrupt driven systems. This enables interrupts. The .iopoll ; routine is always called at least once. For polled systems ; a,f ; ; put byte (c) to buffer hl^ when ready, else wait. Enables ; interrupts. The .iopoll routine is called whenever the buffer ; is full. For interrupt driven systems. ; a,f ; ; put byte (c) to buffer hl^ when ready, else wait. Also an entry ; for interrupt driven systems. Enables interrupts. The .iopoll ; routine is always called at least once. For polled systems. ; a,f ; ; Iopoll operation. Null here. Link in your own. ; Can replace interrupt driven io by action here ; a,f (allowed) ; ; ------ Buffer primitives ------- ; ; return bc=space available in buffer hl^. If buffer empty align ; pointers and return 0, else return 0ffh (ptrs unchanged) ; z flag set accordingly ; a,f,b,c ; ; Fill buffer hl^ with (c) until it holds a multiple of ; 128 bytes. Used in final flushing of output buffers. ; CAUTION: buffer must hold at least 128 bytes ; a,f ; ; get byte from buffer hl^. No ready/range checks. Clear carry ; a,f ; ; put byte c to buffer hl^. No ready/range checks. Clear carry ; a,f ; ; Return ordy and inrdy bits in (a) for buffer hl^ ; ordy means buffer can accept a byte, inrdy means buffer has a byte ; a,f ; ; binit, but ensure size (bc) is a multiple of 128 by truncating ; a,f,c ; ; initialize buffer hl^ to empty, size bc, attach file de^ ; set initial flags (lo byte only) to a, clear hi byte. ; For file reads the initial flag should be 0, for write b.wflg. ; The caller must make (bc) + b.ohead bytes of storage available. ; a,f ; ; Set pointers back to start for aligned read/writes. ; Discard any data in buffer. Return a=0 and z flag. ; a,f ; ; Return bc := space available. ; If buffer empty return z flag, else 0ffh and non-z flag ; a,f,b,c ; ; Compute a CRC16 checksum over the content of buffer hl^. The ; initial CRC checksum value is passed and returned in (bc). It ; should be initialized to 0ffffh. .bcrc entry does not initialize, ; thus allowing the crc checksum to be applied over multiple buffer ; loads. This is intended to be used with large buffered transfers, ; between calls on .bload and the following .bdump. A file re-read ; can then quickly verify an accurate transfer. This code assumes ; the buffer never wraps, i.e. it is used solely for file/file ; transfers, so that it is always loaded from the bottom. If not ; unloaded it should be flushed (use .bflush) before reloading. ; Carry for invalid buffer state. ; a,f,b,c ; ; -------- File name parsing routines and support --------- ; ; Parse the next field from the command line (de^) into fcb hl^. ; Drive id is set, name and type are parsed into fname and ftype, ; with any '*'s expanded into '?'s, and the fields are blank padded. ; At exit de points to the field terminating delimiter char, (a) is ; the count of '?' chars in fname & ftype fields, with flags set on ; it. Thus the Z flag on exit indicates no wild cards. (c) contains ; the drive specifier (if any), (b) holds 0 (default user). ; a,f,b,c,d,e,h,l ; ; Parse the next field from the command line (de^) into fcb hl^. Any ; drive/user specifications are recorded in c and b respectively, ; (which default to 0s), with drive recorded in the FCB. Name and ; type are parsed into fname and ftype, with any '*'s expanded into ; '?'s, and the fields are blank padded. At exit de points to the ; field terminating delimiter char., (a) is the count of '?' chars. ; in fname & ftype fields, with flags set on it, bc as above. ; ; NOTE that 0 means default user, and a specified user is returned ; as user no. + 1, i.e. the identical convention to that for drives. ; This also allows the user specification to be stored in a 5 or 6 ; bit field, depending on whether the max user is 15 or 31. ; a,f,b,c,d,e,h,l ; ; .getdu returns any "du" spec. in b and c, with b = user, c = drv ; The default user is signified by a -1 value, default drive by 0 ; At entry, de points to the start of the field to be parsed. At ; exit, either de is unchanged (no du found), or points to ':'. ; ; NOTE that the user convention here is different from that used ; in the remainder of the system. Convert by incrementing. ; a,f,b,c,d,e ; ; Parse any options from text line de^ into storage hl^. Advance ; de to 1st non-blank character, and to option string delimiter ; if a valid option string found. bc is a pointer to an option ; definition string, in the form: ; bc^ char Required "header" char for an option string ; bc+1^ count Number of options available ; bc+2^ char A char that may appear in the option string ; .... etc. (for count chars) ; (The storage at bc^ is an image, and is never altered). ; ; At exit, if a valid option string is found, hl^ contains a copy ; of the definition string, with all chars found in the input ; string ZEROED. i.e. a zero value means option set. Options ; returns with a = 0ffh, and the NZ flag set in this case. ; ; If no valid option string is found, or some characters are not ; present in the image (or present more than once), hl^ contains ; an unmodified copy of the definition string, and options returns ; a = 0, with the Z flag set. ; ; All candidate characters are upshifted before testing. Thus an ; option definition string containing lower case characters can never ; be matched. Similarly, if the definition string contains 0 bytes, ; these are pre-matched locations. This allows configuration of ; valid input options in the image string for installation purposes. ; ; An option string (not the definition string) consists of a trigger ; character, followed by a series of characters. If any string char ; acter is not present in the option template, the whole string is not ; an option string, and input conditions are restored. If all chars ; are present in the template, those positions are zeroed, and the ; input parser is advanced to the terminal blank (or control char). ; ; If a valid option list is found, 0ffh and nz is returned, ; otherwise 0 and z flag signal no valid option parsed. In any ; case all initial blanks in the input string have been skipped. ; a,f,d,e ; ; initialize fcb hl^ to blanks and nulls ; a,f ; ; Open file de^ on user a for read. User number is absolute. ; Carry if file not found. Read mechanism must control user. ; If de^.drv is 0 (default drive) lock to current drive, to ; allow drive changes while the file is open. ; a,f ; ; Open file de^, user a, for write. User number is absolute. ; Carry for error. Purge any previous file. Write mechanism must ; control user settings. If de^.drv is 0 (default drive), lock to ; current drive to allow drive changes while the file is open. ; a,f ; ; reset current record, extent, file de^ ; f ; ; If fcb de^ uses default drive, lock it to current drive. ; This allows drive switches after file is opened. ; a,f ; ; ------- Wild card expansion routines -------- ; ; Fill area hl^ up with wild card expansions of fcb de^, on the ; current user. Returned entries are the 1st 16 bytes of the ; directory entry. Return count of files in bc, pointer to ; unused buffer area in hl. Zero flag if no matching files. ; CAUTION - modifies defdma setting. Buffer must provide at ; least 128 bytes more than space required for storage. ; Carry for insufficient memory, (based on SP pointing to top ; of memory) when the search is truncated. ; This procedure is normally used only at initialization time. ; a,f,b,c,h,l ; ; Copy file name from fcb hl^ to fcb de^, ; only in wild card locations of de^. ; a,f ; ; copy file name from hl^ to de^ fcbs (name/ext only) ; removing any attribute bits. ; a,f ; ; Reset the file name in fcb de^ from entry hl^, clear attribs. ; At entry hl points one byte below the fname field, i.e. ; to the user # entry of the file list. At exit, the ; fcb de^ has the extent, record pointer, etc zeroed. ; The drive identifier byte is NOT altered. ; a returns the user no. in the list hl. ; This is used to scan file names from wildx lists ; a,f ; ; next output file name. Copy hl^ to de^, then update from ; bc^. Thus all wild areas in entry hl^ are filled in with ; the actual chars in entry bc^. For wild card copy operations ; normally bc is the input fcb, hl the output pattern (with ; wild cards), and de points to the actual output fcb. ; a,f ; ; Check fcbs hl^ and de^ have wild cards in the same areas. ; Carry if not. This checks compatibility between input ; and output wild card specifications. ; ; ------- Utility/support routines, available to user ------- ; ; adv ptr hl^ by 128 modulo bc, de := unadvanced ptr, hl:= hl+1 ; Wrap around signalled by no carry on exit with nz flag, when ; c returns the bytes to be wrapped. ; a,f,c,d,e,h,l ; ; advance de by 1, modulo bc ; a,f,d,e ; ; Check hl for the value 0, preserve a. Carry if zero ; f ; ; fill hl^ for b with a, advance hl ; f,b,h,l ; ; move hl^ to de^ for bc bytes. Advance ptrs de and hl ; guarded against 0 length move. ; Interchanged source/dest regs 86/11/27 to agree with ldir <---* ; a,f,b,c,d,e,h,l ; ; load de from hl^, advance hl by 2 ; d,e,h,l ; ; store de to hl^, advance hl by 2 ; h,l ; ; decrement word hl^, advance hl by 1 (to hi byte of m) ; z flag for zero after decrementing ; a,f,h,l ; ; increment word hl^, advance hl by 1 (to hi byte of m) ; z flag for zero after incrementing ; a,f,h,l ; ; trade de^ and hl^ for c bytes ; a,f ; ; compare hl and de (unsigned) ; if de > hl then z reset, carry set ; if de = hl then z set, carry clear ; if de < hl then z reset, carry clear ; (organized like "cmp r", using hl as accumulator) ; f ; ; subtract de from hl. Like "DAD d" ; f,h,l ; ; This crc routine updates the checkword in bc using the byte ; passed in a. The two byte checkword is produced by the ; generating polynomial x**16+x**12+x**5+1. The checksum should ; be initialized to 0ffffh (i.e. 0ffffh is passed in bc when the ; checksum sequence is started). bc returns the new checksum. ; a,f,b,c ; ; Get next character from line, upshifted, Z flag for a delimiter, ; carry if the character is illegal or eoln. No advance past eoln. ; Return char in a and leave de pointing to it. cy for eoln ; a,f,d,e ; ; Return last character, as above. Carry if invalid or eoln ; a,f ; ; skip blanks and tabs in input line. Carry on illegal chars. ; return the 1st non-blank char. found. ; a,f,d,e ; ; Advance to non-blank, line de^. "call .nextch ! call .skipblks" ; a,f,d,e ; ; Check white space, carry for illegals or eoln. z flag for white ; ; upshift a if lower case ; a,f ; ; check a for numeric char, carry if not ; f ; ; unsigned integer multiply. Reverse of .idiv ; operand range 0 to 65535, product 0 to 4295*10^6 (approx) ; (dehl) := (bc) * (de) ; d,e,h,l ; ; unsigned integer divide. Reverse of .imul ; (de) := (dehl) DIV (bc); (hl) := (dehl) MOD (bc) ; carry for overflow (or zero divide), when registers unchanged ; divisor, remainder and quotient range 0 to 65535 ; dividend range 0 to 4295*10^6 (approx) ; f, d, e, h, l ; ; 2's complement (bc), leave (b) in (a) ; a,b,c ; ; 1's complement (bc), leave (b) in (a) ; a,b,c ; ; divide unsigned integer (hl) by 10 ; remainder appears in (a) with flags set on it ; a,f,h,l ; ; convert 4 bit hex value to ascii in (a) ; a,f ; ; xltusr imposes the same user/default relationship as used for ; drives, i.e. 0 returns the current logged in user, other values ; return value - 1. ; a,f ; ; get current user ; a,f ; ; setuser # a ; a,f ; ; bdos call #(a), preserve registers, set flags on returned (a) ; Do not use when 16 bit return values needed in hl. ; a,f ; ; ----- Utility Console Output via bdos calls ----- ; ; output (a) in decimal to console, suppress leading zeroes ; f ; ; write (hl) in decimal to console, suppress leading zeroes. ; ; Write hl (dec) in minimum (a) char. field, right justified. ; (If the field is too small more columns are used). Max field 128 ; a,f ; ; write filename for fcb (de)^, user (a), to console, string format ; a,f ; ; console output (a) ; a,f ; ; Blank to console ; a,f ; ; (a) blanks to console. 0 value valid ; a,f ; ; cr & lf to console ; a,f ; ; .crlf and then .t4hx ; ; print (hl) in hex (4 chars.) on console ; a,f ; ; list a byte (a) as 2 ascii char. ; a,f ; ; convert (a) 4 lower bits to hex & print on console ; a,f ; ; --- Stack frame allocation/deallocation/addressing ---- ; ; ; Allocate space for (bc) bytes on stack, rounding up to next 16 ; at exit (sp)+2 points to allocated space. See salloc. ; Exit with carry set if space requested too large (over 4k). ; Note that this does not check for stack overflow. ; a,f (sp) ; ; Allocate 16*a bytes on the stack, and leave a deallocate pointer ; on TOS. Thus "pop h | sphl" will deallocate. A maximum of 4096 ; bytes can be allocated (a=0 means 256). Remember to round up byte ; requirements to the next multiple of 16, or use sbcalloc entry. ; For more do the following in line: ; mvi a,0 ; call salloc; 1st 4k ; pop h; dealloc ptr, destroy hl ; mvi a,extra; part from 4096 to 8192 ; call salloc ; xthl; save dealloc to 1st part ; At exit sp+2 is the lowest byte of the allocated memory. ; and carry is reset. ; a,f, (sp) ; ; load hl from stack level l (with respect to caller). ; i.e. l=0 corresponds to sp = TOS ; l=1 corresponds to sp+2 (value under TOS) etc. ; Use this like lhld, with relative word address in l. ; Maximum l value on entry is 127 ; h,l ; ; ---- Data Segment Control ---- ; ; Marker for end of data segment. Value is that of FREE byte. ; LAST item in library. dseg