4 title CP
/DOS DosGetMessage mapper
6 messages
segment word public 'messages'
8 OurMessage db 0dh,0ah,"DosGetMessage returning ->",'$'
18 ; This macro is used to define/declare all of the messages
20 ; We will have four macros, msg -> defines a complete message
21 ; msgStart -> defines the first part of a message
22 ; msgContinue -> continues a started message
23 ; msgEnd -> ends a message
27 ;----------------------------------------------
29 MsgError
macro text
; message string error
41 ;----------------------------------------------
46 MsgError
<Cannot use the
'Msg' Macro when inside a message definition
.>
50 Message
&Number
db text
53 if MaxMessageNumber lt
&number
54 MaxMessageNumber
= &Number
61 ;----------------------------------------------
63 msgStart
macro number
,text
; start of a message string
66 MsgError
<Cannot use the
'MsgStart' macro when inside a message definition
.>
70 Message
&Number
db text
72 if MaxMessageNumber lt
&number
73 MaxMessageNumber
= &Number
80 ;----------------------------------------------
82 msgContinue
macro text
; messgage string contination
85 MsgError
<Cannot use the
'MsgContinue' macro unless inside a message definition
.>
95 ;----------------------------------------------
97 msgEnd
macro ; end of message string
100 MsgError
<Cannot use the
'MsgEnd' macro unless inside a message definition
.>
111 ;-----------------------------------------------
113 ; Define/declare the messages first!
119 NotFoundMessage
label byte
120 msg NotFoundNumber
,<'We could not find your message #'>
122 ; Now, for each defined message, generate an index
127 dw offset messages
:Message
&Number
133 MessageIndex
label word
135 ThisMessageNumber
= 0
136 rept MaxMessageNumber
+ 1
137 msgidx %ThisMessageNumber
138 ThisMessageNumber
= ThisMessageNumber
+ 1
144 dw offset messages
:NotFoundMessage
148 dosxxx
segment byte public 'dos'
149 assume
cs:dosxxx
,ds:nothing
,es:nothing
,ss:nothing
151 ;**********************************************************************
153 ;* MODULE: dosgetmessage
155 ;* FILE NAME: dos029.asm
159 ;* push@ other insert variable table
160 ;* push word insert variable count
161 ;* push@ other message buffer address
162 ;* push word buffer length
163 ;* push word message number
164 ;* push@ asciiz message file name
165 ;* push@ word returned message length
166 ;* call dosgetmessage
168 ;* MODULES CALLED: None (preliminary version)
170 ;*********************************************************************
181 ReturnLengthPtr dd ?
; length of returned message
182 MessageFileName dd ?
; message file name
183 MessageNumber dw ?
; number of the message
184 MessageBufferLen dw ?
; length of the message buffer
185 MessageBufferPtr dd ?
; buffer address to return message
186 VariablesCount dw ?
; number of variables
187 VariableTablePtr dd ?
; table of variables to insert
191 dosgetmessage proc
far
193 Enter Dosgetmessage
; push registers
194 mov ax,messages
; setup message buffer
197 mov ErrorMessageFlag
,0 ; reset error message flag
199 mov bx,[bp].MessageNumber
; get message number
200 mov si,offset messages
:MessageIndex
202 SearchForMessageLoop: ; search for message in table
205 je FoundMessage
; jump if true
207 add si,2 ; if not serach continues
209 jne SearchForMessageLoop
211 mov si,offset messages
:NotFoundIndex
+ 2
212 mov ErrorMessageFlag
,1
214 ; Here, ds:[si] -> word message number, followed by word message offset
219 ; Here, ds:[si] -> message text bytes
221 les di,[bp].VariableTablePtr
; get variable address
222 mov word ptr NextVarPointer
+0,di ; save it
223 mov word ptr NextVarPointer
+2,es
225 mov di,[bp].VariablesCount
; get variable count
226 mov VarsToGo
,di ; save it
228 les di,[bp].MessageBufferPtr
; get return message buffer
230 mov ax,[bp].MessageBufferLen
; get return message buffer
231 mov MessageToGo
,ax ; length
233 cmp ax,0 ; length = 0 ??
234 jne HaveLengthToCopy
; if not, jump
236 jmp GetMessageDone
; done
239 mov MessageLength
,0 ; initialize counter
242 lodsb ; get next character
243 cmp al,'%' ; is it a % sign
244 je DoSubstitution
; if so, need substitution
246 cmp al,0 ; end of string ??
247 jne RealCharacter
; if not look for real chars
249 jmp GetMessageDone
; else, jump to update
250 ; return message length
252 RealCharacter: ; look for real character
254 inc MessageLength
; update message length counter
256 jnz MoveCharsLoop
; branch if not all done
258 jmp GetMessageDone
; else alldone, branch
260 DoSubstitution: ; do substitution
261 lodsb ; get character
262 cmp al,'%' ; check for %%
263 je RealCharacter
; if so, get next character
267 ; skip the numbers that indicate field width!
269 SkipFieldWidth: ; check for field width digit
270 cmp al,'0' ; indicator digits
275 ; if field width indicator
276 lodsb ; jump to examine next char
279 ;-----------------------------------------
281 CheckChar: ; check for char substitution
282 cmp al,'c' ; if true go do character
283 je SubstituteChar
; substitution
287 SubstituteChar: ; do character subtitution
290 lds si,NextVarPointer
291 lds si,ds:dword ptr [si]
301 add word ptr NextVarPointer
,4
306 ;-----------------------------------------
308 CheckDecimal: ; check for decimal subtitution
309 cmp al,'d' ; if true, do decimal
310 je SubstituteDecimal
; substitution
314 SubstituteDecimal: ; do decimal subtitution
317 lds si,NextVarPointer
318 lds si,ds:dword ptr [si]
328 add word ptr NextVarPointer
,4
343 ;-----------------------------------------
346 cmp al,'s' ; check for string subtitution
347 je SubstituteString
; if true, do string
348 cmp al,'S' ; substitution
351 SubstituteString: ; do string substitution
356 lds si,NextVarPointer
357 lds si,ds:dword ptr [si]
360 ContinueStringSubstitution:
363 je EndOfSubstituteString
367 loop ContinueStringSubstitution
369 EndOfSubstituteString:
374 add word ptr NextVarPointer
,4
383 ;-----------------------------------------
385 CheckLong: ; need long substitution
387 je SubstituteLong
; if true go do it
389 jne Unknown
; else unknown substitution
392 jmp RealCharacter
; just go back
394 ;-----------------------------------------
397 jmp RealCharacter
; just go back
402 ; Update the return message length
408 lds si,[bp].ReturnLengthPtr
415 cmp ErrorMessageFlag
,0
418 mov ErrorMessageFlag
,0
421 cmp es:byte ptr [di-1],0
425 jmp KeepGoingBackwards
428 mov ax,[bp].MessageNumber
432 lds si,[bp].ReturnLengthPtr
434 add ax,3 ; for cr, lf, nul
450 mov dx,offset messages
:OurMessage
452 mov ah,9 ; load op code
453 int 21h
; display message
455 lds si,[bp].ReturnLengthPtr
457 lds dx,[bp].MessageBufferPtr
461 int 21h
; display message
464 xor ax,ax ; set good return code
466 mexit
; pop registers
467 ret size
str - 6 ; return
473 ;������������������������������������������������������������������
487 ; input es:di -> location to put decimal characters at
488 ; dx:ax -> 32bit value to be displayed
490 ; output es:di -> next location for output characters
491 ; ax = number of characters output
497 DecLength equ
word ptr [bp+0]
498 LowValue equ
word ptr [bp+2]
499 HighValue equ
word ptr [bp+4]
505 mov bx,offset dosxxx
:Tens
507 ; Start with a count of zero.
512 ; Loop, counting the number of times you can subtract the current digit value
520 inc dx ; Subtraction did no go negative, inc digit
523 ; Since we know when this digit is done by the number going negative, we must
532 ; We need to supress leading zeros, so check to see if this digit is non zero
537 ; Digit is zero, check to see if we have put out any digits yet?
542 ; Either digit was non zero, or we have already output the leading non-zero.
543 ; It really doesn't matter, display the digit
551 ; Set up for the next digit, and determine if we are done
555 cmp cs:word ptr [bx+0],0
557 cmp cs:word ptr [bx+2],0
560 ; Check to see that we at least put out a single 0 character
565 ; We didn't, so let's put the zero there
571 ; The decimal display is complete. Get the return value and return