Subversion Repositories SvarDOS

Rev

Rev 1480 | Go to most recent revision | Details | Last modification | View Log | RSS feed

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