#ifndef _UTILS_H_ #define _UTILS_H_ #include <stdio.h> #include <sys/types.h> #include <string.h> #include <stdlib.h> #include <stdarg.h> // Define constants #define MAXLENGTH 1000 // Each command has no more than 1000 characters #define MAXSUSPEND 100 // There are no more than 100 suspended jobs at one time #define MAXDIRECTORY 256 // Directory names (including the directory delimiter) within a path are limited to 255 bytes // Declare variables and structures int subCommandCount; // The number of tokens separated by the pipes int tokenCount; // The number of tokens in the command line (no piping) int pipeCount; // The number of pipes in the command line int hasInput; // Whether the command line has specified an external input file int hasOutput; // Whether the command line has specified an external output file and the output type // 0: no output file; 1: > write to output file; 2: >> append to output file int inputIndex; // The index of the external input specifier > int outputIndex; // The index of the external output specifier > or >> (first) char *inputFileName; // The name of the specified external input file char *outputFileName; // The name of the specified external output file char *commandLine; // The string of the input command line char **parsedTokens; // The parsed tokens of the command line char **pipedCommands; // The piped commands of the command line pid_t shell; // The process id of the shell int isBackground; // Whether the process is in the background char baseDirectory[MAXDIRECTORY]; // The string of the absolute base directory (base) char curDirectory[MAXDIRECTORY]; // The string of the absolute current working directory (cwd) int jobCount; // The number of suspended jobs struct Job { pid_t pid; // The process identification id char *pname; // The string of the name of the process } suspendedJobs[MAXSUSPEND]; // The array of suspended jobs // ========== ========== ========== ========== ========== // // // // PARSER.C // // // // ========== ========== ========== ========== ========== // /** * Reads the command line as a string. * * Input: * commandLine Empty string for writing the command line. * Initialized by mallocing sizeof(char) * MAXLENGTH. * * Output: * None. **/ void readCommandLine(char *commandLine); /** * Parses the command line by spaces to get each token, except for the specified external input and/or output. * Updates pipeCount, hasInput, hasOutput, inputIndex, outputIndex, inputFileName, and outputFileName accordingly. * * Input: * commandLine The string of the command line. * buf A string buffer, for tracking the pointer to be freed. * * Output: * The number of tokens in the command line, except for the specified external input and/or output. * Returns -1 if the program failed to satisfy any `if` condition in this function. **/ int parseNoPiping(char *commandLine, char *buf); /** * Checks for the pipings and redirections in the command line. * Updates pipeCount, hasInput, hasOutput, inputIndex, and outputIndex accordingly. * Updates parsedTokens accordingly. * * Input: * commandLine The string of the command line. * * Output: * The number of pipes in the command line. **/ int checkPipingAndRedirection(char *commandLine); /** * Parses the command line by pipes to get piped command. * Updates pipedCommands accordingly. * * Input: * commandLine The string of the command line. * buf A string buffer, for tracking the pointer to be freed. * * Output: * The number of piped commands in the command line. **/ int parseByPipe(char *commandLine, char *buf); /** * Updates the specified token array according to the specified delimiter. * * Input: * tokenArray The token array to be updated * buf The copied command line. * delimiter The delimiter to parse based on. * token The temporary storage for each token. * * Output: * The number of parsed tokens based on the specified delimiter. **/ int updateParsedTokens(char **tokenArray, char *buf, char *delimiter, char *token); // ========== ========== ========== ========== ========== // // // // EXECUTOR.C // // // // ========== ========== ========== ========== ========== // /** * Executes the command line which involves no piping. * Process termination and suspension, signal handling, I/O redirection, built-in commands, etc. are involved in this function. * * Input: * parsedTokens The array of strings of the parsed tokens from the command line. * tokenCount The number of parsed tokens from the command line. * buf A string buffer, the pointer for freeing the allocated memory. * * Output: * None. **/ void executeCommandNoPiping(char **parsedTokens, int tokenCount, char *buf); /** * Executes the command line which involves at least one pipe. * Process termination and suspension, signal handling, I/O redirection, built-in commands, etc. are involved in this function. * * Input: * pipedCommands The array of strings of the piped commands from the command line. * subCommandCount The number of subcommands separated by the pipes. * buf A string buffer, the pointer for freeing the allocated memory. * * Output: * None. **/ void executeCommandWithPiping(char **pipedCommands, int subCommandCount, char *buf); /** * Executes the nyush version of `cd` command. * * Input: * parsedTokens The array of strings of the parsed tokens from the command line. * curDirectory The string of the current working directory (cwd). * * Output: * Returns 0 if succeeded and -1 if failed. **/ int nyushCd(char **parsedTokens, char *curDirectory); /** * Executes the nyush version of `exit` command. * * Input: * parsedTokens The array of strings of the parsed tokens from the command line. * buf A string buffer, the pointer for freeing the allocated memory on exit. * firstToken The first token of the current command, pointer for freeing upon error. * * Output: * Returns 0 if succeeded and -1 if failed. **/ int nyushExit(char **parsedTokens, char *buf, char *firstToken); /** * Executes the nyush version of `fg` command. * * Input: * parsedTokens The array of strings of the parsed tokens from the command line. * * Output: * Returns 0 if succeeded and -1 if failed. **/ int nyushFg(char **parsedTokens); /** * Executes the nyush version of `jobs` command. * * Input: * parsedTokens The array of strings of the parsed tokens from the command line. * * Output: * Returns 0 if succeeded and -1 if failed. **/ int nyushJobs(char **parsedTokens); /** * Executes other programs and commands. * * Input: * parsedTokens The array of strings of the parsed tokens from the command line. * buf A string buffer, the pointer for freeing the allocated memory on exit. * firstToken The first token of the current command, pointer for freeing upon error. * * Output: * Returns 0 if succeeded and -1 if failed. **/ int nyushRun(char **parsedTokens, char *buf, char *firstToken); /** * Suspends a new job, updating the list of suspended jobs. * * Input: * pid The process id of the new job * pname The procecss name of the new job, i.e., the (sub)command line. * * Output: * None. **/ void suspendNewJob(pid_t pid, char *pname); /** * Releases the suspended job with the specified process id. * * Input: * pid The process id of the suspended job to be released. * * Output: * None. **/ void releaseSuspendedJob(pid_t pid); /** * Deep copies a string. * Same functionalities as `strdup()`, but `strdup()` is not C standard. * * Input: * str The original string to be copied. * * Output: * The pointer to the copied string. **/ char *copyString(char *str); /** * Free all assigned arguments. Notice that these are just direct freeing. * The argument is a format specifier, followed by corresponding arguments. There is not NULL termination. * * Input: * format The format specifier of the input arguments. * 1: char *; 2: char **; d: int * * * Output: * None. **/ void freeAll(const char *format, ...); #endif