@* Input and output. \noindent Terminal output is done by writing on file |term_out|, which is assumed to consist of characters of type |text_char|. Terminal input is read from |term_in|. @^system dependencies@> @d print(X) = fprintf(stderr,X) /* `|print|' means write on the terminal */ @d new_line = putc('\n',stderr) /* start new line */ @d print_ln(X) = {print(X); new_line;} @d print_nl(X) = { new_line; print(X);} @d term_in = stdin @d term_out = stderr @ The |update_terminal| procedure is called when we want to make sure that everything we have output to the terminal so far has actually left the computer's internal buffers and been sent. @^system dependencies@> @d update_terminal = fflush(term_out) {empty the terminal output buffer} @ If an error occurs we indicate this calling a procedure named |err_print|. This procedure is implemented as a macro. It gives a message and an indication of the offending file. The actions to determine the error location will be explained later. @d err_print(MSG,LOC) = {print_nl(MSG); err_loc(LOC); history=troublesome;} @ The basic procedure |get_ln_from_file| can be used to get a line from an input file. The line is stored in |input_files[i].buffer|. The components |limit| and |lineno| are updated. If the end of the file is reached |input_files[i].mode| is set to |ignore|. On some systems it might be useful to replace tab characters by a proper number of spaces since several editors used to create change files insert tab characters into a source file not under control of the user. So it might be a problem to create a matching change file. @^tab character expansion@> We define |get_line| to read a line from a file specified by number. To ease an inplementation without arrays of files we introduce one more parameter. In such cases |get_line| is best replaced by a procedure containing a |case| statement to select the file needed. @d get_line(X) = get_ln_from_file(X,input_files[X]); @c get_ln_from_file(i,cur_file) int i; text_file cur_file; { int final_limit; int c; if (input_organization[i].mode==ignore) return; if (feof(cur_file)) @; @; } @ End of file is special if this file is the master file. @= { input_organization[i].mode=ignore; if (input_organization[i].type_of_file==master) input_has_ended=true; return; } @ Lines must fit into the buffer completely. Tab character expansion might be done here. @^tab character expansion@> @= (input_organization[i].lineno)++; input_organization[i].limit=0; final_limit = 0; while ((input_organization[i].limit<=buf_size) && (c=getc(cur_file)) != EOF && c!='\n') { input_organization[i].buffer[input_organization[i].limit]=xord[c]; (input_organization[i].limit)++; if ((input_organization[i].buffer[input_organization[i].limit-1]!=' ') && (input_organization[i].buffer[input_organization[i].limit-1] != tab_mark)) final_limit=input_organization[i].limit; } if (input_organization[i].limit>buf_size) if ((c=getc(cur_file))!=EOF && c!='\n') { ungetc(c,cur_file); err_print("! Input line too long",i); @.Input line too long@> } @@; input_organization[i].limit=final_limit; @ We have to check for end of file in the middle of reading @= if (input_organization[i].limit==0 && c==EOF) @@;