************************************************************************** * * The GNO Shell Project * * Developed by: * Jawaid Bazyar * Tim Meekins * * $Id: shell.asm,v 1.11 1999/11/30 17:53:27 tribby Exp $ * ************************************************************************** * * SHELL.ASM * By Tim Meekins * Modified by Dave Tribby for GNO 2.0.6 * * This is the main routines for the shell. * * Note: text set up for tabs at col 16, 22, 41, 49, 57, 65 * | | | | | | * ^ ^ ^ ^ ^ ^ ************************************************************************** * * Interfaces defined in this file: * * shell subroutine (0:dummy) * NOTE: gnoloop is an entry defined in shell. * * AppendHome subroutine (4:str) * return 4:outPtr * * Dogshrc jsr with no parameters * * signal2 subroutine (4:fubar) * * signal18 subroutine (4:fubar) * * signal21 subroutine (4:fubar) * ************************************************************************** mcopy /obj/gno/bin/gsh/shell.mac dummyshell start ; ends up in .root end setcom 60 SIGINT gequ 2 SIGTSTP gequ 18 SIGCHLD gequ 20 SIGTTIN gequ 21 cmdbuflen gequ 1024 ************************************************************************** * * shell: entry point for acting upon commands * ************************************************************************** case on shell start case off using global using pdata using HistoryData using termdata p equ 0 General pointer cflag equ p+4 Flag: set when path converted space equ cflag+2 subroutine (0:dummy),space tsc Save stack pointer sta cmdcontext in cmdcontext tdc and direct page reg sta cmddp in cmddp. PushVariablesGS NullPB Save environment variables. Open ttyopen Open tty, bcc settty checking for error. ErrWriteCString #ttyerr jmp quit ttyerr dc c'gsh: Failed opening tty.',h'0d00' settty mv2 ttyref,gshtty tcnewpgrp gshtty settpgrp gshtty getpid sta gshpid jsr InitTerm lda FastFlag If FastFlag is set, bne fastskip1 skip copyright message. lda gshpid Only print the copyright msg cmp #2 if not using login bne fastskip1 ldx #^gnostr lda #gnostr jsr puts fastskip1 anop ; ; Set up signal handlers ; signal (#SIGINT,#signal2) signal (#SIGTSTP,#signal18) signal (#SIGCHLD,#pchild) signal (#SIGTTIN,#signal21) ; ; Set entry point for users calling system ; setsystemvector #system ; ; Initialize some stuff ; jsr initalias Set all AliasTable entries to 0. jsr InitDStack Zero out directory stack. jsr InitVars Set value of all env var flags. ; ; Check for login shell (argv[0] starts with '-') ; mv4 ~COMMANDLINE,p Copy commandline addr to dir page. ldy #8 Skip over shell identifier lda [p],y to get first char of and #$FF command name. cmp #'-' If not '-', bne nologin_init skip over login initialization. ; Change ":" to " " in $PATH if it doesn't start with ":" or contain a " " ph4 #pathname Get $PATH environment variable string jsl getenv sta p Save address of allocated buffer. stx p+2 in direct page variable ora p+2 If null, beq nopathconv no need to convert stz cflag Initialize conversion flag = false. ldy #4 Index over GS/OS length fields. short m Use 8-bit mode. lda [p],y beq endpathconv If null string, or cmp #':' if first character is ':', beq endpathconv don't do the conversion. bumpit iny lda [p],y beq endpathconv If at end of string, all done. cmp #' ' If $PATH contains a space, bne chkcolon stz cflag abort the conversion. bra endpathconv chkcolon cmp #':' If next character is ':', bne bumpit lda #' ' change it to ' ', and sta [p],y sta cflag set conversion flag = true. bra bumpit endpathconv long m Back to 16-bit mode. lda cflag If there was no conversion, beq freepath skip the setting of $PATH. clc Address of $PATH as a GS/OS lda p output string is 2 bytes adc #2 beyond the input string sta SetValue starting address. lda p+2 adc #0 sta SetValue+2 SetGS SetPB Set $PATH to the converted value. freepath ph4 p Free the $PATH C string. jsl nullfree nopathconv anop ; Read and execute /etc/glogin ph4 #etcglogin path = "/etc/glogin" lda #0 pha argc = 0 pha argv = NULL pha lda #$8000 pha jobflag = $8000 jsl ShellExec ; Read and execute $HOME/glogin jsr Doglogin ; ; Initialization that is not specific to login shells ; nologin_init anop lda FastFlag If fast startup flag isn't set, bne fastskip2 jsr InitHistory Init: historyFN->"$HOME/history", jsr ReadHistory read in history from disk, jsr Dogshrc and read $HOME/gshrc. jsr newline fastskip2 anop lda didReadTerm bne didit jsr readterm didit anop jsr dispose_hash Remove old table (if set in jsl hashpath login files) and hash $PATH. ld2 1,done_init Set initialization done flag. ; ; Check for command-line arguments -c and -e ; lda CmdFlag beq cmdskip ; ; The -c flag is set: execute remaining arguments as a command file and exit. ; mv4 CmdArgV,p ldy #2 lda [p],y pha lda [p] pha ph2 CmdArgc argc pei (p+2) argv pei (p) pea 0 jobflag = 0 jsl ShellExec jmp done1 cmdskip lda ExecFlag beq execskip ; ; The -e flag is set: execute remaining arguments as a command and exit. ; ph4 ExecCmd cmdline ph2 #0 jobflag = 0 jsl execute jmp done1 ; ; Parameter block for shell SetGS calls (p 427 in ORCA/M manual) ; SetPB dc i2'3' pCount dc i4'pathname' Name (pointer to GS/OS string) SetValue ds 4 Value (pointer to GS/OS string) dc i2'1' Export flag pathname gsstr 'path' GS/OS string etcglogin dc c'/etc/glogin',h'00' execskip anop **************************************************************** * * Main loop for reading and executing commands * **************************************************************** stz lastabort gnoloop entry ; ; Set the fundamental registers. ; phk Copy Program Bank register plb into Data Bank register. lda cmdcontext Set Stack Pointer and tcs Direct Page register lda cmddp to values saved when tcd entering shell. jsl WritePrompt Print prompt. jsr GetCmdLine Get response. bcs done jsr newline lda cmdlen Check for empty string. beq gnoloop jsr cursoron jsr newlineX jsr flush ph4 #cmdline execute(cmdline,0) ph2 #0 jobflag = 0 jsl execute lda exit_requested bne done1 jsr newlineX stz lastabort bra gnoloop ; ; shut down gsh ; done jsr newline jsr newlineX done1 ora2 pjoblist,pjoblist+2,@a beq done2 lda lastabort bne donekiller inc lastabort stz exit_requested ldx #^stopstr Print message: lda #stopstr "There are stopped jobs" jsr puts jsr newlineX bra gnoloop Continue getting commands. donekiller jsl jobkiller done2 lda FastFlag bne fastskip5 jsl SaveHistory fastskip5 jsr dispose_hash quit PopVariablesGS NullPB Quit QuitParm QuitParm dc i'0' ; Null parameter block used for shell calls PushVariables ; (ORCA/M manual p.420) and PopVariablesGS (p. 419) NullPB dc i2'0' pCount gnostr dc h'0d',c'GNO/Shell 2.0.6',h'0d' dc c'Copyright 1991-1993, Procyon, Inc. & Tim Meekins. ' dc c'ALL RIGHTS RESERVED',h'0d' dc h'0d00' stopstr dc c'gsh: There are stopped jobs.',h'0d00' ttyopen dc i2'2' ttyref dc i2'0' dc i4'ttyname' ttyname gsstr '.tty' exitstr dc c'000000',h'0d00' lastabort ds 2 END ;========================================================================= ; ; Interpret the login file (gshrc). ; If $HOME is set, we presume the gshrc file is there. If not, ; or if an error occurs getting the $HOME variable, we use ; @:gshrc. ; ;========================================================================= Dogshrc START ph4 #gshrcName bra doit ; Alternate entry point: execute $HOME/glogin Doglogin ENTRY ph4 #gloginName doit jsl AppendHome phx Save pointer to GS/OS input pha string for later. clc Adjust the pointer adc #2 to skip the length word bcc no_ovf so it's a C string. inx no_ovf phx pha * ShellExec subroutine (4:path,2:argc,4:argv,2:jobflag) ; (ptr to $HOME/gshrc is on stack) lda #0 pha argc = 0 pha argv = NULL pha lda #$8000 pha jobflag = $8000 jsl ShellExec ; Dispose $HOME/gshrc string pla Get address of plx GS/OS input string. sec Subtract two bytes to get sbc #2 addr of original output buffer. bcs no_undf dex no_undf phx pha jsl nullfree rts gshrcName dc c'/gshrc',h'00' gloginName dc c'/glogin',h'00' END ;========================================================================= ; ; Append a C string to the value of the $HOME variable. If $HOME is ; not set, then it appends the C string to the string '@/'. Returns ; a pointer to a GS/OS input string. ; ;========================================================================= AppendHome START outPtr equ 0 Pointer into allocated memory str_len equ outPtr+4 Length of string parameter buf_len equ str_len+2 Size of GS/OS buffer space equ buf_len+2 subroutine (4:str),space lock mutex ; ; Get the variable's length using ReadVariableGS ; ld4 TempResultBuf,RVresult Use temporary result buf. ReadVariableGS ReadVar Get length. ; ; Allocate memory for value string ; pei (str+2) Get length of pei (str) string to be jsr cstrlen appended. sta str_len lda TempRBlen Get length of value. bne notnull If 0, inc a increment because "@" will be used. notnull inc2 a Add 4 bytes for result buf len words. inc2 a clc Add length of string parameter. adc str_len sta buf_len Save result buf length. inc a Add 1 more for terminating null byte. pea 0 pha ~NEW Request the memory. sta RVresult Store address in ReadVariable stx RVresult+2 parameter block and sta outPtr direct page pointer. stx outPtr+2 ora outPtr+2 If address == NULL, beq exit return NULL to user. lda buf_len Store result buffer length sta [outPtr] at beginning of buf. ; ; Read the full value into the allocated memory ; ReadVariableGS ReadVar ReadVariable $HOME bcs doAtSign If error, use @/ ldy #2 Get length of lda [outPtr],y GS/OS string. beq doAtSign If $HOME not defined, use "@". clc adc #4 Turn into a c-string tay by storing a 0 byte short m after the last $HOME lda #0 character. sta [outPtr],y long m bra doAppend ; ; $HOME is null string or not defined. Use @ ; doAtSign lda atSign ldy #4 sta [outPtr],y lda #1 Set GS/OS buffer ldy #2 string length word sta [outPtr],y to 1. doAppend anop ldy #4 Start index beyond length words. short m lp lda [outPtr],y beq noSep cmp #':' beq foundSep cmp #'/' beq foundSep iny bra lp noSep lda #':' No separator found; use ":". foundSep sta [str] Store sep at start of appended string. long m pei (str+2) pei (str) ldx outPtr+2 lda outPtr clc adc #4 bcc pushptr inx pushptr phx pha case on jsl strcat case off clc Add 2 bytes to address of lda outPtr GS/OS output buffer to adc #2 get address of GS/OS bcc no_ovf input string. inc outPtr+2 no_ovf sta outPtr lda [outPtr] Adjust string length clc to include appended adc str_len string (parameter). sta [outPtr] ; ; NOTE: The returned value points to a GS/OS string, two bytes offset ; from the allocated memory for a GS/OS result buffer. When the ; memory is deallocated, the address must be adjusted back. ; exit unlock mutex return 4:outPtr mutex key atSign dc c'@',i1'0' ; ; Parameter block for Shell call ReadVariable (p 423 in ORCA/M reference) ; ReadVar anop dc i2'3' pCount dc a4'home' address of variable's name RVresult ds 4 GS/OS Output buffer ptr ds 2 export flag (returned) ; ; GS/OS result buffer for getting the full length of the HOME env var. ; TempResultBuf dc i2'5' Only five bytes total. TempRBlen ds 2 Value's length returned here. ds 1 Only 1 byte for value. ; ; "HOME" as a GS/OS string ; home gsstr 'HOME' END ;========================================================================= ; ; GLOBAL data ; ;========================================================================= global DATA ID ds 2 GSOSDP ds 2 cmdloc ds 2 cmdlen ds 2 cmdline ds cmdbuflen wordlen ds 2 nummatch ds 2 matchbuf ds 512*4 cmdcontext ds 2 cmddp ds 2 gshtty ds 2 gshpid ds 2 exit_requested dc i'0' ;!=0 if exit signalled dc i'0' done_init dc i2'0' 0 until init is complete FastFlag dc i'0' CmdFlag dc i'0' CmdArgV ds 4 CmdArgC ds 2 ExecFlag dc i'0' ExecCmd ds 4 END ;========================================================================= ; ; SIGINT handler when typed at command-line ; ;========================================================================= signal2 START using global subroutine (4:fubar),0 WriteCString #msg inc signalled ; ld2 $80,$E0C000 return msg dc c'^C',h'0d0a00' END ;========================================================================= ; ; SIGTSTP handler when typed at command-line ; ;========================================================================= signal18 START using global subroutine (4:fubar),0 WriteCString #msg inc signalled ; ld2 $80,$E0C000 return msg dc c'^Z',h'0d0a00' END ;========================================================================= ; ; SIGTTIN handler ; ;========================================================================= ; ; Work-around for kernel problem: if background read error signal ; is received, gsh will hang forever. Instead, quit. ; signal21 START using global subroutine (4:fubar),0 WriteCString #bg_msg Print message. Quit QuitParm QuitParm dc i'0' ; return bg_msg dc c'gsh: SIGTTIN received!!',h'0d0a00' END