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