/* indirect Usage: #include #include For RSX I/O error codes int indirect (filename, function) STRING filename; Name of the idirect file INTFUNC function; Function to process the arguments Description: The specified filename is opened in read mode. If the open fails, the function returns with the error code; the normal return value is 0. If an indirect file is already open, the current file is queued onto a FILE_QUEUE (see qfile.c) and processing continues on the new file. The only limit to the number of indirect files that may be queued in this way (the nesting level) is the amount of dynamic memory available to the task. >>> CAUTION <<< A single file pointer and queue is used for all files accessed by this routine. Thus it cannot be used independently in parallel for multiple indirect file sets. It can be used sequentially (indirection has completed for all nesting levels) for different indirect file sets. Each text line (up to MAX_LINE_SIZE characters) from the current file is parsed into an argument vector (see arg_parse) containing arg_count argument strings. A call is then made to the function that will process the vector: (*function) (arg_count, argument); This form is identical to that used by the main function, which, of course, may be the argument processing function if desired (though care should then be taken to use the return fucntion from main rather than the exit function). Note that no consideration is given to the value returned from the argument processing function. The text line string and the argument vector are located in dynamically allocated memory which makes this function reentrant. One text line buffer is allocated for each open indirect file. Thus when an argument vector contains an argument that invokes another indirect file, the current argument vector remains pending until all other nested levels of processing are completed, so that the processing of the pending argument vector can continue normally upon the appropriate return from the call to the indirect function (this, of course, is all invisible to the user). If the needed dynamic memory space isn't available, an IE_NBF (no buffer space) error code is returned. >>> NOTE <<< Because the text string from the file is read into dynamically allocated memory which is reused for each line read from the file; and because the argument vectors, which are also located in reused dynamic memory, point to locations in the parsed text string: when the argument processing function is called it must COPY any argument strings that must be retained after they have been initially processed. When the end-of-file for the current indirect file is encountered, the previously queued indirect file, if any, is dequeued and processing continues in that file at the next text line following the one where the interruption occured. ******************************************************************************/ #include #include #include #include #define MAX_LINE_SIZE 132 #define MAX_ARGUMENTS 20 #define ARGV_STORAGE (sizeof (char *) * MAX_ARGUMENTS) static FILE *file = 0; /* File pointer */ static FILE_QUEUE *queue = 0; /* File queue */ INTEGER indirect (filename, function) STRING filename; INTFUNC function; { INTEGER status; STRING string; /* Input string from indirect file */ STRING argument; /* Argument vector */ FILE_QUEUE *enQ_file(), *deQ_file(); IO_ERROR = 0; if (file) { /* An indirect file is open: Queue up the current file and start on the next one */ queue = enQ_file (queue, file, filename); if (IO_ERROR) return (IO_ERROR); } else if (!(file = fopen (filename, "r"))) /* Open the indirect file */ return (IO_ERROR); /* Allocate line storage memory */ if (! (argument = malloc (MAX_LINE_SIZE + ARGV_STORAGE))) return (IO_ERROR = IE_NBF); /* Couldn't allocate dynamic storage */ string = argument + ARGV_STORAGE; /* Get text lines and process them: */ #ifdef DEBUG printf ("indirect: getting text lines from file\n"); #endif while (fgetss (string, MAX_LINE_SIZE, file)) /* Parse the string, and call the argument processing function */ (*function) (arg_parse (string, argument, MAX_ARGUMENTS), argument); /* Current indirect file processing ended. */ status = IO_ERROR; mfree (argument); /* Release the storage area */ if (queue) { /* Open the previously queued file */ #ifdef DEBUG printf ("indirect: Previous indirect file being dequeued.\n"); #endif queue = deQ_file (queue, file); if (IO_ERROR) return (IO_ERROR); } else { /* End of indirect file processing (all levels) */ fclose (file); file = NULL; } return ((status == IE_EOF) ? 0 : status); }