! ABEL_PARSE.TPU ! ! Table of Contents as of 27-Mar-1988 ! ! Procedure name Page Description ! -------------- ---- ----------- ! ! eve$index_over_whitespace 2 Move over whitespace ! eve$get_token 3 Returns the next token in command ! eve$add_final_string 4 Parse rest of command line as string ! eve$parse 5 Main command line parsing routine ! abl$init_qualifiers 6 Initialize qualifier variables ! abl$process_qualifier 7 Process command line qualifier ! abl$show_qualifiers 8 Display qualifiers for command ! eve$prompt_string 9 Eve's string prompting routine ! abl$prompt_word 10 Abel's word prompting routine ! eve$process_command 11 Process command in cmd line editor ! Page 1 ! Modifications to Eve's parsing mechanism: ! The developers' philosophy on Eve's command interface was that it should ! be as simple as possible. This means that slight variations in the function ! of a command need to be separate commands. I personally don't like this for ! several reasons: people that would be using TPU in the first place are most ! likely familiar with DCL and the nuances of command execute you can get ! using qualifiers, I don't want to have to write a separate TPU routine for ! each variation of a command, I have enough routines to worry about as it is, ! and I don't want the "list command" to take any longer than it has to. ! Perhaps a description of how an Eve command is defined to Eve is in order... ! When you type a command at the Eve "Command:" prompt (ie, use the eve_do ! function, you are actually building a call to an Eve routine written in TPU. ! Eve_do parses "tokens" off the command line, prefixing the first token with ! "eve_", then looking for an Eve routine that matches. Through a bit of magic ! and lots of confusing code, multiple word commands are also understood ! (multiple spaces are reduced to 1 and changed to "_"'s). ! Therefore, any TPU routine whose procedure name begins with ! "eve_" is an Eve command; the name of the routine for the Eve "line" function ! is eve_line. Some "eve_" TPU routines may have arguments to them, and Eve ! needs to know about these to put together the routine call. This is done by ! setting a TPU variable; the variable name is the function name prefixed with ! "eve$arg1_" for the first argument, "eve$arg2_" for the second, and so on. ! The value of this variable can be either "string" or "integer". ! Since eve_line takes an integer argument (the line number to go to), ! there is a variable eve$arg1_line whose value is "integer". When you use the ! line command "LINE 12", Eve generates the TPU routine call "eve_line(12)". ! Abel provides an extension to this command parsing system. The user may also ! specify qualifiers on the command line to better control how a command gets ! executed. For example, using the Eve "remove" command always clears the ! paste buffer before removing text, but what if I wanted to append what I've ! currently selected to the end of the paste buffer? I would normally have to ! write a separate command to do this, but the code would be exactly the same ! as the code for eve_remove with the exception of one executable line ! that says to erase the buffer. Using qualifiers, the Eve command becomes ! something like "remove /append" and the same code can be used for both ! variations. ! To make qualifiers work, they must first be defined in a similar manner as ! the arguments. If a command has qualifiers, there should be a variable ! prefixed with "abl$qd_" (actually, whatever abl$x_qual_def_prefix is) that is ! the qualifier definition string. The Eve "remove" command would have a ! qualifier definition variable named abl$qd_remove. The symbol used for ! introducing qualifiers is defined by abl$x_qualifier_character and is ! currently "/" (without "'s) to maintain some consistency with DCL (if you ! change this, be prepared to change all the qualifier defintions, too). ! The contents of the qualifier definition string should be ! qualifiers = qualifier[qualifier...] ! qualifier = name [ ~ | $ [string] | % [integer] ] ! name = abl$x_qualifier_character + alphanum ! alphanum = alphanumerics ! string = any alphanumeric letters ! integer = an integer number ! Note: spaces are not permitted in the definition string. ! A qualifier name followed by a "$" is a string, and following the $ is the ! initial value for string (if any). Likewise for the "%". If a qualifier ! name is followed by "~" or nothing, then it is a boolean qualifier; the "~" ! denotes a false initial value, and nothing denotes a true initial value. ! Using the value of the qualifier definition string, the command parser ! initializes TPU variables to represent the default qualifier values. The ! variables initialized are handled similar to the qualifier definition string ! variables, except their prefix is defined by abl$x_qualifier_prefix ! (currently "abl$q_"). These variable initializations happen just before any ! user-supplied qualifiers are processed, so the last value of the variable is ! the user's definition if any, and the same qualifiers can be used by ! different commands. ! To continue the Eve "remove" example, abl$qd_remove might equal "/append~", ! which means that by default abl$q_append will be false, but if the user ! specifies "remove /append" on the Eve command line, then abl$q_append will ! be true. Look at the values of the abl$q_ variables for more examples of ! qualifier definition strings. ! When qualifiers are used multiple times on the Eve command line, only the ! last usage will be effective (just like DCL). ! Some global variables make qualifier processing easier/faster/better. These ! should be initialized at the beginning of the Abel session. All of these are ! new Abel variables, except for the modification of Eve's ! eve$x_token_separators. ! ! abl$x_is_qualifier := 0; !token type ! abl$x_qualifier_character := "/"; !qualifier introducer ! abl$x_qualifier_characters := "_0123456789abcdefghijklmnopqustuvwxyz" + ! "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; !valid qualifier name characters ! abl$x_qual_def_prefix := "abl$qd_"; !prefix for qualifier definitions ! abl$x_qualifier_prefix := "abl$q_"; !variable prefix for qualifiers ! eve$x_token_separators := eve$x_token_separators + ! abl$x_qualifier_character; !makes "/hello/there" 2 tokens ! The changes to Eve's TPU code to provide qualifier support are well ! documented and pretty limited. Hopefully this won't break too much, later. ! Page 2 procedure eve$index_over_whitespace ! Move over whitespace ! Move eve$x_command_index over whitespace. Stay put if not on whitespace ! when starting. ! ! Use the whitespace variable (eve$x_whitespace) instead of the token ! separators variable (eve$x_token_separators); the token sep's variable ! includes the qualifier symbol as a valid token separator, but it ! should not be considered whitespace. ! ! Source: ! Eve local c; ! Current character in command line loop exitif eve$x_command_index > eve$x_command_length; c := substr (eve$x_command_line, eve$x_command_index, 1); exitif index (eve$x_whitespace, c) = 0; eve$x_command_index := eve$x_command_index + 1; endloop; endprocedure; ! Page 3 procedure eve$get_token ! Returns the next token in command ! Eve$get_token returns the next token in the command line. ! Returns a null string if no more tokens. ! ! Tokens include symbols, quoted strings, and punctuation, and strings ! that are "none of the above." A quoted string at the end of a line ! does not have to have a final close quote. ! ! Source: ! Eve ! ! Edit History: ! [1] 28-Mar-87 Jef Change so eve$x_is_number is not left to ! default. ! ! [2] 28-Mar-87 Jef Add support for qualifiers as a valid token. local original_index, ! Original index into command line quote_char, ! Quote character being used for quoted string c, ! Current character in command line closed_quote, ! True if quote_char ends quoted string work_token; ! Temporary string for building current token quote_char := eve$kt_null; c := eve$kt_null; closed_quote := 0; work_token := eve$kt_null; eve$x_is_symbol := 0; eve$x_is_quoted_string := 0; eve$x_is_punctuation := 0; eve$x_is_number := 0; ! [1] change from 1 to zero abl$x_is_qualifier := 0; ! [2] add line eve$index_over_whitespace; original_index := eve$x_command_index; if eve$x_command_index > eve$x_command_length then ! eve$x_is_number := 0; ! [1] line not necessary eve$get_token := eve$kt_null; return; endif; c := substr (eve$x_command_line, eve$x_command_index, 1); ! [2] + if c = abl$x_qualifier_character then abl$x_is_qualifier := 1; loop eve$x_command_index := eve$x_command_index + 1; exitif eve$x_command_index > eve$x_command_length; c := substr(eve$x_command_line, eve$x_command_index,1); exitif index(eve$x_token_separators, c) > 0; endloop; eve$get_token := substr (eve$x_command_line, original_index, eve$x_command_index - original_index); return; endif; ! [2] - if index (eve$x_symbol_characters, c) > 0 then eve$x_is_symbol := 1; eve$x_is_number := 1; ! [1] add line loop eve$x_is_number := eve$x_is_number and (index (eve$x_digit_characters, c) > 0); eve$x_is_symbol := eve$x_is_symbol and (index (eve$x_symbol_characters, c) > 0); eve$x_command_index := eve$x_command_index + 1; exitif eve$x_command_index > eve$x_command_length; c := substr (eve$x_command_line, eve$x_command_index, 1); exitif index (eve$x_token_separators, c) > 0; endloop; eve$get_token := substr (eve$x_command_line, original_index, eve$x_command_index - original_index); return; endif; !eve$x_is_number := 0; ! [1] eliminate line if (c = "'") or (c = '"') then eve$x_is_quoted_string := 1; quote_char := c; loop eve$x_command_index := eve$x_command_index + 1; exitif eve$x_command_index > eve$x_command_length; c := substr (eve$x_command_line, eve$x_command_index, 1); if c = quote_char then ! Check for doubled quotes eve$x_command_index := eve$x_command_index + 1; if eve$x_command_index > eve$x_command_length then closed_quote := 1; exitif 1; endif; c := substr (eve$x_command_line, eve$x_command_index, 1); if c <> quote_char then closed_quote := 1; exitif 1; endif; endif; endloop; work_token := substr (eve$x_command_line, original_index, eve$x_command_index - original_index); ! Add close quote if there wasn't one due to end of line. if closed_quote then eve$get_token := work_token; else eve$get_token := work_token + quote_char; endif; return; endif; ! Not a symbol, not a quoted string, so just return the single character and ! set eve$x_punctuation. eve$x_punctuation := 1; eve$x_command_index := eve$x_command_index + 1; eve$get_token := substr (eve$x_command_line, original_index, 1); endprocedure; ! Page 4 procedure eve$add_final_string ! Parse rest of command line as string (result_so_far, current_token) ! Procedure for handling the last string argument in a command line ! when it is not a quoted string. Returns result of parse after ! handling the string. ! ! Look for additional qualifiers in the rest of the line. If found, move ! the eve$x_command_index as necessary else move it to the end of the string. ! ! Parameters: ! result_so_far string containing parse to date - input ! current_token string containing current token - input ! ! Globals: ! eve$x_command_length integer length of eve$x_command_line ! eve$x_command_index integer pointer into eve$x_command_line ! ! Source: ! Eve local qualifier_location, ! Found a qualifier parse_result, ! Result of parsing complete command line rest_of_line, ! Remainer of command line including this token quote_mark; ! Quote mark to be used in parse_result parse_result := result_so_far; rest_of_line := current_token + substr (eve$x_command_line, eve$x_command_index, (eve$x_command_length - eve$x_command_index) + 1); ! ! See if there's a qualifier later on this line ! qualifier_location := index(rest_of_line,"/"); if qualifier_location <> 0 then ! ! Found a qualifier, cut rest of line short and adjust eve$x_command_index ! rest_of_line :=substr(rest_of_line,1,qualifier_location -1); eve$x_command_index := eve$x_command_index - length(current_token) + length(rest_of_line); edit(rest_of_line,trim,off); else ! ! Didn't find a qualifier, so move index to end of line ! eve$x_command_index := eve$x_command_length; endif; !message("command_line """ + eve$x_command_line + """"); !message("command_length " + str(eve$x_command_length)); !message("command_index " + str(eve$x_command_index)); !message("qualifier_loc " + str(qualifier_location)); !message("rest_of_line """ + rest_of_line + """"); !message("parse_result """ + parse_result + """"); !abort; if index (rest_of_line, '"') = 0 then quote_mark := '"'; else if index (rest_of_line, "'") = 0 then quote_mark := "'"; else ! double the quote marks in string quote_mark := '"'; rest_of_line := eve$double_quotes (rest_of_line); endif; endif; ! parse_result := parse_result + quote_mark + rest_of_line + quote_mark +")"; return (parse_result); endprocedure; ! Page 5 procedure eve$parse (line_to_parse) ! Main command line parsing routine ! The main command line parsing procedure. Returns a VAXTPU command string. ! Parses Eve commands, which call procedures whose names start with "eve_". ! Commands can be typed with or without parentheses and quotation marks. ! Multi-word commands like fill_paragraph may be typed with a space instead ! of an underscore. Defaults are provided so that procedures will prompt ! for missing arguments (prompting varies too much for effective ! centralization). ! ! Expand_name currently will not find matches past the 32nd char, so ! all command names must be less than 23 (not including "eve_") since ! "eve$argx_" takes up 9 characters ! ! Using substr on the command token assures that we look for matches ! in the first 32 characters only; commands that are not unique in the ! first 23 characters will cause a problem ! ! Parameters: ! line_to_parse string Eve command ! ! Globals: ! eve$x_command_line string line-to-parse ! eve$x_command_length integer length of eve$x_command_line ! eve$x_command_index integer pointer into eve$x_command_line ! ! Source: ! Eve ! ! Edit History: ! [1] 29-Mar-87 Jef ! Add support for qualifiers. Note that commands that accept a string ! as the last argument must quote the string if it contains the "/" ! character, otherwise the parser will try to interpret it as a qualifier. local parse_result, ! String containing VAXTPU command to execute current_token, ! String currently being processed uppercase_token, ! Uppercase version of current_token expanded_token, ! String with all candidate commands choice_token, ! Current item from expanded_token command_token, ! Eve command name, with underscores command_name, ! Eve command name, without underscores choices, ! Subset of expanded_token that match how_many_choices, ! How many items in choices possible_completion, ! String containing first n words of command completion, ! First possible_completion ambiguous_completion, ! True if possible_completion is not unique no_more_words, ! True when all words in command name parsed reusing_token, ! True if lookahead found an argument instead ! of part of a command name this_buffer, ! Current buffer arguments, ! Number of arguments expected for this command which_argument; ! Number of argument currently being processed on_error ! Trap messages with tpu$_nonames and tpu$_multiplenames endon_error; eve$x_command_line := line_to_parse; eve$x_command_index := 1; eve$x_command_length := length (eve$x_command_line); eve$x_ambiguous_parse := 0; eve$x_argument_type := eve$kt_null; parse_result := eve$kt_null; command_token := eve$kt_null; command_name := eve$kt_null; expanded_token := eve$kt_null; uppercase_token := eve$kt_null; erase (eve$choice_buffer); ! Get command name - since commands may have spaces, this can ! involve parsing several tokens ! Handle first token separately, outside the loop, for easier diagnostics ! and handling eve_ prefix current_token := eve$get_token; if current_token = eve$kt_null then message ("No command given"); return (eve$kt_null); endif; if not eve$x_is_symbol then message (fao ("Unrecognized command: !AS", current_token)); return (eve$kt_null); endif; uppercase_token := current_token; change_case (uppercase_token, upper); if substr (uppercase_token, 1, 4) <> "EVE_" then uppercase_token := "EVE_" + uppercase_token; endif; this_buffer := current_buffer; ! Loop for parsing command token loop expanded_token := expand_name (uppercase_token, procedures); if expanded_token = eve$kt_null then if parse_result <> eve$kt_null then reusing_token := 1; exitif 1; else ! Usually will get leading space due to "Command: " prompt message (fao ("Don't understand command: !AS", substr (eve$x_command_line, 1, eve$x_command_index - 1))); return (eve$kt_null); endif; endif; how_many_choices := 0; ambiguous_completion := 0; completion := eve$kt_null; choices := eve$kt_null; ! Move to choice buffer and loop through the choices. eve$expand_to_choices (expanded_token); loop exitif mark (none) = end_of (eve$choice_buffer); choice_token := current_line; how_many_choices := how_many_choices + 1; if uppercase_token = choice_token then ! found an exact match parse_result := choice_token; endif; possible_completion := eve$complete (uppercase_token, choice_token); if possible_completion = choice_token then no_more_words := 1; endif; if how_many_choices = 1 then completion := possible_completion; else if completion <> possible_completion then ambiguous_completion := 1; endif; endif; move_vertical (1); endloop; eve$strip_choices (4); position (this_buffer); translate (eve$choice_buffer, " ", "_"); if parse_result = uppercase_token then reusing_token := 0; exitif 1; else if how_many_choices = 1 then parse_result := expanded_token; else if ambiguous_completion then eve$display_choices (fao ("Ambiguous command name: !AS", substr (eve$x_command_line, 1, eve$x_command_index - 1))); return (eve$kt_null); else if no_more_words then parse_result := completion; reusing_token := 0; exitif 1; endif; endif; endif; endif; ! Get next token and try to build command current_token := eve$get_token; if current_token = eve$kt_null then if parse_result <> eve$kt_null then reusing_token := 1; exitif 1; else eve$display_choices (fao ("Ambiguous command name: !AS", substr (eve$x_command_line, 1, eve$x_command_index - 1))); return (eve$kt_null); endif; else uppercase_token := completion + "_" + current_token; change_case (uppercase_token, upper); endif; endloop; command_token := substr (parse_result, 5, 1); change_case (parse_result, lower); command_token := command_token + substr (parse_result, 6, length (parse_result) - 5); command_name := command_token; translate (command_name, " ", "_"); ! Check for arguments that this command expects arguments := 1; loop ! ! Expand_name currently will not find matches past the 32nd char, so ! all command names must be less than 23 (not including "eve_") since ! "eve$argx_" takes up 9 characters ! ! Using substr on the command token assures that we look for matches ! in the first 32 characters only; commands that are not unique in the ! first 23 characters will cause a problem ! exitif expand_name ("eve$arg" + str (arguments) + "_" + substr(command_token,1,23), variables) = eve$kt_null; arguments := arguments + 1; endloop; arguments := arguments - 1; ! Since execute can only take 132 character strings, Eve command ! names can only be (132 - 30) = 102 characters long. ! If arguments = 0 or eve$arg* is uninitialized, eve$x_argument_type ! has already been initialized to the null string. if arguments > 0 then execute ("eve$x_argument_type:=eve$arg1_" + command_token); endif; ! Get second token - if it's an open paren, get the next token. ! Parsing command name may have stopped on real 2nd token, so check. if not reusing_token then current_token := eve$get_token; endif; which_argument := 0; if arguments > 0 then parse_result := parse_result + "("; endif; ! Loop to handle arguments, in 4 steps: ! 1) If last argument, check for closing punctuation and return ! 2) If last token, handle defaults for remaining arguments ! 3) Handle the argument ! 4) Get the next token ! [1] + ! Logic changed to support qualifiers for commands: ! 0) If token is qualifier, process it ! 1) If last argument, check for closing punctuation and return ! 2) If last token, handle defaults for remaining arguments ! 3) Handle the argument ! 4) Get the next token ! ! Step 2 has been modified to support qualifiers imbedded in unquoted strings. ! ! Initialize qualifier definition string and qualifiers if necessary ! if expand_name(abl$x_qual_def_prefix + command_token, variables) <> "" then execute("abl$qualifier_definition := " + abl$x_qual_def_prefix + command_token); abl$init_qualifiers(abl$qualifier_definition); else abl$qualifier_definition := eve$kt_null; endif; ! [1] - loop ! [1] + !message("command_line """ + eve$x_command_line + """"); !message("command_length " + str(eve$x_command_length)); !message("command_index " + str(eve$x_command_index)); !message("current_token """ + current_token + """"); !message("which_argument " + str(which_argument)); !message("arguments " + str(arguments)); !message("parse_result """ + parse_result + """"); if abl$x_is_qualifier then if substr(current_token,1,2) = abl$x_qualifier_character + "?" then execute("abl$show_qualifiers('" + command_token + "', abl$qualifier_definition)"); return eve$kt_null; endif; if not abl$process_qualifier(abl$qualifier_definition,current_token) then return eve$kt_null; endif; ! ! Get the next token here without adding anything to parse_result ! current_token := eve$get_token; else ! [1] - ! If last argument, handle closing punctuation and return if which_argument = arguments then if (current_token = "\") or (current_token = "|") then current_token := eve$get_token; endif; if current_token = eve$kt_null then ! [1] + ! If this command had arguments it should end with ")", but ! if qualifiers followed the last argument, then add_final pu ! the ")" on for us, so make sure we don't do that twice ! if (arguments > 0) and (substr(parse_result,length(parse_result),1) <> ")") then parse_result := parse_result + ")"; endif; ! [1]- return (parse_result); else if arguments = 0 then message (fao ("!AS does not take any arguments", command_name)); else message (fao ("!AS takes only !SL argument!%S", command_name, arguments)); endif; return (eve$kt_null); endif; endif; ! If there are no more tokens, handle default arguments. ! All Eve functions will prompt appropriately when they get the ! null string or negative numbers as arguments if current_token = eve$kt_null then loop exitif which_argument = arguments; which_argument := which_argument + 1; execute ("eve$x_argument_type:=eve$arg" + str (which_argument) + "_" + command_token); change_case (eve$x_argument_type, lower); if eve$x_argument_type = "string" then parse_result := parse_result + '""'; else if eve$x_argument_type = "integer" then parse_result := parse_result + 'eve$k_no_arg+0'; else message (fao ("Argument type !AS must be integer or string", eve$x_argument_type)); return (eve$kt_null); endif; endif; if which_argument < arguments then parse_result := parse_result + ","; endif; endloop; parse_result := parse_result + ")"; return (parse_result); endif; ! Handle current argument which_argument := which_argument + 1; execute ("eve$x_argument_type:=eve$arg" + str (which_argument) + "_" + command_token); change_case (eve$x_argument_type, lower); if eve$x_argument_type = "string" then if eve$x_is_quoted_string then parse_result := parse_result + current_token; else if which_argument = arguments then parse_result := eve$add_final_string (parse_result, current_token); ! [1] + ! Add_final_string advanced command_index to either the ! command_length (done processing comand) or to a qualifier; ! if we're done, then return, otherwise let eve$parse do ! qualifier(s) ! if eve$x_command_index = eve$x_command_length then return (parse_result); endif; ! [1] - else loop exitif eve$x_command_index > eve$x_command_length; exitif index (eve$x_token_separators, substr (eve$x_command_line, eve$x_command_index, 1)) > 0; current_token := current_token + eve$get_token; endloop; current_token := eve$double_quotes (current_token); parse_result := parse_result + '"' + current_token + '"'; endif; endif; else if eve$x_argument_type = "integer" then if eve$x_is_number then translate (current_token, "1", "l"); parse_result := parse_result + current_token; else message (fao ("!AS expects a number for argument !SL", command_name, which_argument)); return (eve$kt_null); endif; else message (fao ("Argument type !AS must be integer or string", eve$x_argument_type)); return (eve$kt_null); endif; endif; ! Get next token current_token := eve$get_token; if current_token = "," then current_token := eve$get_token; parse_result := parse_result + ","; else if which_argument < arguments then parse_result := parse_result + ","; endif; endif; endif; endloop; endprocedure; ! Page 6 procedure abl$init_qualifiers ! Initialize qualifier variables ($qualifiers) ! Accepts a qualifier definition string and initializes the proper qualifier ! variables. This is not a modified Eve routine. Called by the command ! parser. ! ! Parameters: ! $qualifiers string qualifier definition string ! ! Source: ! Abel local eoq, ! end of qualifier in "qualifiers" boqn, ! beginning of name in "qualifier" eoqn, ! end of qualifier name in "qualifier" tpu_cmd, ! tpu command to execute qualifier, ! current qualifier in process qualifier_name, ! name of qualifier qualifier_type, ! { "$" | "%" | "~" | " "} qualifier_value, ! value of qualifier qualifiers; ! qualifiers string qualifiers:=$qualifiers; edit(qualifiers,trim); boqn:=2; ! skip leading abl$x_qualifier_character loop exitif qualifiers=""; tpu_cmd:=""; eoq:=index(substr(qualifiers,2,length(qualifiers)), abl$x_qualifier_character); if eoq=0 then eoq:=length(qualifiers) endif; qualifier:=substr(qualifiers,1,eoq); qualifiers:=substr(qualifiers,eoq+1,length(qualifiers)); if substr(qualifier,1,1)<>abl$x_qualifier_character then message("Illegal qualifier string"); return 0; endif; ! message("qualifier: "+qualifier); eoqn:=boqn; !find last alpha char loop exitif index(abl$x_qualifier_characters, substr(qualifier,eoqn,1))=0; eoqn:=eoqn+1; endloop; qualifier_name:=substr(qualifier,boqn,eoqn-boqn); if length(qualifier_name)=0 then message('No qualifier name in "'+qualifier+'"'); return 0; endif; qualifier_name:=abl$x_qualifier_prefix + qualifier_name; ! message("qualifier name: '"+qualifier_name+"'"); qualifier_type:=substr(qualifier,eoqn,1); if qualifier_type="" then qualifier_type:=" " endif; case qualifier_type from " " to "~" [" "]: tpu_cmd:=tpu_cmd+qualifier_name+":="+str(true)+";"; ["~"]: tpu_cmd:=tpu_cmd+qualifier_name+":="+str(false)+";"; ["$"]: qualifier_value:=substr(qualifier,eoqn+1,length(qualifier)); tpu_cmd:=tpu_cmd+qualifier_name+":='"+qualifier_value+"';"; ["%"]: qualifier_value:=substr(qualifier,eoqn+1,length(qualifier)); if qualifier_value="" then qualifier_value:="0" endif; tpu_cmd:=tpu_cmd+qualifier_name+":="+qualifier_value+";"; [inrange,outrange]: message('Unrecognized qualifier qualifier "'+qualifier_type+ '" in "'+qualifier+'"'); return 0; endcase; ! message(tpu_cmd); execute(tpu_cmd); endloop; return true; endprocedure ! Page 7 procedure abl$process_qualifier ! Process command line qualifier ($qual_def,$qualifier) ! Sets the value of qualifier variables based on the qualifier. Called by the ! command line parser. ! ! Parameters: ! $qual_def string qualifier definition string ! $qualifier string user's qualifier ! ! Source: ! Abel local boqn, !beg of qualifier name in qualifier bov, !beg of qualifier value in qualifier eoq, !eoq of qualifier in qualifier eoqn, !eoq of qualifier name in qualifier command_string, !command string produced qc, !same as abl$x_qualifier_character qualifier, !qualifier string qualifier_name, !qualifier name string qualifier_negated, !qualifier preceded with "no" boolean qualifier_value, !qualifier value string qualifiers, !qualifiers to parse string qual_def, !local copy of qualifier definition tmp$boq, !beg of qualifier in qual_def tmp$boqn, !beg of qualifier name in qual_def tmp$eoqn, !end of qualifier name in qual_def tmp$loq, !length of qualifier in qual_def tmp$qualifier, !qualifier string from qual_def tmp$qualifier_name, !qualifier name from qual_def tmp$qualifier_type; !qualifier type qualifier string ! ! Massage input ! qual_def := $qual_def; edit(qual_def,trim,lower); qualifier:=$qualifier; edit(qualifier,trim,lower); qc:=abl$x_qualifier_character; !to save typing command_string := ""; eoq:=length(qualifier); ! ! If user is asking about qualifiers, display them and quit ! if index(qualifier, qc + "?") <> 0 then abl$show_qualifiers(eve$kt_null,qual_def); return 0; endif; ! ! Get user's qualifier name ! boqn:=2; eoqn:=boqn; loop exitif index(abl$x_qualifier_characters, substr(qualifier,eoqn,1))=0; eoqn:=eoqn+1; endloop; eoqn:=eoqn-1; !is last char of name in qualifier qualifier_name:=substr(qualifier,boqn,eoqn-boqn+1); if length(qualifier_name)=0 then !really a qual name? message('No qualifier name in "'+qualifier+'"'); ! no...err & ret return 0; endif; ! ! Try to find qualifier name in the qualifier definition string ! If can't find it, see if the qualifier is negated...if it is, strip off "no", ! remember that the qualifier was negated, and try to find it in the qualifier ! definition string again ! qualifier_negated:=false; tmp$boq:=index(qual_def,"/"+qualifier_name); !find qual in def'n str if tmp$boq=0 then !find it? if substr(qualifier_name,1,2)<>"no" then ! no...qual neg? message("Unrecognized qualifier: /"+qualifier_name); ! no...err & ret return 0; endif; qualifier_name:= !strip off "no" substr(qualifier_name,3,length(qualifier_name)); if length(qualifier_name)=0 then !really a qual name? message('No qualifier name in "'+qualifier+'"');! no...err & ret return 0; endif; tmp$boq:=index(qual_def,"/"+qualifier_name); !find qual in tmp if tmp$boq=0 then !find it? message("Unrecognized qualifier: /"+qualifier_name); ! no...err & ret return 0; endif; qualifier_negated:=true; !remember negated endif; ! ! We found a match in the qualifier definition string...make sure the match ! is the only one ! if index(substr(qual_def,tmp$boq+1,length(qual_def)),"/"+qualifier_name)<>0 then message('"'+qualifier+'"'+" is an ambiguous qualifier"); return 0; endif; ! ! From now on, use the qualifier from the qualifier definition string ! (in case the user abbreviated his qualifier) ! tmp$loq:=index(substr(qual_def,tmp$boq+1,length(qual_def)),"/"); if tmp$loq=0 then tmp$loq:=length(qual_def) endif; tmp$qualifier:=substr(qual_def,tmp$boq,tmp$loq); tmp$boqn:=2; !get qualifier name tmp$eoqn:=tmp$boqn; loop exitif index(abl$x_qualifier_characters, substr(tmp$qualifier,tmp$eoqn,1)) = 0; tmp$eoqn:=tmp$eoqn+1; endloop; tmp$qualifier_name:=substr(tmp$qualifier,tmp$boqn,tmp$eoqn-tmp$boqn); ! ! Determine the qualifier type, and dispatch ! tmp$qualifier_type:=substr(tmp$qualifier,tmp$eoqn,1); if tmp$qualifier_type="" then tmp$qualifier_type:=" " endif; case tmp$qualifier_type from " " to "~" ! ! Boolean ! [" ","~"]: edit(qualifier,trim); if length(qualifier) then message('Junk at end of qualifier: "'+qualifier+'"'); return 0; endif; command_string := command_string + abl$x_qualifier_prefix + tmp$qualifier_name + ":="; if qualifier_negated then command_string:=command_string+ str(false)+";" else command_string:=command_string+str(true)+";" endif; ! ! String or integer ! ["$","%"]: if qualifier_negated then message("Qualifier may not be negated: "+tmp$qualifier_name); return 0; endif; bov:=eoqn+1; loop exitif bov>eoq; exitif substr(qualifier,bov,1) = "="; bov:=bov+1; endloop; if bov>eoq then message('"=" expected on qualifier: '+tmp$qualifier_name); return 0; endif; qualifier_value:=substr(qualifier,bov+1,length(qualifier)); edit(qualifier_value,trim); if tmp$qualifier_type="$" then command_string := command_string + abl$x_qualifier_prefix + tmp$qualifier_name + ':="' + qualifier_value + '";'; else command_string := command_string + abl$x_qualifier_prefix + tmp$qualifier_name + ":=" + str(int(qualifier_value)) + ";"; endif; [inrange,outrange]: message('Unrecognized qualifier type "' + tmp$qualifier_type + '" in "' + tmp$qualifier + '"'); return 0; endcase; !message(command_string); if command_string<>"" then execute(command_string) endif; return true; endprocedure ! Page 8 procedure abl$show_qualifiers ! Display qualifiers for command ($command,$qualifiers) ! Abel routine to show qualifier definition in readable fashion ! ! Parameters: ! $command string command that qualifiers are for ! $qualifiers string qualifier definition ! ! Source: ! Abel local starting_position, ! where the user started had_to_map, ! set if had to map show_buf to info_win dummy_input, ! wait for user's return key to continue eoq, ! pointer to end of qualifier definition boqn, ! pointer to beginning of qualifier name eoqn, ! pointer to end of qualifier name qualifier, ! single qualifier definition (name and val) qualifier_name, ! single qualifier name qualifier_type, ! single qualifier's type char (~,$,%," ") qualifier_value, ! single qualifier's default value qualifiers; ! local copy of qualifier definition string on_error endon_error ! ! Initializations ! starting_position := mark(none); qualifiers := $qualifiers; edit(qualifiers,trim,lower); if qualifiers = eve$kt_null then if $command <> eve$kt_null then message("No qualifiers for " + $command + " command"); else message("No qualifiers"); endif; return 0; endif; ! ! If the show_buffer isn't mapped on the screen, map it to the info_window ! if get_info(show_buffer,"map_count")=0 then had_to_map := true; map(info_window,show_buffer); else had_to_map := false; endif; ! ! Write some header stuff to the show buffer ! erase(show_buffer); position(show_buffer); split_line; copy_text("Qualifier Listing"); if $command <> eve$kt_null then copy_text(" for " + $command); endif; split_line; split_line; copy_text(" Qualifier Type Default Value"); split_line; copy_text(" ----------- ---- -------------"); split_line; ! ! For each qualifier in the definition string ! loop exitif qualifiers = ""; ! ! Strip one qualifier off of qualifiers ! eoq := index(substr(qualifiers,2,length(qualifiers)), abl$x_qualifier_character); if eoq = 0 then eoq := length(qualifiers) endif; qualifier := substr(qualifiers,1,eoq); qualifiers := substr(qualifiers,eoq+1,length(qualifiers)); ! ! Check the 1st char to make sure we have a real qualifier here ! if substr(qualifier,1,1) <> abl$x_qualifier_character then message("Illegal qualifier definition string"); exitif 1; endif; ! ! Get the qualifier's name ! boqn := 2; eoqn := boqn; !find last alpha char loop exitif index(abl$x_qualifier_characters,substr(qualifier,eoqn,1)) = 0; eoqn := eoqn+1; endloop; qualifier_name := substr(qualifier,boqn,eoqn-boqn); if length(qualifier_name) = 0 then message('No qualifier name in "'+qualifier+'"'); return 0; endif; qualifier_name := abl$x_qualifier_character + qualifier_name; copy_text(" "); copy_text(qualifier_name+substr(eve$x_spaces,1,20-length(qualifier_name))); ! ! Determine qualifier's type ! qualifier_type := substr(qualifier,eoqn,1); if qualifier_type = "" then qualifier_type:=" " endif; ! ! Write out qualifier's type and default value ! case qualifier_type from " " to "~" ! ! Boolean qualifier ! [" ","~"]: copy_text("boolean "); if qualifier_type = " " then copy_text("true"); else copy_text("false"); endif; split_line; ! ! String ! ["$"]: qualifier_value := substr(qualifier,eoqn+1,length(qualifier)); copy_text('string "'+qualifier_value+'"'); split_line; ! ! Integer ! ["%"]: qualifier_value := substr(qualifier,eoqn+1,length(qualifier)); copy_text("integer "+str(int(qualifier_value))); split_line; ! ! Unknown types ! [inrange,outrange]: message('Unrecognized qualifier qualifier "'+qualifier_type+ '" in "'+qualifier+'"'); return 0; endcase; endloop; ! ! If we had to map, wait for user then put his screen back ! position(beginning_of(show_buffer)); eve$update_status_lines; if had_to_map then update(info_window); dummy_input := read_line("Press return to continue"); unmap(info_window); endif; position(starting_position); endprocedure !End of command parser enhancements/modifications ! Page 9 procedure eve$prompt_string ! Eve's string prompting routine (old_string, new_string, prompt_string, no_value_message) ! Prompt for input to new_string if old_string is empty; allow old_string and ! new_string to be same variable in call to eve$prompt_string ! ! Parameters: ! old_string string current value of string ! new_string string returned string ! prompt_string string prompt ! no_value_me... string displayed if nothing entered ! ! Source: ! Eve local read_line_string, temp; ! String read after prompt temp:=old_string; !Save value of old_string ! in case old_string and ! new_string are same variable if old_string = eve$x_null then new_string := read_line (prompt_string); if new_string = eve$x_null then message (no_value_message); return (0); else return (1); endif; else new_string := temp; return (1); endif; endprocedure; ! Page 10 procedure abl$prompt_word ! Abel's word prompting routine ($word_list, $old_word, $new_word, $prompt_string, $no_value_message) ! Prompts the user for one of the words in the word list, based loosely on ! Eve's eve$prompt_string routine. The word_list is the list of words, each ! prefaced by "/" (since it is already a reserved character in Abel). No ! checking is done on the word_list parameter, so it must be correct. An ! example word_list might be "/yes/no". Case is not important in the word_list ! (it is always raised) and spaces are eliminated from the string. The ! returned $new_word is always in upper case, and contains the full word; in ! the above example, a user could enter "n" but "NO" would be returned. ! ! Parameters: ! $word_list string list of possible options ! $old_word string current value of word ! $new_word string returned word ! $prompt_string string prompt ! $no_value_me... string displayed if nothing entered ! ! Source: ! Abel local had_to_complain, ! set if had to tell user the options options, ! text if bad word entered word_list, ! local copy of $word_list next_word_ptr, ! pointer in word_list to start of next word new_word_ptr, ! pointer in word_list to user's choice ambiguous_word, ! pointer in word_list to another user's choice new_word, ! local copy of $new_word old_word; ! local copy of $old_word old_word := $old_word; edit(old_word,lower,trim); had_to_complain := false; ! ! Massage the word_list for the message to display for words not found ! word_list := substr($word_list,2,1000); !drop the first "/" edit(word_list,lower,collapse); options := "Valid options are: "; loop ! ! keep moving a word and ", " from the word list to the options ! until the word_list is exhausted ! exitif word_list = ""; next_word_ptr := index(word_list,"/"); if next_word_ptr = 0 then next_word_ptr := 1000 endif; options := options + substr(word_list, 1, next_word_ptr - 1) + ", "; word_list := substr(word_list, next_word_ptr + 1, 1000); endloop; ! ! remove trailing ", " from choice message ! options := substr(options,1,length(options)-2); word_list := $word_list; edit(word_list,lower,collapse); ! ! loop until valid word entered or aborted with a return ! loop ! ! get a value into old_word ! if old_word = eve$kt_null then old_word := read_line ($prompt_string); edit(old_word,lower,trim,collapse); if old_word = eve$kt_null then message ($no_value_message); $new_word := eve$kt_null; return (0); endif; endif; ! ! if the word is in our list then ! make sure word matches our list only once (non-ambiguous) ! get value in new_word and leave ! else reprompt ! new_word_ptr := index(word_list, "/" + old_word); if new_word_ptr <> 0 then new_word := substr(word_list, new_word_ptr + 1, 1000); ambiguous_word := index(substr(word_list,new_word_ptr + 1,1000), "/" + old_word); if ambiguous_word = 0 then next_word_ptr := index(new_word,"/"); if next_word_ptr = 0 then next_word_ptr := 1000; endif; new_word := substr(new_word, 1, next_word_ptr - 1); exitif 1; endif; endif; ! ! Word not found...tell user correct options ! message(options); had_to_complain := true; old_word := eve$kt_null; ! so that we reparse endloop; if had_to_complain then message(eve$kt_null); endif; $new_word := new_word; return 1; endprocedure; ! Page 11 procedure eve$process_command ! Process command in cmd line editor (new_do_line) ! Process command selected in command line editor ! ! Parameters: ! new_do_line string containing Eve command ! ! Source: ! Eve ! ! Edit History: ! Jef Just to be consistent with the bolded no_write buffer stuff in the ! eveplus routines, bold the choice buffer status line ! ! Jef Re-init qualifiers when re-doing a command local repetitions, ! Number of times to execute this command this_position, ! Marker for current cursor position this_window, ! Current window command_token, ! Token necessary to init qualifier variables choice_msg; ! [1] Message text for choice buffer status line on_error endon_error; ! Make sure we do not repeat the current repeat command repetitions := eve$x_repeat_count; eve$x_repeat_count := 1; if new_do_line <> eve$x_null then eve$x_do_line := new_do_line; eve$parsed_do_line := eve$parse (eve$x_do_line); if eve$parsed_do_line = eve$x_null then ! message sent during parse error eve$x_do_line := eve$x_null; else ! Unmap choice window before executing the command if get_info (eve$choice_window, "buffer") <> 0 then unmap (eve$choice_window); endif; loop exitif repetitions = 0; execute (eve$parsed_do_line); repetitions := repetitions - 1; endloop; endif; else eve$x_ambiguous_parse := 0; ! need this since eve$parse is not called here if (eve$x_start_do_key = "do") and (eve$x_stop_do_key = "do") then if eve$x_do_line = eve$x_null then message ("No previous command given"); else message (fao ("Doing previous command: !AS", eve$x_do_line)); ! ! Initialize qualifiers for this command, if any ! command_token := substr(eve$parsed_do_line,5,255); if index(command_token,"(") <> 0 then command_token := substr(command_token,1, index(command_token,"(")-1); endif; if expand_name (abl$x_qual_def_prefix + command_token, variables) <> eve$kt_null then execute ("abl$init_qualifiers(" + abl$x_qual_def_prefix + command_token + ")"); endif; ! ! Perform the command ! loop exitif repetitions = 0; execute (eve$parsed_do_line); repetitions := repetitions - 1; endloop; endif; else message ("No command given"); endif; endif; if eve$x_ambiguous_parse then if get_info (eve$choice_window, "buffer") = 0 then map (eve$choice_window, eve$choice_buffer); endif; if get_info (eve$choice_buffer, "record_count") >= eve$x_choice_window_length then choice_msg:= ![1] and next 7 or so lines " Choices Press Next Screen or Prev Screen to see other choices"; else choice_msg:=" Choices"; endif; set(status_line,eve$choice_window,reverse,"X"); set(status_line,eve$choice_window,bold,choice_msg); update (eve$choice_window); position (eve$command_window); position (end_of (eve$command_buffer)); move_horizontal (-1); else ! Unmap choice window if not done previously if get_info (eve$choice_window, "buffer") <> 0 then unmap (eve$choice_window); endif; this_position := mark (none); this_window := current_window; position (eve$command_window); position (end_of (eve$command_buffer)); if new_do_line = eve$x_null then move_vertical (-1); erase_line; endif; update (eve$command_window); position (this_window); position (this_position); endif; endprocedure;