• Open Library books

    From T. Ment@21:1/5 to All on Fri Jun 5 15:49:18 2020
    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.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Johann 'Myrkraverk' Oskarsson@21:1/5 to T. Ment on Sat Jun 6 20:20:00 2020
    On 05/06/2020 11:49 pm, T. Ment wrote:
    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

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From T. Ment@21:1/5 to Johann 'Myrkraverk' Oskarsson on Sat Jun 6 15:22:17 2020
    On Sat, 6 Jun 2020 20:20:00 +0800, Johann 'Myrkraverk' Oskarsson wrote:

    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.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From T. Ment@21:1/5 to T. Ment on Sat Jun 6 17:55:22 2020
    On Sat, 06 Jun 2020 15:22:17 +0000, T. Ment wrote:

    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.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From T. Ment@21:1/5 to T. Ment on Sat Jun 6 19:39:39 2020
    XPost: alt.os.development

    On Fri, 05 Jun 2020 15:49:18 +0000, T. Ment wrote:

    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.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From T. Ment@21:1/5 to Johann 'Myrkraverk' Oskarsson on Tue Jun 9 18:44:00 2020
    On Sat, 6 Jun 2020 20:20:00 +0800, Johann 'Myrkraverk' Oskarsson wrote:

    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.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From T. Ment@21:1/5 to T. Ment on Fri Jun 12 05:57:43 2020
    On Sat, 06 Jun 2020 17:55:22 +0000, T. Ment wrote:

    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.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)