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