Subversion Repositories SvarDOS

Rev

Rev 1479 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
1479 mateusz.vi 1
;
1480 mateusz.vi 2
; SvarDOS MORE
1479 mateusz.vi 3
;
4
; Displays output one screen at a time
5
;
6
;  - multilingual (looks up the LANG env variable)
7
;  - tiny (fits in a single disk sector)
8
;
1480 mateusz.vi 9
; This program is part of the SvarDOS project <http://svardos.org>
1479 mateusz.vi 10
;
1480 mateusz.vi 11
; ****************************************************************************
1479 mateusz.vi 12
; *** Distributed under the terms of the MIT LICENSE *************************
1480 mateusz.vi 13
; ****************************************************************************
1479 mateusz.vi 14
;
15
; Copyright (C) 2023 Mateusz Viste
16
;
17
; Permission is hereby granted, free of charge, to any person obtaining a copy
18
; of this software and associated documentation files (the "Software"), to
19
; deal in the Software without restriction, including without limitation the
20
; rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
21
; sell copies of the Software, and to permit persons to whom the Software is
22
; furnished to do so, subject to the following conditions:
23
;
24
; The above copyright notice and this permission notice shall be included in
25
; all copies or substantial portions of the Software.
26
;
27
; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
28
; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
29
; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
30
; AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
31
; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
32
; FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
33
; IN THE SOFTWARE.
34
; ****************************************************************************
35
;
36
; To be compiled with the A72 assembler:
37
; A72 MORE.ASM MORE.COM
38
;
39
 
40
 
41
; COM file always has a 100h origin
42
ORG     100h
43
 
44
 
45
; ****************************************************************************
46
; * Display a short help screen if any (non-empty) argument is provided.     *
47
; *                                                                          *
48
; * detect presence of arguments in the command's tail (PSP 81h), looking    *
49
; * at the first non-space character. If it's a CR then no argument (CR is   *
50
; * the tail's terminator).                                                  *
51
; ****************************************************************************
52
mov     ax, ds
53
mov     es, ax
54
mov     al, ' '
55
mov     cx, 0ffh
56
mov     di, 81h
57
repe    scasb                          ; compare AL with [ES:DI++]
58
mov     al, [di-1]
59
 
60
cmp     al, 0Dh
61
je      NO_ARGS
62
 
63
; some arg found: display help and quit
64
mov     ah, 9h
65
mov     dx, offset HELP
66
int     21h
67
int     20h
68
 
1480 mateusz.vi 69
HELP db "SvarDOS MORE 2023.0", 13, 10
1479 mateusz.vi 70
     db 10
71
     db "MORE < README.TXT", 13, 10
1480 mateusz.vi 72
     db "TYPE README.TXT | MORE", 13, 10, '$'
1479 mateusz.vi 73
 
74
NO_ARGS:
75
 
76
 
77
; ****************************************************************************
78
; * detect screen dimensions (max usable row and column)                     *
79
; ****************************************************************************
80
mov     ah, 0Fh                        ; GET CURRENT VIDEO MODE
81
int     10h
82
mov     byte ptr [MAXCOL], ah
83
mov     ax, 40h
84
mov     es, ax
85
mov     ah, [es:84h]                   ; 0040:0084
86
test    ah, ah                         ; ancient PCes do not know this
87
jz      SKIP_ROWS_DETECTION
88
mov     byte ptr [MAXROW], ah
89
 
90
SKIP_ROWS_DETECTION:
91
 
92
 
93
; ****************************************************************************
94
; * Scan the environement block looking for the LANG variable                *
95
; ****************************************************************************
96
 
