Discussion:
Open Library books
(too old to reply)
T. Ment
2020-06-05 15:49:18 UTC
Permalink
Open Library has DOS programming books. Not many, but some good ones.

https://openlibrary.org/

Requires Adobe Digital Editions, but with Calibre and the DeDRM plugin,
you can make a copy of the PDF. 3.48 is the last version of Calibre for
Windows 7.

With scanned PDFs in Adobe Reader, copying and pasting code loses extra
spaces and some comments. Fixing it by hand is doable, but tedious.

An easier way is:

a) print the pages you want from Adobe Reader to a XPS file.
b) convert the XPS to PDF https://xpstopdf.com/
c) split the pages https://www.pdf2go.com/split-pdf
d) OCR convert each page to text https://www.onlineocr.net/

The result is not perfect, but it's good enough to fix by hand. Easier
than typing all the code.

At the online OCR service, if you register with an email address, they
give you 50 free pages, so you can omit splitting the PDF. If you don't
want to purchase more, you can still use the unregistered one page at a
time free service.

I tried other online OCR services, but that was the best one I found.
The others lost all spacing, like direct copying and pasting from Adobe
Reader.
Johann 'Myrkraverk' Oskarsson
2020-06-06 12:20:00 UTC
Permalink
Post by T. Ment
Open Library has DOS programming books. Not many, but some good ones.
https://openlibrary.org/
Thanks; though I just log in and read on my tablet. I don't feel the
need to jump through hoops to download the text & code.

At least not yet.
--
Johann | email: invalid -> com | www.myrkraverk.com/blog/
I'm not from the Internet, I just work there. | twitter: @myrkraverk
T. Ment
2020-06-06 15:22:17 UTC
Permalink
Post by Johann 'Myrkraverk' Oskarsson
Post by T. Ment
https://openlibrary.org/
Thanks; though I just log in and read on my tablet. I don't feel the
need to jump through hoops to download the text & code.
At least not yet.
To read, you must check it out. While you have it, up to two weeks,
other people wait. An organization like open library follows the law.

But there are ways to reduce the wait. Legal or not.

I like to try the code without typing it all in. That's too tedious and
error prone. I adjust the spacing and verify each line of the converted
OCR, but I need to read it anyway. Still much easier than typing.

I later found the OCR service adds a NUL after each character. I didn't
notice it before because I was using Notepad++ to view the file. When I
moved it to DOS, it was obvious, an extra space between each character.

Easy to fix in Notepadd++ though. Convert the file to ANSI and it strips
the NULs.
T. Ment
2020-06-06 17:55:22 UTC
Permalink
I adjust the spacing and verify each line of the converted OCR
I'm working on STDMAC.INC from MS-DOS Developer's Guide now. It's almost
20 pages.

The first full page has EQU character definitions in binary. Lots of 0s
and 1s. The OCR misread one of the 0s as an O (oh) but the rest it got
right. Considering how similar they look in the scanned PDF, I'm amazed
how well it works.
T. Ment
2020-06-12 05:57:43 UTC
Permalink
Post by T. Ment
I'm working on STDMAC.INC from MS-DOS Developer's Guide now. It's almost
20 pages.
I soon discovered STDMAC.INC depends on STDLIB.ASM. which is another 18
pages. Converting all that took some time. Glad to have it done.

I assembled STDMAC.INC in a skeleton wrapper to check for syntax errors,
found a few, and fixed them. I've not tested the code so I don't know if
any of it works, But FWIW, here it is.


;----------------------------------------------------------------
; MACRO DEFINITIONS INCLUDE FILE
;----------------------------------------------------------------
; STANDARD EQUATES:
;
TRUE EQU 0FFFFh ; TRUE
FALSE EQU 0 ; FALSE
;
; Standard nonprintable ASCII characters:
NUL EQU 00000000b ; null
BEL EQU 00000111b ; bell
BS EQU 00001000b ; backspace
HT EQU 00001001b ; horizontal tab
LF EQU 00001010b ; line feed
FF EQU 00001100b ; form feed
CR EQU 00001101b ; carriage return
SUBST EQU 00011010b ; substitute
ESCAPE EQU 00011011b ; escape
SPACE EQU 00100000b ; space
COLON EQU 00111010b ; colon
SCOLON EQU 00111011b ; semicolon

