// CmdScanAux.bcpl -- Auxiliary command scanner utilities // Copyright Xerox Corporation 1979, 1981, 1982 // Last modified April 9, 1982 6:02 PM by Taft get "cmdscan.decl" external [ // outgoing procedures GetNumber; GetString; GetFile; Confirm; GetKeyword; KeywordHelp // incoming procedures GetPhrase; TerminatingChar; CurrentPhrase; AppendChar LookupKeyword; EnumerateKeywordTable DefaultArgs; Gets; Puts; Endofs; Errors; Wss; Wns Allocate; Free; OpenFile; TruePredicate; FalsePredicate; Zero; DoubleAdd ] structure String [ length byte; char↑1,255 byte ] //--------------------------------------------------------------------------- let GetNumber(cs, radix, lvResult; numargs na) = valof //--------------------------------------------------------------------------- // Interprets the next phrase as a signed or unsigned number in the specified // radix (default 10). If lvResult is supplied, accepts a 32-bit number and // stores it in @lvResult. In any event, returns the low-order 16 bits of // the result. [ let digit = nil let myResult = vec 1 DefaultArgs(lv na, -1, 10, myResult) // Frame offsets of above args and locals used by assembly language: manifest [ oRadix = 5; olvResult = 6; oDigit = 8 ] // na is offset 7 let digitSeen = false let negative = false Zero(lvResult, 2) GetPhrase(cs, 0, 0, 0, NumberHelp, radix) until Endofs(cs) do [ digit = Gets(cs)-$0 if digit uge radix then [ if (digit eq $+-$0 % digit eq $--$0) & not digitSeen then [ negative = digit eq $--$0; loop ] Errors(cs, ecNonNumericChar) ] digitSeen = true if (table [ // @lvResult = (@lvResult)*radix + digit with overflow check #55001 // sta 3 1 2 #155000 // mov 2 3 #11400+olvResult // isz olvResult 3 #21400+oDigit // lda 0 oDigit 3 #27400+olvResult // lda 1 @olvResult 3 #31400+oRadix // lda 2 oRadix 3 #61020 // mul #47400+olvResult // sta 1 @olvResult 3 #15400+olvResult // dsz olvResult 3 #27400+olvResult // lda 1 @olvResult 3 #61020 // mul #47400+olvResult // sta 1 @olvResult 3 #171000 // mov 3 2 #35001 // lda 3 1 2 #1401 // jmp 1 3 ])() ne 0 then Errors(cs, ecNumberOverflow) ] unless digitSeen do Errors(cs, ecEmptyNumber) if lvResult!0 ne 0 & lvResult eq myResult then Errors(cs, ecNumberOverflow) if negative then [ lvResult!0 = not lvResult!0; lvResult!1 = not lvResult!1 DoubleAdd(lvResult, table [ 0; 1 ]) ] resultis lvResult!1 ] //--------------------------------------------------------------------------- and NumberHelp(str, radix) be //--------------------------------------------------------------------------- [ switchon radix into [ case 10: [ Wss(str, "decimal"); endcase ] case 8: [ Wss(str, "octal"); endcase ] default: [ Wss(str, "base "); Wns(str, radix) ] ] Wss(str, " number") ] //--------------------------------------------------------------------------- and GetString(cs, PhraseTerminator, Help, helpArg, Echo; numargs na) = valof //--------------------------------------------------------------------------- // Returns the next phrase as a bcpl string [ DefaultArgs(lv na, -1, 0, 0, 0, 0) let n = GetPhrase(cs, 0, PhraseTerminator, Echo, Help, helpArg) let s = Allocate(cs>>CS.zone, n rshift 1 +1) s>>String.length = n for i = 1 to n do s>>String.char↑i = Gets(cs) resultis s ] //--------------------------------------------------------------------------- and GetFile(cs, ksType, itemSize, versionControl, hintFp, errRtn, zone, logInfo, disk; numargs na) = valof //--------------------------------------------------------------------------- // Returns a stream for a file whose name is the next phrase. // All arguments except the first are passed directly to OpenFile. [ DefaultArgs(lv na, -1, 0, 0, 0, 0, 0, 0, 0, 0) let string = GetString(cs, 0, Wss, "file name") let stream = OpenFile(string, ksType, itemSize, versionControl, hintFp, errRtn, zone, logInfo, disk) Free(cs>>CS.zone, string) if stream eq 0 then Errors(cs, ecCantOpenFile) resultis stream ] //--------------------------------------------------------------------------- and Confirm(cs, string; numargs na) = valof //--------------------------------------------------------------------------- // Inputs and returns a true or false confirmation [ if na gr 1 & string ne 0 then Wss(cs, string) Wss(cs, " [Confirm] ") GetPhrase(cs, TruePredicate, TruePredicate, FalsePredicate, Wss, "y or n") switchon TerminatingChar(cs) into [ case $Y: case $y: case $*n: [ Wss(cs, "yes. "); resultis true ] case $N: case $n: [ Wss(cs, "no. "); resultis false ] default: Errors(cs, ecBadConfirmingChar) ] ] //--------------------------------------------------------------------------- and GetKeyword(cs, kt, returnOnFail, PhraseTerminator; numargs na) = valof //--------------------------------------------------------------------------- // Looks up phrase in keyword table kt and returns pointer to corresponding // table entry. If returnOnFail is true, returns zero on failure. // If an abbreviated keyword is recognized, appends the remainder of the // keyword to the command line iff the terminating character did not echo. [ DefaultArgs(lv na, -2, false, 0) let key = GetString(cs, PhraseTerminator, KeywordHelp, kt) let length = key>>String.length let tableKey = nil let entry = LookupKeyword(kt, key, lv tableKey) Free(cs>>CS.zone, key) if entry eq 0 then test tableKey eq 0 % length eq 0 // ambiguous or outright failure? ifso resultis returnOnFail? 0, Errors(cs, ecKeyNotFound) ifnot Errors(cs, ecKeyAmbiguous) if length ls tableKey>>String.length then [ let char = TerminatingChar(cs) unless CurrentPhrase(cs)>>PD.Echo(cs, char) do [ // append tail of keyword as if it had been typed in cs>>CS.iChIn = cs>>CS.iChIn-1 for i = length+1 to tableKey>>String.length do Puts(cs, tableKey>>String.char↑i) CurrentPhrase(cs)>>PD.iLast = cs>>CS.iChIn AppendChar(cs, char, false) ] ] resultis entry ] //--------------------------------------------------------------------------- and KeywordHelp(str, kt) be //--------------------------------------------------------------------------- [ Wss(str, "one of the following:*n") let count, str1 = 0, str EnumerateKeywordTable(kt, PrintKeyword, lv count) ] //--------------------------------------------------------------------------- and PrintKeyword(entry, kt, key, lvCount) be //--------------------------------------------------------------------------- [ let count = @lvCount let str = lvCount!1 test count+key>>String.length gr 60 ifso [ Wss(str, ",*n"); count = 0 ] ifnot if count ne 0 then [ Wss(str, ", "); count = count+2 ] Wss(str, key) @lvCount = count+key>>String.length ]