1 ; **************************************************************************** 2 ; sh386.s (sh6.s) - Retro Unix 386 v1 Shell - /bin/sh 3 ; ---------------------------------------------------------------------------- 4 ; 5 ; RETRO UNIX 386 (Retro Unix == Turkish Rational Unix) 6 ; Operating System Project (v0.2) by ERDOGAN TAN (Beginning: 24/12/2013) 7 ; 8 ; Derived from 'Retro UNIX 8086 v1' source code by Erdogan Tan 9 ; (v0.1 - Beginning: 11/07/2012) 10 ; 11 ; [ Last Modification: 17/06/2022 ] 12 ; 13 ; Derived from UNIX Operating System (v1.0 for PDP-11) 14 ; (Original) Source Code by Ken Thompson (Bell Laboratories, 1971-1972) 15 ; **************************************************************************** 16 ; 17 ; 18 ; 19 ; 20 ; 21 ; **************************************************************************** 22 23 ; Assembler: NASM v2.15 24 ; ((nasm sh6.s -l sh6.txt -o sh6 -Z error.txt)) 25 26 ; sh6.s (17/06/2022, Retro UNIX 386 v1) -- (modified sh2.s) -- 27 ; sh5.s (17/06/2022, Retro UNIX 386 v1.1) -- (modified sh2.s) -- 28 ; sh4.s (13/06/2022, Retro UNIX 386 v1.2) -- (modified sh2.s) --- 29 ; sh3.s (29/05/2022, Retro UNIX 386 v1) -- (modified sh0.s) --- 30 ; sh2.s (29/05/2022, Retro UNIX 386 v1.1 & v1.2) -- (modified sh1.s) -- 31 ; sh1.s (03/01/2016, Retro UNIX 386 v1.1) 32 ; sh0.s (28/12/2015, Retro UNIX 386 v1, NASM 2.11, 32 bit version of 'sh.asm') 33 ; SHELL03.ASM, 13/11/2013 - 27/06/2014 (sh.asm, Retro UNIX 8086 v1, MASM 6.11) 34 35 ; 12/01/2022 (Retro UNIX 386 v1.2) 36 ; 13/10/2015 37 ; 27/08/2015 38 ; 24/08/2015 39 ; 08/04/2014 40 ; 13/11/2013 41 42 ; UNIX v1 system calls 43 _rele equ 0 44 _exit equ 1 45 _fork equ 2 46 _read equ 3 47 _write equ 4 48 _open equ 5 49 _close equ 6 50 _wait equ 7 51 _creat equ 8 52 _link equ 9 53 _unlink equ 10 54 _exec equ 11 55 _chdir equ 12 56 _time equ 13 57 _mkdir equ 14 58 _chmod equ 15 59 _chown equ 16 60 _break equ 17 61 _stat equ 18 62 _seek equ 19 63 _tell equ 20 64 _mount equ 21 65 _umount equ 22 66 _setuid equ 23 67 _getuid equ 24 68 _stime equ 25 69 _quit equ 26 70 _intr equ 27 71 _fstat equ 28 72 _emt equ 29 73 _mdate equ 30 74 _stty equ 31 75 _gtty equ 32 76 _ilgins equ 33 77 _sleep equ 34 ; Retro UNIX 8086 v1 feature only ! 78 _msg equ 35 ; Retro UNIX 386 v1 feature only ! 79 _geterr equ 36 ; Retro UNIX 386 v1 feature only ! 80 ; 12/01/2022 - Retro UNIX 386 v1.2 81 ; Retro UNIX 386 v2 system calls 82 _setgid equ 37 83 _getgid equ 38 84 _sysver equ 39 ; (get) Retro Unix 386 version 85 86 %macro sys 1-4 87 ; 03/09/2015 88 ; 13/04/2015 89 ; Retro UNIX 386 v1 system call. 90 %if %0 >= 2 91 mov ebx, %2 92 %if %0 >= 3 93 mov ecx, %3 94 ;%if %0 = 4 95 %if %0 >= 4 ; 11/03/2022 96 mov edx, %4 97 %endif 98 %endif 99 %endif 100 mov eax, %1 101 int 30h 102 %endmacro 103 104 ; 17/06/2022 - Retro UNIX 386 v1.1 105 struc stat 106 ; Retro UNIX v1 'sysstat' output ! 107 ; (34 bytes) 108 00000000 ???? .inode: resw 1 109 00000002 ???? .mode: resw 1 110 00000004 ?? .nlinks: resb 1 111 00000005 ?? .uid: resb 1 112 00000006 ???? .size: resw 1 113 00000008 .dskptr: resw 8 114 00000018 ???????? .ctime: resd 1 115 0000001C ???????? .mtime: resd 1 116 00000020 ???? .rsvd: resw 1 117 .strucsize: 118 endstruc 119 120 ; Retro UNIX 386 v1 system call format: 121 ; sys systemcall (eax) , , 122 123 ;----------------------------------------------------------------- 124 ; text - code 125 ;----------------------------------------------------------------- 126 127 [BITS 32] ; 32-bit intructions (for 80386 protected mode) 128 129 [ORG 0] 130 131 START_CODE: 132 ;/ sh -- command interpreter 133 134 ; 17/06/2022 135 ; 29/05/2022 - Erdogan Tan 136 ; (Modified by using disassembled unix v2 'sh' code.) 137 138 ;;27/12/2015 139 ;;clear BSS 140 ;mov ecx, ((bss_end - bss_start) + 3) / 4 141 ;sub eax, eax 142 ;mov edi, bss_start 143 ;rep stosd 144 s0: 145 00000000 89E5 mov ebp, esp 146 ; mov sp,r5 147 00000002 892D[820C0000] mov [shellarg], ebp 148 ; mov r5,shellarg / save orig sp in shellarg 149 00000008 8B5D04 mov ebx, [ebp+4] 150 0000000B 803B2D cmp byte [ebx], '-' 151 ; cmpb *2(r5),$'- / was this sh called by init or login 152 0000000E 752E jne short s1 153 ; bne 2f / no 154 sys _intr, 0 87 <1> 88 <1> 89 <1> 90 <1> %if %0 >= 2 91 00000010 BB00000000 <1> mov ebx, %2 92 <1> %if %0 >= 3 93 <1> mov ecx, %3 94 <1> 95 <1> %if %0 >= 4 96 <1> mov edx, %4 97 <1> %endif 98 <1> %endif 99 <1> %endif 100 00000015 B81B000000 <1> mov eax, %1 101 0000001A CD30 <1> int 30h 155 ; sys intr; 0 / yes, turn off interrupts 156 sys _quit, 0 87 <1> 88 <1> 89 <1> 90 <1> %if %0 >= 2 91 0000001C BB00000000 <1> mov ebx, %2 92 <1> %if %0 >= 3 93 <1> mov ecx, %3 94 <1> 95 <1> %if %0 >= 4 96 <1> mov edx, %4 97 <1> %endif 98 <1> %endif 99 <1> %endif 100 00000021 B81A000000 <1> mov eax, %1 101 00000026 CD30 <1> int 30h 157 ; sys quit; 0 158 sys _write, 1, msg_unix_sh, msgsh_size 87 <1> 88 <1> 89 <1> 90 <1> %if %0 >= 2 91 00000028 BB01000000 <1> mov ebx, %2 92 <1> %if %0 >= 3 93 0000002D B9[FD050000] <1> mov ecx, %3 94 <1> 95 <1> %if %0 >= 4 96 00000032 BA1B000000 <1> mov edx, %4 97 <1> %endif 98 <1> %endif 99 <1> %endif 100 00000037 B804000000 <1> mov eax, %1 101 0000003C CD30 <1> int 30h 159 s1: ;2: 160 sys _getuid 87 <1> 88 <1> 89 <1> 90 <1> %if %0 >= 2 91 <1> mov ebx, %2 92 <1> %if %0 >= 3 93 <1> mov ecx, %3 94 <1> 95 <1> %if %0 >= 4 96 <1> mov edx, %4 97 <1> %endif 98 <1> %endif 99 <1> %endif 100 0000003E B818000000 <1> mov eax, %1 101 00000043 CD30 <1> int 30h 161 ; sys getuid / who is user 162 ;and eax, eax 163 00000045 20C0 and al, al 164 ; tst r0 / is it superuser 165 00000047 7507 jnz short s2 166 ; bne 2f / no 167 00000049 C605[89060000]23 mov byte [_at], '#' 168 ; movb $'#,at / yes, set new prompt symbol 169 s2: ;2: 170 00000050 837D0001 cmp dword [ebp], 1 171 ; cmp (r5),$1 / tty input? 172 00000054 7631 jna short newline 173 ; ble newline / yes, call with '-' (or with no command 174 ; / file name) 175 00000056 31DB xor ebx, ebx 176 ; clr r0 / no, set tty 177 sys _close 87 <1> 88 <1> 89 <1> 90 <1> %if %0 >= 2 91 <1> mov ebx, %2 92 <1> %if %0 >= 3 93 <1> mov ecx, %3 94 <1> 95 <1> %if %0 >= 4 96 <1> mov edx, %4 97 <1> %endif 98 <1> %endif 99 <1> %endif 100 00000058 B806000000 <1> mov eax, %1 101 0000005D CD30 <1> int 30h 178 ; sys close / close it 179 0000005F 8B5D08 mov ebx, [ebp+8] ; arg 1 180 ; mov 4(r5),0f / get new file name 181 00000062 31C9 xor ecx, ecx ; arg 2 182 sys _open 87 <1> 88 <1> 89 <1> 90 <1> %if %0 >= 2 91 <1> mov ebx, %2 92 <1> %if %0 >= 3 93 <1> mov ecx, %3 94 <1> 95 <1> %if %0 >= 4 96 <1> mov edx, %4 97 <1> %endif 98 <1> %endif 99 <1> %endif 100 00000064 B805000000 <1> mov eax, %1 101 00000069 CD30 <1> int 30h 183 ; sys open; 0:..; 0 / open it 184 0000006B 7311 jnc short s3 185 ; bec 1f / branch if no error 186 0000006D BE[25060000] mov esi, msgNotFound 187 00000072 E8EA010000 call error 188 ; jsr r5,error / error in file name 189 ; ; .even 190 sys _exit 87 <1> 88 <1> 89 <1> 90 <1> %if %0 >= 2 91 <1> mov ebx, %2 92 <1> %if %0 >= 3 93 <1> mov ecx, %3 94 <1> 95 <1> %if %0 >= 4 96 <1> mov edx, %4 97 <1> %endif 98 <1> %endif 99 <1> %endif 100 00000077 B801000000 <1> mov eax, %1 101 0000007C CD30 <1> int 30h 191 ; sys exit 192 s3: ;1: 193 0000007E C605[89060000]00 mov byte [_at], 0 194 ; clr at / clear prompt character, if reading non-tty 195 ; / input file 196 00000085 EB1F jmp short newcom 197 newline: 198 00000087 803D[89060000]00 cmp byte [_at], 0 199 ; tst at / is there a prompt symbol 200 0000008E 7616 jna short newcom 201 ; beq newcom / no 202 ; mov $1,r0 / yes 203 nl: 204 sys _write, 1, prompt, p_size 87 <1> 88 <1> 89 <1> 90 <1> %if %0 >= 2 91 00000090 BB01000000 <1> mov ebx, %2 92 <1> %if %0 >= 3 93 00000095 B9[87060000] <1> mov ecx, %3 94 <1> 95 <1> %if %0 >= 4 96 0000009A BA04000000 <1> mov edx, %4 97 <1> %endif 98 <1> %endif 99 <1> %endif 100 0000009F B804000000 <1> mov eax, %1 101 000000A4 CD30 <1> int 30h 205 ;sys _write, 1, _at, 2 206 ; sys write; at; 2. / print prompt 207 newcom: 208 000000A6 8B25[820C0000] mov esp, [shellarg] 209 ; mov shellarg,sp / 210 000000AC BE[B6060000] mov esi, parbuf 211 ; mov $parbuf,r3 / initialize command list area 212 000000B1 BF[B00A0000] mov edi, parp 213 ; mov $parp,r4 / initialize command list pointers 214 000000B6 31C0 xor eax, eax 215 000000B8 A3[A40A0000] mov [infile], eax ; 0 216 ; clr infile / initialize alternate input 217 000000BD A3[A80A0000] mov [outfile], eax ; 0 218 ; clr outfile / initialize alternate output 219 000000C2 A2[A20A0000] mov [glflag], al ; 0 220 ;mov [glflag], ax ; 0 221 ; clr glflag / initialize global flag 222 ; 27/12/2015 223 000000C7 A2[86060000] mov [FCAT], al ; 0 224 newarg: 225 000000CC E8B8030000 call blank 226 ; jsr pc,blank / squeeze out leading blanks 227 000000D1 E894030000 call delim 228 000000D6 7467 je short nch4 ; '\n', ';', '&' 229 ; jsr r5,delim / is new character a ; \n or & 230 ; br 2f / yes 231 000000D8 56 push esi 232 ; mov r3,-(sp) / no, push arg pointer onto stack 233 000000D9 3C3C cmp al, '<' 234 ; cmp r0,$'< / new input file? 235 000000DB 7508 jne short na1 236 ; bne 1f / no 237 000000DD 8935[A40A0000] mov [infile], esi 238 ; mov (sp),infile / yes, save arg pointer 239 ;jmp short na4 240 000000E3 EB1E jmp short na3 241 ;mov dword [esp], 0 242 ; clr (sp) / clear pointer 243 ;jmp short nch1 244 ; br 3f 245 na1: ;1: 246 000000E5 3C3E cmp al, '>' 247 ; cmp r0,$'> / new output file? 248 000000E7 7530 jne short nch0 249 ;jne short newchar 250 ; bne newchar / no 251 000000E9 8935[A80A0000] mov [outfile], esi 252 ; mov (sp),outfile / yes, save arg pointer 253 ; 27/12/2015 254 000000EF E8A7030000 call getc 255 000000F4 3C3E cmp al, '>' 256 000000F6 7507 jne short na2 257 ; 258 000000F8 A2[86060000] mov [FCAT], al ; '>>' 259 000000FD EB04 jmp short na3 260 na2: 261 000000FF 3C20 cmp al, 20h ; ' ' 262 00000101 7505 jne short na4 263 na3: 264 00000103 E881030000 call blank 265 na4: 266 00000108 C7042400000000 mov dword [esp], 0 267 ; clr (sp) / clear pointer 268 ;jmp short nch1 269 ; br 3f 270 0000010F EB12 jmp short nch7 271 newchar: 272 00000111 3C20 cmp al, 20h 273 ; cmp $' ,r0 / is character a blank 274 00000113 7415 je short nch2 275 ; beq 1f / branch if it is (blank as arg separator) 276 00000115 3C8D cmp al, 8Dh ; 128 + 13 277 00000117 7411 je short nch2 278 ; cmp $'\n+200,r0 / treat \n preceded by ; beq 1f / as blank 280 nch0: 281 00000119 E8A0010000 call putc 282 ; jsr pc,putc / put this character in parbuf list 283 nch1: ;3: 284 0000011E E878030000 call getc 285 ; jsr pc,getc / get next character 286 nch7: 287 00000123 E842030000 call delim 288 00000128 75E7 jne short newchar 289 ;jz short nch2 ; '\n', ';', '&' 290 ; jsr r5,delim / is char a ; \n or &, 291 ; br 1f / yes 292 ;jmp short newchar 293 ; br newchar / no, start new character tests 294 nch2: ;1: 295 0000012A C60600 mov byte [esi], 0 296 0000012D 46 inc esi 297 ; clrb (r3)+ / end name with \0 when read blank, 298 ; or delim 299 0000012E 5B pop ebx 300 0000012F 891F mov [edi], ebx 301 ; mov (sp)+,(r4)+ / move arg ptr to parp location 302 00000131 09DB or ebx, ebx 303 00000133 7403 jz short nch3 304 ;jnz short nch3 305 ; bne 1f / if (sp)=0, in file or out file points 306 ; to arg 307 00000135 83C704 add edi, 4 308 ; tst -(r4) / so ignore dummy (0), in pointer list 309 nch3: ;1: 310 00000138 E82D030000 call delim 311 0000013D 758D jne short newarg 312 ;jz short nch4 ; '\n', ';', '&' 313 ; jsr r5,delim / is char a ; \n or &. 314 ; br 2f / yes 315 ;jmp short newarg 316 ; br newarg / no, start newarg processing 317 nch4: ;2: 318 0000013F C70700000000 mov dword [edi], 0 319 ; clr (r4) / \n, &, or ; takes to here 320 ; / (end of arg list) after 'delim' call 321 00000145 50 push eax 322 ; mov r0,-(sp) / save delimiter in stack 323 00000146 E827000000 call docom 324 ; jsr pc,docom / go to exec command in parbuf 325 0000014B 803C2426 cmp byte [esp], '&' 326 ; cmpb (sp),$'& / get a new command without wait? 327 ;je newcom 328 ; ; beq newcom / yes 329 ; 29/05/2022 330 0000014F 7505 jne short nch_9 331 nch_8: 332 00000151 E950FFFFFF jmp newcom 333 nch_9: 334 00000156 21D2 and edx, edx 335 ; tst r1 / was chdir just executed or line ended 336 ; / with ampersand? 337 00000158 740D jz short nch6 338 ; beq 2f / yes 339 nch5: ;1: 340 sys _wait 87 <1> 88 <1> 89 <1> 90 <1> %if %0 >= 2 91 <1> mov ebx, %2 92 <1> %if %0 >= 3 93 <1> mov ecx, %3 94 <1> 95 <1> %if %0 >= 4 96 <1> mov edx, %4 97 <1> %endif 98 <1> %endif 99 <1> %endif 100 0000015A B807000000 <1> mov eax, %1 101 0000015F CD30 <1> int 30h 341 ; sys wait / no, wait for new process to terminate 342 ; / command executed) 343 00000161 7204 jc short nch6 344 ; bcs 2f / no, children not previously waited for 345 00000163 39D0 cmp eax, edx 346 ; cmp r0,r1 / is this my child 347 00000165 75F3 jne short nch5 348 ; bne 1b 349 nch6: ;2: 350 00000167 803C240D cmp byte [esp], 0Dh 351 ;cmp byte [esp], 0Ah 352 ; cmp (sp),$'\n / was delimiter a new line 353 ;je newline 354 ; ; beq newline / yes 355 ; 29/05/2022 356 ;jmp newcom 357 ; ; br newcom / no, pick up next command 358 0000016B 75E4 jne short nch_8 ; jne newcom 359 0000016D E915FFFFFF jmp newline ; je newline 360 docom: 361 00000172 81EF[B00A0000] sub edi, parp 362 ; sub $parp,r4 / out arg count in r4 363 00000178 7503 jne short dcom1 364 ; bne 1f / any arguments? 365 dcom0: 366 0000017A 29D2 sub edx, edx ; 0 367 ; clr r1 / no, line ended with ampersand 368 0000017C C3 retn 369 ; rts pc / return from call 370 dcom1: ;1: 371 0000017D 89FB mov ebx, edi 372 ; 06/12/2013 373 0000017F BE[8B060000] mov esi, qecho 374 00000184 E827010000 call chcom 375 00000189 7543 jnz short dcom7 376 ; 28/12/2015 377 0000018B 89DD mov ebp, ebx 378 0000018D BF[B00A0000] mov edi, parp 379 dcom9: ; CRLF 380 sys _write, 1, nextline, 2 87 <1> 88 <1> 89 <1> 90 <1> %if %0 >= 2 91 00000192 BB01000000 <1> mov ebx, %2 92 <1> %if %0 >= 3 93 00000197 B9[22060000] <1> mov ecx, %3 94 <1> 95 <1> %if %0 >= 4 96 0000019C BA02000000 <1> mov edx, %4 97 <1> %endif 98 <1> %endif 99 <1> %endif 100 000001A1 B804000000 <1> mov eax, %1 101 000001A6 CD30 <1> int 30h 381 ; 382 000001A8 83ED04 sub ebp, 4 ; remain arg count x 4 383 000001AB 76CD jna short dcom0 384 000001AD 83C704 add edi, 4 385 000001B0 8B37 mov esi, [edi] 386 ;or esi, esi 387 ;jz short dcom0 388 000001B2 89F2 mov edx, esi ; string address 389 dcom10: 390 000001B4 AC lodsb 391 000001B5 08C0 or al, al 392 000001B7 75FB jnz short dcom10 393 000001B9 87D6 xchg edx, esi 394 000001BB 29F2 sub edx, esi ; byte count 395 000001BD 4A dec edx 396 ;jz short dcom0 397 ; write string 398 sys _write, 1, esi ; edx = byte count 87 <1> 88 <1> 89 <1> 90 <1> %if %0 >= 2 91 000001BE BB01000000 <1> mov ebx, %2 92 <1> %if %0 >= 3 93 000001C3 89F1 <1> mov ecx, %3 94 <1> 95 <1> %if %0 >= 4 96 <1> mov edx, %4 97 <1> %endif 98 <1> %endif 99 <1> %endif 100 000001C5 B804000000 <1> mov eax, %1 101 000001CA CD30 <1> int 30h 399 000001CC EBC4 jmp short dcom9 400 dcom7: 401 000001CE BE[93060000] mov esi, qchdir 402 000001D3 E8D8000000 call chcom 403 000001D8 752D jnz short dcom4 404 ; jsr r5,chcom; qchdir / is command chdir? 405 ; br 2f / command not chdir 406 dcom12: 407 000001DA 80FB08 cmp bl, 8 ; 8 = arg count x 4 (24/08/2015) 408 ;cmp bx, 8 409 ; cmp r4,$4 / prepare to exec chdir, 410 ; 4 = arg count x 2 411 000001DD 740C je short dcom2 412 ; beq 3f 413 dcom8: 414 000001DF BE[35060000] mov esi, msgArgCount 415 000001E4 E878000000 call error 416 ; jsr r5,error / go to print error 417 ; ; .even 418 ;jmp short dcom3 419 ; br 4f 420 000001E9 EB8F jmp short dcom0 421 dcom2: ;3: 422 000001EB 8B1D[B40A0000] mov ebx, [parp+4] 423 ;mov parp+2,0f / move directory name to sys call 424 sys _chdir 87 <1> 88 <1> 89 <1> 90 <1> %if %0 >= 2 91 <1> mov ebx, %2 92 <1> %if %0 >= 3 93 <1> mov ecx, %3 94 <1> 95 <1> %if %0 >= 4 96 <1> mov edx, %4 97 <1> %endif 98 <1> %endif 99 <1> %endif 100 000001F1 B80C000000 <1> mov eax, %1 101 000001F6 CD30 <1> int 30h 425 ; sys chdir; 0:0 / exec chdir 426 000001F8 730A jnc short dcom3 427 ; bec 4f / no error exit 428 000001FA BE[3F060000] mov esi, msgBadDir 429 000001FF E85D000000 call error 430 ; jsr r5,error / go to print error 431 ; ; .even 432 ; / this diagnostic 433 dcom3: ;4: 434 00000204 31D2 xor edx, edx ; 0 435 ; clr r1 / set r1 to zero to skip wait 436 00000206 C3 retn 437 ; rts pc / and return 438 dcom4: ;2: 439 ; 06/12/2013 440 00000207 BE[90060000] mov esi, qcd 441 0000020C E89F000000 call chcom 442 00000211 74C7 jz short dcom12 443 dcom11: 444 00000213 BE[99060000] mov esi, glogin 445 00000218 E893000000 call chcom 446 0000021D 7522 jnz short dcom5 447 ; jsr r5,chcom; glogin / is command login? 448 ; br 2f / not loqin, go to fork 449 sys _exec, parbuf, parp 87 <1> 88 <1> 89 <1> 90 <1> %if %0 >= 2 91 0000021F BB[B6060000] <1> mov ebx, %2 92 <1> %if %0 >= 3 93 00000224 B9[B00A0000] <1> mov ecx, %3 94 <1> 95 <1> %if %0 >= 4 96 <1> mov edx, %4 97 <1> %endif 98 <1> %endif 99 <1> %endif 100 00000229 B80B000000 <1> mov eax, %1 101 0000022E CD30 <1> int 30h 450 ; sys exec; parbuf; parp / exec login 451 sys _exec, binpb, parp 87 <1> 88 <1> 89 <1> 90 <1> %if %0 >= 2 91 00000230 BB[B1060000] <1> mov ebx, %2 92 <1> %if %0 >= 3 93 00000235 B9[B00A0000] <1> mov ecx, %3 94 <1> 95 <1> %if %0 >= 4 96 <1> mov edx, %4 97 <1> %endif 98 <1> %endif 99 <1> %endif 100 0000023A B80B000000 <1> mov eax, %1 101 0000023F CD30 <1> int 30h 452 ; sys exec; binpb; parp / or /bin/login 453 dcom5: ;2: / no error return?? 454 00000241 BB[F3020000] mov ebx, newproc 455 ; child process will return to 'newproc' address 456 sys _fork 87 <1> 88 <1> 89 <1> 90 <1> %if %0 >= 2 91 <1> mov ebx, %2 92 <1> %if %0 >= 3 93 <1> mov ecx, %3 94 <1> 95 <1> %if %0 >= 4 96 <1> mov edx, %4 97 <1> %endif 98 <1> %endif 99 <1> %endif 100 00000246 B802000000 <1> mov eax, %1 101 0000024B CD30 <1> int 30h 457 ; sys fork / generate sh child process 458 ; for command 459 ; br newproc / exec command with 460 ; new process 461 ; parent process will return here 462 0000024D 730F jnc short dcom6 463 ; bec 1f / no error exit, old process 464 0000024F BE[4D060000] mov esi, msgTryAgain 465 00000254 E808000000 call error 466 ; jsr r5,error / go to print error 467 ; ; .even / this diagnostic 468 00000259 E929FEFFFF jmp newline 469 ; jmp newline / and return for next try 470 dcom6: ;1: 471 0000025E 89C2 mov edx, eax ; child process ID 472 ; mov r0,r1 / save id of child sh 473 00000260 C3 retn 474 ; rts pc / return to "jsr pc, docom" call 475 ; in parent sh 476 error: 477 sys _write, 1, nextline, 2 87 <1> 88 <1> 89 <1> 90 <1> %if %0 >= 2 91 00000261 BB01000000 <1> mov ebx, %2 92 <1> %if %0 >= 3 93 00000266 B9[22060000] <1> mov ecx, %3 94 <1> 95 <1> %if %0 >= 4 96 0000026B BA02000000 <1> mov edx, %4 97 <1> %endif 98 <1> %endif 99 <1> %endif 100 00000270 B804000000 <1> mov eax, %1 101 00000275 CD30 <1> int 30h 478 s4: 479 00000277 AC lodsb 480 00000278 A2[800C0000] mov [och], al 481 ; movb (r5)+,och / pick up diagnostic character 482 0000027D 20C0 and al, al 483 0000027F 7418 jz short s5 484 ; beq 1f / 0 is end of line 485 sys _write, 1, och, 1 87 <1> 88 <1> 89 <1> 90 <1> %if %0 >= 2 91 00000281 BB01000000 <1> mov ebx, %2 92 <1> %if %0 >= 3 93 00000286 B9[800C0000] <1> mov ecx, %3 94 <1> 95 <1> %if %0 >= 4 96 0000028B BA01000000 <1> mov edx, %4 97 <1> %endif 98 <1> %endif 99 <1> %endif 100 00000290 B804000000 <1> mov eax, %1 101 00000295 CD30 <1> int 30h 486 ; mov $1,r0 / set for tty output 487 ; sys write; och; 1 / print it 488 00000297 EBDE jmp short s4 489 ;jmp short error 490 ; br error / continue to get characters 491 s5: ;1: 492 ;inc esi 493 ; inc r5 / inc r5 to point to return 494 ;;and si, 0FFFEh 495 ;shr esi, 1 496 ;shl esi, 1 497 ; bic $1,r5 / make it even 498 sys _seek, 0, 0, 2 87 <1> 88 <1> 89 <1> 90 <1> %if %0 >= 2 91 00000299 BB00000000 <1> mov ebx, %2 92 <1> %if %0 >= 3 93 0000029E B900000000 <1> mov ecx, %3 94 <1> 95 <1> %if %0 >= 4 96 000002A3 BA02000000 <1> mov edx, %4 97 <1> %endif 98 <1> %endif 99 <1> %endif 100 000002A8 B813000000 <1> mov eax, %1 101 000002AD CD30 <1> int 30h 499 ; clr r0 / set for input 500 ; sys seek; 0; 2 / exit from runcom. skip to 501 ; / end of input file 502 000002AF C3 retn 503 ;; rts r5 ; unix v2 shell ; 29/05/2022 504 ;; (not in original unix v1 'sh.s') 505 506 chcom: ; / has no effect if tty input 507 ; mov (r5)+,r1 / glogin gchdir r1, bump r5 508 000002B0 BF[B6060000] mov edi, parbuf 509 ; mov $parbuf,r2 / command address r2 'login' 510 s6: ;1: 511 000002B5 AC lodsb 512 ; movb (r1)+,r0 / is this command 'chdir' 513 000002B6 AE scasb 514 ; cmpb (r2)+,r0 / compare command name byte 515 ; / with 'login' or 'chdir' 516 000002B7 7504 jne short s7 517 ; bne 1f / doesn't compare 518 000002B9 08C0 or al, al 519 ; tst r0 / is this 520 000002BB 75F8 jnz short s6 521 ; bne 1b / end of names 522 ; tst (r5)+ / yes, bump r5 again to execute 523 ; / login or chdir 524 s7: ;1: 525 000002BD C3 retn 526 ; rts r5 / no, return to exec command 527 528 putc: 529 000002BE 3C27 cmp al, 27h ; ' 530 ; cmp r0,$'' / single quote? 531 000002C0 740A je short pch1 532 ; beq 1f / yes 533 000002C2 3C22 cmp al, 22h ; " 534 ; cmp r0,$'" / double quote 535 000002C4 7406 je short pch1 536 ; beq 1f / yes 537 000002C6 247F and al, 7Fh 538 ; bic $!177,r0 / no, remove 200, if present 539 000002C8 8806 mov [esi], al 540 000002CA 46 inc esi 541 ; movb r0,(r3)+ / store character in parbuf 542 000002CB C3 retn 543 ; rts pc 544 pch1: ;1: 545 000002CC 50 push eax 546 ; mov r0,-(sp) / push quote mark onto stack 547 pch2: ;1: 548 000002CD E8C9010000 call getc 549 ; jsr pc,getc / get a quoted character 550 000002D2 3C0D cmp al, 0Dh 551 ;cmp al, 0Ah ; \n 552 ; cmp r0,$'\n / is it end or line 553 000002D4 750F jne short pch3 554 ; bne 2f / no 555 000002D6 BE[57060000] mov esi, msgImbalance 556 000002DB E881FFFFFF call error 557 ; jsr r5,error / yes, indicate missing 558 ; quote mark 559 ; <"' imbalance\n\0>; .even 560 000002E0 E9A2FDFFFF jmp newline 561 ; jmp newline / ask for new line 562 pch3: ;2: 563 000002E5 380424 cmp [esp], al 564 ; cmp r0,(sp) / is this closing quote mark 565 000002E8 7407 je short pch4 566 ; beq 1f / yes 567 000002EA 247F and al, 7Fh 568 ; bic $!177,r0 / no, strip off 200 569 ; if present 570 000002EC 8806 mov [esi], al 571 000002EE 46 inc esi 572 ; movb r0,(r3)+ / store quoted character 573 ; in parbuf 574 000002EF EBDC jmp short pch2 575 ; br 1b / continue 576 pch4: ;1: 577 000002F1 58 pop eax 578 ; tst (sp)+ / pop quote mark off stack 579 000002F2 C3 retn 580 ; rts pc / return 581 582 ; / thp`e new process 583 584 newproc: 585 000002F3 8B35[A40A0000] mov esi, [infile] 586 000002F9 09F6 or esi, esi 587 000002FB 7456 jz short np2 588 ; mov infile,0f / move pointer to new file name 589 ; beq 1f / branch if no alternate read file given 590 000002FD 803E00 cmp byte [esi], 0 591 ; tstb *0f 592 00000300 7640 jna short np1 593 ; beq 3f / branch if no file name given 594 595 ; 17/06/2022 - Retro UNIX 386 v1.1 596 sys _stat, esi, stbuf ; get file (inode) status 87 <1> 88 <1> 89 <1> 90 <1> %if %0 >= 2 91 00000302 89F3 <1> mov ebx, %2 92 <1> %if %0 >= 3 93 00000304 B9[880C0000] <1> mov ecx, %3 94 <1> 95 <1> %if %0 >= 4 96 <1> mov edx, %4 97 <1> %endif 98 <1> %endif 99 <1> %endif 100 00000309 B812000000 <1> mov eax, %1 101 0000030E CD30 <1> int 30h 597 00000310 7230 jc short np1 598 ; 599 ; (regular files, disk blocks may be used as input source) 600 ; ((pseudo tty input redirection not allowed)) 601 602 00000312 66A1[880C0000] mov ax, [stbuf] ; inode number 603 00000318 6683F813 cmp ax, 19 ; > tty9 inode number (regular file) ? 604 0000031C 7708 ja short np13 ; yes 605 0000031E 3C0A cmp al, 10 ; < tty0 ? 606 00000320 7320 jnb short np1 ; yes 607 00000322 3C01 cmp al, 1 608 00000324 741C je short np1 609 np13: 610 sys _close, 0 87 <1> 88 <1> 89 <1> 90 <1> %if %0 >= 2 91 00000326 BB00000000 <1> mov ebx, %2 92 <1> %if %0 >= 3 93 <1> mov ecx, %3 94 <1> 95 <1> %if %0 >= 4 96 <1> mov edx, %4 97 <1> %endif 98 <1> %endif 99 <1> %endif 100 0000032B B806000000 <1> mov eax, %1 101 00000330 CD30 <1> int 30h 611 ; clr r0 / set tty input file name 612 ; sys close / close it 613 sys _open, esi, 0 87 <1> 88 <1> 89 <1> 90 <1> %if %0 >= 2 91 00000332 89F3 <1> mov ebx, %2 92 <1> %if %0 >= 3 93 00000334 B900000000 <1> mov ecx, %3 94 <1> 95 <1> %if %0 >= 4 96 <1> mov edx, %4 97 <1> %endif 98 <1> %endif 99 <1> %endif 100 00000339 B805000000 <1> mov eax, %1 101 0000033E CD30 <1> int 30h 614 ; sys open; 0:..; 0 / open new input file 615 ; for reading 616 00000340 7311 jnc short np2 617 ; bcc 1f / branch if input file ok 618 np1: ;3: 619 00000342 BE[64060000] mov esi, msgInputFile 620 00000347 E815FFFFFF call error 621 ; jsr r5,error / file not ok, print error 622 ; ; .even / this diagnostic 623 sys _exit 87 <1> 88 <1> 89 <1> 90 <1> %if %0 >= 2 91 <1> mov ebx, %2 92 <1> %if %0 >= 3 93 <1> mov ecx, %3 94 <1> 95 <1> %if %0 >= 4 96 <1> mov edx, %4 97 <1> %endif 98 <1> %endif 99 <1> %endif 100 0000034C B801000000 <1> mov eax, %1 101 00000351 CD30 <1> int 30h 624 ; sys exit / terminate this process 625 ; and make parent sh 626 np2: ;1: 627 00000353 8B35[A80A0000] mov esi, [outfile] 628 ; mov outfile,r2 / more pointer to new file name 629 00000359 21F6 and esi, esi 630 ;jz short np6 631 ; beq 1f / branch if no alternate write file 632 ; 17/06/2022 633 0000035B 7505 jnz short np11 634 0000035D E9AB000000 jmp np6 635 np11: 636 ; 27/12/2015 637 00000362 803E00 cmp byte [esi], 0 638 00000365 763D jna short np4 639 ; 640 ;cmp byte [esi], '>' 641 ; cmpb (r2),$'> / is > at beqinning of file name? 642 ;jne short np3 643 ; bne 4f / branch if it isn't 644 ;inc esi 645 ; inc r2 / yes, increment pointer 646 ; 647 ; 17/06/2022 648 ;cmp byte [FCAT], '>' ; '>>' 649 ;jne short np3 650 651 ; 17/06/2022 - Retro UNIX 386 v1.1 652 sys _stat, esi, stbuf ; get file (inode) status 87 <1> 88 <1> 89 <1> 90 <1> %if %0 >= 2 91 00000367 89F3 <1> mov ebx, %2 92 <1> %if %0 >= 3 93 00000369 B9[880C0000] <1> mov ecx, %3 94 <1> 95 <1> %if %0 >= 4 96 <1> mov edx, %4 97 <1> %endif 98 <1> %endif 99 <1> %endif 100 0000036E B812000000 <1> mov eax, %1 101 00000373 CD30 <1> int 30h 653 00000375 7247 jc short np3 654 655 ; Block devices and dirs must not be target 656 00000377 F605[8B0C0000]40 test byte [stbuf+stat.mode+1], 40h ; directory ? 657 0000037E 7524 jnz short np4 ; yes ; error 658 659 00000380 66A1[880C0000] mov ax, [stbuf] ; inode number 660 00000386 6683F829 cmp ax, 41 ; regular file ? 661 0000038A 7729 ja short np14 ; yes 662 663 0000038C 3C08 cmp al, 8 ; > hd3 inode number ? 664 0000038E 7704 ja short np12 ; yes ; character device 665 666 00000390 3C03 cmp al, 3 ; >= fd0 inode number ? 667 00000392 7310 jnb short np4 ; yes ; output file error 668 np12: 669 sys _open, esi, 1 87 <1> 88 <1> 89 <1> 90 <1> %if %0 >= 2 91 00000394 89F3 <1> mov ebx, %2 92 <1> %if %0 >= 3 93 00000396 B901000000 <1> mov ecx, %3 94 <1> 95 <1> %if %0 >= 4 96 <1> mov edx, %4 97 <1> %endif 98 <1> %endif 99 <1> %endif 100 0000039B B805000000 <1> mov eax, %1 101 000003A0 CD30 <1> int 30h 670 ; mov r2,0f 671 ; sys open; 0:..; 1 / open file for writing 672 000003A2 732A jnc short np5 673 ; bec 3f / if no error 674 np4: ;2: 675 000003A4 BE[6F060000] mov esi, msgOutputFile 676 000003A9 E8B3FEFFFF call error 677 ; jsr r5,error 678 ; ; .even 679 sys _exit 87 <1> 88 <1> 89 <1> 90 <1> %if %0 >= 2 91 <1> mov ebx, %2 92 <1> %if %0 >= 3 93 <1> mov ecx, %3 94 <1> 95 <1> %if %0 >= 4 96 <1> mov edx, %4 97 <1> %endif 98 <1> %endif 99 <1> %endif 100 000003AE B801000000 <1> mov eax, %1 101 000003B3 CD30 <1> int 30h 680 ; sys exit 681 682 ;jmp short np4 683 684 ; 17/06/2022 685 np14: 686 000003B5 803D[86060000]3E cmp byte [FCAT], '>' ; '>>' ? 687 000003BC 74D6 je short np12 ; no, '>' 688 np3: ;4: 689 sys _creat, esi, 15 ; Decimal 15 = Octal 17 87 <1> 88 <1> 89 <1> 90 <1> %if %0 >= 2 91 000003BE 89F3 <1> mov ebx, %2 92 <1> %if %0 >= 3 93 000003C0 B90F000000 <1> mov ecx, %3 94 <1> 95 <1> %if %0 >= 4 96 <1> mov edx, %4 97 <1> %endif 98 <1> %endif 99 <1> %endif 100 000003C5 B808000000 <1> mov eax, %1 101 000003CA CD30 <1> int 30h 690 ; mov r2,0f 691 ; sys creat; 0:..; 17 / create new file 692 ; with this name 693 ;jnc short np5 694 ; bec 3f / branch if no error 695 ; 17/06/2022 696 000003CC 72D6 jc short np4 697 698 np5: ;3: 699 sys _close, eax 87 <1> 88 <1> 89 <1> 90 <1> %if %0 >= 2 91 000003CE 89C3 <1> mov ebx, %2 92 <1> %if %0 >= 3 93 <1> mov ecx, %3 94 <1> 95 <1> %if %0 >= 4 96 <1> mov edx, %4 97 <1> %endif 98 <1> %endif 99 <1> %endif 100 000003D0 B806000000 <1> mov eax, %1 101 000003D5 CD30 <1> int 30h 700 ; sys close / close the new write file 701 ; mov r2,0f / move new name to open 702 np10: 703 sys _close, 1 87 <1> 88 <1> 89 <1> 90 <1> %if %0 >= 2 91 000003D7 BB01000000 <1> mov ebx, %2 92 <1> %if %0 >= 3 93 <1> mov ecx, %3 94 <1> 95 <1> %if %0 >= 4 96 <1> mov edx, %4 97 <1> %endif 98 <1> %endif 99 <1> %endif 100 000003DC B806000000 <1> mov eax, %1 101 000003E1 CD30 <1> int 30h 704 ; mov $1,r0 / set tty file name 705 ; sys close / close it 706 sys _open, esi, 1 87 <1> 88 <1> 89 <1> 90 <1> %if %0 >= 2 91 000003E3 89F3 <1> mov ebx, %2 92 <1> %if %0 >= 3 93 000003E5 B901000000 <1> mov ecx, %3 94 <1> 95 <1> %if %0 >= 4 96 <1> mov edx, %4 97 <1> %endif 98 <1> %endif 99 <1> %endif 100 000003EA B805000000 <1> mov eax, %1 101 000003EF CD30 <1> int 30h 707 ; sys open; 0:..; 1 / open new output file, 708 ; /it now has file descriptor 1 709 ; 27/12/2015 710 000003F1 803D[86060000]3E cmp byte [FCAT], '>' ; '>>' 711 000003F8 7513 jne short np6 712 ; 713 sys _seek, eax, 0, 2 87 <1> 88 <1> 89 <1> 90 <1> %if %0 >= 2 91 000003FA 89C3 <1> mov ebx, %2 92 <1> %if %0 >= 3 93 000003FC B900000000 <1> mov ecx, %3 94 <1> 95 <1> %if %0 >= 4 96 00000401 BA02000000 <1> mov edx, %4 97 <1> %endif 98 <1> %endif 99 <1> %endif 100 00000406 B813000000 <1> mov eax, %1 101 0000040B CD30 <1> int 30h 714 ; sys seek; 0; 2 / set pointer to 715 ; current end of file 716 np6: ;1: 717 0000040D 803D[A20A0000]00 cmp byte [glflag], 0 718 ; tst glflag / was *, ? or [ encountered? 719 00000414 7739 ja short np9 720 ; bne 1f / yes 721 sys _exec, parbuf, parp 87 <1> 88 <1> 89 <1> 90 <1> %if %0 >= 2 91 00000416 BB[B6060000] <1> mov ebx, %2 92 <1> %if %0 >= 3 93 0000041B B9[B00A0000] <1> mov ecx, %3 94 <1> 95 <1> %if %0 >= 4 96 <1> mov edx, %4 97 <1> %endif 98 <1> %endif 99 <1> %endif 100 00000420 B80B000000 <1> mov eax, %1 101 00000425 CD30 <1> int 30h 722 ; sys exec; parbuf; parp / no, execute 723 ; this command 724 sys _exec, binpb, parp 87 <1> 88 <1> 89 <1> 90 <1> %if %0 >= 2 91 00000427 BB[B1060000] <1> mov ebx, %2 92 <1> %if %0 >= 3 93 0000042C B9[B00A0000] <1> mov ecx, %3 94 <1> 95 <1> %if %0 >= 4 96 <1> mov edx, %4 97 <1> %endif 98 <1> %endif 99 <1> %endif 100 00000431 B80B000000 <1> mov eax, %1 101 00000436 CD30 <1> int 30h 725 ; sys exec; binpb; parp / or /bin/this command 726 727 ;------ 29/05/2022 - unix v2 shell 728 ; (source code from disassembled /bin/sh binary) 729 ; following part is not existing in v2 shell 730 ; 731 ;np7: ;2: 732 ; sys _stat, binpb, inbuf 733 ; ; sys stat; binpb; inbuf / if can't execute 734 ; ; / does it exist? 735 ; jc short np8 736 ; ; bes 2f / branch if it doesn't 737 ; mov esi, parp-4 738 ; mov dword [esi], shell 739 ; ; mov $shell,parp-2 / does exist, 740 ; ; not executable 741 ; mov eax, binpb 742 ; mov [parp], eax 743 ; ; mov $binpb,parp / so it must be 744 ; sys _exec, shell, esi 745 ; ; sys exec; shell; parp-2 / a command file, 746 ; ; / get it with sh /bin/x (if x name of file) 747 ;------ 748 749 np8: ;2: 750 00000438 BE[7B060000] mov esi, msgNoCmd 751 0000043D E81FFEFFFF call error 752 ; jsr r5,error / a return for exec 753 ; is the diagnostic 754 ; ; .even 755 00000442 8B25[820C0000] mov esp, [shellarg] 756 sys _exit 87 <1> 88 <1> 89 <1> 90 <1> %if %0 >= 2 91 <1> mov ebx, %2 92 <1> %if %0 >= 3 93 <1> mov ecx, %3 94 <1> 95 <1> %if %0 >= 4 96 <1> mov edx, %4 97 <1> %endif 98 <1> %endif 99 <1> %endif 100 00000448 B801000000 <1> mov eax, %1 101 0000044D CD30 <1> int 30h 757 ; sys exit 758 np9: ;1: 759 0000044F BE[AC0A0000] mov esi, parp-4 760 00000454 C706[A7060000] mov dword [esi], glob 761 ; mov $glob,parp-2 / prepare to process *,? 762 sys _exec, glob, esi 87 <1> 88 <1> 89 <1> 90 <1> %if %0 >= 2 91 0000045A BB[A7060000] <1> mov ebx, %2 92 <1> %if %0 >= 3 93 0000045F 89F1 <1> mov ecx, %3 94 <1> 95 <1> %if %0 >= 4 96 <1> mov edx, %4 97 <1> %endif 98 <1> %endif 99 <1> %endif 100 00000461 B80B000000 <1> mov eax, %1 101 00000466 CD30 <1> int 30h 763 ; sys exec; glob; parp-2 764 ; / execute modified command 765 00000468 EBCE jmp short np8 766 ; br 2b 767 768 delim: 769 0000046A 3C0D cmp al, 0Dh ; carriage return 770 0000046C 741A je short dlim2 771 ;cmp al, 0Ah 772 ; cmp r0,$'\n / is character a newline 773 ;je short dlim2 774 ; beq 1f 775 0000046E 3C26 cmp al, '&' 776 ;cmp r0,$'& / is it & 777 00000470 7416 je short dlim2 778 ; beq 1f / yes 779 00000472 3C3B cmp al, ';' 780 ; cmp r0,$'; / is it ; 781 00000474 7412 je short dlim2 782 ; beq 1f / yes 783 00000476 3C3F cmp al, '?' 784 ; cmp r0,$'? / is it ? 785 00000478 7408 je short dlim1 786 ; beq 3f 787 ; 788 ;------ 29/05/2022 - unix v2 shell 789 ; (source code from disassembled /bin/sh binary) 790 0000047A 3C2A cmp al, '*' 791 ; cmp r0,$'* / is it * 792 0000047C 7404 je short dlim1 793 ; beq 3f 794 795 0000047E 3C5B cmp al, '[' 796 ; cmp r0,$'[ / is it beginning of character string 797 ; / (for glob) 798 00000480 7506 jne short dlim2 799 ; bne 2f 800 dlim1: ;3: 801 00000482 FE05[A20A0000] inc byte [glflag] 802 ; inc glflag / ? or * or [ set flag 803 ;2: 804 ;tst (r5)+ / bump to process all except \n,;,& 805 dlim2: ;1: 806 ; zf = 1 if the char is '\n' or ';' or '&' 807 00000488 C3 retn 808 ; rts r5 809 blank: 810 00000489 E80D000000 call getc 811 ; jsr pc,getc / get next character 812 0000048E 3C20 cmp al, 20h 813 ; cmp $' ,r0 / leading blanks 814 00000490 74F7 je short blank 815 ; beq blank / yes, 'squeeze out' 816 00000492 3C8D cmp al, 8Dh ; 80h + 0Dh 817 ;cmp al, 8Ah ; 80h + 0Ah 818 00000494 74F3 je short blank 819 ; cmp r0,$200+'\n / new-line preceded by ; is translated 821 ; beq blank / into blank 822 ; 28/12/2015 823 00000496 3C0A cmp al, 0Ah 824 00000498 74EF je short blank 825 ; 826 0000049A C3 retn 827 ; rts pc 828 getc: 829 0000049B 833D[9E0A0000]00 cmp dword [param], 0 830 ; tst param / are we substituting for $n 831 000004A2 773D ja short gch3 832 ; bne 2f/ yes 833 gch0: 834 000004A4 8B1D[780C0000] mov ebx, [inbufp] 835 ; mov inbufp,r1 / no, move normal input pointer to r1 836 s8: 837 000004AA 3B1D[7C0C0000] cmp ebx, [einbuf] 838 ; cmp r1,einbuf / end of input line? 839 000004B0 7207 jb short gch1 840 ; bne 1f / no 841 000004B2 E877000000 call getbuf 842 ; jsr pc,getbuf / yes, put next console line 843 ; in buffer 844 000004B7 EBEB jmp short gch0 845 ; br getc 846 gch1: ;1: 847 000004B9 8A03 mov al, [ebx] 848 000004BB 43 inc ebx 849 ; movb (r1)+,r0 / move byte from input buffer to r0 850 000004BC 891D[780C0000] mov [inbufp], ebx 851 ; mov r1,inbufp / increment routine 852 000004C2 0A05[860C0000] or al, [escap] 853 ;or ax, escap 854 ; bis escap,r0 / if last character was \ this adds 855 ; / 200 to current character 856 ;mov byte [escap], 0 857 ;mov word [escap], 0 858 ; clr escap / clear, so escap normally zero 859 000004C8 3C5C cmp al, '\' 860 ; cmp r0,$'\\ / note that \\ is equal \ in as 861 000004CA 740C je short gch2 862 ; beq 1f 863 000004CC C605[860C0000]00 mov byte [escap], 0 864 000004D3 3C24 cmp al, '$' 865 ; cmp r0,$'$ / is it $ 866 000004D5 7429 je short gch5 867 ; beq 3f / yes 868 000004D7 C3 retn 869 ; rts pc / no 870 gch2: ;1: 871 000004D8 C605[860C0000]80 mov byte [escap], 80h 872 ;mov word [escap], 128 873 ; mov $200,escap / mark presence of \ in command line 874 000004DF EBC9 jmp short s8 875 ;jmp short gch0 876 ; br getc / get next character 877 gch3: ;2: 878 000004E1 8B1D[9E0A0000] mov ebx, [param] 879 000004E7 8A03 mov al, [ebx] 880 ; movb *param,r0 / pick up substitution character 881 ; / put in r0 882 000004E9 08C0 or al, al 883 000004EB 7407 jz short gch4 884 ; beq 1f / if end of substitution arg, branch 885 000004ED FF05[9E0A0000] inc dword [param] 886 ; inc param / if not end, set for next character 887 000004F3 C3 retn 888 ; rts pc / return as though character in ro is normal 889 ; / input 890 gch4: ;1: 891 000004F4 C705[9E0A0000]0000- mov dword [param], 0 891 000004FC 0000 892 ; clr param / unset substitution pointer 893 000004FE EBA4 jmp short gch0 894 ; br getc / get next char in normal input 895 gch5: ;3: 896 00000500 E89FFFFFFF call gch0 897 ;call getc 898 ; jsr pc,getc / get digit after $ 899 00000505 2C30 sub al, '0' 900 ; sub $'0,r0 / strip off zone bits 901 00000507 3C09 cmp al, 9 902 ; cmp r0,$9. / compare with digit 9 903 00000509 7602 jna short gch6 904 ; blos 1f / less than or equal 9 905 0000050B B009 mov al, 9 906 ; mov $9.,r0 / if larger than 9, force 9 907 gch6: ;1: 908 0000050D 8B1D[820C0000] mov ebx, [shellarg] 909 ; mov shellarg,r1 / get pointer to stack for 910 ; / this call of shell 911 00000513 0FB6C0 movzx eax, al ; al->eax 912 00000516 FEC0 inc al 913 ;inc eax 914 ; inc r0 / digit +1 915 00000518 3B03 cmp eax, [ebx] 916 ; cmp r0,(r1) / is it less than # of args 917 ; in this call 918 0000051A 7388 jnb short gch0 919 ; bge getc / no, ignore it. so this $n is not replaced 920 0000051C C0E002 shl al, 2 ; multiply by 4 (24/08/2015) 921 ;shl al, 1 922 ;;shl ax, 1 923 ; asl r0 / yes, multiply by 2 (to skip words) 924 0000051F 01C3 add ebx, eax 925 ; add r1,r0 / form pointer to arg pointer (-2) 926 00000521 8B4304 mov eax, [ebx+4] 927 00000524 A3[9E0A0000] mov [param], eax 928 ; mov 2(r0),param / move arg pointer to param 929 00000529 E96DFFFFFF jmp getc 930 ; br getc / go to get substitution arg for $n 931 getbuf: 932 0000052E B9[780B0000] mov ecx, inbuf 933 ; mov $inbuf,r0 / move input buffer address 934 00000533 890D[780C0000] mov [inbufp], ecx 935 ; mov r0,inbufp / to input buffer pointer 936 00000539 890D[7C0C0000] mov [einbuf], ecx 937 ; mov r0,einbuf / and initialize pointer to end of 938 ; / character string 939 0000053F 49 dec ecx 940 ; dec r0 / decrement pointer so can utilize normal 941 ; / 100p starting at 1f 942 ; mov r0,0f / initialize address for reading 1st char 943 00000540 BA01000000 mov edx, 1 944 gbuf0: ;1: 945 00000545 41 inc ecx 946 ; inc 0f / this routine filles inbuf with line from 947 ; / console - if there is cnc 948 00000546 51 push ecx 949 ; edx = 1 950 sys _read, 0, och 87 <1> 88 <1> 89 <1> 90 <1> %if %0 >= 2 91 00000547 BB00000000 <1> mov ebx, %2 92 <1> %if %0 >= 3 93 0000054C B9[800C0000] <1> mov ecx, %3 94 <1> 95 <1> %if %0 >= 4 96 <1> mov edx, %4 97 <1> %endif 98 <1> %endif 99 <1> %endif 100 00000551 B803000000 <1> mov eax, %1 101 00000556 CD30 <1> int 30h 951 00000558 59 pop ecx 952 ;xor ebx, ebx ; 0 953 ;sys _read ; sys _read, ebx, ecx, edx ; ebx = 0, edx = 1 954 ; sys read; 0:0; 1 / read next char into inbuf 955 00000559 7254 jc short xit1 ; 29/05/2022 956 ; bcs xit1 / error exit 957 0000055B 21C0 and eax, eax 958 ; tst r0 / a zero input is end of file 959 0000055D 7450 jz short xit1 ; 29/05/2022 960 ; beq xit1 / exit 961 0000055F FF05[7C0C0000] inc dword [einbuf] ; 08/04/2014 (24/08/2015, 32 bit) 962 00000565 A0[800C0000] mov al, [och] 963 0000056A 803D[89060000]00 cmp byte [_at], 0 964 00000571 7608 jna short gbuf1 965 00000573 3C08 cmp al, 8 ; backspace 966 00000575 746B je short gbuf3 967 00000577 3C7F cmp al, 127 ; delete 968 00000579 7460 je short gbuf6 ; 06/12/2013 969 gbuf1: 970 ;mov ebx, ecx 971 ;inc dword [einbuf] 972 ; inc einbuf / eventually einbuf points to \n 973 ; / (+1) of this line 974 0000057B 81F9[780C0000] cmp ecx, inbuf + 256 975 ; cmp 0b,$inbuf+256. / have we exceeded 976 ; input buffer size 977 00000581 732C jnb short xit1 ; 29/05/2022 978 ; bhis xit1 / if so, exit assume some sort of binary 979 ; 08/04/2014 980 00000583 3C0D cmp al, 0Dh 981 00000585 752F jne short gbuf8 982 00000587 8B1D[7C0C0000] mov ebx, [einbuf] 983 0000058D 4B dec ebx 984 0000058E 8803 mov [ebx], al 985 00000590 C3 retn 986 987 gbuf2: 988 ; 28/12/2015 989 00000591 803D[89060000]00 cmp byte [_at], 0 990 00000598 76AB jna short gbuf0 ; 29/05/2022 991 gbuf7: 992 0000059A 51 push ecx 993 ;mov [och], al 994 ; edx = 1 995 sys _write, 1, och 87 <1> 88 <1> 89 <1> 90 <1> %if %0 >= 2 91 0000059B BB01000000 <1> mov ebx, %2 92 <1> %if %0 >= 3 93 000005A0 B9[800C0000] <1> mov ecx, %3 94 <1> 95 <1> %if %0 >= 4 96 <1> mov edx, %4 97 <1> %endif 98 <1> %endif 99 <1> %endif 100 000005A5 B804000000 <1> mov eax, %1 101 000005AA CD30 <1> int 30h 996 ;sys _write, 1, och, 1 ; echo (write char on tty) 997 000005AC 59 pop ecx 998 000005AD EB96 jmp short gbuf0 ; 29/05/2022 999 1000 xit1: ; 29/05/2022 1001 sys _exit 87 <1> 88 <1> 89 <1> 90 <1> %if %0 >= 2 91 <1> mov ebx, %2 92 <1> %if %0 >= 3 93 <1> mov ecx, %3 94 <1> 95 <1> %if %0 >= 4 96 <1> mov edx, %4 97 <1> %endif 98 <1> %endif 99 <1> %endif 100 000005AF B801000000 <1> mov eax, %1 101 000005B4 CD30 <1> int 30h 1002 ; sys exit 1003 1004 gbuf8: 1005 000005B6 89CB mov ebx, ecx 1006 000005B8 8803 mov [ebx], al 1007 ;cmp al, 0Ah ; \n 1008 ; cmpb *0b,$'\n / end of line? 1009 ;je short gbuf5 1010 ;jne short gbuf1 1011 ; bne 1b / no, go to get next char 1012 ;cmp al, 0Dh ; ENTER 1013 ;je short gbuf5 1014 000005BA 803D[89060000]00 cmp byte [_at], 0 ; at > 0 --> tty input 1015 000005C1 7682 jna short gbuf0 1016 000005C3 3C1B cmp al, 1Bh ; ESC 1017 000005C5 75CA jne short gbuf2 1018 000005C7 B8[780B0000] mov eax, inbuf 1019 000005CC A3[780C0000] mov [inbufp], eax 1020 000005D1 A3[7C0C0000] mov [einbuf], eax 1021 000005D6 E9B5FAFFFF jmp nl ; cancel current command, new line 1022 1023 ; 29/05/2022 1024 ;gbuf2: 1025 ; ; 28/12/2015 1026 ; cmp byte [_at], 0 1027 ; jna gbuf0 1028 ;gbuf7: 1029 ; push ecx 1030 ; ;mov [och], al 1031 ; ; edx = 1 1032 ; sys _write, 1, och 1033 ; ;sys _write, 1, och, 1 ; echo (write char on tty) 1034 ; pop ecx 1035 ; jmp gbuf0 1036 1037 gbuf6: ; DELETE key -> BACKSPACE key 1038 ;mov al, 8 1039 000005DB C605[800C0000]08 mov byte [och], 8 ; 06/12/2013 1040 gbuf3: 1041 ; 08/04/2014 1042 000005E2 FF0D[7C0C0000] dec dword [einbuf] ; (24/08/2015, 32 bit code) 1043 ; 12/12/2013 1044 000005E8 49 dec ecx 1045 000005E9 81F9[780B0000] cmp ecx, inbuf 1046 000005EF 7203 jb short gbuf4 1047 000005F1 49 dec ecx 1048 ; 08/04/2014 1049 ;jmp short gbuf2 1050 000005F2 EBA6 jmp short gbuf7 1051 gbuf4: 1052 ;mov al, 7 1053 000005F4 C605[800C0000]07 mov byte [och], 07h ; beep 1054 ; 08/04/2014 1055 ;jmp short gbuf2 1056 000005FB EB9D jmp short gbuf7 1057 ;gbuf5: 1058 ; retn 1059 ; rts pc / yes, return 1060 1061 ; 29/05/2022 1062 ;xit1: 1063 ; sys _exit 1064 ; ; sys exit 1065 1066 ;----------------------------------------------------------------- 1067 ; data - initialized data 1068 ;----------------------------------------------------------------- 1069 1070 ; /// Messages 1071 1072 000005FD 0D0A msg_unix_sh: db 0Dh, 0Ah 1073 000005FF 526574726F20556E69- db 'Retro Unix 386 v1 - shell' 1073 00000608 782033383620763120- 1073 00000611 2D207368656C6C 1074 ;db 0Dh, 0Ah 1075 msgsh_size equ $ - msg_unix_sh 1076 ;db 0 1077 00000618 31372F30362F323032- db '17/06/2022' 1077 00000621 32 1078 00000622 0D0A00 nextline: db 0Dh, 0Ah, 0 1079 ;Error messages: 1080 00000625 496E707574206E6F74- msgNotFound: db 'Input not found', 0 1080 0000062E 20666F756E6400 1081 00000635 41726720636F756E74- msgArgCount: db 'Arg count', 0 1081 0000063E 00 1082 0000063F 426164206469726563- msgBadDir: db 'Bad directory', 0 1082 00000648 746F727900 1083 0000064D 54727920616761696E- msgTryAgain: db 'Try again', 0 1083 00000656 00 1084 00000657 222720696D62616C61- msgImbalance: db 22h, 27h, 20h, 'imbalance', 0 1084 00000660 6E636500 1085 00000664 496E7075742066696C- msgInputFile: db 'Input file', 0 1085 0000066D 6500 1086 0000066F 4F7574707574206669- msgOutputFile: db 'Output file', 0 1086 00000678 6C6500 1087 0000067B 4E6F20636F6D6D616E- msgNoCmd: db 'No command', 0 1087 00000684 6400 1088 1089 ; /// Commands, files, parameters 1090 1091 ; 27/12/2015 1092 FCAT: ; '>>' 1093 00000686 00 db 0 1094 1095 ;quest: 1096 ;db '?', 0Dh, 0Ah 1097 ; 1098 1099 prompt: 1100 00000687 0D0A db 0Dh, 0Ah 1101 _at: 1102 00000689 4020 db '@ ' 1103 ;<@ > 1104 p_size equ $ - prompt 1105 1106 0000068B 6563686F00 qecho: db 'echo', 0 1107 ; 1108 00000690 636400 qcd: db 'cd', 0 1109 ; 1110 qchdir: 1111 00000693 636864697200 db 'chdir', 0 1112 ; 1113 glogin: 1114 00000699 6C6F67696E00 db 'login', 0 1115 ; 1116 shell: 1117 0000069F 2F62696E2F736800 db '/bin/sh', 0 1118 ; 1119 glob: 1120 000006A7 2F6574632F676C6F62- db '/etc/glob', 0 1120 000006B0 00 1121 ; 1122 binpb: 1123 000006B1 2F62696E2F db '/bin/' 1124 ; 1125 1126 ;----------------------------------------------------------------- 1127 ; bss - uninitialized data 1128 ;----------------------------------------------------------------- 1129 1130 bss_start: 1131 1132 ABSOLUTE bss_start 1133 1134 parbuf: 1135 000006B6 resb 1000 1136 ; .=.+1000. 1137 alignb 2 1138 ;.even 1139 param: 1140 00000A9E ???????? resd 1 1141 ;.=.+2 1142 glflag: 1143 00000AA2 ?? resb 1 1144 00000AA3 ?? resb 1 1145 ;.=.+2 1146 infile: 1147 00000AA4 ???????? resd 1 1148 ; .=.+2 1149 outfile: 1150 00000AA8 ???????? resd 1 1151 ;.=.+2 1152 ; parp-4 1153 00000AAC ???????? resd 1 1154 ;.=.+2 / room for glob 1155 parp: 1156 00000AB0 resb 200 1157 ;.=.+200. 1158 inbuf: 1159 00000B78 resb 256 1160 ;.=.+256. 1161 ;escap: 1162 ;resw 1 1163 ;.=.+2 1164 inbufp: 1165 00000C78 ???????? resd 1 1166 ;.=.+2 1167 einbuf: 1168 00000C7C ???????? resd 1 1169 ;.=.+2 1170 och: 1171 00000C80 ?? resb 1 1172 00000C81 ?? resb 1 1173 ;.=.+2 1174 shellarg: 1175 00000C82 ???????? resd 1 1176 ;.=.+2 1177 escap: 1178 00000C86 ?? resb 1 1179 ; 1180 00000C87 ?? resb 1 1181 1182 stbuf: ; 17/06/2022 - Retro UNIX 386 v1.1 1183 00000C88 resb 34 ; sysstat output buffer 1184 1185 bss_end: 1186 1187 ; 29/05/2022 1188 ;----------------------------------------------------------------- 1189 ; Original UNIX v2 - shell - PDP-11 assembly source code (sh.s) 1190 ;----------------------------------------------------------------- 1191 ; UNIX V2 source code: see www.tuhs.org for details. 1192 ;----------------------------------------------------------------- 1193 ; /// Modified unix v1 shell (sh.s) source code by Erdogan Tan /// 1194 ;----------------------------------------------------------------- 1195 ; s2.tar.gz - \bin\sh 1196 ; 1197 ; Source code modified via disassembled unix v2 /bin/sh binary file 1198 ; Dissasembler: Hex-Rays Interactive Disassembler (IDA) 1199 ; 1200 ;/ sh -- command interpreter 1201 ; mov sp,r5 1202 ; mov r5,shellarg / save orig sp in shellarg 1203 ; cmpb *2(r5),$'- / was this sh called by init or login 1204 ; bne 2f / no 1205 ; sys intr; 0 / yes, turn off interrupts 1206 ; sys quit; 0 1207 ;2: 1208 ; sys getuid / who is user 1209 ; tst r0 / is it superuser 1210 ; bne 2f / no 1211 ; movb $'#,at / yes, set new prompt symbol 1212 ;2: 1213 ; cmp (r5),$1 / tty input? 1214 ; ble newline / yes, call with '-(or with no command 1215 ; / file name) 1216 ; clr r0 / no, set ttv 1217 ; sys close / close it 1218 ; mov 4(r5),0f / get new file name 1219 ; sys open; 0:..; 0 / open it 1220 ; bec 1f / branch if no error 1221 ; jsr r5,error / error in file name 1222 ; ; .even 1223 ; sys exit 1224 ;1: 1225 ; clr at / clear prompt character, if reading non-tty 1226 ; / input file 1227 ;newline: 1228 ; tst at / is there a prompt symbol 1229 ; beq newcom / no 1230 ; mov $1,r0 / yes 1231 ; sys write; at; 2. / print prompt 1232 ;newcom: 1233 ; mov shellarg,sp / 1234 ; mov $parbuf,r3 / initialize command list area 1235 ; mov $parp,r4 / initialize command list pointers 1236 ; clr infile / initialize alternate input 1237 ; clr outfile / initialize alternate output 1238 ; clr glflag / initialize global flag 1239 ;newarg: 1240 ; jsr pc,blank / squeeze out leading blanks 1241 ; jsr r5,delim / is new character a ; \n or & 1242 ; br 2f / yes 1243 ; mov r3,-(sp) / no, push arg pointer onto stack 1244 ; cmp r0,$'< / new input file? 1245 ; bne 1f / no 1246 ; mov (sp),infile / yes, save arg pointer 1247 ; clr (sp) / clear pointer 1248 ; br 3f 1249 ;1: 1250 ; cmp r0,$'> / new output file? 1251 ; bne newchar / no 1252 ; mov (sp),outfile / yes, save arg pointer 1253 ; clr (sp) / clear pointer 1254 ; br 3f 1255 ;newchar: 1256 ; cmp $' ,r0 / is character a blank 1257 ; beq 1f / branch if it is (blank as arg separator) 1258 ; cmp $'\n+200,r0 / treat \n preceded by ; beq 1f / as blank 1260 ; jsr pc,putc / put this character in parbuf list 1261 ;3: 1262 ; jsr pc,getc / get next character 1263 ; jsr r5,delim / is char a ; \n or &, 1264 ; br 1f / yes 1265 ; br newchar / no, start new character tests 1266 ;1: 1267 ; clrb (r3)+ / end name with \0 when read blank, or 1268 ; / delim 1269 ; mov (sp)+,(r4)+ / move arg ptr to parp location 1270 ; bne 1f / if (sp)=0, in file or out file points to arg 1271 ; tst -(r4) / so ignore dummy (0), in pointer list 1272 ;1: 1273 ; jsr r5,delim / is char a ; \n or &. 1274 ; br 2f / yes 1275 ; br newarg / no, start newarg processing 1276 ;2: 1277 ; clr (r4) / \n, &, or ; takes to here (end of arg list) 1278 ; / after 'delim' call 1279 ; mov r0,-(sp) / save delimiter in stack 1280 ; jsr pc,docom / go to exec command in parbuf 1281 ; cmpb (sp),$'& / get a new command without wait? 1282 ; beq newcom / yes 1283 ; tst r1 / was chdir just executed or line ended with 1284 ; / ampersand? 1285 ; beq 2f / yes 1286 ;1: 1287 ; sys wait / no, wait for new process to terminate 1288 ; / command executed) 1289 ; bcs 2f / no, children not previously waited for 1290 ; cmp r0,r1 / is this my child 1291 ; bne 1b 1292 ;2: 1293 ; cmp (sp),$'\n / was delimiter a new line 1294 ; beq newline / yes 1295 ; br newcom / no, pick up next command 1296 ;docom: 1297 ; sub $parp,r4 / out arg count in r4 1298 ; bne 1f / any arguments? 1299 ; clr r1 / no, line ended with ampersand 1300 ; rts pc / return from call 1301 ;1: 1302 ; jsr r5,chcom; qchdir / is command chdir? 1303 ; br 2f / command not chdir 1304 ; cmp r4,$4 / prepare to exec chdir, 4=arg count x 2 1305 ; beq 3f 1306 ; jsr r5,error / go to print error 1307 ; ; .even 1308 ; br 4f 1309 ;3: 1310 ; mov parp+2,0f / more directory name to sys coll 1311 ; sys chdir; 0:0 / exec chdir 1312 ; bec 4f / no error exit 1313 ; jsr r5,error / go to print error 1314 ; ; .even / this diagnostic 1315 ;4: 1316 ; clr r1 / set r1 to zero to dkip wait 1317 ; rts pc / and return 1318 ;2: 1319 ; jsr r5,chcom; glogin / is command login? 1320 ; br 2f / not loqin, go to fork 1321 ; sys exec; parbuf; parp / exec login 1322 ; sys exec; binpb; parp / or /bin/login 1323 ;2: / no error return?? 1324 ; sys fork / generate sh child process for command 1325 ; br newproc / exec command with new process 1326 ; bec 1f / no error exit, old orocess 1327 ; jsr r5,error / go to print error 1328 ; ; .even / this diaonostic 1329 ; jmp newline / and return for next try 1330 ;1: 1331 ; mov r0,r1 / save id of child sh 1332 ; rts pc / return to "jsr pc, docom" call in parent sh 1333 ; 1334 ;error: 1335 ; movb (r5)+,och / pick up diagnostic character 1336 ; beq 1f / 0 is end of line 1337 ; mov $1,r0 / set for tty output 1338 ; sys write; och; 1 / print it 1339 ; br error / continue to get characters 1340 ;1: 1341 ; inc r5 / inc r5 to point to return 1342 ; bic $1,r5 / make it even 1343 ; clr r0 / set for input 1344 ; sys seek; 0; 2 / exit from runcom. skip to end of 1345 ; / input file 1346 ; 1347 ;/------ 29/05/2022 - unix v2 shell 1348 ;/ (source code from disassembled /bin/sh binary) 1349 ; rts r5 1350 ; 1351 ;chcom: / has no effect if tty input 1352 ; mov (r5)+,r1 / glogin gchdir r1, bump r5 1353 ; mov $parbuf,r2 / command address r2 'login' 1354 ;1: 1355 ; movb (r1)+,r0 / is this command 'chdir' 1356 ; cmpb (r2)+,r0 / compare command name byte with 'login' 1357 ; / or 'chdir' 1358 ; bne 1f / doesn't compare 1359 ; tst r0 / is this 1360 ; bne 1b / end of names 1361 ; tst (r5)+ / yes, bump r5 again to execute login 1362 ; / chdir 1363 ;1: 1364 ; rts r5 / no, return to exec command 1365 ; 1366 ;putc: 1367 ; cmp r0,$'' / single quote? 1368 ; beq 1f / yes 1369 ; cmp r0,$'" / double quote 1370 ; beq 1f / yes 1371 ; bic $!177,r0 / no, remove 200, if present 1372 ; movb r0,(r3)+ / store character in parbuf 1373 ; rts pc 1374 ;1: 1375 ; mov r0,-(sp) / push quote mark onto stack 1376 ;1: 1377 ; jsr pc,getc / get a quoted character 1378 ; cmp r0,$'\n / is it end or line 1379 ; bne 2f / no 1380 ; jsr r5,error / yes, indicate missing quote mark 1381 ; <"' imbalance\n\0>; .even 1382 ; jmp newline / ask for new line 1383 ;2: 1384 ; cmp r0,(sp) / is this closing quote mark 1385 ; beq 1f / yes 1386 ; bic $!177,r0 / no, strip off 200 if present 1387 ; movb r0,(r3)+ / store quoted character in parbuf 1388 ; br 1b / continue 1389 ;1: 1390 ; tst (sp)+ / pop quote mark off stack 1391 ; rts pc / return 1392 ; 1393 ;/ thp`e new process 1394 ; 1395 ;newproc: 1396 ; mov infile,0f / move pointer to new file name 1397 ; beq 1f / branch if no alternate read file given 1398 ; tstb *0f 1399 ; beq 3f / branch if no file name miven 1400 ; clr r0 / set tty input file name 1401 ; sys close / close it 1402 ; sys open; 0:..; 0 / open new input file for reading 1403 ; bcc 1f / branch if input file ok 1404 ;3: 1405 ; jsr r5,error / file not ok, print error 1406 ; ; .even / this diagnostic 1407 ; sys exit / terminate this process and make parent sh 1408 ;1: 1409 ; mov outfile,r2 / more pointer to new file name 1410 ; beq 1f / branch if no alternate write file 1411 ; cmpb (r2),$'> / is > at beqinning of file name? 1412 ; bne 4f / branch if it isn't 1413 ; inc r2 / yes, increment pointer 1414 ; mov r2,0f 1415 ; sys open; 0:..; 1 / open file for writing 1416 ; bec 3f / if no error 1417 ;4: 1418 ; mov r2,0f 1419 ; sys creat; 0:..; 17 / create new file with this name 1420 ; bec 3f / branch if no error 1421 ;2: 1422 ; jsr r5,error 1423 ; ; .even 1424 ; sys exit 1425 ;3: 1426 ; sys close / close the new write file 1427 ; mov r2,0f / move new name to open 1428 ; mov $1,r0 / set ttv file name 1429 ; sys close / close it 1430 ; sys open; 0:..; 1 / open new output file, it now has 1431 ; / file descriptor 1 1432 ; sys seek; 0; 2 / set pointer to current end of file 1433 ;1: 1434 ; tst glflag / was *, ? or [ encountered? 1435 ; bne 1f / yes 1436 ; sys exec; parbuf; parp / no, execute this commend 1437 ; sys exec; binpb; parp / or /bin/this command 1438 ; 1439 ;/------ 29/05/2022 - unix v2 shell 1440 ;/ (source code from disassembled /bin/sh binary) 1441 ;/ following part is not existing in v2 shell 1442 ; 1443 ;/2: 1444 ;/ sys stat; binpb; inbuf / if can't execute does it 1445 ;/ / exist? 1446 ;/ bes 2f / branch if it doesn't 1447 ;/ mov $shell,parp-2 / does exist, not executable 1448 ;/ mov $binpb,parp / so it must be 1449 ;/ sys exec; shell; parp-2 / a command file, get it with 1450 ;/ / sh /bin/x (if x name of file) 1451 ;/------ 1452 ;2: 1453 ; jsr r5,error / a return for exec is the diagnostic 1454 ; ; .even 1455 ; sys exit 1456 ;1: 1457 ; mov $glob,parp-2 / prepare to process *,? 1458 ; sys exec; glob; parp-2 / execute modified command 1459 ; br 2b 1460 ; 1461 ;delim: 1462 ; cmp r0,$'\n / is character a newline 1463 ; beq 1f 1464 ; cmp r0,$'& / is it & 1465 ; beq 1f / yes 1466 ; cmp r0,$'; / is it ; 1467 ; beq 1f / yes 1468 ; cmp r0,$'? / is it ? 1469 ; beq 3f 1470 ; 1471 ;/------ 29/05/2022 - unix v2 shell 1472 ;/ (source code from disassembled /bin/sh binary) 1473 ; cmp r0,$'* / is it * 1474 ; beq 3f 1475 ; 1476 ; cmp r0,$'[ / is it beginning of character string 1477 ; / (for glob) 1478 ; bne 2f 1479 ;3: 1480 ; inc glflag / ? or * or [ set flag 1481 ;2: 1482 ; tst (r5)+ / bump to process all except \n,;,& 1483 ;1: 1484 ; rts r5 1485 ; 1486 ;blank: 1487 ; jsr pc,getc / get next character 1488 ; cmp $' ,r0 / leading blanks 1489 ; beq blank / yes, 'squeeze out' 1490 ; cmp r0,$200+'\n / new-line preceded by \ is translated 1491 ; beq blank / into blank 1492 ; rts pc 1493 ;getc: 1494 ; tst param / are we substituting for $n 1495 ; bne 2f/ yes 1496 ; mov inbufp,r1 / no, move normal input pointer to r1 1497 ; cmp r1,einbuf / end of input line? 1498 ; bne 1f / no 1499 ; jsr pc,getbuf / yes, put next console line in buffer 1500 ; br getc 1501 ;1: 1502 ; movb (r1)+,r0 / move byte from input buffer to r0 1503 ; mov r1,inbufp / increment routine 1504 ; bis escap,r0 / if last character was \ this adds 1505 ; / 200 to current character 1506 ; clr escap / clear, so escap normally zero 1507 ; cmp r0,$'\\ / note that \\ is equal \ in as 1508 ; beq 1f 1509 ; cmp r0,$'$ / is it $ 1510 ; beq 3f / yes 1511 ; rts pc / no 1512 ;1: 1513 ; mov $200,escap / mark presence of \ in command line 1514 ; br getc / get next character 1515 ;2: 1516 ; movb *param,r0 / pick up substitution character put in 1517 ; / r0 1518 ; beq 1f / if end of substitution arg, branch 1519 ; inc param / if not end, set for next character 1520 ; rts pc / return as though character in ro is normal 1521 ; / input 1522 ;1: 1523 ; clr param / unset substitution pointer 1524 ; br getc / get next char in normal input 1525 ;3: 1526 ; jsr pc,getc / get digit after $ 1527 ; sub $'0,r0 / strip off zone bits 1528 ; cmp r0,$9. / compare with digit 9 1529 ; blos 1f / less than or equal 9 1530 ; mov $9.,r0 / if larger than 9, force 9 1531 ;1: 1532 ; mov shellarg,r1 / get pointer to stack for 1533 ; / this call of shell 1534 ; inc r0 / digit +1 1535 ; cmp r0,(r1) / is it less than # of args in this call 1536 ; bge getc / no, ignore it. so this $n is not replaced 1537 ; asl r0 / yes, multiply by 2 (to skip words) 1538 ; add r1,r0 / form pointer to arg pointer (-2) 1539 ; mov 2(r0),param / move arg pointer to param 1540 ; br getc / go to get substitution arg for $n 1541 ;getbuf: 1542 ; mov $inbuf,r0 / move input buffer address 1543 ; mov r0,inbufp / to input buffer pointer 1544 ; mov r0,einbuf / and initialize pointer to end of 1545 ; / character string 1546 ; dec r0 / decrement pointer so can utilize normal 1547 ; / 100p starting at 1f 1548 ; mov r0,0f / initialize address for reading 1st char 1549 ;1: 1550 ; inc 0f / this routine filles inbuf with line from 1551 ; / console - if there is cnc 1552 ; clr r0 / set for tty input 1553 ; sys read; 0:0; 1 / read next char into inbuf 1554 ; bcs xit1 / error exit 1555 ; tst r0 / a zero input is end of file 1556 ; beq xit1 / exit 1557 ; inc einbuf / eventually einbuf points to \n 1558 ; / (+1) of this line 1559 ; cmp 0b,$inbuf+256. / have we exceeded input buffer size 1560 ; bhis xit1 / if so, exit assume some sort of binary 1561 ; cmpb *0b,$'\n / end of line? 1562 ; bne 1b / no, go to get next char 1563 ; rts pc / yes, return 1564 ; 1565 ;xit1: 1566 ; sys exit 1567 ; 1568 ;quest: 1569 ; 1570 ; 1571 ;at: 1572 ; <@ > 1573 ; 1574 ;qchdir: 1575 ; 1576 ;glogin: 1577 ; 1578 ;shell: 1579 ; 1580 ;glob: 1581 ; 1582 ;binpb: 1583 ; 1584 ;parbuf: .=.+1000. 1585 ; .even 1586 ;param: .=.+2 1587 ;glflag: .=.+2 1588 ;infile: .=.+2 1589 ;outfile:.=.+2 1590 ; .=.+2 / room for glob 1591 ;parp: .=.+200. 1592 ;inbuf: .=.+256. 1593 ;escap: .=.+2 1594 ;inbufp: .=.+2 1595 ;einbuf: .=.+2 1596 ;och: .=.+2 1597 ;shellarg:.=.+2 1598 1599 ; 29/05/2022 1600 ;----------------------------------------------------------------- 1601 ; Original UNIX v1 - shell - PDP-11 assembly source code (sh.s) 1602 ;----------------------------------------------------------------- 1603 ; UNIX V1 source code: see www.tuhs.org for details. 1604 ;----------------------------------------------------------------- 1605 ; PreliminaryUnixImplementationDocument_Jun72.pdf - Section: E11 1606 ;----------------------------------------------------------------- 1607 ; https://minnie.tuhs.org/cgi-bin/utree.pl?file=V1/sh.s 1608 ; 1609 ;/ sh -- command interpreter 1610 ; mov sp,r5 1611 ; mov r5,shellarg / save orig sp in shellarg 1612 ; cmpb *2(r5),$'- / was this sh called by init or login 1613 ; bne 2f / no 1614 ; sys intr; 0 / yes, turn off interrupts 1615 ; sys quit; 0 1616 ;2: 1617 ; sys getuid / who is user 1618 ; tst r0 / is it superuser 1619 ; bne 2f / no 1620 ; movb $'#,at / yes, set new prompt symbol 1621 ;2: 1622 ; cmp (r5),$1 / tty input? 1623 ; ble newline / yes, call with '-(or with no command 1624 ; / file name) 1625 ; clr r0 / no, set ttv 1626 ; sys close / close it 1627 ; mov 4(r5),0f / get new file name 1628 ; sys open; 0:..; 0 / open it 1629 ; bec 1f / branch if no error 1630 ; jsr r5,error / error in file name 1631 ; ; .even 1632 ; sys exit 1633 ;1: 1634 ; clr at / clear prompt character, if reading non-tty 1635 ; / input file 1636 ;newline: 1637 ; tst at / is there a prompt symbol 1638 ; beq newcom / no 1639 ; mov $1,r0 / yes 1640 ; sys write; at; 2. / print prompt 1641 ;newcom: 1642 ; mov shellarg,sp / 1643 ; mov $parbuf,r3 / initialize command list area 1644 ; mov $parp,r4 / initialize command list pointers 1645 ; clr infile / initialize alternate input 1646 ; clr outfile / initialize alternate output 1647 ; clr glflag / initialize global flag 1648 ;newarg: 1649 ; jsr pc,blank / squeeze out leading blanks 1650 ; jsr r5,delim / is new character a ; \n or & 1651 ; br 2f / yes 1652 ; mov r3,-(sp) / no, push arg pointer onto stack 1653 ; cmp r0,$'< / new input file? 1654 ; bne 1f / no 1655 ; mov (sp),infile / yes, save arg pointer 1656 ; clr (sp) / clear pointer 1657 ; br 3f 1658 ;1: 1659 ; cmp r0,$'> / new output file? 1660 ; bne newchar / no 1661 ; mov (sp),outfile / yes, save arg pointer 1662 ; clr (sp) / clear pointer 1663 ; br 3f 1664 ;newchar: 1665 ; cmp $' ,r0 / is character a blank 1666 ; beq 1f / branch if it is (blank as arg separator) 1667 ; cmp $'\n+200,r0 / treat \n preceded by ; beq 1f / as blank 1669 ; jsr pc,putc / put this character in parbuf list 1670 ;3: 1671 ; jsr pc,getc / get next character 1672 ; jsr r5,delim / is char a ; \n or &, 1673 ; br 1f / yes 1674 ; br newchar / no, start new character tests 1675 ;1: 1676 ; clrb (r3)+ / end name with \0 when read blank, or 1677 ; / delim 1678 ; mov (sp)+,(r4)+ / move arg ptr to parp location 1679 ; bne 1f / if (sp)=0, in file or out file points to arg 1680 ; tst -(r4) / so ignore dummy (0), in pointer list 1681 ;1: 1682 ; jsr r5,delim / is char a ; \n or &. 1683 ; br 2f / yes 1684 ; br newarg / no, start newarg processing 1685 ;2: 1686 ; clr (r4) / \n, &, or ; takes to here (end of arg list) 1687 ; / after 'delim' call 1688 ; mov r0,-(sp) / save delimiter in stack 1689 ; jsr pc,docom / go to exec command in parbuf 1690 ; cmpb (sp),$'& / get a new command without wait? 1691 ; beq newcom / yes 1692 ; tst r1 / was chdir just executed or line ended with 1693 ; / ampersand? 1694 ; beq 2f / yes 1695 ;1: 1696 ; sys wait / no, wait for new process to terminate 1697 ; / command executed) 1698 ; bcs 2f / no, children not previously waited for 1699 ; cmp r0,r1 / is this my child 1700 ; bne 1b 1701 ;2: 1702 ; cmp (sp),$'\n / was delimiter a new line 1703 ; beq newline / yes 1704 ; br newcom / no, pick up next command 1705 ;docom: 1706 ; sub $parp,r4 / out arg count in r4 1707 ; bne 1f / any arguments? 1708 ; clr r1 / no, line ended with ampersand 1709 ; rts pc / return from call 1710 ;1: 1711 ; jsr r5,chcom; qchdir / is command chdir? 1712 ; br 2f / command not chdir 1713 ; cmp r4,$4 / prepare to exec chdir, 4=arg count x 2 1714 ; beq 3f 1715 ; jsr r5,error / go to print error 1716 ; ; .even 1717 ; br 4f 1718 ;3: 1719 ; mov parp+2,0f / more directory name to sys coll 1720 ; sys chdir; 0:0 / exec chdir 1721 ; bec 4f / no error exit 1722 ; jsr r5,error / go to print error 1723 ; ; .even / this diagnostic 1724 ;4: 1725 ; clr r1 / set r1 to zero to dkip wait 1726 ; rts pc / and return 1727 ;2: 1728 ; jsr r5,chcom; glogin / is command login? 1729 ; br 2f / not loqin, go to fork 1730 ; sys exec; parbuf; parp / exec login 1731 ; sys exec; binpb; parp / or /bin/login 1732 ;2: / no error return?? 1733 ; sys fork / generate sh child process for command 1734 ; br newproc / exec command with new process 1735 ; bec 1f / no error exit, old orocess 1736 ; jsr r5,error / go to print error 1737 ; ; .even / this diaonostic 1738 ; jmp newline / and return for next try 1739 ;1: 1740 ; mov r0,r1 / save id of child sh 1741 ; rts pc / return to "jsr pc, docom" call in parent sh 1742 ; 1743 ;error: 1744 ; movb (r5)+,och / pick up diagnostic character 1745 ; beq 1f / 0 is end of line 1746 ; mov $1,r0 / set for tty output 1747 ; sys write; och; 1 / print it 1748 ; br error / continue to get characters 1749 ;1: 1750 ; inc r5 / inc r5 to point to return 1751 ; bic $1,r5 / make it even 1752 ; clr r0 / set for input 1753 ; sys seek; 0; 2 / exit from runcom. skip to end of 1754 ; / input file 1755 ;chcom: / has no effect if tty input 1756 ; mov (r5)+,r1 / glogin gchdir r1, bump r5 1757 ; mov $parbuf,r2 / command address r2 'login' 1758 ;1: 1759 ; movb (r1)+,r0 / is this command 'chdir' 1760 ; cmpb (r2)+,r0 / compare command name byte with 'login' 1761 ; / or 'chdir' 1762 ; bne 1f / doesn't compare 1763 ; tst r0 / is this 1764 ; bne 1b / end of names 1765 ; tst (r5)+ / yes, bump r5 again to execute login 1766 ; / chdir 1767 ;1: 1768 ; rts r5 / no, return to exec command 1769 ; 1770 ;putc: 1771 ; cmp r0,$'' / single quote? 1772 ; beq 1f / yes 1773 ; cmp r0,$'" / double quote 1774 ; beq 1f / yes 1775 ; bic $!177,r0 / no, remove 200, if present 1776 ; movb r0,(r3)+ / store character in parbuf 1777 ; rts pc 1778 ;1: 1779 ; mov r0,-(sp) / push quote mark onto stack 1780 ;1: 1781 ; jsr pc,getc / get a quoted character 1782 ; cmp r0,$'\n / is it end or line 1783 ; bne 2f / no 1784 ; jsr r5,error / yes, indicate missing quote mark 1785 ; <"' imbalance\n\0>; .even 1786 ; jmp newline / ask for new line 1787 ;2: 1788 ; cmp r0,(sp) / is this closing quote mark 1789 ; beq 1f / yes 1790 ; bic $!177,r0 / no, strip off 200 if present 1791 ; movb r0,(r3)+ / store quoted character in parbuf 1792 ; br 1b / continue 1793 ;1: 1794 ; tst (sp)+ / pop quote mark off stack 1795 ; rts pc / return 1796 ; 1797 ;/ thp`e new process 1798 ; 1799 ;newproc: 1800 ; mov infile,0f / move pointer to new file name 1801 ; beq 1f / branch if no alternate read file given 1802 ; tstb *0f 1803 ; beq 3f / branch if no file name miven 1804 ; clr r0 / set tty input file name 1805 ; sys close / close it 1806 ; sys open; 0:..; 0 / open new input file for reading 1807 ; bcc 1f / branch if input file ok 1808 ;3: 1809 ; jsr r5,error / file not ok, print error 1810 ; ; .even / this diagnostic 1811 ; sys exit / terminate this process and make parent sh 1812 ;1: 1813 ; mov outfile,r2 / more pointer to new file name 1814 ; beq 1f / branch if no alternate write file 1815 ; cmpb (r2),$'> / is > at beqinning of file name? 1816 ; bne 4f / branch if it isn't 1817 ; inc r2 / yes, increment pointer 1818 ; mov r2,0f 1819 ; sys open; 0:..; 1 / open file for writing 1820 ; bec 3f / if no error 1821 ;4: 1822 ; mov r2,0f 1823 ; sys creat; 0:..; 17 / create new file with this name 1824 ; bec 3f / branch if no error 1825 ;2: 1826 ; jsr r5,error 1827 ; ; .even 1828 ; sys exit 1829 ;3: 1830 ; sys close / close the new write file 1831 ; mov r2,0f / move new name to open 1832 ; mov $1,r0 / set ttv file name 1833 ; sys close / close it 1834 ; sys open; 0:..; 1 / open new output file, it now has 1835 ; / file descriptor 1 1836 ; sys seek; 0; 2 / set pointer to current end of file 1837 ;1: 1838 ; tst glflag / was *, ? or [ encountered? 1839 ; bne 1f / yes 1840 ; sys exec; parbuf; parp / no, execute this commend 1841 ; sys exec; binpb; parp / or /bin/this command 1842 ;2: 1843 ; sys stat; binpb; inbuf / if can't execute does it 1844 ; / exist? 1845 ; bes 2f / branch if it doesn't 1846 ; mov $shell,parp-2 / does exist, not executable 1847 ; mov $binpb,parp / so it must be 1848 ; sys exec; shell; parp-2 / a command file, get it with 1849 ; / sh /bin/x (if x name of file) 1850 ;2: 1851 ; jsr r5,error / a return for exec is the diagnostic 1852 ; ; .even 1853 ; sys exit 1854 ;1: 1855 ; mov $glob,parp-2 / prepare to process *,? 1856 ; sys exec; glob; parp-2 / execute modified command 1857 ; br 2b 1858 ; 1859 ;delim: 1860 ; cmp r0,$'\n / is character a newline 1861 ; beq 1f 1862 ; cmp r0,$'& / is it & 1863 ; beq 1f / yes 1864 ; cmp r0,$'; / is it ; 1865 ; beq 1f / yes 1866 ; cmp r0,$'? / is it ? 1867 ; beq 3f 1868 ; cmp r0,$'[ / is it beginning of character string 1869 ; / (for glob) 1870 ; bne 2f 1871 ;3: 1872 ; inc glflag / ? or * or [ set flag 1873 ;2: 1874 ; tst (r5)+ / bump to process all except \n,;,& 1875 ;1: 1876 ; rts r5 1877 ; 1878 ;blank: 1879 ; jsr pc,getc / get next character 1880 ; cmp $' ,r0 / leading blanks 1881 ; beq blank / yes, 'squeeze out' 1882 ; cmp r0,$200+'\n / new-line preceded by \ is translated 1883 ; beq blank / into blank 1884 ; rts pc 1885 ;getc: 1886 ; tst param / are we substituting for $n 1887 ; bne 2f/ yes 1888 ; mov inbufp,r1 / no, move normal input pointer to r1 1889 ; cmp r1,einbuf / end of input line? 1890 ; bne 1f / no 1891 ; jsr pc,getbuf / yes, put next console line in buffer 1892 ; br getc 1893 ;1: 1894 ; movb (r1)+,r0 / move byte from input buffer to r0 1895 ; mov r1,inbufp / increment routine 1896 ; bis escap,r0 / if last character was \ this adds 1897 ; / 200 to current character 1898 ; clr escap / clear, so escap normally zero 1899 ; cmp r0,$'\\ / note that \\ is equal \ in as 1900 ; beq 1f 1901 ; cmp r0,$'$ / is it $ 1902 ; beq 3f / yes 1903 ; rts pc / no 1904 ;1: 1905 ; mov $200,escap / mark presence of \ in command line 1906 ; br getc / get next character 1907 ;2: 1908 ; movb *param,r0 / pick up substitution character put in 1909 ; / r0 1910 ; beq 1f / if end of substitution arg, branch 1911 ; inc param / if not end, set for next character 1912 ; rts pc / return as though character in ro is normal 1913 ; / input 1914 ;1: 1915 ; clr param / unset substitution pointer 1916 ; br getc / get next char in normal input 1917 ;3: 1918 ; jsr pc,getc / get digit after $ 1919 ; sub $'0,r0 / strip off zone bits 1920 ; cmp r0,$9. / compare with digit 9 1921 ; blos 1f / less than or equal 9 1922 ; mov $9.,r0 / if larger than 9, force 9 1923 ;1: 1924 ; mov shellarg,r1 / get pointer to stack for 1925 ; / this call of shell 1926 ; inc r0 / digit +1 1927 ; cmp r0,(r1) / is it less than # of args in this call 1928 ; bge getc / no, ignore it. so this $n is not replaced 1929 ; asl r0 / yes, multiply by 2 (to skip words) 1930 ; add r1,r0 / form pointer to arg pointer (-2) 1931 ; mov 2(r0),param / move arg pointer to param 1932 ; br getc / go to get substitution arg for $n 1933 ;getbuf: 1934 ; mov $inbuf,r0 / move input buffer address 1935 ; mov r0,inbufp / to input buffer pointer 1936 ; mov r0,einbuf / and initialize pointer to end of 1937 ; / character string 1938 ; dec r0 / decrement pointer so can utilize normal 1939 ; / 100p starting at 1f 1940 ; mov r0,0f / initialize address for reading 1st char 1941 ;1: 1942 ; inc 0f / this routine filles inbuf with line from 1943 ; / console - if there is cnc 1944 ; clr r0 / set for tty input 1945 ; sys read; 0:0; 1 / read next char into inbuf 1946 ; bcs xit1 / error exit 1947 ; tst r0 / a zero input is end of file 1948 ; beq xit1 / exit 1949 ; inc einbuf / eventually einbuf points to \n 1950 ; / (+1) of this line 1951 ; cmp 0b,$inbuf+256. / have we exceeded input buffer size 1952 ; bhis xit1 / if so, exit assume some sort of binary 1953 ; cmpb *0b,$'\n / end of line? 1954 ; bne 1b / no, go to get next char 1955 ; rts pc / yes, return 1956 ; 1957 ;xit1: 1958 ; sys exit 1959 ; 1960 ;quest: 1961 ; 1962 ; 1963 ;at: 1964 ; <@ > 1965 ; 1966 ;qchdir: 1967 ; 1968 ;glogin: 1969 ; 1970 ;shell: 1971 ; 1972 ;glob: 1973 ; 1974 ;binpb: 1975 ; 1976 ;parbuf: .=.+1000. 1977 ; .even 1978 ;param: .=.+2 1979 ;glflag: .=.+2 1980 ;infile: .=.+2 1981 ;outfile:.=.+2 1982 ; .=.+2 / room for glob 1983 ;parp: .=.+200. 1984 ;inbuf: .=.+256. 1985 ;escap: .=.+2 1986 ;inbufp: .=.+2 1987 ;einbuf: .=.+2 1988 ;och: .=.+2 1989 ;shellarg:.=.+2