static void performCommand(char *acLine, DynArray_T oHistoryList, char *pcProgName) /* Expand any !commandprefix in acLine. Insert acLine into oHistoryList iff the expanding succeeds and acLine does not consist of entirely whitespace characters. Lexically and syntactically analyze acLine. Execute acLine if no errors are found. It is a checked runtime error for acLine, oHistory, or pcProgName to be NULL. */ { char *pcTemp; Command_T oCommand; DynArray_T oTokens; int iSuccessful; assert(acLine != NULL); assert(oHistoryList != NULL); assert(pcProgName != NULL); if(histHasCommandPrefix(acLine)) { iSuccessful = histExpandLine(acLine, oHistoryList, pcProgName); if(iSuccessful) printf("%s\n", acLine); else return; } oTokens = DynArray_new(0); iSuccessful = lexLine(acLine, oTokens, pcProgName); if(DynArray_getLength(oTokens) > 0) { /* Allocate memory to store command in oHistoryList iff command does not consist of entirely whitespace characters. */ pcTemp = (char*)malloc(strlen(acLine) + 1); assert(pcTemp != NULL); strcpy(pcTemp, acLine); DynArray_add(oHistoryList, pcTemp); if(iSuccessful) { oCommand = Command_new(); iSuccessful = parseToken(oTokens, oCommand, pcProgName); if(iSuccessful) execute(oCommand, oHistoryList, pcProgName); Command_free(oCommand, NULL); } } DynArray_map(oTokens, Token_free, NULL); DynArray_free(oTokens); }
/** * test_DynArray_alloc * ----------------------------------------------------- * Tests the functionality of DynArray_new() and * DynArray_free() functions. */ static int test_DynArray_alloc() { printf("Testing DynArray_new(), DynArray_free(): "); int result = 1; DynArray_t* da = DynArray_new(10); result &= (da != NULL); result &= (da->length == 10); result &= (da->contents != NULL); DynArray_free(da); printf("%d\n", result); return result; }
static DynArray_T lexLine(const char *pcLine) { /* lexLine() uses a DFA approach. It "reads" its characters from pcLine. The DFA has these three states: */ enum LexState {STATE_START, STATE_IN_NUMBER, STATE_IN_WORD}; /* The current state of the DFA. */ enum LexState eState = STATE_START; /* An index into pcLine. */ int iLineIndex = 0; /* Pointer to a buffer in which the characters comprising each token are accumulated. */ char *pcBuffer; /* An index into the buffer. */ int iBufferIndex = 0; char c; struct Token *psToken; DynArray_T oTokens; int iSuccessful; assert(pcLine != NULL); /* Create an empty token DynArray object. */ oTokens = DynArray_new(0); if (oTokens == NULL) {perror(pcPgmName); exit(EXIT_FAILURE);} /* Allocate memory for a buffer that is large enough to store the largest token that might appear within pcLine. */ pcBuffer = (char*)malloc(strlen(pcLine) + 1); if (pcBuffer == NULL) {perror(pcPgmName); exit(EXIT_FAILURE);} for (;;) { /* "Read" the next character from pcLine. */ c = pcLine[iLineIndex++]; switch (eState) { /* Handle the START state. */ case STATE_START: if (c == '\0') { free(pcBuffer); return oTokens; } else if (isdigit(c)) { pcBuffer[iBufferIndex++] = c; eState = STATE_IN_NUMBER; } else if (isalpha(c)) { pcBuffer[iBufferIndex++] = c; eState = STATE_IN_WORD; } else if (isspace(c)) eState = STATE_START; else { fprintf(stderr, "Invalid line\n"); free(pcBuffer); freeTokens(oTokens); DynArray_free(oTokens); return NULL; } break; /* Handle the IN_NUMBER state. */ case STATE_IN_NUMBER: if (c == '\0') { /* Create a NUMBER token. */ pcBuffer[iBufferIndex] = '\0'; psToken = newToken(TOKEN_NUMBER, pcBuffer); iSuccessful = DynArray_add(oTokens, psToken); if (! iSuccessful) {perror(pcPgmName); exit(EXIT_FAILURE);} iBufferIndex = 0; free(pcBuffer); return oTokens; } else if (isdigit(c)) { pcBuffer[iBufferIndex++] = c; eState = STATE_IN_NUMBER; } else if (isspace(c)) { /* Create a NUMBER token. */ pcBuffer[iBufferIndex] = '\0'; psToken = newToken(TOKEN_NUMBER, pcBuffer); iSuccessful = DynArray_add(oTokens, psToken); if (! iSuccessful) {perror(pcPgmName); exit(EXIT_FAILURE);} iBufferIndex = 0; eState = STATE_START; } else { fprintf(stderr, "Invalid line\n"); free(pcBuffer); freeTokens(oTokens); DynArray_free(oTokens); return NULL; } break; /* Handle the IN_WORD state. */ case STATE_IN_WORD: if (c == '\0') { /* Create a WORD token. */ pcBuffer[iBufferIndex] = '\0'; psToken = newToken(TOKEN_WORD, pcBuffer); iSuccessful = DynArray_add(oTokens, psToken); if (! iSuccessful) {perror(pcPgmName); exit(EXIT_FAILURE);} iBufferIndex = 0; free(pcBuffer); return oTokens; } else if (isalpha(c)) { pcBuffer[iBufferIndex++] = c; eState = STATE_IN_WORD; } else if (isspace(c)) { /* Create a WORD token. */ pcBuffer[iBufferIndex] = '\0'; psToken = newToken(TOKEN_WORD, pcBuffer); iSuccessful = DynArray_add(oTokens, psToken); if (! iSuccessful) {perror(pcPgmName); exit(EXIT_FAILURE);} iBufferIndex = 0; eState = STATE_START; } else { fprintf(stderr, "Invalid line\n"); free(pcBuffer); freeTokens(oTokens); DynArray_free(oTokens); return NULL; } break; default: assert(0); } } }
Command_T Command_new(char *pcName, DynArray_T oArgs, char *pcStdIn, char *pcStdOut) { int i; int argsLength; /* length of oArgs array */ char* pcArg; size_t pcArgLength; /* track how much memory to give pcArg */ Command_T oCommand; /* a command must have a name */ assert(pcName != NULL); assert(oArgs != NULL); oCommand = (Command_T) malloc(sizeof(struct Command)); if (oCommand == NULL) { fprintf(stderr, "%s: Can't allocate memory for command\n", pcPgmName); exit(EXIT_FAILURE); } /* allocate memory for and set the command name */ oCommand->pcName = (char*)malloc(strlen(pcName) + 1); if (oCommand->pcName == NULL) { fprintf(stderr, "%s: Can't allocate memory for command\n", pcPgmName); exit(EXIT_FAILURE); } strcpy(oCommand->pcName, pcName); /* allocate memory for and set the command arguments*/ argsLength = DynArray_getLength(oArgs); oCommand->oArgs = DynArray_new(0); for (i = 0; i < argsLength; i++) { pcArgLength = strlen((char*) DynArray_get(oArgs, i)); pcArg = (char*) malloc(pcArgLength + 1); strcpy(pcArg, DynArray_get(oArgs, i)); if (pcArg == NULL) { fprintf(stderr, "%s: Can't allocate memory for command args\n", pcPgmName); exit(EXIT_FAILURE); } DynArray_add(oCommand->oArgs, pcArg); } /* allocate memory for and set the command stdin redirect */ if (pcStdIn == NULL) { oCommand->pcStdIn = NULL; } else { oCommand->pcStdIn = (char*)malloc(strlen(pcStdIn) + 1); if (oCommand->pcStdIn == NULL) { fprintf(stderr, "%s: Can't allocate memory for command\n", pcPgmName); exit(EXIT_FAILURE); } strcpy(oCommand->pcStdIn, pcStdIn); } /* allocate memory for and set the command stdout redirect*/ if (pcStdOut == NULL) { oCommand->pcStdOut = NULL; } else { oCommand->pcStdOut = (char*)malloc(strlen(pcStdOut) + 1); if (oCommand->pcStdOut == NULL) { fprintf(stderr, "%s: Can't allocate memory for command\n", pcPgmName); exit(EXIT_FAILURE); } strcpy(oCommand->pcStdOut, pcStdOut); } return oCommand; }
int main(int argc, char *argv[]) /* Read lines from the .ishrc file residing in the HOME directory until EOF is reached. Write each line that is read to stdout and execute each line. Read a line from stdin and execute it. Repeat until EOF. Return 0. */ { char acLine[MAX_LINE_SIZE]; char *pcTemp; DynArray_T oHistoryList; FILE *psFile; int i; void (*pfRet)(int); pfRet = signal(SIGINT, SIG_IGN); if(pfRet == SIG_ERR) {perror(argv[0]); exit(EXIT_FAILURE); } oHistoryList = DynArray_new(0); pcTemp = getIshrc(); psFile = fopen(pcTemp, "r"); free(pcTemp); while (psFile != NULL && fgets(acLine, MAX_LINE_SIZE, psFile) != NULL) { /* Remove '\n' if acLine ends with '\n'. This is done so the commands in the history list do not end with '\n', which is necessary to properly expand !commandprefix. */ if(acLine[strlen(acLine)-1] == '\n') acLine[strlen(acLine)-1] = '\0'; printf("%% %s\n", acLine); /* Explicitly flush the stdout buffer so we can test ish properly by redirecting the output to a file. */ fflush(stdout); performCommand(acLine, oHistoryList, argv[0]); } printf("%% "); fflush(stdout); while (fgets(acLine, MAX_LINE_SIZE, stdin) != NULL) { /* Remove '\n' if acLine ends with '\n'. This is done so the commands in the history list do not end with '\n', which is necessary to properly expand !commandprefix. */ if(acLine[strlen(acLine)-1] == '\n') acLine[strlen(acLine)-1] = '\0'; performCommand(acLine, oHistoryList, argv[0]); printf("%% "); fflush(stdout); } printf("\n"); fflush(stdout); for(i = 0; i < DynArray_getLength(oHistoryList); i++) free(DynArray_get(oHistoryList, i)); DynArray_free(oHistoryList); return 0; }