1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
|
10 REM Customization!
19 REM Maybe you want to name the computer?
20 COMPNAME$ = ENVIRON$("HOSTNAME")
28 REM Uptime can be shown, but is meaningless if the system has a clock
29 REM battery or the time has been set
30 SHOWUPTIME = 1
200 PRINT "Working..."
210 TMPFILE$ = "TEST.TMP"
219 REM Determine the OS and interpretter
220 CMD$ = "ver":GOSUB 5000:GOSUB 10000
230 REM PRINT "INTERPRETER: ";INTERP$
240 REM IF LEN(VERSION$) > 0 THEN PRINT "VERSION: ";VERSION$
250 REM Determine memory
260 CMD$ = "chkdsk":GOSUB 5000:GOSUB 11000
270 REM CPU Detection
280 GOSUB 12000:GOSUB 12300
290 REM Get a machine name
300 GOSUB 14000
500 REM Just produce an MSDOS logo for now
510 DIM LOGO$(25)
520 GOSUB 20000
1000 REM Output time
1001 CLS
1002 GOSUB 30100
1003 GOSUB 3000
1010 R = 2:C=41
1020 IF LEN(COMPNAME$) = 0 THEN GOTO 1100
1030 LOCATE R,C:PRINT COMPNAME$;
1035 R = R + 1
1040 LOCATE R,C:PRINT STRING$(LEN(COMPNAME$),"-");
1095 R = R + 1
1100 REM Normal output
1180 IF LEN(MACHINE$) = 0 THEN GOTO 1200
1190 LOCATE R,C:PRINT "Host: ";MACHINE$;
1195 R = R + 1
1199 REM Uptime really only makes sense if the time was never set
1200 IF SHOWUPTIME <> 1 THEN GOTO 1220
1201 LOCATE R,C:PRINT "Uptime Today: ";:GOSUB 13000
1205 R = R + 1
1220 LOCATE R,C:PRINT "Shell: ";INTERP$;
1222 IF LEN(VERSION$) > 0 THEN PRINT " ";VERSION$;
1225 R = R + 1
1230 LOCATE R,C:PRINT "CPU: ";CPU$;
1235 R = R + 1
1240 LOCATE R,C:PRINT "Memory: ";MEMFREE$;" / ";MEMTOTAL$;
1998 LOCATE ROWS, 41:PRINT "Press any key...";
1999 WHILE LEN(INKEY$) = 0:WEND
2000 END
3000 REM Logo output
3010 FOR I = 1 TO ROWS
3020 LOCATE I, 1:PRINT LOGO$(I);
3030 NEXT I
3040 RETURN
5000 REM Run and pipe command
5010 REM TMPFILE$ contains the file for capture
5020 REM CMD$ contains the command to run
5030 SHELL CMD$ + " > " + TMPFILE$
5040 RETURN
10000 REM 'ver' output parser
10010 REM TMPFILE$ contains the file to open
10011 REM output: INTERP$ is the interpeter
10012 REM VERSION$ is the version
10020 OPEN TMPFILE$ FOR INPUT AS #2
10030 IF EOF(2) THEN GOTO 10060
10040 INPUT#2, VERLINE$
10050 IF LEN(G$) = 0 THEN GOTO 10030 ELSE GOTO 10060
10060 CLOSE#2
10070 REM VERLINE$ now contains the first non-blank version
10080 REM output. Technically it is just the command
10090 REM interpreter version.
10100 IDX = INSTR(VERLINE$, "ersion")
10110 IF IDX = 0 THEN GOTO 10210
10120 IDX = IDX - 1
10130 INTERP$ = LEFT$(VERLINE$, IDX - 2)
10140 IDX = IDX + 7
10150 VERSION$ = RIGHT$(VERLINE$, LEN(VERLINE$) - IDX)
10160 FOR IDX = 1 TO LEN(VERSION$)
10170 IF MID$(VERSION$, IDX, 1) = " " THEN VERSION$ = LEFT$(VERSION$,IDX-1)
10180 NEXT IDX
10190 IF INTERP$ = "MS-DOS" OR INTERP$="PC-DOS" THEN INTERP$ = INTERP$ + " Command"
10200 RETURN
10210 REM If we're here, the word "version" wasn't found, but no worries
10220 SPACED = 0:IDX=0:VERSION$ = ""
10230 FOR IDX = 2 TO LEN(VERLINE$)
10240 C$ = MID$(IDX, 1)
10250 GOSUB 30200
10240 IF SPACED > 0 AND ISNUM = 1 THEN VERSION$ = VERSION$ + C$ ELSE GOTO 10270
10250 IF SPACED = 0 AND C$ = " " THEN SPACED = IDX
10260 NEXT IDX
10270 IF LEN(VERSION$) > 0 AND SPACED > 0 THEN INTERP$ = LEFT$(VERLINE$, SPACED - 1) ELSE INTERP$ = VERLINE$
10280 RETURN
11000 REM 'chkdsk' output parser
11010 REM TMPFILE$ contains the file to open
11011 REM output: MEMTOTAL$ is the total memory in bytes
11012 REM MEMFREE$ is the available memory in bytes
11020 MEMTOTAL$ = "":MEMFREE$ = ""
11030 OPEN TMPFILE$ FOR INPUT AS #2
11040 INPUT#2, MEMLINE$
11050 IDX = INSTR(MEMLINE$, "bytes total memory")
11060 IF IDX > 0 THEN MEMTOTAL$ = LEFT$(MEMLINE$, IDX-1):GOTO 11090
11070 IDX = INSTR(MEMLINE$, "bytes free")
11080 IF IDX > 0 THEN MEMFREE$ = LEFT$(MEMLINE$, IDX-1)
11085 IF EOF(2) THEN GOTO 11110
11090 IF LEN(MEMTOTAL$) = 0 OR LEN(MEMFREE$) = 0 THEN GOTO 11040 ELSE GOTO 11110
11100 RESUME 11110
11110 CLOSE#2
11120 TOTRIM$ = MEMTOTAL$:GOSUB 30000:MEMTOTAL$ = TOTRIM$
11130 TOTRIM$ = MEMFREE$:GOSUB 30000:MEMFREE$ = TOTRIM$
11140 RETURN
12000 REM CPU Identity
12001 DIM Q%(400)
12005 DEF SEG=VARSEG(Q%(0))
12006 OS%=VARPTR(Q%(0))
12007 BWOFFSET = -1 : LASTBYTE = 0
12010 FOR I = 1 TO 100
12020 READ JC:POKE I+OS%, JC
12021 REM Detect where we need to insert an offset for bus width detection
12022 IF LASTBYTE=99 AND JC=0 THEN BWOFFSET = I+OS% - 1
12029 LASTBYTE = JC
12030 NEXT I
12039 REM Need to set the offset for bus width
12040 TGTOFFSET = BWOFFSET + 16
12050 POKE BWOFFSET, (TGTOFFSET MOD 256)
12060 POKE BWOFFSET+1, INT(TGTOFFSET / 256)
12080 CPUQ = 1 + OS%
12090 CALL CPUQ(CPUID%)
12097 DEF SEG
12100 REM ; Results:
12101 REM ; 0 - 8088
12102 REM ; 1 - 8086
12103 REM ; 2 - V20
12104 REM ; 3 - V30
12105 REM ; 4 - 80188
12106 REM ; 5 - 80186
12107 REM ; 6 - 80286
12108 REM ; 7 - 80386+
12109 DATA &H55 : REM push bp
12110 DATA &H89, &HE5 : REM mov bp, sp
12111 REM ; push zero onto the stack and pop it into flags.
12112 REM ; some bits won't change
12113 DATA &H31, &HC0 : REM xor ax,ax
12114 DATA &H50 : REM push ax
12115 DATA &H9D : REM popf
12116 DATA &H9C : REM pushf
12117 DATA &H58 : REM pop ax
12118 DATA &H25, &H00, &HF0 : REM and ax, 0xf000 ;0f000h
12119 DATA &H3D, &H00, &HF0 : REM cmp ax, 0xf000 ;0f000h
12120 DATA &H74, &H13 : REM je lessthantwoeightsix
12121 REM ; marked as 286 (6)
12122 DATA &HB2, &H06 : REM mov dl, 6
12123 DATA &HB8, &H00, &H70 : REM mov ax, 0x7000 ;7000h
12124 DATA &H50 : REM push ax
12125 DATA &H9D : REM popf
12126 DATA &H9C : REM pushf
12127 DATA &H58 : REM pop ax
12128 DATA &H25, &H00, &H70 : REM and ax, 0x7000 ;7000h
12129 DATA &H74, &H3A : REM jz alldone
12130 REM ; mark as 386 (7)
12131 DATA &HFE, &HC2 : REM inc dl
12132 DATA &HE9, &H35, &H00 : REM jmp alldone
12133 REM lessthantwoeightsix:
12134 REM ; Mark as 80188 (4)
12135 DATA &HB2, &H04 : REM mov dl, 4
12136 DATA &HB0, &HFF : REM mov al, 0xff ;0ffh
12137 DATA &HB1, &H21 : REM mov cl, 0x21 ;21h
12138 DATA &HD2, &HE8 : REM shr al, cl
12139 REM ; if the shift leaves zero, it's a 8088 class cpu, else 8018
12140 DATA &H75, &H14 : REM jnz buswidth
12141 REM ; Lets see if we have a V2
12142 DATA &HB2, &H02 : REM mov dl, 2
12143 DATA &HFB : REM sti
12144 DATA &H56 : REM push si
12145 DATA &HBE, &H00, &H00 : REM mov si, 0
12146 DATA &HB9, &HFF, &HFF : REM mov cx, 0xffff ;0ffffh
12147 REM ;rep lods [BYTE PTR es:si]
12148 REM ; INLINE assembler doesn't understand above - must be replaced after...
12149 REM ; because we need a lods with ES as a parameter
12150 REM ; so drop a 3-byte nonsense call to be replaced
12151 DATA &HF3, &H26, &HAC : REM mov cx, 0x0f99 ; replace with 0xF3, 0x26, 0xAC
12152 DATA &H5E : REM pop si
12153 DATA &H09, &HC9 : REM or cx, cx
12154 DATA &H74, &H02 : REM jz buswidth
12155 REM ; mark as a 808
12156 DATA &HB2, &H00 : REM mov dl, 0
12157 REM buswidth:
12158 REM ; we are destroying es now, must be restored later
12159 DATA &H0E : REM push cs
12160 DATA &H07 : REM pop es
12161 DATA &HFD : REM std
12162 REM ; The 99 _must_ be replaced with the true offset of qqend
12163 DATA &HBF, &H63, &H00 : REM mov di, 99 ; OFFSET qqend ;99
12164 REM ;set up al and cx: 0xfb is the 'sti' instruction
12165 DATA &HB0, &HFB : REM mov al, 0xfb
12166 DATA &HB9, &H03, &H00 : REM mov cx, 3
12167 REM ; disable interrupts
12168 DATA &HFA : REM cli
12169 DATA &HF2, &HAA : REM rep stosb
12170 DATA &HFC : REM cld
12171 DATA &H90 : REM nop
12172 DATA &H90 : REM nop
12173 DATA &H90 : REM nop
12174 DATA &H42 : REM inc dx
12175 DATA &H90 : REM nop
12176 REM qqend:
12177 DATA &HFB : REM sti
12178 REM ; ES must be restored
12179 DATA &H1E : REM push ds
12180 DATA &H07 : REM pop es
12181 REM alldone:
12182 REM ; store in ax
12183 DATA &H30, &HF6 : REM xor dh, dh
12184 DATA &H8B, &H7E, &H06 : REM mov di, [bp]+6
12185 DATA &H89, &H15 : REM mov [di], dx
12186 DATA &H5D : REM pop bp
12187 DATA &HCA, &H02, &H00 : REM ); { retf 2}
12188 REM Total Bytes in Data: 100
12200 RETURN
12300 REM Interprets CPUID% and returns a CPU name
12310 DIM CPUNAME$(7)
12320 CPUNAME$(0) = "8088" : CPUNAME$(1) = "8086"
12330 CPUNAME$(2) = "V20" : CPUNAME$(3) = "V30"
12340 CPUNAME$(4) = "80188" : CPUNAME$(5) = "80186"
12350 CPUNAME$(6) = "80286"
12360 CPUNAME$(7) = "80386"
12370 IF CPUID% = 2 OR CPUID% = 3 THEN MFG$ = "NEC" ELSE MFG$ = "Intel"
12380 CPU$ = MFG$+" "+CPUNAME$(CPUID%)
12390 RETURN
13000 REM Create an Uptime string
13010 HOURS = INT(TIMER / 3600)
13020 MINUTES = INT(TIMER / 60) MOD 60
13040 IF HOURS > 0 THEN PRINT HOURS;" hours ";
13050 PRINT MINUTES;" minutes";
13060 RETURN
14000 REM Guess machine
14010 REM output: MACHINE$
14015 MACHID = 0
14020 REM Check for Rainbow video memory first
14030 DEF SEG=&HEE00
14040 IF PEEK(0) = &HFF AND PEEK(1) = 3 AND PEEK(3) = &HFF AND PEEK(4) = 18 THEN MACHID=100
14050 DEF SEG
14099 IF MACHID > 0 THEN GOTO 14200
14100 REM Detect using the machine id from the IBM bios
14110 DEF SEG=&HF000
14120 MACHID = PEEK(&HFFFE)
14130 DEF SEG
14200 REM Parse Machine ID
14210 IF MACHID = 100 THEN MACHINE$="Digital Rainbow 100":GOTO 14299
14220 IBMID = MACHID - &HF8
14230 DIM IBMMODELS$(7)
14240 IBMMODELS$(0) = "PS/2 Model 80":IBMMODELS$(1) = "Convertible PC":IBMMODELS$(2) = "PS/2 Model 30"
14241 IBMMODELS$(3) = "PC/XT":IBMMODELS$(4) = "PC/AT or Compatible":IBMMODELS$(5) = "PCjr"::
14242 IBMMODELS$(6) = "PC/XT":IBMMODELS$(7) = "PC"
14250 IF IBMID >= 0 THEN MACHINE$ = "IBM "+IBMMODELS$(IBMID):GOTO 14299
14260 IF MACHID = 154 OR MACHID = 46 THEN MACHINE$ = "Compaq PC":GOTO 14299
14270 IF MACHID = 49 THEN MACHINE$ = "Sperry PC":GOTO 14299
14299 RETURN
20000 REM MS-DOS Logo
20010 LOGO$(1) = " "
20011 LOGO$(2) = " &&&&&& &&&&&& &&&&&&&&"
20012 LOGO$(3) = " &&&&&&. &&&&&&& &&&&&&&&&&&&"
20013 LOGO$(4) = " &&&&&&& &&&&&&&.&&&& &&&&"
20014 LOGO$(5) = " &&&&&&& &&&&&&&&&&&+"
20015 LOGO$(6) = " &&&&&&&; &&&&&&&& &&&&&&&&"
20016 LOGO$(7) = " &&&&&&&& &&& &&&& &&&&&&&&&&"
20017 LOGO$(8) = " &&&& &&&&&&& &&&& &&&&&&&
20018 LOGO$(9) = " &&&& &&&&&&& &&&&&&&& &&&&
20019 LOGO$(10) = " &&&& ;&&&&& &&&& &&&&+ &&&&&
20020 LOGO$(11) = " &&&& &&&&& &&&& &&&&&&&&&&&$"
20021 LOGO$(12) = " &&&&. &&&& &&&& &&&&&&"
20022 LOGO$(13) = " $$$$$$$$$$ $$$$$$$ :::::::."
20023 LOGO$(14) = " $$$$$$$$.$$$$$$$$.::::::::::::"
20024 LOGO$(15) = " $$$$ $$$$$X :::: &$$ .::::"
20025 LOGO$(16) = " $$$$ $$$$$ $$ .::: $$$$& ...."
20026 LOGO$(17) = " $$$$ $$$$;$$$$ ::::&$$$$"
20027 LOGO$(18) = " $$$$ $$$$ $$$$ ::;$$$$ ::."
20028 LOGO$(19) = " $$$$ . $$$$ $$$$ &$$$$ ::::"
20029 LOGO$(20) = " $$$$ $$$&$$$$$:::: $$$$& .::::"
20030 LOGO$(21) = " $$$$.. $$$$$$::::: $$$ ..::::"
20031 LOGO$(22) = " $$$$$$$$$$$$$$$$&::::::::::::::"
20032 LOGO$(23) = " $$$$$$$$$$$$$$$$$$..::::::::.."
20033 LOGO$(24) = " "
20034 LOGO$(25) = " "
20035 RETURN
30000 REM String Trim Function
30010 REM input/output: TOTRIM$
30015 IF LEN(TOTRIM$) = 0 THEN RETURN
30016 IF INSTR(TOTRIM$, " ") = 0 THEN RETURN
30020 FOR IDX = 1 TO LEN(TOTRIM$):IF MID$(TOTRIM$, IDX, 1) <> " " THEN GOTO 30030:NEXT IDX
30030 FOR RDX = LEN(TOTRIM$) TO IDX STEP -1:IF MID$(TOTRIM$, RDX, 1) <> " " THEN GOTO 30050:NEXT RDX
30040 TOTRIM$ = MID$(TOTRIM$, IDX, RDX - IDX)
30050 RETURN
30100 REM Row check
30110 REM output: ROWS - number of screen rows
30120 ON ERROR GOTO 30150
30130 LOCATE 25,1
30140 ROWS=25:GOTO 30170
30150 RESUME 30160
30160 ROWS=24
30170 ON ERROR GOTO 0
30180 RETURN
30200 REM Character is number or dot
30210 REM input: C$
30220 REM output: ISNUM
30230 IF C$ = "." THEN ISNUM = 1:RETURN
30240 IF ASC(C$) >= ASC("0") AND ASC(C$) <= ASC("9") THEN ISNUM = 1:RETURN
30250 ISNUM = 0:RETURN
|