page ,132 ; title New_C.C - DOS entry to the KWC's 'C' programs ; ; This module has been modified extensively for my personal ; use. ; ; name XCMAIN -- initiate execution of C program ; ; description This is the main module for a C program on the ; DOS implementation. It initializes the segment ; registers, sets up the stack, and calls the C main ; function _main with a pointer to the remainder of ; the command line. ; ; Also defined in this module is the exit entry point ; XCEXIT. ; ; $salut (4,12,18,41) SETBLOCK EQU 4AH ;MODIFY ALLOCATED MEMORY BLOCKS ;ES = SEGMENT OF THE BLOCK ;BX = NEW REQUESTED BLOCK SIZE ; IN PARAGRAPHS ;OUTPUT: BX=MAX SIZE POSSIBLE IF CY SET ;AX = ERROR CODE IF CY SET RET_CD_EXIT EQU 4CH ;EXIT TO DOS, PASSING RETURN CODE ;AL=RETURN CODE RET_EXIT equ 4ch ;AN000; ;terminate ABORT equ 2 ;AN000; ;if >=, retry XABORT equ 1 ;AN000; ;errorlevel return in al extrn _inmain:near ;AC000; extrn _Reset_appendx:near ;AN000; extrn _old_int24_off:dword ;AN000; psp segment at 0 ;<--emk psp_ret dw ? ;int 20h psp_memsz dw ? ;memory size org 2ch psp_env dw ? ;segid of environment org 80h psp_parlen db ? ;length of DOS command line parms psp_par db 127 dup(?) ;DOS command line parms psp ends page ; ; The following segment serves only to force "pgroup" lower in ; memory. ; base segment PARA PUBLIC 'DATA' db 00dh,00ah db "----------\x0d\x0a" db " DOS ATTRIB function \x0d\x0a" db "--------------------\x0d\x0a" db 00dh,00ah,01ah base ends ; ; The data segment defines locations which contain the offsets ; of the base and top of the stack. ; _data segment PARA public 'DATA' irp name,<_top,_base,_cs,_ss,_psp,_env,_rax,_rbx,_rcx,_rdx,_rds,_rsi,_rbp,_res,_rdi> public name name dw 0 endm _data ends ; ; The stack segment is included to prevent the warning from the ; linker, and also to define the base (lowest address) of the stack. ; stack segment PARA stack 'data' SBase dw 128 dup (?) stack ends null segment para public 'BEGDATA' null ends const segment word public 'CONST' const ends _bss segment word public 'BSS' _bss ends pgroup group base,_text dgroup group null, _data, const, _bss, stack page ; ; The main program must set up the initial segment registers ; and the stack pointer, and set up a far return to the DOS ; exit point at ES:0. The command line bytes from the program ; segment prefix are moved onto the stack, and a pointer to ; them supplied to the C main module _main (which calls main). ; _text segment PARA public 'CODE' public XCMAIN assume cs:pgroup assume ds:psp ;<--emk assume es:psp ;<--emk assume ss:stack ;<--emk XCMAIN proc far mov ax,dgroup mov ds,ax ;initialize ds and ss assume ds:dgroup mov bx,psp_memsz ;total memory size (paragraphs) sub bx,ax test bx,0f000h ; $IF Z ;branch if more than or equal 64K bytes JNZ $$IF1 mov cl,4 shl bx,cl ;highest available byte ; $ELSE JMP SHORT $$EN1 $$IF1: mov bx,0fff0h ; $ENDIF $$EN1: cli ; disable interrupts while changing stack <---kwc mov ss,ax ; set ss <---kwc mov sp,bx ; set stack pointer <---kwc sti ;enable interrupts assume ss:DGroup ;<--emk mov _ss,ss mov _cs,cs mov _top,bx ;save top of stack mov ax,offset DGroup:SBase mov _base,ax ;store ptr to bottom of stack ; code added here to allow allocates and exec's in the c code ; we will have to calculate the size of the code that has been loaded mov bx,sp ; bx = length of the stack shr bx,1 shr bx,1 shr bx,1 shr bx,1 ; bx = number of paragraphs in stack, add bx,1 ; (fudge factor!)<--emk ,was 10 mov ax,ss add bx,ax ; bx = paragraph a little past the stack mov ax,es ; ax = paragraph of the psp sub bx,ax ; bx = number of paragraphs in code mov ah,setblock int 021h ; end of added code! mov _psp,es ; save pointer to psp for setblock <---kwc mov cl,psp_parlen ;get number of bytes <--emk xor ch,ch ;cx = number of bytes of parms! mov si,offset psp_par ;point to DOS command line parms <--emk ; more modified code, picking up argv[0] from the environment! mov ds,psp_env ;set ds to segid of environment from es:psp assume ds:nothing mov _env,ds ;remember where environment is mov si,0 ;clear index to step thru env ;The env has a set of keyword=operand, each one ending with a single null byte. ;At the end of the last one is a double null. We are looking for the end of ;all these keywords, by looking for the double null. ; $DO COMPLEX JMP SHORT $$SD4 $$DO4: inc si ;bump index to look at next byte in env ; $STRTDO $$SD4: cmp word ptr [si],0 ;is this a double null delimiter? ; $ENDDO E ;ifdouble null found, exit JNE $$DO4 ;At end of env is the double null and a word counter add si,4 ;step over this double null delimiter ; and the following word counter push si ;save pointer to next field in env ;This is the invocation statement, including the path name, even if not specified ;but supplied by PATH. ;continue stepping thru env looking for one more null byte, which indicates ;the end of the invocation command. ; $DO $$DO7: lodsb ;get a byte from env to al cmp al,0 ;is this a null byte? ; $ENDDO E ;quit if null is found JNE $$DO7 mov bx,si ; bx -> asciiz zero pop si ; si -> first byte of agrv[0], the invocation command sub bx,si ; bx = length of argv[0] mov dx,bx ; (save for the copy later) dec dx add bx,cx ; add in the length of the rest of the parms inc bx ; add one for the asciiz zero! and bx,0fffeh ;force even number of bytes add bx,2 ;adjust for possible rounding error sub sp,bx ;allocate space on stack mov di,sp ; (es:di) -> where we will put the stuff push es mov ax,ss mov es,ax xchg cx,dx ; length of argv[0] to copy, save length of parms rep movsb ; (ds:si) already point to argv[0] pop es mov ss:byte ptr [di],' ' ;store trailing blank! inc di mov _rdi,di ;AN000; save start of command parms xchg cx,dx ; restore length of parms ; $IF NCXZ ;if some bytes to move, JCXZ $$IF9 mov si,offset psp_par ;point to DOS command line parms in psp ; $DO $$DO10: mov al,es:[si] ;move bytes to stack mov ss:[di],al inc si inc di ; $ENDDO LOOP LOOP $$DO10 ; $ENDIF ;bytes to move? $$IF9: xor ax,ax mov ss:[di],al ;store null byte mov ax,ss mov ds,ax ;es, ds, and ss are all equal assume ds:DGroup mov es,ax ;es, ds, and ss are all equal assume es:DGroup mov ax,_rdi ;AN000; restore offset of parms on stack push ax ;ptr to command line call _inmain ;AC000; call C main mov ah,ret_cd_exit ;return to DOS int 21h ;errorlevel ret code in al XCMAIN endp page ; ; name XCEXIT -- terminate execution of C program ; ; description This function terminates execution of the current ; program by returning to DOS. The error code ; argument normally supplied to XCEXIT is ignored ; in this implementation. ; ; input - al = binary return code for dos/ERRORLEVEL ; assume cs:PGroup assume ds:DGroup assume es:DGroup assume ss:DGroup public xcexit XCEXIT proc far mov ah,ret_cd_exit ; <--- kwc int 021h ; <--- kwc XCEXIT endp ;-------------------------------------------------------------------------- PAGE CENTER MACRO NAMELIST PUSH BP ; SAVE CURRENT BP MOV BP,SP ; POINT AT STACK WITH BP WORKOFS = 0 IRP ANAME, ; FOR EACH WORKING VARIABLE IFNB <&ANAME> WORKOFS = WORKOFS-2 ; WE WILL ALLOCATE ONE DOEQU &ANAME,%WORKOFS ; WORD ON THE STACK THAT ENDIF ENDM ; IS UNDER SS,BP ADD SP,WORKOFS ENDM DOEQU MACRO NAME,VALUE &NAME EQU &VALUE ENDM CEXIT MACRO VALUE MOV SP,BP POP BP RET ENDM PAGE ; INPUT PARAMATERS PASSED ON STACK PARMS STRUC OLD_BP DW ? ; SAVED BP RETADD DW ? ; RETURN ADDRESS PARM_1 DW ? PARM_2 DW ? PARM_3 DW ? PARM_4 DW ? PARM_5 DW ? PARM_6 DW ? PARM_7 DW ? PARM_8 DW ? PARMS ENDS SAVE_SS DW 0 SAVE_SP DW 0 PAGE ;************************************************************************ ; ; ; Subroutine Name: ; ; getpspbyte ; ; ; ; Subroutine Function: ; ; get a byte from PSP ; ; ; ; ; Input: ; ; SS:[BP]+PARM1 = offset in PSP ; ; ; ; Output: ; ; AL = byte from PSP:offset ; ; ; ; C calling convention: ; ; char = getpspbyte(offset); ; ; ; ;************************************************************************ MOFFSET EQU PARM_1 ;AN000; ASSUME CS:PGROUP ;AN000; ASSUME DS:DGROUP ;AN000; ASSUME ES:DGROUP ;AN000; ASSUME SS:DGROUP ;AN000; PUBLIC _GETPSPBYTE ;AN000; _GETPSPBYTE PROC NEAR ;AN000; CENTER ;AN000; PUSH DS ;AN000; MOV DS,_PSP ;AN000; get save PSP segment MOV SI,[BP].MOFFSET ;AN000; get offset into PSP LODSB ;AN000; get PSP byte MOV AH,0 ;AN000; zero high byte POP DS ;AN000; CEXIT ;AN000; _GETPSPBYTE ENDP ;************************************************************************ ; ; ; Subroutine Name: ; ; putpspbyte ; ; ; ; Subroutine Function: ; ; put a byte into PSP ; ; ; ; ; Input: ; ; SS:[BP]+MVALUE = byte in AL ; ; SS:[BP]+MOFFSET = offset in PSP ; ; ; ; Output: ; ; none ; ; ; ; C calling convention: ; ; putpspbyte(offset,char); ; ; ; ;************************************************************************ MVALUE EQU PARM_2 ;AN000; MOFFSET EQU PARM_1 ;AN000; ASSUME CS:PGROUP ;AN000; ASSUME DS:DGROUP ;AN000; ASSUME ES:DGROUP ;AN000; ASSUME SS:DGROUP ;AN000; PUBLIC _PUTPSPBYTE ;AN000; _PUTPSPBYTE PROC NEAR ;AN000; CENTER ;AN000; PUSH ES ;AN000; MOV AX,[BP].MVALUE ;AN000; get byte to store in PSP MOV ES,_PSP ;AN000; get saved PSP segment MOV DI,[BP].MOFFSET ;AN000; get offset in PSP STOSB ;AN000; store the byte POP ES ;AN000; CEXIT ;AN000; _PUTPSPBYTE ENDP ;------------------------------------------------------------------- ; ; MODULE: crit_err_handler() ; ; PURPOSE: Supplies assembler exit routines for ; critical error situations ; ; CALLING FORMAT: ; crit_err_handler; ;------------------------------------------------------------------- public _crit_err_handler ;AN000; public vector ;AN000; vector dd 0 ;AN000; ; ;AN000; _crit_err_handler proc near ;AN000; pushf ;AN000; push ax ; save registers ;AN000; push ds ;AN000; mov ax,dgroup ;get C data segment ;AN000; mov ds,ax ;AN000; mov ax,word ptr ds:_old_int24_off ;get int24 offset ;AN000; mov word ptr cs:vector,ax ;AN000; mov ax,word ptr ds:_old_int24_off+2 ;get int24 segment ;AN000; mov word ptr cs:vector+2,ax ;AN000; pop ds ;restore registers ;AN000; pop ax ;AN000; ; ;AN000; call dword ptr cs:vector ; invoke DOS err hndlr ;AN000; cmp al,ABORT ; what was the user's response ;AN000; jnge retry ; ;AN000; ; ;AN000; mov ax,dgroup ;get C data segment ;AN000; mov ds,ax ;AN000; mov es,ax ;AN000; call _Reset_appendx ; restore user's orig append/x ;AN000; ; ;AN000; mov ax,(RET_EXIT shl 8)+XABORT ; return to DOS w/criterr error ;AN000; int 21h ; ;AN000; retry: ;AN000; iret ;AN000; ; ;AN000; _crit_err_handler endp ;AN000; _text ends ;AN000; end XCMAIN ;AN000;