; IBM Extended characters:
SLINE EQU 11000100b ; horizontal line
;
;----------------------------------------------------------------
.XLIST ; suppress listing macro defs.
;;.LALL ; list everything
;;
;;
;;** @Model *************************** GENERAL PURPOSE MACRO **
;; Set up segments according to memory model.
;; This macro emulates the MASM 5.X .MODEL
;; directive for use with earlier versions of
;; of MASM.
IF1 ;; assemble only during Pass 1
@Model MACRO memory_model,code_name,stack_size
;; NOTE: "code_name" is used only with medium,
;; large, and huge memory models.
IFNB <memory_model> ;; was memory model specified?
;;
IF memory_model EQ 0
@TinyModel stack_size
ELSE
IF memory_model EQ 1
@SmallModel stack_size
ELSE
IF memory_model EQ 2
@MediumModel code_name,stack_size
ELSE
IF memory_model EQ 3
@CompactModel stack_size
ELSE
IF memory_model EQ 4
@LargeModel code_name,stack_size
ELSE
IF memory_model EQ 5
@LargeModel code_name,stack_size
ELSE
.ERR
%OUT @Model macro: unknown memory model
ENDIF ;; end of huge model check
ENDIF ;; end of large model check
ENDIF ;; end of compact model check
ENDIF ;; end of medium model check
ENDIF ;; end of small model check
ENDIF ;; end of tiny model check
;;
ELSE ;; memory model was not specified
.ERR ;; terminate with error message
%OUT @Model macro error: Memory model not specified.
ENDIF ;; end of memory-model parameter check
;;
ENDM ;; end of macro definition
ENDIF ;; end of pass execution
;;
;;** @Tiny **************************** GENERAL PURPOSE MACRO **
;; Direct macro to set up TINY memory model (.COM type programs)
;; (This macro is called via "@Model 0".
;; This macro may also be called directly.)
;; Note that this macro, unlike the other memory-model macros,
;; does not make use of the @Stack macro, since alternate
;; stacks in .COM programs must be defined at the end of
;; of the program. To define an alternate stack in a .COM
;; program, execute the @Stack macro at the appropriate position
;; in the source code.
IF1 ;; assemble only during Pass 1
@TinyModel MACRO
MEMODEL = 0
_TEXT SEGMENT BYTE PUBLIC 'CODE' ; code segment
_TEXT ENDS
;; Assign physical segments:
ASSUME cs:_TEXT, ds:_TEXT, ss:_TEXT, es:_TEXT
;;-----------------------------------------------
;; Insert the following code manually after @Model 0:
;;
;; _TEXT SEGMENT
;; main PROC near
;; entry: ORG 0100h
;; jmp start
;; ; <insert data here if desired>
;; start:
;; ; <insert program code here>
;; main ENDP
;; ; <insert routines here>
;; ; <insert optional stack here>
;; ; <insert data at the end if desired>
;; _TEXT ENDS
;; END entry
;;------------------------------------------------
;;
ENDM ;; end of macro definition
ENDIF ;; end of pass execution
;;
;;** @Small *************************** GENERAL PURPOSE MACRO **
;; Direct macro to set up SMALL memory model
;; (This macro is called via "@Model small".
;; This macro may also be called directly.)
IF1 ;; assemble only during Pass 1
@SmallModel MACRO stack_size
MEMODEL = 1
_TEXT SEGMENT BYTE PUBLIC 'CODE' ; code segment
_TEXT ENDS
_DATA SEGMENT WORD PUBLIC 'DATA' ; data seg. (DGROUP)
_DATA ENDS
CONST SEGMENT WORD PUBLIC 'CONST' ; constants segment
CONST ENDS ; ... (DGROUP)
_BSS SEGMENT WORD PUBLIC 'BSS' ; uninitialized data
_BSS ENDS ; ... (DGROUP)
STACK SEGMENT PARA STACK 'STACK' ; stack seg. (DGROUP)
STACK ENDS
;;
IFNB <stack_size>
@Stack stack_size
ENDIF
;;
DGROUP GROUP _DATA,CONST,_BSS,STACK ; data seg. grouping
;;
;; Assign physical segments:
ASSUME cs:_TEXT, ds:DGROUP, ss:DGROUP, es:DGROUP
ENDM ;; end of macro definition
ENDIF ;; end of pass execution
;;
;;** @Medium ************************** GENERAL PURPOSE MACRO **
;; Direct macro to set up MEDIUM memory model
;; (This macro is called via "@Model medium".
;; This macro may also be called directly.)
IF1 ;; assemble only during Pass 1
@MediumModel MACRO code_name,stack_size
MEMODEL = 2
code_name_TEXT SEGMENT BYTE PUBLIC 'CODE' ; named code
code_name_TEXT ENDS ; ... segment
_DATA SEGMENT WORD PUBLIC 'DATA' ; data segment (DGROUP)
_DATA ENDS
CONST SEGMENT WORD PUBLIC 'CONST' ; constants segment
CONST ENDS ; ... (DGROUP)
_BSS SEGMENT WORD PUBLIC 'BSS' ; uninitialized data
_BSS ENDS ; ... segment (DGROUP)
STACK SEGMENT PARA STACK 'STACK' ; stack seg. (DGROUP)
STACK ENDS
;;
IFNB <stack_size>
@Stack stack_size
ENDIF
;;
DGROUP GROUP _DATA,CONST,_BSS,STACK ; data seg. grouping
;;
;; Assign physical segments:
ASSUME cs:_TEXT, ds:DGROUP, ss:DGROUP, es:DGROUP
;;
ENDM ;; end of macro definition
ENDIF ;; end of pass execution
;;
;;** @Compact ************************* GENERAL PURPOSE MACRO **
;; Direct macro to set up COMPACT memory model
;; (This macro is called via "@Model compact".
;; This macro may also be called directly.)
IF1 ;; assemble only during Pass 1
@CompactModel MACRO stack_size
MEMODEL = 3
_TEXT SEGMENT BYTE PUBLIC 'CODE' ; code segment
_TEXT ENDS
FAR_DATA SEGMENT PARA 'FAR_DATA' ; private far data
FAR_DATA ENDS ; ... segment (DGROUP)
FAR_BSS SEGMENT PARA 'FAR_BSS' ; private far uninitialized
FAR_BSS ENDS ; ... data seg. (DGROUP)
_DATA SEGMENT WORD PUBLIC 'DATA' ; data segment (DGROUP)
_DATA ENDS
CONST SEGMENT WORD PUBLIC 'CONST' ; constants segment
CONST ENDS ; ... (DGROUP)
_BSS SEGMENT WORD PUBLIC 'BSS' ; uninitialized data
_BSS ENDS ; ... segment (DGROUP)
STACK SEGMENT PARA STACK 'STACK' ; stack seg. (DGROUP)
STACK ENDS
;;
IFNB <stack_size>
@Stack stack_size
ENDIF
;;
DGROUP GROUP _DATA,CONST,_BSS,STACK ; data seg. grouping
;;
;; Assign physical segments:
ASSUME cs:_TEXT, ds:DGROUP, ss:DGROUP, es:DGROUP
;;
ENDM ;; end of macro definition
ENDIF ;; end of pass execution
;;
;;** @Large *************************** GENERAL PURPOSE MACRO **
;; Direct macro to set up LARGE memory model
;; (This macro is called via "@Model large".
;; This macro may also be called directly.)
IF1 ;; assemble only during Pass 1
@LargeModel MACRO code_name,stack_size
MEMODEL = 4
code_name_TEXT SEGMENT BYTE PUBLIC 'CODE' ; named code seg.
code_name_TEXT ENDS
FAR_DATA SEGMENT PARA 'FAR_DATA' ; private far data
FAR_DATA ENDS ; ... segment (DGROUP)
FAR_BSS SEGMENT PARA 'FAR_BSS' ; private far uninitialized
FAR_BSS ENDS ; ... data seg. (DGROUP)
_DATA SEGMENT WORD PUBLIC 'DATA' ; data segment (DGROUP)
_DATA ENDS
CONST SEGMENT WORD PUBLIC 'CONST' ; constants segment
CONST ENDS ; ... (DGROUP)
_BSS SEGMENT WORD PUBLIC 'BSS' ; uninitialized data
_BSS ENDS ; ... segment (DGROUP)
STACK SEGMENT PARA STACK 'STACK' ; stack seg. (DGROUP)
STACK ENDS
;;
IFNB <stack_size>
@Stack stack_size
ENDIF
;;
DGROUP GROUP _DATA,CONST,_BSS,STACK ; data seg. grouping
;;
;; Assign physical segments:
ASSUME cs:_TEXT, ds:DGROUP, ss:DGROUP, es:DGROUP
;;
ENDM ;; end of macro definition
ENDIF ;; end of pass execution
;;
;;** @Huge **************************** GENERAL PURPOSE MACRO **
;; Direct macro to set up HUGE memory model
;; (This macro is called via "@Model huge".
;; This macro may also be called directly.)
;; The HUGE memory model is currently set up the
;; same as the LARGE memory model.
IF1 ;; assemble only during Pass 1
@HugeModel MACRO code_name,stack_size
MEMODEL = 5
@LargeModel code_name,stack_size
ENDM ;; end of macro definition
ENDIF ;; end of pass execution
;;
;;** @Stack *************************** GENERAL PURPOSE MACRO **
;; Direct macro to establish the size of the stack
IF1 ;; assemble only during Pass 1
@Stack MACRO stack_size,prog_type
;;
IFB <prog_type> ;; if prog_type parameter is blank ...
IF MEMODEL EQ 0
PROGTYPE = 0
ELSE
IF MEMODEL EQ 1
PROGTYPE = 1
ELSE
IF MEMODEL EQ 2
PROGTYPE = 1
ELSE
IF MEMODEL EQ 3
PROGTYPE = 1
ELSE
IF MEMODEL EQ 4
PROGTYPE = 1
ELSE
IF MEMODEL EQ 5
PROGTYPE = 1
ELSE
.ERR
%OUT @Stack macro: The memory model or
%OUT program type was not established.
ENDIF ;; end of huge model check
ENDIF ;; end of large model check
ENDIF ;; end of compact model check
ENDIF ;; end of medium model check
ENDIF ;; end of small model check
ENDIF ;; end of tiny model check
ELSE ;; prog_type parameter was specified
IF prog_type EQ 0 ;; set up for .COM type program
PROGTYPE = 0
ELSE
IF prog_type EQ 1
PROGTYPE = 1
ELSE
.ERR ;; exit with error message
%OUT @Stack macro: Incorrect prog. type specified.
ENDIF ;; end of .EXE type check
ENDIF ;; end of .COM type check
ENDIF ;; end of "prog_type" parameter check
;;
IFNB <stack_size>
;;
IF PROGTYPE EQ 0
; Optional stack. CAUTION! You MUST use
; function 4Ch to terminate the program
; when using a local stack!
db stack_size DUP ('stack ')
top_of_stack EQU $
ELSE ;; prog. type is .EXE
STACK SEGMENT
db stack_size DUP ('stack ')
STACK ENDS
ENDIF ;; end of PROGTYPE check
;;
ELSE ;; "stack_size" parameter wasn't specified
;;
IF PROGTYPE EQ 0
; Optional stack. CAUTION! You MUST use
; function 4Ch to terminate the program
; when using a local stack!
db 32 DUP ('stack ')
top_of_stack EQU $
ELSE ;; prog. type is .EXE
STACK SEGMENT
db 32 DUP ('stack ')
STACK ENDS
ENDIF ;; end of PROGTYPE check
ENDIF ;; end of "stack_size" check
;;
ENDM ;; end of macro definition
ENDIF ;; end of pass execution
;;
;;** @SwapNewStack ******************** GENERAL PURPOSE MACRO **
;; Switch stack to a new stack
IF1 ;; assemble only during Pass 1
@SwapNewStack MACRO tos
LOCAL bypass
;;
jmp bypass ;; skip data area
old_stk_seg dw ;; space for caller's stack segment
old_stk_ptr dw ;; space for caller's stack pointer
new_stk_seg dw ;; space for new stack segment
new_stk_ptr dw offset tos ;; space for new stack pointer
;;
bypass:
mov cs:new_stk_seg,cs ;; set new stack segment
mov cs:old_stk_seg,ss ;; save old stack values
mov cs:old_stk_ptr,sp ;; save old stack pointer
mov ss,cs:new_stk_seg ;; get new stack values
mov sp,cs:new_stk_ptr ;; get new stack pointer
@PushAll ;; save flags and all registers
ENDM ;; end of macro definition
ENDIF ;; end of pass execution
;;
;;** @SwapOldStack ******************** GENERAL PURPOSE MACRO **
;; Switch from new stack to the original stack.
IF1 ;; assemble only during Pass 1
@SwapOldStack MACRO
@PopAll ;; restore flags and all regs.
mov ss,cs:old_stk_seg ;; restore old stack values
mov sp,cs:old_stk_ptr
ENDM ;; end of macro definition
ENDIF ;; end of pass execution
;;
;;** @DosCall ************************* GENERAL PURPOSE MACRO **
;; Call an MS-DOS function
IF1 ;; assemble only during Pass 1
@DosCall MACRO
int 21h
ENDM ;; end of macro definition
ENDIF ;; end of pass execution
;;
;;** @DirConCharIO ******************** GENERAL PURPOSE MACRO **
IF1 ;; assemble only during Pass 1
@DirConCharIO MACRO ; check keyboard status & read
push dx ; save DX
mov dl,0FFh ; no character to output
mov ah,06h
@DosCall
pop dx ; restore DX
ENDM
ENDIF ;; end of pass execution
;;
;;** @ReadCon_NoEcho ****************** GENERAL PURPOSE MACRO **
IF1 ;; assemble only during Pass 1
@ReadCon_NoEcho MACRO
mov ah,08h ; read keyboard without echo
aDosCall
ENDM
ENDIF ;; end of pass execution
;;
;;** @ReadBufflnput ******************* GENERAL PURPOSE MACRO **
IF1 ;; assemble only during Pass 1
@ReadBufflnput MACRO buffname ; read buffered keyboard input
mov dx,offset bufname
mov ah,0Ah
@DosCall
ENDM
ENDIF ;; end of pass execution
;;
;;** @DisChr ************************** GENERAL PURPOSE MACRO **
;; Display an immediate character
IF1 ;; assemble only during Pass 1
@DisChr MACRO char
IFNB <char> ;; was character argument specified?
;; yes, so insert code
push ax ;; save registers used
push dx
mov dl,char ;; load character
mov ah,02h ;; load func. number
@DosCall ;; call MS-DOS
pop dx ;; restore registers
pop ax
ELSE ;; otherwise
.ERR ;; generate error and output message
%OUT @DisChr macro: "char" argument not supplied.
ENDIF
;;
ENDM ;; end of macro definition
ENDIF ;; end of pass execution
;;
;;** @DisStr ************************** GENERAL PURPOSE MACRO **
;; Display a string from memory with default "$"
;; end-of-string terminator or with a specified
;; terminator.
;; (Calls @DisStr1 or cDisStr2 internal macros.)
IF1 ;; assemble only during Pass 1
@DisStr MACRO string,terminator
IFNB <string> ;; was string argument specified?
;; yes, so ...
IFB <terminator> ;; was terminator specified?
;; no, so insert default code for "$" terminator
@DisStr1 string
ELSE ;; otherwise, a terminator was specified
@DisStr2 string,terminator
ENDIF ;; end "terminator" check
ELSE ;; otherwise, "string" was not specified
.ERR ;; generate error and output message
%OUT @DisStr macro: "string" argument not supplied.
ENDIF
ENDM ;; end of macro definition
ENDIF ;; end of pass execution
;;
;;** @DisStr1 ********************************* SUPPORT MACRO **
;; Called by @DisStr to display a string from memory with
;; default "$" end-of-string terminator.
IF1 ;; assemble only during Pass 1
@DisStr1 MACRO string
push ax ;;save registers used
push dx
mov dx,offset ds:string ;; point to string
;; in memory
mov ah,09h ;; load func. number
@DosCall ;; call MS-DOS
pop dx ;; restore registers used
pop ax
ENDM ;; end of macro definition
ENDIF ;; end of pass execution
;;
;;** @DisStr2 ********************************* SUPPORT MACRO **
;; Called by @DisStr to display a string from memory with a
;; specified end-of-string terminator.
IF1 ;; assemble only during Pass 1
@DisStr2 MACRO string,terminator
LOCAL strloop,strloopdone ;; create local labels
push si ;; save registers
push ax
push bx
push dx
xor bh,bh ;; clear BX
mov bl,terminator ;; get the terminator
mov si,offset string ;; point to string
xor dx,dx
strloop:
mov dl,byte ptr [si] ;; get next char.
cmp dl,bl ;; is it the terminator?
je strloopdone ;; yes, we're done
mov ah,02h ;; load output-char. function
@DosCall ;; and call DOS
inc si ;; point to next char.
jmp short strloop ;; and go thru again
strloopdone:
pop dx ;; restore registers
pop bx
pop ax
pop si
ENDM ;; end of macro definition
ENDIF ;; end of pass execution
;;** @TypeStr ************************* GENERAL PURPOSE MACRO **
;; Display an immediate string (string defined on the fly)
;; NOTE: "string" must be presented within quotes so that
;; it is treated as a single argument to the macro and to
;; ensure that the data is encoded correctly.
IF1 ;; assemble only during Pass 1
@TypeStr MACRO string ;; define and display a string
LOCAL TypeStrAddr ;; set up a local label
;;
IF MEMODEL NE 0 ;; if not .COM type
_TEXT ENDS ;; end code segment
_DATA SEGMENT ;; change to data segment
ENDIF
TypeStrAddr DB string,'$' ;; define string in data segment
IF MEMODEL NE 0 ;; if not .COM type
_DATA ENDS ;; end data segment
_TEXT SEGMENT ;; return to code segment
ENDIF
;;
@DisStr TypeStrAddr ;; display string
ENDM ;; end of macro definition
ENDIF ;; end of pass execution
;;
;;** @TypeStrCR *********************** GENERAL PURPOSE MACRO **
;; Display an immediate string terminated with a CR/LF
;; "string" must be presented within quotes so that it is
;; treated as a single argument to the macro.
IF1 ;; assemble only during Pass 1
@TypeStrCR MACRO string
@TypeStr string ;; define and display string
@NewLine ;; terminate with a CR/LF
ENDM ;; end of macro definition
ENDIF ;; end of pass execution
;;
;;** @NewLine ************************* GENERAL PURPOSE MACRO **
;; Display a carriage return and linefeed
IF1 ;; assemble only during Pass 1
@NewLine MACRO
IFNDEF EXT_NEWLINE ;; was EXT_NEWLINE symbol defined?
EXTRN newline:NEAR ;; no, insert EXTRN only once
EXT_NEWLINE EQU 0 ;; and define equate only once
ENDIF ;; (the above 2 lines won't be inserted
;; in subsequent calls of the macro)
call newline ;; call NEWLINE procedure
ENDM ;; end of macro definition
ENDIF ;; end of pass execution
;;
;;** @DisNum ************************** GENERAL PURPOSE MACRO **
;; Display a binary number in ASCII decimal or hexadecimal
IF1 ;; assemble only during Pass 1
@DisNum MACRO number,type,digits,sign
;; Test for required parameters first
IFB <number> ;; was number parameter specified?
.ERR ;; no, exit with error message
%OUT @DisNum macro: "number" parameter not specified.
ELSE
IFB <type> ;; was type of output specified?
.ERR ;; no, exit with error message
%OUT @DisNum macro: "type" parameter not specified.
ELSE
IF type NE 10 AND type NE 16
.ERR
%OUT @DisNum Macro: Illegal "type" specified.
ELSE ;; parameters OK
IF type EQ 10 ;; decimal conversion specified?
IFNDEF EXT_BIN2DEC ;; was EXT_BIN2DEC defined?
EXTRN bin2dec:NEAR ;; no, insert EXTRN declaration
EXT_BIN2DEC EQU 0 ;; and equate only once
ENDIF
ELSE ;; hex. conversion specified
IFNDEF EXT_BIN2HEX ;; was EXT_BIN2HEX defined?
EXTRN bin2hex:NEAR ;; no, insert EXTRN declaration
EXT_BIN2HEX EQU 0 ;; and equate only once
ENDIF
ENDIF
;;
;; Begin code insertion
push ax ;; save registers
push cx
push dx
;;
mov ax,number ;; put number in AX
;;
IFNB <digits> ;; was digits argument specified?
mov ch,digits ;; yes, put value in CH
ELSE ;; otherwise
mov ch,1 ;; default to disp. at least 1 digit
ENDIF
;;
IFNB <sign> ;; was the sign argument specified?
mov dx,sign ;; yes, so put it in DX
ELSE ;; otherwise
mov dx,0 ;; default to unsigned
ENDIF
;;
IF type EQ 10 ;; decimal conversion specified?
call bin2dec
ELSE ;; hex. conversion specified
call bin2hex
ENDIF
;;
pop dx ;; restore registers
pop cx
pop ax
;;
ENDIF ;; parameters OK
ENDIF
ENDIF
;;
ENDM ;; end of macro definition
ENDIF ;; end of pass execution
;;
;;** @GetDate ************************* GENERAL PURPOSE MACRO **
;; Get the system date
IF1 ;; assemble only during Pass 1
@GetDate MACRO
mov ah,2Ah ;; load func. number
@DosCall ;; call MS-DOS
ENDM ;; end of macro definition
ENDIF ;; end of pass execution
;;
;;** @GetTime ************************* GENERAL PURPOSE MACRO **
;; Get the system time
IF1 ;; assemble only during Pass 1
@GetTime MACRO
mov ah,2Ch ;; load func. number
@DosCall ;; call MS-DOS
ENDM ;; end of macro definition
ENDIF ;; end of pass execution
;;
;;** @DiskRead ************************ GENERAL PURPOSE MACRO **
;; Read from logical sector(s)
IF1 ;; assemble only during Pass 1
@DiskRead MACRO
int 25h ;; execute absolute disk-read interrupt
ENDM ;; end of macro definition
ENDIF ;; end of pass execution
;;
;;** @DiskWrite *********************** GENERAL PURPOSE MACRO **
;; Write to logical sector(s)
IF1 ;; assemble only during Pass 1
@DiskWrite MACRO
int 26h ;; execute absolute disk-write interrupt
ENDM ;; end of macro definition
ENDIF ;; end of pass execution
;;
;;** @GetDOSVersion ******************* GENERAL PURPOSE MACRO **
;; Get DOS Version number
IF1 ;; assemble only during Pass 1
@GetDOSVersion MACRO
push bx ;; save registers destroyed
push cx
mov ah,30h ;; load func. number
@DosCall ;; call MS-DOS
pop cx ;; restore registers
pop bx
ENDM ;; end of macro definition
ENDIF ;; end of pass execution
;;
;;** GetDOSVer ********************** GENERAL PURPOSE MACRO **
;; Get DOS Version number
IF1 ;; assemble only during Pass 1
@GetDOSVer MACRO
IFNDEF EXT_GDOSV ;; was symbol defined?
EXTRN GETDOSV:NEAR ;; no, insert EXTRN only once
EXT_GDOSV EQU 0 ;; and define equate only once
ENDIF ;; (the above 2 lines won't be inserted
;; in subsequent calls of the macro)
call dosver ;; call library routine
ENDM ;; end of macro definition
ENDIF ;; end of pass execution
;;
;;** @DisDOSVer ********************** GENERAL PURPOSE MACRO **
;; Get and display DOS Version number
IF1 ;; assemble only during Pass 1
@DisDOSVer MACRO
IFNDEF EXT_DDOSV ;; was symbol defined?
EXTRN DOSV2CON:NEAR ;; no, insert EXTRN only once
EXT_DDOSV EQU 0 ;; and define equate only once
ENDIF ;; (the above 2 lines won't be inserted
;; in subsequent calls of the macro)
call dosv2con ;; call library routine
ENDM ;; end of macro definition
ENDIF ;; end of pass execution
;;
;;** @ChangeCase ********************** GENERAL PURPOSE MACRO **
;; Change case of character
IF1 ;; execute only on pass 1
@ChangeCase MACRO char,type
IFB <char> ;; was char to be converted specified?
.ERR ;; no, generate error and output message
%OUT @ChangeCase macro: "char" parameter not defined!
ELSE ;; otherwise
mov al,char ;; load char into AL
ENDIF
;;
IFB <type> ;; was type of conversion specified?
mov ah,0 ;; no, so Load 0 into AH
ELSE
mov ah,type ;; load type of conversion into AH
ENDIF
;;
IFNDEF EXT_CHGCASE ;; was EXT_CHGCASE symbol defined?
EXTRN CHGCASE:NEAR ;; no, insert EXTRN only once
EXT_CHGCASE EQU 0 ;; and define equate only once
ENDIF ;; (the above 2 lines won't be inserted
;; in subsequent calls of the macro)
;;
call chgcase ;; call change-case library procedure
ENDM ;; end of macro definition
ENDIF ;; end of pass execution
;;
;;** @Case **************************** GENERAL PURPOSE MACRO **
;; CASE macro for assembly language
@Case MACRO key,case_list,jmp_labels
??tmp_1 = 0
IRP match,<&case_list> ;; sequence through cases
??tmp_1 = ??tmp_1 + 1 ;; set index number
cmp key,&&match ; case match?
??tmp_2 = 0
IRP retl,<&jmp_labels> ;; sequence through jumps
??tmp_2 = ??tmp_2 + 1 ;; ... until index matches
IF (??tmp_1 EQ ??tmp_2)
je &&&retl ; yes!
EXITM
ENDIF ;; end condition check
ENDM ;; end 2nd IRP block
ENDM ;; end 1st IRP block
ENDM ;; end macro definition
;;
;;***************************************************************
;; Use the @PushAll and @PopAll macros instead of the
;; PUSHA and POPA instructions supported by the
;; 80186/80188/80286/80386 processors to maintain
;; compatibility with the 8086/8088 processors.
;;
;;** @PushAll ************************* GENERAL PURPOSE MACRO **
;; Push all registers
IF1 ;; execute only during pass 1
@PushAll MACRO ;; save all registers onto the stack
push ax
push bx
push cx
push dx
push bp
push di
push si
ENDM ;; end of macro definition
ENDIF ;; end of pass execution
;;
;;** @PopALL ************************** GENERAL PURPOSE MACRO **
;; Pop all registers
IF1 ;; execute only during pass 1
@PopAll MACRO ;; restore all registers off of the stack
pop si
pop di
pop bp
pop dx
pop cx
pop bx
pop ax
ENDM ;; end of macro definition
ENDIF ;; end of pass execution
;;
;;** @ExitToDos *********************** GENERAL PURPOSE MACRO **
;; Terminate process with optional ERRORLEVEL settings
IF1 ;; execute only during pass 1
@ExitToDOS MACRO errorcode
IFB <errorcode> ;; was an errorcode specified?
mov ax,4C0Oh ;; no, load func. & errorlevel 0 into AX
ELSE ;; otherwise
mov ah,4Ch ;; load function
mov al,errorcode ;; and errorlevel separately
ENDIF
;;
@DosCall ;; call MS-DOS
ENDM ;; end of macro definition
ENDIF ;; end of pass execution
;;
;;***************************************************************
;; END OF MACRO DEFINITIONS
;;***************************************************************
.LIST ; restore listing back to normal
; End of macro definitions include file.

T. Ment
2020-06-09 18:44:00 UTC
Permalink
Post by Johann 'Myrkraverk' Oskarsson
Post by T. Ment
https://openlibrary.org/
Thanks; though I just log in and read on my tablet. I don't feel the
need to jump through hoops to download the text & code.
At least not yet.
During the pandemic, they allowed unlimited borrowers of a book, and on
June 1, 2020, a group of publishers sued them.

Likely they will lose the suit and be forced to shut down. Get what you
can while it lasts.
T. Ment
2020-06-06 19:39:39 UTC
Permalink
Post by T. Ment
Open Library has DOS programming books. Not many, but some good ones.
As I said, not many. They need more.

I have DOS programming books I can't keep forever. They take donations,
but their scan backlog is a year. They do accept money to sponsor a book
for expedited scanning.

They also say in the future, you can sponsor your own book donations. I
emailed them to ask when, I'll post more when they reply.

How about it, who has books to give them. Your books will be lost when
you die. Your heirs won't know what to do with them.
Loading...