home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
ftp.barnyard.co.uk
/
2015.02.ftp.barnyard.co.uk.tar
/
ftp.barnyard.co.uk
/
cpm
/
walnut-creek-CDROM
/
MBUG
/
MBUG145.ARC
/
FCRLZH11.LBR
/
BUFFERS.DYC
/
BUFFERS.DYC
Wrap
Text File
|
1979-12-31
|
24KB
|
701 lines
; 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
.bver:
;
; ------- 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)
.bfwopen:
;
; 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)
.bfropen:
;
; Close buffered write file hl^. Carry for failure.
; Flush buffers to file.
; a,f
.bfclose:
;
; Input (a) from buffered file via buffer hl^.
; Carry on eof or error.
; a,f
.bfgetc:
;
; Put byte c to buffered file hl^. Carry for write error
; a,f
.bfputc:
;
; 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
.bload:
;
; 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
.bfswap:
;
; 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
.bdump:
;
; ------ 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
.bgetc:
;
; 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
.bgetp:
;
; 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
.bputc:
;
; 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
.bputp:
;
; Iopoll operation. Null here. Link in your own.
; Can replace interrupt driven io by action here
; a,f (allowed)
.iopoll: ret
;
; ------ 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
.bspace:
;
; 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
.bfill:
;
; get byte from buffer hl^. No ready/range checks. Clear carry
; a,f
.bget:
;
; put byte c to buffer hl^. No ready/range checks. Clear carry
; a,f
.bput:
;
; 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
.bsta:
;
; binit, but ensure size (bc) is a multiple of 128 by truncating
; a,f,c
.bfinit:
;
; 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
.binit:
;
; Set pointers back to start for aligned read/writes.
; Discard any data in buffer. Return a=0 and z flag.
; a,f
.bflush:
;
; Return bc := space available.
; If buffer empty return z flag, else 0ffh and non-z flag
; a,f,b,c
.broom:
;
; 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
.bcrc:
;
; -------- 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
.pfnm:
;
; 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
.pfnmdu:
;
; .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
.getdu:
;
; 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
.options:
;
; initialize fcb hl^ to blanks and nulls
; a,f
.initfcb:
;
; 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
.fopnr:
;
; 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
.fopnw:
;
; reset current record, extent, file de^
; f
.freset:
;
; If fcb de^ uses default drive, lock it to current drive.
; This allows drive switches after file is opened.
; a,f
.drvlock:
;
; ------- 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
.wildx::
;
; Copy file name from fcb hl^ to fcb de^,
; only in wild card locations of de^.
; a,f
.fcwild:
;
; copy file name from hl^ to de^ fcbs (name/ext only)
; removing any attribute bits.
; a,f
.fncpy:
;
; 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
.nxtfn:
;
; 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
.nxtout:
;
; 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.
.wldck:
;
; ------- 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:
;
; advance de by 1, modulo bc
; a,f,d,e
.advptr:
;
; Check hl for the value 0, preserve a. Carry if zero
; f
.nilchk:
;
; fill hl^ for b with a, advance hl
; f,b,h,l
.fillc:
;
; 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
.move:
;
; load de from hl^, advance hl by 2
; d,e,h,l
.ldem:
;
; store de to hl^, advance hl by 2
; h,l
.sdem:
;
; decrement word hl^, advance hl by 1 (to hi byte of m)
; z flag for zero after decrementing
; a,f,h,l
.dcxm:
;
; increment word hl^, advance hl by 1 (to hi byte of m)
; z flag for zero after incrementing
; a,f,h,l
.inxm:
;
; trade de^ and hl^ for c bytes
; a,f
.mxchg:
;
; 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
.dcmp:
;
; subtract de from hl. Like "DAD d"
; f,h,l
.dsub:
;
; 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
.crc:
;
; 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
.nextch:
;
; Return last character, as above. Carry if invalid or eoln
; a,f
.lastch:
;
; skip blanks and tabs in input line. Carry on illegal chars.
; return the 1st non-blank char. found.
; a,f,d,e
.skipblks:
;
; Advance to non-blank, line de^. "call .nextch ! call .skipblks"
; a,f,d,e
.nxt:
;
; Check white space, carry for illegals or eoln. z flag for white
.qwhite:
;
; upshift a if lower case
; a,f
.upshft:
;
; check a for numeric char, carry if not
; f
.qnum:
;
; 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
.imul:
;
; 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
.idiv:
;
; 2's complement (bc), leave (b) in (a)
; a,b,c
.c2bc:
;
; 1's complement (bc), leave (b) in (a)
; a,b,c
.c1bc:
;
; divide unsigned integer (hl) by 10
; remainder appears in (a) with flags set on it
; a,f,h,l
.dten:
;
; convert 4 bit hex value to ascii in (a)
; a,f
.hexa:
;
; 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
.xltusr:
;
; get current user
; a,f
.getusr:
;
; setuser # a
; a,f
.setusr:
;
; bdos call #(a), preserve registers, set flags on returned (a)
; Do not use when 16 bit return values needed in hl.
; a,f
.dos:
;
; ----- Utility Console Output via bdos calls -----
;
; output (a) in decimal to console, suppress leading zeroes
; f
.tadzs:
;
; write (hl) in decimal to console, suppress leading zeroes.
.tdzs:
;
; 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
.tdzsf:
;
; write filename for fcb (de)^, user (a), to console, string format
; a,f
.tfnam:
;
; console output (a)
; a,f
.couta:
;
; Blank to console
; a,f
.blk:
;
; (a) blanks to console. 0 value valid
; a,f
.blks:
;
; cr & lf to console
; a,f
.crlf:
;
; .crlf and then .t4hx
.t4hxc:
;
; print (hl) in hex (4 chars.) on console
; a,f
.t4hx:
;
; list a byte (a) as 2 ascii char.
; a,f
.t2hx:
;
; convert (a) 4 lower bits to hex & print on console
; a,f
.hxd:
;
; --- 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)
.sbcalloc:
;
; 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)
.salloc:
;
; 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
.lhlstk:
;
; ---- Data Segment Control ----
;
; Marker for end of data segment. Value is that of FREE byte.
; LAST item in library.
dseg
.endata equ $