]> wirehaze git hosting - MS-DOS.git/blob - v4.0/src/MAPPER/GETMSG.ASM

wirehaze git hosting

MZ is back!
[MS-DOS.git] / v4.0 / src / MAPPER / GETMSG.ASM
1 ;
2 page 80,132
3 ;
4 title CP/DOS DosGetMessage mapper
5 ;
6 messages segment word public 'messages'
7
8 OurMessage db 0dh,0ah,"DosGetMessage returning ->",'$'
9
10 ErrorMessageFlag db 0
11 MessageToGo dw 0
12 MessageLength dw 0
13 NextVarPointer dd 0
14 VarsToGo dw 0
15
16 MaxMessageNumber = 0
17
18 ; This macro is used to define/declare all of the messages
19
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
24
25 MacroState = 0
26
27 ;----------------------------------------------
28
29 MsgError macro text ; message string error
30
31 if1
32 else
33 %out \a
34 %out $ERROR - &text
35 endif
36
37 $ERROR - &text
38
39 endm
40
41 ;----------------------------------------------
42
43 msg macro number,text
44
45 if MacroState NE 0
46 MsgError <Cannot use the 'Msg' Macro when inside a message definition.>
47 mexit
48 endif
49
50 Message&Number db text
51 db 0
52
53 if MaxMessageNumber lt &number
54 MaxMessageNumber = &Number
55 endif
56
57 MacroState = 0
58
59 endm
60
61 ;----------------------------------------------
62
63 msgStart macro number,text ; start of a message string
64
65 if MacroState NE 0
66 MsgError <Cannot use the 'MsgStart' macro when inside a message definition.>
67 mexit
68 endif
69
70 Message&Number db text
71
72 if MaxMessageNumber lt &number
73 MaxMessageNumber = &Number
74 endif
75
76 MacroState = 1
77
78 endm
79
80 ;----------------------------------------------
81
82 msgContinue macro text ; messgage string contination
83
84 if MacroState EQ 0
85 MsgError <Cannot use the 'MsgContinue' macro unless inside a message definition.>
86 mexit
87 endif
88
89 db text
90
91 MacroState = 1
92
93 endm
94
95 ;----------------------------------------------
96
97 msgEnd macro ; end of message string
98
99 if MacroState EQ 0
100 MsgError <Cannot use the 'MsgEnd' macro unless inside a message definition.>
101 mexit
102 endif
103
104 db 0
105
106 MacroState = 0
107
108 endm
109
110
111 ;-----------------------------------------------
112
113 ; Define/declare the messages first!
114
115 include messages.inc
116
117 NotFoundNumber = -2
118
119 NotFoundMessage label byte
120 msg NotFoundNumber,<'We could not find your message #'>
121
122 ; Now, for each defined message, generate an index
123
124 msgidx macro number
125 ifdef Message&Number
126 dw &Number
127 dw offset messages:Message&Number
128 endif
129 endm
130
131 even
132
133 MessageIndex label word
134
135 ThisMessageNumber = 0
136 rept MaxMessageNumber + 1
137 msgidx %ThisMessageNumber
138 ThisMessageNumber = ThisMessageNumber + 1
139 endm
140
141 dw -1
142
143 NotFoundIndex dw -2
144 dw offset messages:NotFoundMessage
145
146 messages ends
147 ;
148 dosxxx segment byte public 'dos'
149 assume cs:dosxxx,ds:nothing,es:nothing,ss:nothing
150 ;
151 ;**********************************************************************
152 ;*
153 ;* MODULE: dosgetmessage
154 ;*
155 ;* FILE NAME: dos029.asm
156 ;*
157 ;* CALLING SEQUENCE:
158 ;*
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
167 ;*
168 ;* MODULES CALLED: None (preliminary version)
169 ;*
170 ;*********************************************************************
171 ;
172 public dosgetmessage
173 .sall
174 .xlist
175 include macros.inc
176 .list
177
178 str struc
179 old_bp dw ?
180 return dd ?
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
188 str ends
189
190
191 dosgetmessage proc far
192
193 Enter Dosgetmessage ; push registers
194 mov ax,messages ; setup message buffer
195 mov ds,ax
196 assume ds:messages
197 mov ErrorMessageFlag,0 ; reset error message flag
198
199 mov bx,[bp].MessageNumber ; get message number
200 mov si,offset messages:MessageIndex
201
202 SearchForMessageLoop: ; search for message in table
203 lodsw
204 cmp ax,bx ; found ??
205 je FoundMessage ; jump if true
206
207 add si,2 ; if not serach continues
208 cmp ax,-1
209 jne SearchForMessageLoop
210
211 mov si,offset messages:NotFoundIndex + 2
212 mov ErrorMessageFlag,1
213
214 ; Here, ds:[si] -> word message number, followed by word message offset
215
216 FoundMessage:
217 mov si,ds:[si]
218
219 ; Here, ds:[si] -> message text bytes
220
221 les di,[bp].VariableTablePtr ; get variable address
222 mov word ptr NextVarPointer+0,di ; save it
223 mov word ptr NextVarPointer+2,es
224
225 mov di,[bp].VariablesCount ; get variable count
226 mov VarsToGo,di ; save it
227
228 les di,[bp].MessageBufferPtr ; get return message buffer
229 ; address
230 mov ax,[bp].MessageBufferLen ; get return message buffer
231 mov MessageToGo,ax ; length
232
233 cmp ax,0 ; length = 0 ??
234 jne HaveLengthToCopy ; if not, jump
235
236 jmp GetMessageDone ; done
237
238 HaveLengthToCopy:
239 mov MessageLength,0 ; initialize counter
240
241 MoveCharsLoop:
242 lodsb ; get next character
243 cmp al,'%' ; is it a % sign
244 je DoSubstitution ; if so, need substitution
245
246 cmp al,0 ; end of string ??
247 jne RealCharacter ; if not look for real chars
248
249 jmp GetMessageDone ; else, jump to update
250 ; return message length
251
252 RealCharacter: ; look for real character
253 stosb
254 inc MessageLength ; update message length counter
255 dec MessageToGo
256 jnz MoveCharsLoop ; branch if not all done
257
258 jmp GetMessageDone ; else alldone, branch
259
260 DoSubstitution: ; do substitution
261 lodsb ; get character
262 cmp al,'%' ; check for %%
263 je RealCharacter ; if so, get next character
264
265
266
267 ; skip the numbers that indicate field width!
268
269 SkipFieldWidth: ; check for field width digit
270 cmp al,'0' ; indicator digits
271 jc CheckChar
272
273 cmp al,'9'+1
274 jnc CheckChar
275 ; if field width indicator
276 lodsb ; jump to examine next char
277 jmp SkipFieldWidth
278
279 ;-----------------------------------------
280
281 CheckChar: ; check for char substitution
282 cmp al,'c' ; if true go do character
283 je SubstituteChar ; substitution
284 cmp al,'C'
285 jne CheckDecimal
286
287 SubstituteChar: ; do character subtitution
288 push ds
289 push si
290 lds si,NextVarPointer
291 lds si,ds:dword ptr [si]
292
293 assume ds:nothing
294
295 lodsb
296 pop si
297 pop ds
298
299 assume ds:messages
300
301 add word ptr NextVarPointer,4
302 dec VarsToGo
303
304 jmp RealCharacter
305
306 ;-----------------------------------------
307
308 CheckDecimal: ; check for decimal subtitution
309 cmp al,'d' ; if true, do decimal
310 je SubstituteDecimal ; substitution
311 cmp al,'D'
312 jne CheckString
313
314 SubstituteDecimal: ; do decimal subtitution
315 push ds
316 push si
317 lds si,NextVarPointer
318 lds si,ds:dword ptr [si]
319
320 assume ds:nothing
321
322 lodsw
323 pop si
324 pop ds
325
326 assume ds:messages
327
328 add word ptr NextVarPointer,4
329 dec VarsToGo
330
331 mov dx,0
332 call ConvDec
333
334 add MessageLength,ax
335 sub MessageToGo,ax
336 jc PastEndOfBuffer
337
338 jmp MoveCharsLoop
339
340 PastEndOfBuffer:
341 jmp GetMessageDone
342
343 ;-----------------------------------------
344
345 CheckString:
346 cmp al,'s' ; check for string subtitution
347 je SubstituteString ; if true, do string
348 cmp al,'S' ; substitution
349 jne CheckLong
350
351 SubstituteString: ; do string substitution
352 push ds
353 push si
354 mov cx,MessageToGo
355 mov dx,MessageLength
356 lds si,NextVarPointer
357 lds si,ds:dword ptr [si]
358 assume ds:nothing
359
360 ContinueStringSubstitution:
361 lodsb
362 cmp al,0
363 je EndOfSubstituteString
364
365 stosb
366 inc dx
367 loop ContinueStringSubstitution
368
369 EndOfSubstituteString:
370 pop si
371 pop ds
372 assume ds:messages
373
374 add word ptr NextVarPointer,4
375 dec VarsToGo
376
377 mov MessageLength,dx
378 mov MessageToGo,cx
379 jcxz PastEndOfBuffer
380
381 jmp MoveCharsLoop
382
383 ;-----------------------------------------
384
385 CheckLong: ; need long substitution
386 cmp al,'l'
387 je SubstituteLong ; if true go do it
388 cmp al,'L'
389 jne Unknown ; else unknown substitution
390
391 SubstituteLong:
392 jmp RealCharacter ; just go back
393
394 ;-----------------------------------------
395
396 Unknown:
397 jmp RealCharacter ; just go back
398
399
400
401
402 ; Update the return message length
403
404 GetMessageDone:
405 push ds
406 push si
407 mov ax,MessageLength
408 lds si,[bp].ReturnLengthPtr
409 assume ds:nothing
410 mov ds:[si],ax
411 pop si
412 pop ds
413 assume ds:messages
414
415 cmp ErrorMessageFlag,0
416 je NotErrorMessage
417
418 mov ErrorMessageFlag,0
419
420 KeepGoingBackwards:
421 cmp es:byte ptr [di-1],0
422 jne PutItHere
423
424 dec di
425 jmp KeepGoingBackwards
426
427 PutItHere:
428 mov ax,[bp].MessageNumber
429 mov dx,0
430
431 call convdec
432 lds si,[bp].ReturnLengthPtr
433 assume ds:nothing
434 add ax,3 ; for cr, lf, nul
435 add ds:[si],ax
436
437 mov al,0dh
438 stosb
439 mov al,0ah
440 stosb
441
442 mov al,0
443 stosb
444
445 NotErrorMessage:
446 jmp SkipToHere
447
448 mov dx,seg messages
449 mov ds,dx
450 mov dx,offset messages:OurMessage
451
452 mov ah,9 ; load op code
453 int 21h ; display message
454
455 lds si,[bp].ReturnLengthPtr
456 mov cx,ds:[si]
457 lds dx,[bp].MessageBufferPtr
458
459 mov bx,1
460 mov ah,40h
461 int 21h ; display message
462
463 SkipToHere:
464 xor ax,ax ; set good return code
465
466 mexit ; pop registers
467 ret size str - 6 ; return
468
469 dosgetmessage endp
470
471 page
472
473 ;������������������������������������������������������������������
474
475 Tens dd 10000000
476 dd 1000000
477 dd 100000
478 dd 10000
479 dd 1000
480 dd 100
481 dd 10
482 dd 1
483 dd 0
484
485 convdec proc near
486
487 ; input es:di -> location to put decimal characters at
488 ; dx:ax -> 32bit value to be displayed
489
490 ; output es:di -> next location for output characters
491 ; ax = number of characters output
492
493 push bp
494 sub sp,6
495 mov bp,sp
496
497 DecLength equ word ptr [bp+0]
498 LowValue equ word ptr [bp+2]
499 HighValue equ word ptr [bp+4]
500
501 mov DecLength,0
502 mov HighValue,dx
503 mov LowValue,ax
504
505 mov bx,offset dosxxx:Tens
506
507 ; Start with a count of zero.
508
509 DigitLoop:
510 mov dx,0
511
512 ; Loop, counting the number of times you can subtract the current digit value
513
514 CountLoop:
515 mov ax,cs:[bx+0]
516 sub LowValue,ax
517 mov ax,cs:[bx+2]
518 sbb HighValue,ax
519 jc TooFar
520 inc dx ; Subtraction did no go negative, inc digit
521 jmp CountLoop
522
523 ; Since we know when this digit is done by the number going negative, we must
524 ; fixup the damage.
525
526 TooFar:
527 mov ax,cs:[bx+0]
528 add LowValue,ax
529 mov ax,cs:[bx+2]
530 adc HighValue,ax
531
532 ; We need to supress leading zeros, so check to see if this digit is non zero
533
534 cmp dx,0
535 jnz DoDisplay
536
537 ; Digit is zero, check to see if we have put out any digits yet?
538
539 cmp Declength,0
540 jz NextDigit
541
542 ; Either digit was non zero, or we have already output the leading non-zero.
543 ; It really doesn't matter, display the digit
544
545 DoDisplay:
546 mov al,dl
547 add al,'0'
548 stosb
549 inc DecLength
550
551 ; Set up for the next digit, and determine if we are done
552
553 NextDigit:
554 add bx,4
555 cmp cs:word ptr [bx+0],0
556 jnz DigitLoop
557 cmp cs:word ptr [bx+2],0
558 jnz DigitLoop
559
560 ; Check to see that we at least put out a single 0 character
561
562 cmp DecLength,0
563 jne Done
564
565 ; We didn't, so let's put the zero there
566
567 mov al,'0'
568 stosb
569 inc DecLength
570
571 ; The decimal display is complete. Get the return value and return
572
573 Done:
574 mov ax,DecLength
575
576 mov sp,bp
577 add sp,6
578 pop bp
579
580 ret
581
582 convdec endp
583
584 dosxxx ends
585
586 end