# texttool: process text # usage: texttool # 2000-03-08 erikt@uia.ua.ac.be # 2000-03-11 added comment lines # This program is capable of dealing with different texts. It stores # them in the hash %text. For example: if we want a text with name "abc" # and contents "This is a test\nLine 2\n" to be put in the hash %text, # then we can use: $text{"abc"} = "This is a test\nLine 2\n"; # We start with an empty hash. %text = (); # Initially we will generate an error message for two problems: # (1) when a command is entered with an incorrect number of arguments, # and (2) when a command tries to use a text which is undefined. We # need two error messages. In the future, we might need more so we # store the error messages in a list. Here we initialize this list # @errorMsg. @errorMsg = (); $errorMsg[1] = "incorrect number of arguments"; $errorMsg[2] = "text variable does not exist"; # We will use a variable $errorNbr for indicating what error the # program has detected. The number will correspond with the index # of @errorMsg: $errorNbr==1 means that a command was entered # with an incorrect number of arguments and $errorNbr==2 means that # a command has tried to process an undefined text. As long as no # error has been detected, $errorNbr will contain value 0. $errorNbr = 0; # In case we make an error while changing this program, it might # happen that the program tries to print $errorMsg[$errorNbr] when # $errorNbr==0. In order to recognize this problem, we put a nonsense # text in this part of @errorMsg. $errorMsg[0] = "cannot happen"; # The program reads commands until the user wants to quit. We define # a variable $quit which we will set to 1 (=yes) when the user has # entered the quit command. As long as the quit command has not been # used, the $quit variable will contain value 0 (=no). $quit = 0; # This while command will read and execute commands as long as the # variable $quit is equal to 0 (=no). As soon as the user enters # the quit command, the program will set $quit to 1 and the loop # will be ended. while (not $quit) { # Read a command: print a prompt "> " to show that the program # expects a command, read the command and put it in $commandLine print "> "; $commandLine = <>; # When the user enters Control-Z (=end of file), the variable # $commandLine will be empty. This will generate Perl problems # in the rest of the program. Therefore we test whether this # variable is empty and change it to the quit command if the # test succeeds. It is reasonable to change it to quit since # this is probably what the user wanted. if (not defined($commandLine)) { $commandLine = "quit"; # On some operating systems you do not have to enter a newline # behind an end-of-file token. This may result in the prompt # of the operating system being printed behind the prompt # of texttool. This is ugly, so we print a newline character # here to make sure that the operating system prompt appears # on a new line. print "\n"; } # Remove the final newline from $commandLine chomp($commandLine); # Remove line-initial and line-final white space $commandLine =~ s/^\s+//; $commandLine =~ s/\s+$//; # Divide the command line in a command and a list of arguments. # We use split for this and use \s+ as field separator. This is # important: we cannot just use a single space as a separator # because the result would be incorrect when a user separated # commands and arguments with more than one space or with tabs. # The result of this statement with $commandLine=="print x" is # $command=="print" and in @args: $arg[0]=="x". ($command,@args) = split(/\s+/,$commandLine); # Test command format: the user may have made errors and we # want to check the commands before we execute them. The # user might have pressed Return without entering a command. # Therefore we check whether $command is defined and non-empty. # When one of these tests fails, we will skip the command without # printing an error message. if (defined($command) and $command ne "") { # The previous command might have contained an error which # changed the value of $errorNbr. We are checking a new # command and we will start with assuming that it is correct. # Therefore we make sure that $errorNbr contains value 0. $errorNbr = 0; # A command should have the correct number of arguments: # zero for quit and one for read and print. We check this # and change $errorNbr to value 1 if a problem is detected. # The number of arguments can be found out by checking the # number of elements of the @args list. This can be done by # comparing the list with a number so @args!=0 means that the # number of elements of the list @args is not equal to zero. if ($command eq "quit" and @args != 0) { $errorNbr = 1; } if ($command eq "read" and @args != 1) { $errorNbr = 1; } if ($command eq "print" and @args != 1) { $errorNbr = 1; } # Whenever a command tries to access a list, the list should # be defined. Initially texttool contains one command that # accesses lists: print. We check that whenever the command # is print and the number of arguments is correct (==1) then # the first element of @args should be a valid text name. # We can check if some string abc is a valid text name by # checking if there is a text for abc in %text, or in other # words: if $text{"abc"} is defined. Here the name of the # text is stored in the first element of @args: $args[0]. # Therefore we check if $text{$args[0]} is defined. If this # is not the case, we set $errorNbr to 2. if ($command eq "print" and @args == 1 and not(defined($text{$args[0]}))) { $errorNbr = 2; } # We are done with error checking and are about to execute # the command. However, if an error was detected then we # will not execute the command. Therefore we test if $errorNbr # has a value which is different from 0. if ($errorNbr > 0) { # Since $errorNbr is different from 0, there was a problem # with the command that was entered. Therefore we print the # corresponding error message. This is the text stored in # @errorMsg for that particular value of $errorNbr. print "$errorMsg[$errorNbr]\n"; } else { # Execute command: since $errorNbr is 0, the command is # correct and can be executed. We start with the quit # command. If a user has entered quit than the while # loop should be terminated. The loop continues while # variable $quit contains value 0 so we change this # variable to some other value. if ($command eq "quit") { $quit = 1; } # If the command is print then we print the text which # corresponds with its arguments. We have already checked # that the command has exactly one argument and that the # argument is a valid text name. The text name is stored # in $args[0] and therefore we print $text{$args[0]}. elsif ($command eq "print") { print $text{$args[0]}; } # If the command is read then we will read a text from # the keyboard, line by line, and store in the location # associated with the specified name. elsif ($command eq "read") { # The user has specified the name of the text to be # read. This name can be found in the first argument # of @args, that is in $args[0]. We will read the # text line by line and add each next line behind the # previously read lines. The first line should be # added behind an empty text so we start with making # the text empty. Its name is stored in $args[0] so # we put the empty string in $text{$args[0]}. $text{$args[0]} = ""; # Next we read lines and store them in the default # variable $_ until the user enters an end-of-file # token (Control-Z). while (<>) { # We add the line to the text. The operator .= # means "put behind". Actually $x .= $y is # an abbreviation for $x = $x . $y in which # . means concatenate. Note that we have not # removed the final newline from the line read # in $_. We allow texts to contain newlines. $text{$args[0]} .= $_; } } else { # If the command is neither of the ones specified # above (initially quit, print and read), then an # unknown command has been entered. We signal this # to the user by printing an error message. print "unknown command $command\n"; } } } } # This exit statement is optional. The program would have made an exit # here anyhow but by saying exit(0) here we force the program to exit # with exit code 0. This exit code might be useful for other programs # that are communicating with this program. Exit code 0 means that the # program finished in a normal fashion. Other exit codes mean that the # program has detected some problem. The exit codes work in a similar # way as the error numbers we have used in this program. exit(0);