97
; set ES to point at the environment segment (PSP's offset 2Ch)
98
mov     es, [2Ch]
99
 
100
; compare DS:[SI] with ES:[DI], up to 5 bytes ("LANG=")
101
cld
102
mov     di, 0
103
CMP_NEXT_VAR:
104
 
105
; if it points at a nul already then it's the end of the env block
106
mov     al, [es:di]
107
test    al, al
108
jz      ENDOFENV
109
 
110
mov     si, LANG
111
mov     cx, 5
112
repe    cmpsb
113
 
114
; if CX == 0 then found a LANG= match
115
jcxz    FOUND_LANG
116
 
117
; otherwise jump to next var (look for nearest nul terminator)
118
xor     al, al
119
mov     cx, 0ffffh
120
repne   scasb                          ; compare AL with [ES:DI++]
121
jmp     CMP_NEXT_VAR
122
 
123
; FOUND THE LANG VARIABLE (at ES:DI)
124
FOUND_LANG:
125
 
126
mov     ax, [es:di]                    ; load the LANG ID to AX and make
127
and     ax, 0DFDFh                     ; sure it is always upper case
128
 
129
 
130
; ****************************************************************************
131
; * Now I have a LANG ID in AX and I have to match it for something I know.  *
132
; * The LANG ID is simply the value for the two uppercase LANG letters, for  *
133
; * example the LANG ID for "PL" is 4C50h (50h = 'P', 4Ch = 'L').            *
134
; ****************************************************************************
135
 
136
; DE [44h 45h]
137
mov     di, TEXT_DE
138
cmp     ax, 4544h
139
je      LANGOK
140
 
141
; FR [46h 52h]
142
mov     di, TEXT_FR
143
cmp     ax, 5246h
144
je      LANGOK
145
 
146
; NL [4Eh 4Ch]
147
mov     di, TEXT_NL
148
cmp     ax, 4C4Eh
149
je      LANGOK
150
 
151
; PL [50h 4Ch]
152
mov     di, TEXT_PL
153
cmp     ax, 4C50h
154
je      LANGOK
155
 
156
; RU [52h 55h]
157
mov     di, TEXT_RU
158
cmp     ax, 5552h
159
je      LANGOK
160
 
161
; TR [54h 52h]
162
mov     di, TEXT_TR
163
cmp     ax, 5254h
164
je      LANGOK
165
 
166
 
167
; *** LANG NOT FOUND OR LANG ID MATCH FAILED: FALL BACK TO EN ****************
168
 
169
ENDOFENV:
170
mov di, TEXT_EN
171
 
172
LANGOK:
173
 
174
 
175
; ****************************************************************************
176
; * DUPLICATING HANDLES: here I duplicate stdin into a new handle so I can   *
177
; * safely close original stdin (file handle 0) and then duplicate stderr    *
178
; * into stdin. The purpose of these shenanigans is to be able to cope with  *
179
; * situations when stdin is redirected (eg. with CTTY)                      *
180
; ****************************************************************************
181
 
182
; duplicate stdin and keep the new file handle in BP
183
xor     bx, bx
184
mov     ah, 45h
185
int     21h
186
mov     bp, ax
187
 
188
; I can close stdin now
189
mov     ah, 3Eh
190
int     21h
191
 
192
; duplicate stderr to stdin
193
; bx = file handle / cx = file handle to become duplicate of bx
194
mov     ah, 46h
195
mov     bx, 2
196
xor     cx, cx
197
int     21h
198
; ****************************************************************************
199
 
200
 
201
; make sure cursor is on column 0
202
mov ah, 2h                             ; write character in DL to stdout
203
mov dl, 0Dh                            ; carriage return
204
int 21h
205
 
206
 
207
; consume stdin bytes by loading them into buffer
208
RELOADBUF:
209
mov     ah, 3Fh                        ; DOS 2+ - read from file or device
210
mov     bx, bp                         ; duplicated stdin is still in bp
211
mov     cx, 1024
212
mov     dx, offset BUFFER
213
int     21h
214
 
215
; abort on error
216
jc EXIT
217
 
218
; did I get any bytes? 0 bytes read means "EOF"
219
test    ax, ax
220
jnz     PREPLOOP
221
 
222
EXIT:
223
int     20h
224
 
225
; prepare the LODSB loop
226
PREPLOOP:
227
mov     cx, ax
228
mov     si, dx
229
 
230
NEXTCHAR:
231
 
232
; AL = DS:[SI++]
233
cld
234
lodsb
235
 
236
; EOF char? (check this first so a short jump to exit is still possible)
237
cmp     al, 1Ah
238
jz      EXIT
239
 
240
; [7h] BELL?
241
cmp     al, 7h
242
je      OUTPUT_CHAR
243
 
244
; [8h] BACKSPACE? moves the cursor back by one column, no effect if it is on
245
; first column already. it does not blank the characters it passes over.
246
cmp     al, 8h
247
jne     NOTBS
248
cmp     byte ptr [CURCOL], 0
249
je      OUTPUT_CHAR
250
dec     byte ptr [CURCOL]
251
jmp     short OUTPUT_CHAR
252
NOTBS:
253
 
254
; [9h] TAB?
255
cmp     al, 9h
256
jne     NOTTAB
257
mov     ah, [CURCOL]
258
add     ah, 7
259
and     ah, 11111000b
260
inc     ah
261
mov     [CURCOL], ah
262
jmp     short OUTPUT_CHAR
263
NOTTAB:
264
 
265
; [0Ah] LF?
266
cmp     al, 0Ah
267
jne     NOTLF
268
inc     byte ptr [CURROW]
269
jmp     short OUTPUT_CHAR
270
NOTLF:
271
 
272
; [0Dh] CR?
273
cmp     al, 0Dh
274
jnz     NOTCR
275
mov     byte ptr [CURCOL], 0
276
jmp     short OUTPUT_CHAR
277
NOTCR:
278
 
279
; otherwise: increment cur column, and then maybe cur row
280
inc     byte ptr [CURCOL]
281
mov     ah, [CURCOL]
282
cmp     ah, [MAXCOL]
283
jb      OUTPUT_CHAR
284
inc     byte ptr [CURROW]
285
mov     byte ptr [CURCOL], 0
286
 
287
OUTPUT_CHAR:
288
mov     dl, al
289
mov     ah, 2h
290
int     21h
291
mov     ah, [CURROW]
292
cmp     ah, [MAXROW]
293
jae     PRESSANYKEY
294
 
295
CHARLOOP:
296
loop    NEXTCHAR                       ; dec cx and jmp to NEXTCHAR if cx > 0
297
jmp     RELOADBUF
298
 
299
 
1480 mateusz.vi 300
; display " --- More --- "
1479 mateusz.vi 301
PRESSANYKEY:
302
mov     dx, di
303
mov     ah, 9h                         ; disp $-termin. string pointed by DX
304
int     21h
305
mov     dx, DOTS
306
int     21h
307
 
308
mov     ax, 0C08h                      ; flush keyb + wait for key, no echo
309
int     21h
310
 
311
; output a CR/LF pair and reset counters
312
mov     dx, offset CRLF
313
mov     ah, 9h
314
int     21h
315
mov     byte ptr [CURCOL], 0
316
mov     byte ptr [CURROW], 0
317
jmp     CHARLOOP
318
 
319
 
320
; ****************************************************************************
321
; * DATA                                                                     *
322
; ****************************************************************************
323
 
324
MAXROW  db      24                     ; maximum *addressable* row (not total)
325
MAXCOL  db      80                     ; total available columns
326
CURROW  db      0
327
CURCOL  db      0
328
 
329
 
330
CRLF DB 13, 10, '$'
331
LANG DB "LANG="
332
DOTS DB "...$"
333
 
334
TEXT_DE DB "WEITER$"
335
TEXT_EN DB "MORE$"
336
TEXT_FR DB "PLUS$"
337
TEXT_NL DB "MEER$"
338
TEXT_PL DB "DALEJ$"
1480 mateusz.vi 339
TEXT_RU DB 84h,80h,8Bh,85h,85h,'$'     ; "DALEE" (CP 866)
1479 mateusz.vi 340
TEXT_TR DB "DAHA FAZLA$"
341
 
342
; uninitialized buffer area (must be defined last)
343
BUFFER: