| 1 | ;
|
|---|
| 2 | ; EMXL.ASM -- emx loader (emxl.exe)
|
|---|
| 3 | ;
|
|---|
| 4 | ; Copyright (c) 1991-1996 by Eberhard Mattes
|
|---|
| 5 | ;
|
|---|
| 6 | ; This file is part of emx.
|
|---|
| 7 | ;
|
|---|
| 8 | ; emx is free software; you can redistribute it and/or modify it
|
|---|
| 9 | ; under the terms of the GNU General Public License as published by
|
|---|
| 10 | ; the Free Software Foundation; either version 2, or (at your option)
|
|---|
| 11 | ; any later version.
|
|---|
| 12 | ;
|
|---|
| 13 | ; emx is distributed in the hope that it will be useful,
|
|---|
| 14 | ; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|---|
| 15 | ; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|---|
| 16 | ; GNU General Public License for more details.
|
|---|
| 17 | ;
|
|---|
| 18 | ; You should have received a copy of the GNU General Public License
|
|---|
| 19 | ; along with emx; see the file COPYING. If not, write to
|
|---|
| 20 | ; the Free Software Foundation, 59 Temple Place - Suite 330,
|
|---|
| 21 | ; Boston, MA 02111-1307, USA.
|
|---|
| 22 | ;
|
|---|
| 23 | ; <START_OF_EXCEPTION>
|
|---|
| 24 | ; As a special exception, if you bind emxl.exe to an executable file
|
|---|
| 25 | ; (using emxbind), this does not cause the resulting executable file
|
|---|
| 26 | ; to be covered by the GNU General Public License. This exception
|
|---|
| 27 | ; does not however invalidate any other reasons why the executable
|
|---|
| 28 | ; file might be covered by the GNU General Public License. However,
|
|---|
| 29 | ; if you bind a modified copy of emxl.exe to an executable file, you
|
|---|
| 30 | ; have to include source code for emxl.exe. When distributing
|
|---|
| 31 | ; emxl.exe as separate file, the GPL applies without exceptions to
|
|---|
| 32 | ; emxl.exe.
|
|---|
| 33 | ;
|
|---|
| 34 | ; If you modify this file, you have to replace the text between
|
|---|
| 35 | ; the outer <START_OF_EXCEPTION> and <END_OF_EXCEPTION> markers with
|
|---|
| 36 | ; the following paragraph (which currently does not apply as you have
|
|---|
| 37 | ; not modified this file):
|
|---|
| 38 | ;
|
|---|
| 39 | ; As a special exception, if you bind emxl.exe to an executable file
|
|---|
| 40 | ; (using emxbind), this does not cause the resulting executable file
|
|---|
| 41 | ; to be covered by the GNU General Public License. The source code
|
|---|
| 42 | ; for emxl.exe must be distributed with the executable file. This
|
|---|
| 43 | ; exception does not however invalidate any other reasons why the
|
|---|
| 44 | ; executable file might be covered by the GNU General Public License.
|
|---|
| 45 | ; <END_OF_EXCEPTION>
|
|---|
| 46 | ;
|
|---|
| 47 |
|
|---|
| 48 | INCLUDE EMX.INC
|
|---|
| 49 | INCLUDE HEADERS.INC
|
|---|
| 50 | INCLUDE VERSION.INC
|
|---|
| 51 |
|
|---|
| 52 | .8086
|
|---|
| 53 |
|
|---|
| 54 | ;
|
|---|
| 55 | ; Data (the name SV_DATA stems from emx, we're using EMX.INC!)
|
|---|
| 56 | ;
|
|---|
| 57 | SV_DATA SEGMENT
|
|---|
| 58 |
|
|---|
| 59 | PSP_SEG WORD ? ; Program prefix segment
|
|---|
| 60 | ENV_SEG WORD ? ; Environment segment
|
|---|
| 61 | NAME_OFF WORD ? ; Offset of prog name (ENV_SEG)
|
|---|
| 62 | NAME_LEN WORD ? ; Length of prog name
|
|---|
| 63 |
|
|---|
| 64 | ;
|
|---|
| 65 | ; Parameter block for INT 21H, AX=4B00H
|
|---|
| 66 | ;
|
|---|
| 67 | PAR_BLOCK WORD 0 ; Copy parent's environment
|
|---|
| 68 | WORD OFFSET CMD_LINE ; Command line
|
|---|
| 69 | WORD SEG CMD_LINE
|
|---|
| 70 | WORD 5CH ; FCB1
|
|---|
| 71 | PB_SEG1 WORD ?
|
|---|
| 72 | WORD 6CH ; FCB2
|
|---|
| 73 | PB_SEG2 WORD ?
|
|---|
| 74 |
|
|---|
| 75 | ;
|
|---|
| 76 | ; DPMI_FLAG is non-zero if a DPMI server has been found, but no
|
|---|
| 77 | ; VCPI server
|
|---|
| 78 | ;
|
|---|
| 79 | DPMI_FLAG BYTE FALSE ; Initially FALSE
|
|---|
| 80 |
|
|---|
| 81 | ;
|
|---|
| 82 | ; Messages
|
|---|
| 83 | ;
|
|---|
| 84 | $EMX_NOT_FOUND BYTE "emx not found", CR, LF, "$"
|
|---|
| 85 | $RSX_NOT_FOUND BYTE "rsx not found, DPMI not supported by emx", CR, LF, "$"
|
|---|
| 86 | $USE_EMXBIND BYTE "Use emxbind", CR, LF, "$"
|
|---|
| 87 | $BAD_ENV BYTE "Bad environment", CR, LF, "$"
|
|---|
| 88 |
|
|---|
| 89 | ;
|
|---|
| 90 | ; Names of devices implemented by expanded memory managers
|
|---|
| 91 | ;
|
|---|
| 92 | EMS_FNAME BYTE "EMMXXXX0", 0 ; EMS enabled
|
|---|
| 93 | NOEMS_FNAME1 BYTE "EMMQXXX0", 0 ; EMS disabled
|
|---|
| 94 | NOEMS_FNAME2 BYTE "$MMXXXX0",0 ; EMS disabled
|
|---|
| 95 |
|
|---|
| 96 | ;
|
|---|
| 97 | ; Names of environment variables
|
|---|
| 98 | ;
|
|---|
| 99 | $EMX BYTE "EMX", 0
|
|---|
| 100 | $PATH BYTE "PATH", 0
|
|---|
| 101 |
|
|---|
| 102 | ;
|
|---|
| 103 | ; Name of emx.exe for searching in the current working directory and PATH
|
|---|
| 104 | ;
|
|---|
| 105 | $EMX_EXE BYTE "emx.exe", 0
|
|---|
| 106 | EMX_EXE_LEN = THIS BYTE - $EMX_EXE ; Length of name, with 0
|
|---|
| 107 |
|
|---|
| 108 | ;
|
|---|
| 109 | ; This command line is passed to emx.exe
|
|---|
| 110 | ;
|
|---|
| 111 | CMD_LINE BYTE 7 ; 7 bytes
|
|---|
| 112 | BYTE "-/" ; Special marker
|
|---|
| 113 | CMD_LINE_PSP BYTE "0000" ; PSP_SEG, hexadecimal
|
|---|
| 114 | BYTE "/" ; Another special marker
|
|---|
| 115 | BYTE CR ; End of command line
|
|---|
| 116 |
|
|---|
| 117 | ;
|
|---|
| 118 | ; Build path name here when using directory from PATH environment variable
|
|---|
| 119 | ;
|
|---|
| 120 | PGM_NAME BYTE 128 DUP (?)
|
|---|
| 121 | PGM_NAME_END LABEL BYTE
|
|---|
| 122 |
|
|---|
| 123 | SV_DATA ENDS
|
|---|
| 124 |
|
|---|
| 125 |
|
|---|
| 126 | ;
|
|---|
| 127 | ; This area will be patched by emxbind
|
|---|
| 128 | ;
|
|---|
| 129 | HDR_SEG SEGMENT
|
|---|
| 130 | PATCH LABEL BIND_HEADER
|
|---|
| 131 | BYTE "emx ", VERSION, 0
|
|---|
| 132 | BYTE (SIZE BIND_HEADER - HDR_VERSION_LEN) DUP (0)
|
|---|
| 133 | HDR_SEG ENDS
|
|---|
| 134 |
|
|---|
| 135 | ;
|
|---|
| 136 | ; Code
|
|---|
| 137 | ;
|
|---|
| 138 | INIT_CODE SEGMENT
|
|---|
| 139 |
|
|---|
| 140 | ASSUME CS:INIT_CODE
|
|---|
| 141 | ASSUME DS:NOTHING, ES:NOTHING
|
|---|
| 142 |
|
|---|
| 143 | ;
|
|---|
| 144 | ; Setup data segment. Note: This macro modifies AX.
|
|---|
| 145 | ;
|
|---|
| 146 | SET_DS MACRO
|
|---|
| 147 | MOV AX, SV_DATA
|
|---|
| 148 | MOV DS, AX
|
|---|
| 149 | ASSUME DS:SV_DATA
|
|---|
| 150 | ENDM
|
|---|
| 151 |
|
|---|
| 152 | ;
|
|---|
| 153 | ; The program starts here
|
|---|
| 154 | ;
|
|---|
| 155 | ENTRY: SET_DS ; Setup data segment
|
|---|
| 156 | MOV PSP_SEG, ES ; Save program prefix segment
|
|---|
| 157 | CALL INIT ; Initialize
|
|---|
| 158 | CALL CHECK_DPMI ; Check for DPMI
|
|---|
| 159 | CALL GET_NAME ; Get program name
|
|---|
| 160 | CALL BIND_HDR ; Check patch area
|
|---|
| 161 | CALL TRY_EMX_ENV ; Use EMX environment variable
|
|---|
| 162 | CALL TRY_CWD ; Search current directory
|
|---|
| 163 | CALL TRY_PATH ; Use PATH environment variable
|
|---|
| 164 | LEA DX, $EMX_NOT_FOUND ; Give up
|
|---|
| 165 | CMP DPMI_FLAG, FALSE
|
|---|
| 166 | JE FAIL
|
|---|
| 167 | LEA DX, $RSX_NOT_FOUND
|
|---|
| 168 | FAIL: JMP ABORT
|
|---|
| 169 |
|
|---|
| 170 | ;
|
|---|
| 171 | ; Initialization
|
|---|
| 172 | ;
|
|---|
| 173 | INIT PROC NEAR
|
|---|
| 174 | MOV AX, PSP_SEG
|
|---|
| 175 | MOV PB_SEG1, AX ; Fill in parameter block
|
|---|
| 176 | MOV PB_SEG2, AX ; for DOS function 4BH (EXEC)
|
|---|
| 177 | MOV ES, AX
|
|---|
| 178 | MOV AX, ES:[2CH] ; Get environment segment
|
|---|
| 179 | MOV ENV_SEG, AX
|
|---|
| 180 | LEA BX, CMD_LINE_PSP ; Insert PSP_SEG, hexadecimal
|
|---|
| 181 | MOV CX, 0404H ; 4 digits, shift by 4 bits
|
|---|
| 182 | MOV DX, PSP_SEG
|
|---|
| 183 | INIT_1: ROL DX, CL
|
|---|
| 184 | MOV AL, DL
|
|---|
| 185 | AND AL, 0FH
|
|---|
| 186 | ADD AL, "0"
|
|---|
| 187 | CMP AL, "9"
|
|---|
| 188 | JBE INIT_2
|
|---|
| 189 | ADD AL, "A" - ("0" + 10)
|
|---|
| 190 | INIT_2: MOV [BX], AL
|
|---|
| 191 | INC BX
|
|---|
| 192 | DEC CH
|
|---|
| 193 | JNZ INIT_1
|
|---|
| 194 | RET
|
|---|
| 195 | INIT ENDP
|
|---|
| 196 |
|
|---|
| 197 |
|
|---|
| 198 | ;
|
|---|
| 199 | ; Check for DPMI server
|
|---|
| 200 | ;
|
|---|
| 201 | CHECK_DPMI PROC NEAR
|
|---|
| 202 | MOV AX, 1687H ; Check for DPMI server
|
|---|
| 203 | INT 2FH
|
|---|
| 204 | OR AX, AX ; Server present?
|
|---|
| 205 | JNZ DPMI_RET ; No -> call emx.exe
|
|---|
| 206 | TEST BX, 1 ; 32-bit programs supported?
|
|---|
| 207 | JZ DPMI_RET ; No -> hope we can get VCPI
|
|---|
| 208 | ;
|
|---|
| 209 | ; Now we have detected a DPMI server. Run rsx if we don't find a
|
|---|
| 210 | ; VCPI server. First we have to check for an EMM.
|
|---|
| 211 | ;
|
|---|
| 212 | ; First, check the EMS interrupt vector
|
|---|
| 213 | ;
|
|---|
| 214 | MOV AX, 3567H ; Get interrupt vector 67H
|
|---|
| 215 | INT 21H
|
|---|
| 216 | MOV AX, ES
|
|---|
| 217 | OR AX, BX ; Is the vector 0:0 ?
|
|---|
| 218 | JZ NO_VCPI ; Yes -> no VCPI
|
|---|
| 219 | ;
|
|---|
| 220 | ; Check for an EMM with EMS enabled
|
|---|
| 221 | ;
|
|---|
| 222 | LEA DX, EMS_FNAME
|
|---|
| 223 | CALL CHECK_EMM ; EMS present?
|
|---|
| 224 | JC EMM_DISABLED ; No -> try disabled EMS
|
|---|
| 225 | ;
|
|---|
| 226 | ; Check EMM status
|
|---|
| 227 | ;
|
|---|
| 228 | MOV AH, 40H ; Get EMM status
|
|---|
| 229 | INT 67H
|
|---|
| 230 | CMP AH, 0 ; Successful?
|
|---|
| 231 | JE EMM_OK ; Yes -> check VCPI
|
|---|
| 232 | JMP NO_VCPI ; No VCPI
|
|---|
| 233 |
|
|---|
| 234 | ;
|
|---|
| 235 | ; Check for an EMM with EMS disabled (using undocumented "features")
|
|---|
| 236 | ;
|
|---|
| 237 | EMM_DISABLED: LEA DX, NOEMS_FNAME1
|
|---|
| 238 | CALL CHECK_EMM
|
|---|
| 239 | JNC EMM_OK ; EMM present
|
|---|
| 240 | LEA DX, NOEMS_FNAME2
|
|---|
| 241 | CALL CHECK_EMM
|
|---|
| 242 | JC NO_VCPI ; No EMM present -> no VCPI
|
|---|
| 243 | ;
|
|---|
| 244 | ; There is an EMM with EMS enabled or disabled. Check for VCPI
|
|---|
| 245 | ;
|
|---|
| 246 | EMM_OK: MOV AX, 0DE00H ; VCPI presence detection
|
|---|
| 247 | INT 67H
|
|---|
| 248 | CMP AH, 0 ; VCPI present?
|
|---|
| 249 | JE DPMI_RET ; Yes -> use emx
|
|---|
| 250 | ;
|
|---|
| 251 | ; Now we have found a DPMI server, but no VCPI server. We
|
|---|
| 252 | ; should use rsx instead of emx
|
|---|
| 253 | ;
|
|---|
| 254 | NO_VCPI: MOV DPMI_FLAG, NOT FALSE ; Set flag
|
|---|
| 255 | MOV AX, "SR" ; First 2 letters of "RSX"
|
|---|
| 256 | MOV WORD PTR $EMX, AX ; Patch name of env. variable
|
|---|
| 257 | MOV AX, "sr" ; First 2 letters of "rsx.exe"
|
|---|
| 258 | MOV WORD PTR $EMX_EXE, AX ; Patch name of executable
|
|---|
| 259 | DPMI_RET: RET
|
|---|
| 260 | CHECK_DPMI ENDP
|
|---|
| 261 |
|
|---|
| 262 |
|
|---|
| 263 | ;
|
|---|
| 264 | ; Check for the presence of an expanded memory manager (emx.exe
|
|---|
| 265 | ; will perform more complete checks)
|
|---|
| 266 | ;
|
|---|
| 267 | ; In: DX Pointer to device name
|
|---|
| 268 | ;
|
|---|
| 269 | ; Out: NC EMM present
|
|---|
| 270 | ;
|
|---|
| 271 | CHECK_EMM PROC NEAR
|
|---|
| 272 | MOV AX, 3D00H ; Open
|
|---|
| 273 | INT 21H
|
|---|
| 274 | JC CE_RET
|
|---|
| 275 | ;
|
|---|
| 276 | ; A file or device with that name exists. Check for a device
|
|---|
| 277 | ;
|
|---|
| 278 | MOV BX, AX ; Handle
|
|---|
| 279 | MOV AX, 4400H ; IOCTL: get device data
|
|---|
| 280 | INT 21H
|
|---|
| 281 | JC CE_FAIL ; Failure -> no EMM
|
|---|
| 282 | TEST DL, 80H ; Device?
|
|---|
| 283 | JZ CE_FAIL ; No -> no EMM
|
|---|
| 284 | MOV AX, 4407H ; IOCTL: check output status
|
|---|
| 285 | INT 21H
|
|---|
| 286 | JC CE_FAIL ; Failure -> no EMM
|
|---|
| 287 | CMP AL, 0FFH ; Ready?
|
|---|
| 288 | JNE CE_FAIL ; No -> no EMM
|
|---|
| 289 | MOV AH, 3EH ; Close
|
|---|
| 290 | INT 21H
|
|---|
| 291 | CLC
|
|---|
| 292 | CE_RET: RET
|
|---|
| 293 |
|
|---|
| 294 | CE_FAIL: MOV AH, 3EH ; Close
|
|---|
| 295 | INT 21H
|
|---|
| 296 | STC
|
|---|
| 297 | RET
|
|---|
| 298 | CHECK_EMM ENDP
|
|---|
| 299 |
|
|---|
| 300 |
|
|---|
| 301 | ;
|
|---|
| 302 | ; Find program name
|
|---|
| 303 | ;
|
|---|
| 304 | GET_NAME PROC NEAR
|
|---|
| 305 | MOV ES, ENV_SEG ; Scan environment
|
|---|
| 306 | XOR DI, DI ; starting at offset 0
|
|---|
| 307 | MOV CX, 8000H ; Maximum environment size
|
|---|
| 308 | XOR AL, AL ; Search for bytes of zeros
|
|---|
| 309 | CLD ; Incrementing
|
|---|
| 310 | GET_NAME_1: REPNE SCAS BYTE PTR ES:[DI] ; Skip string
|
|---|
| 311 | JNE GET_NAME_ERR ; Count exhausted -> error
|
|---|
| 312 | SCAS BYTE PTR ES:[DI] ; End of environment?
|
|---|
| 313 | JE GET_NAME_9 ; Yes -> program name found
|
|---|
| 314 | LOOP GET_NAME_1 ; Next string, 1st char skipped
|
|---|
| 315 | GET_NAME_ERR: LEA DX, $BAD_ENV ; Bad environment
|
|---|
| 316 | JMP ABORT
|
|---|
| 317 |
|
|---|
| 318 | GET_NAME_9: ADD DI, 2 ; Skip count
|
|---|
| 319 | MOV NAME_OFF, DI ; Offset of program name
|
|---|
| 320 | CALL STRLEN ; Compute length
|
|---|
| 321 | MOV NAME_LEN, CX
|
|---|
| 322 | RET
|
|---|
| 323 | GET_NAME ENDP
|
|---|
| 324 |
|
|---|
| 325 |
|
|---|
| 326 | ;
|
|---|
| 327 | ; Check emxbind patch area
|
|---|
| 328 | ;
|
|---|
| 329 | BIND_HDR PROC NEAR
|
|---|
| 330 | MOV AX, HDR_SEG
|
|---|
| 331 | MOV ES, AX ; Access emxbind patch area
|
|---|
| 332 | ASSUME ES:HDR_SEG
|
|---|
| 333 | CMP PATCH.BND_BIND_FLAG, FALSE ; Bound?
|
|---|
| 334 | JNE BIND_HDR_1 ; Yes -> continue
|
|---|
| 335 | LEA DX, $USE_EMXBIND ; Must be bound to a.out
|
|---|
| 336 | JMP ABORT
|
|---|
| 337 | BIND_HDR_1: RET
|
|---|
| 338 | BIND_HDR ENDP
|
|---|
| 339 |
|
|---|
| 340 | ASSUME ES:NOTHING
|
|---|
| 341 |
|
|---|
| 342 | ;
|
|---|
| 343 | ; Display error message and abort program
|
|---|
| 344 | ;
|
|---|
| 345 | ; In: DX Offset of dollar-delimited error message in SV_DATA
|
|---|
| 346 | ;
|
|---|
| 347 | ABORT: SET_DS ; This can't hurt
|
|---|
| 348 | MOV AH, 09H ; Display string
|
|---|
| 349 | INT 21H
|
|---|
| 350 | MOV AX, 4C01H ; Terminate process, rc=1
|
|---|
| 351 | INT 21H
|
|---|
| 352 |
|
|---|
| 353 | ;
|
|---|
| 354 | ; Try to find emx.exe using EMX environment variable
|
|---|
| 355 | ;
|
|---|
| 356 | TRY_EMX_ENV PROC NEAR
|
|---|
| 357 | LEA BX, $EMX
|
|---|
| 358 | CALL GETENV
|
|---|
| 359 | JC TRY_EMX_ENV_RET
|
|---|
| 360 | MOV DX, DI
|
|---|
| 361 | MOV_DS_ES
|
|---|
| 362 | ASSUME DS:NOTHING
|
|---|
| 363 | CALL SPAWN
|
|---|
| 364 | ASSUME DS:SV_DATA
|
|---|
| 365 | TRY_EMX_ENV_RET:RET
|
|---|
| 366 | TRY_EMX_ENV ENDP
|
|---|
| 367 |
|
|---|
| 368 | ;
|
|---|
| 369 | ; Try to find emx.exe in current working directory
|
|---|
| 370 | ;
|
|---|
| 371 | TRY_CWD PROC NEAR
|
|---|
| 372 | LEA DX, $EMX_EXE
|
|---|
| 373 | CALL SPAWN
|
|---|
| 374 | RET
|
|---|
| 375 | TRY_CWD ENDP
|
|---|
| 376 |
|
|---|
| 377 | ;
|
|---|
| 378 | ; Try to find emx.exe in the directories listed in the PATH environment
|
|---|
| 379 | ; variable
|
|---|
| 380 | ;
|
|---|
| 381 | TRY_PATH PROC NEAR
|
|---|
| 382 | LEA BX, $PATH
|
|---|
| 383 | CALL GETENV
|
|---|
| 384 | JC TRY_PATH_RET
|
|---|
| 385 | MOV SI, DI
|
|---|
| 386 | FIND_2: LEA DI, PGM_NAME
|
|---|
| 387 | FIND_3: MOV AL, ES:[SI]
|
|---|
| 388 | INC SI
|
|---|
| 389 | OR AL, AL
|
|---|
| 390 | JZ TRY_PATH_RET
|
|---|
| 391 | CMP AL, " "
|
|---|
| 392 | JE FIND_3
|
|---|
| 393 | CMP AL, TAB
|
|---|
| 394 | JE FIND_3
|
|---|
| 395 | CMP AL, ";"
|
|---|
| 396 | JE FIND_3
|
|---|
| 397 | FIND_4: CMP DI, OFFSET PGM_NAME_END
|
|---|
| 398 | JAE FIND_5
|
|---|
| 399 | MOV [DI], AL
|
|---|
| 400 | MOV AH, AL
|
|---|
| 401 | INC DI
|
|---|
| 402 | FIND_5: MOV AL, ES:[SI]
|
|---|
| 403 | INC SI
|
|---|
| 404 | OR AL, AL
|
|---|
| 405 | JZ FIND_6
|
|---|
| 406 | CMP AL, " "
|
|---|
| 407 | JE FIND_5
|
|---|
| 408 | CMP AL, TAB
|
|---|
| 409 | JE FIND_5
|
|---|
| 410 | CMP AL, ";"
|
|---|
| 411 | JNE FIND_4
|
|---|
| 412 | FIND_6: DEC SI
|
|---|
| 413 | CMP DI, OFFSET PGM_NAME_END - EMX_EXE_LEN
|
|---|
| 414 | JAE FIND_2
|
|---|
| 415 | ;
|
|---|
| 416 | ; We don't support DBCS in emxl.exe: PATH should not contain directories
|
|---|
| 417 | ; whose name ends with a DBCS characters whose 2nd byte is 2F, 3AH, or 5CH.
|
|---|
| 418 | ;
|
|---|
| 419 | CMP AH, "\"
|
|---|
| 420 | JE FIND_7
|
|---|
| 421 | CMP AH, "/"
|
|---|
| 422 | JE FIND_7
|
|---|
| 423 | CMP AH, ":"
|
|---|
| 424 | JE FIND_7
|
|---|
| 425 | CMP DI, OFFSET PGM_NAME_END
|
|---|
| 426 | JAE FIND_7
|
|---|
| 427 | MOV BYTE PTR DS:[DI], "\"
|
|---|
| 428 | INC DI
|
|---|
| 429 | FIND_7: PUSH ES
|
|---|
| 430 | PUSH SI
|
|---|
| 431 | LEA SI, $EMX_EXE
|
|---|
| 432 | MOV CX, EMX_EXE_LEN
|
|---|
| 433 | FIND_8: LODSB
|
|---|
| 434 | MOV [DI], AL
|
|---|
| 435 | INC DI
|
|---|
| 436 | LOOP FIND_8
|
|---|
| 437 | LEA DX, PGM_NAME
|
|---|
| 438 | CALL SPAWN
|
|---|
| 439 | POP SI
|
|---|
| 440 | POP ES
|
|---|
| 441 | JMP FIND_2
|
|---|
| 442 |
|
|---|
| 443 | TRY_PATH_RET: RET
|
|---|
| 444 |
|
|---|
| 445 | TRY_PATH ENDP
|
|---|
| 446 |
|
|---|
| 447 |
|
|---|
| 448 |
|
|---|
| 449 | ;
|
|---|
| 450 | ; Find environment entry
|
|---|
| 451 | ;
|
|---|
| 452 | ; In: BX Points to zero-terminated name of environment variable
|
|---|
| 453 | ;
|
|---|
| 454 | ; Out: CY Not found
|
|---|
| 455 | ; NC Found
|
|---|
| 456 | ; DI Points to value of environment variable
|
|---|
| 457 | ;
|
|---|
| 458 |
|
|---|
| 459 | ASSUME DS:SV_DATA
|
|---|
| 460 |
|
|---|
| 461 | GETENV PROC NEAR
|
|---|
| 462 | MOV ES, ENV_SEG
|
|---|
| 463 | XOR DI, DI
|
|---|
| 464 | CLD
|
|---|
| 465 | GETENV_NEXT: CMP BYTE PTR ES:[DI], 0 ; Empty environment?
|
|---|
| 466 | JE GETENV_FAILURE ; Yes -> not found
|
|---|
| 467 | PUSH BX ; Save pointer to name
|
|---|
| 468 | GETENV_COMPARE: MOV AL, [BX]
|
|---|
| 469 | CMP AL, ES:[DI] ; Compare names
|
|---|
| 470 | JNE GETENV_DIFF ; Mismatch -> try next one
|
|---|
| 471 | OR AL, AL ; Shouldn't happen (`='!)
|
|---|
| 472 | JZ GETENV_DIFF ; (name matches completely)
|
|---|
| 473 | INC BX
|
|---|
| 474 | INC DI
|
|---|
| 475 | JMP GETENV_COMPARE ; Compare next character
|
|---|
| 476 | GETENV_DIFF: POP BX ; Restore pointer to name
|
|---|
| 477 | OR AL, AL ; End of name reached?
|
|---|
| 478 | JE GETENV_EQUAL ; Yes -> candidate found
|
|---|
| 479 | GETENV_SKIP: XOR AL, AL
|
|---|
| 480 | MOV CX, 32767 ; Search for next entry
|
|---|
| 481 | REPNE SCAS BYTE PTR ES:[DI]
|
|---|
| 482 | JMP GETENV_NEXT ; Check that entry
|
|---|
| 483 |
|
|---|
| 484 | GETENV_EQUAL: CMP BYTE PTR ES:[DI], "=" ; Exact match?
|
|---|
| 485 | JNE GETENV_SKIP ; No -> go to next entry
|
|---|
| 486 | INC DI ; Skip `='
|
|---|
| 487 | CLC
|
|---|
| 488 | JMP GETENV_RET ; Return pointer to value
|
|---|
| 489 |
|
|---|
| 490 | GETENV_FAILURE: STC ; Not found
|
|---|
| 491 | GETENV_RET: RET
|
|---|
| 492 |
|
|---|
| 493 | GETENV ENDP
|
|---|
| 494 |
|
|---|
| 495 | ;
|
|---|
| 496 | ; Compute the length of a zero-terminated string
|
|---|
| 497 | ;
|
|---|
| 498 | ; In: ES:SI Points to string
|
|---|
| 499 | ;
|
|---|
| 500 | ; Out: CX Length
|
|---|
| 501 | ;
|
|---|
| 502 | STRLEN PROC NEAR
|
|---|
| 503 | XOR CX, CX
|
|---|
| 504 | XOR AL, AL
|
|---|
| 505 | STRLEN_1: SCASB
|
|---|
| 506 | JE STRLEN_2
|
|---|
| 507 | INC CX
|
|---|
| 508 | JMP STRLEN_1
|
|---|
| 509 | STRLEN_2: RET
|
|---|
| 510 | STRLEN ENDP
|
|---|
| 511 |
|
|---|
| 512 | ;
|
|---|
| 513 | ; Try to run a program. Exit if successful, return if failed.
|
|---|
| 514 | ;
|
|---|
| 515 | ; In: DS:DX Points to path name of program
|
|---|
| 516 | ;
|
|---|
| 517 | ; Out: DS SV_DATA
|
|---|
| 518 | ;
|
|---|
| 519 |
|
|---|
| 520 | ASSUME DS:NOTHING
|
|---|
| 521 |
|
|---|
| 522 | SPAWN PROC NEAR
|
|---|
| 523 | MOV AX, SV_DATA
|
|---|
| 524 | MOV ES, AX
|
|---|
| 525 | ASSUME ES:SV_DATA
|
|---|
| 526 | LEA BX, PAR_BLOCK ; ES:BX -> parameter block
|
|---|
| 527 | MOV AX, 4B00H ; Load and execute program
|
|---|
| 528 | INT 21H
|
|---|
| 529 | SET_DS ; Restore data segment
|
|---|
| 530 | JNC DONE ; Success -> terminate
|
|---|
| 531 | RET
|
|---|
| 532 |
|
|---|
| 533 | DONE: MOV AH, 4DH ; Get return code of child
|
|---|
| 534 | INT 21H ; process
|
|---|
| 535 | MOV AH, 4CH ; terminate process
|
|---|
| 536 | INT 21H
|
|---|
| 537 |
|
|---|
| 538 | SPAWN ENDP
|
|---|
| 539 |
|
|---|
| 540 | ASSUME ES:NOTHING
|
|---|
| 541 |
|
|---|
| 542 |
|
|---|
| 543 | INIT_CODE ENDS
|
|---|
| 544 |
|
|---|
| 545 |
|
|---|
| 546 | RM_STACK SEGMENT
|
|---|
| 547 | WORD 256 DUP (?)
|
|---|
| 548 | RM_STACK ENDS
|
|---|
| 549 |
|
|---|
| 550 | END ENTRY
|
|---|