CodeWiki : IntroToComputing.CW2

WikiHome :: List Pages :: Login
cmantito.com

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define DELIMITER        "."
#define NEWLINE_DELIM    ".\n"

#define STATE_COMMAND     1  
#define STATE_INPUT       2
#define STATE_EXIT        3

#define BUFFER_SIZE     1024
#define CMD_DELIMITER   ";"

#define CMD_PRINT       'p'
#define CMD_QUIT        'q'
#define CMD_APPENDS     'a'
#define CMD_REPLACE     'r'
#define CMD_DELETE      'd'
#define CMD_INSERT      'i'

int main (void) {
    // Setup whatever we need.
    char* buffer = NULL;
    int buffer_size = 0;
    int buffer_length = 0;
    int chars_read = 0;
    int appState = STATE_COMMAND;
    int lineNumber = 0;
    int char_pos = 0;
   
    char valid_cmds[BUFFER_SIZE + 1] = {'\0'};
    char* all_cmds = NULL;
    char* cmd_line = NULL;
   
    int location = 0;
    int locationB = 0;
    char commandLetter;
    char notModifier;
    char rangeModifier;
    char* string = "";
   
    int skipPrint = 0;
   
    // We're going to loop through here until we're all done. (ie, STATE_EXIT)
    do {
        // Read input into the buffer.
        chars_read = getline(&buffer, &buffer_size, stdin);
       
        // Make sure it exists.
        if(chars_read < 1){
            break;
        }
       
        // Delimiters make the state increase.
        if(strcmp(buffer, DELIMITER) == 0 || strcmp(buffer, NEWLINE_DELIM) == 0){
            appState = appState + 1;
            continue;
        }
       
        // Command state.
        if(appState == STATE_COMMAND){
           
            // Get some commands from the buffer.
            // Go through each character of the command, and see if it matches a
            // real command, if it does, put it in the valid commands buffer.
            buffer_length = strlen(buffer);
            for(char_pos = 0; char_pos < buffer_length; char_pos++){
                    if(islower(buffer[char_pos])){
                        if(buffer[char_pos] == CMD_PRINT ||
                            buffer[char_pos] == CMD_QUIT ||
                            buffer[char_pos] == CMD_APPENDS ||
                            buffer[char_pos] == CMD_REPLACE ||
                            buffer[char_pos] == CMD_DELETE ||
                            buffer[char_pos] == CMD_INSERT ){
                                strcat(valid_cmds, buffer);
                                strcat(valid_cmds, CMD_DELIMITER);
                                break;
                        }
                   
                    appState  = STATE_EXIT;
                    break;
                }
            }
        }
       
        // Text input state.
        if(appState == STATE_INPUT){
            skipPrint = 0; // This must must MUST get set to 0 on each loop, or everything will break.
            lineNumber = lineNumber + 1; // Increment the line number each time we go through.
            all_cmds = strdup(valid_cmds); // And now all_cmds is the same as valid_cmds.
           
            // Get a command from the commands buffer.
            for(cmd_line = strtok(all_cmds, CMD_DELIMITER); cmd_line != NULL; cmd_line = strtok(NULL, CMD_DELIMITER)){

                // Match this one first, because it's the most specific - put the various bits of the command
                // into the various variables. Also, make sure the range modifier is one of the valid ones,
                // and that the not modifier is what we expect.
                if(sscanf(cmd_line, "%d%c%d%c%c%s", &location, &rangeModifier, &locationB, &notModifier, &commandLetter, string) == 6
                    && (rangeModifier == ',' || rangeModifier == '~')
                    && notModifier == '!'){

                    // Now check the command issued. Appends? Yeah, check the range --
                    // For comma, make sure the line number isn't in the range specified. (Remember the '!'.)
                    // For tilde, check that A) the line number isn't the one specified, B) the line number minux
                    // the starting point divded by the second number has a remainder, C) the line number is less than
                    // the starting point. If A and B or A and C are true, we'll match.
                    if(commandLetter == CMD_APPENDS && (
                        (rangeModifier == ',' && (location > lineNumber || lineNumber > locationB))
                        || (rangeModifier == '~' && location != lineNumber && ((lineNumber - location) % locationB > 0  || lineNumber < location))
                    )){
                        // Append, stick the string to the end of the existing buffer and attach a newline.
                        // Append will use this same method for the rest off the programme.
                        strcat(buffer, string);
                        strcat(buffer, "\n");
                    }
                   
                    // Same method for matching replace.
                    if(commandLetter == CMD_REPLACE && (
                        (rangeModifier == ',' && (location > lineNumber || lineNumber > locationB))
                        || (rangeModifier == '~' && location != lineNumber && ((lineNumber - location) % locationB > 0  || lineNumber < location))
                    )){
                        // Just replace the buffer with the new string and add a newline to the end.
                        // Replacement will be done the same way as this for the rest of the app.
                        strcpy(buffer, string);
                        strcat(buffer, "\n");
                    }
                   
                    // And insert.
                    if(commandLetter == CMD_INSERT && (
                        (rangeModifier == ',' && (location > lineNumber || lineNumber > locationB))
                        || (rangeModifier == '~' && location != lineNumber && ((lineNumber - location) % locationB > 0  || lineNumber < location))
                    )){
                        // Add a newline to the end of the new string, stick the buffer on after that, and then
                        // move it all in to the buffer. We'll reuse this method for insert throughout the app.
                        strcat(string, "\n");
                        strcat(string, buffer);
                        strcpy(buffer, string);
                    }
               
                // We're moving down in order of most specific matching regime to least specific. So this one's next.
                }else if(sscanf(cmd_line, "%d%c%d%c%c", &location, &rangeModifier, &locationB, &notModifier, &commandLetter) == 5
                    && (rangeModifier == ',' || rangeModifier == '~')
                    && notModifier == '!'){
               
                    // We're using the same matching system as before to match the ranges for print, remembering that
                    // there's still an !.
                    if(commandLetter == CMD_PRINT && (
                        (rangeModifier == ',' && (location > lineNumber || lineNumber > locationB))
                        || (rangeModifier == '~' && location != lineNumber && ((lineNumber - location) % locationB > 0  || lineNumber < location))
                    )){
                        printf("%s", buffer);
                    }
                   
                    // And delete.
                    if(commandLetter == CMD_DELETE && (
                        (rangeModifier == ',' && (location > lineNumber || lineNumber > locationB))
                        || (rangeModifier == '~' && location != lineNumber && ((lineNumber - location) % locationB > 0  || lineNumber < location))
                    )){
                        skipPrint = 1;
                    }
               
                // This is the next one in order, this time no !
                }else if(sscanf(cmd_line, "%d%c%d%c%s", &location, &rangeModifier, &locationB, &commandLetter, string) == 5
                    && (rangeModifier == ',' || rangeModifier == '~')){  
                   
                    // For appends, we're checking if the range is a comma or a tilde. If it's comma, is the line number
                    // in between the addresses specified? If it's a tilde, check A) is line number equal to the location
                    // specified, B) does the line number minus the location, divided by the second number,
                    // have NO remainder? and C) is the line number greater than the location specified?
                    // If A is true, or B and C are true, we match.
                    if(commandLetter == CMD_APPENDS && (
                        (rangeModifier == ',' && location <= lineNumber && lineNumber <= locationB)
                        || (rangeModifier == '~' && (location == lineNumber || (((lineNumber - location) % locationB) == 0 && lineNumber > location)))
                    )){
                        strcat(buffer, string);
                        strcat(buffer, "\n");
                    }
                   
                    if(commandLetter == CMD_REPLACE && (
                        (rangeModifier == ',' && location == lineNumber)
                        || (rangeModifier == '~' && (location == lineNumber || (((lineNumber - location) % locationB) == 0 && lineNumber > location)))
                    )){
                        strcpy(buffer, string);
                        strcat(buffer, "\n");
                    }
                   
                    // Using this to for the ranged replace for a comma-range only, once we've replaced the first line,
                    // We make sure that none of the lines after it print until we're out of the range.
                    // Ref: http://cnfolio.com/IntroComputingTutorial05#example05
                    if(commandLetter == CMD_REPLACE && (
                        (rangeModifier == ',' && lineNumber > location && lineNumber <= locationB)
                    )){
                        skipPrint = 1;
                    }
                   
                    if(commandLetter == CMD_INSERT && (
                        (rangeModifier == ',' && location <= lineNumber && lineNumber <= locationB)
                        || (rangeModifier == '~' && (location == lineNumber || (((lineNumber - location) % locationB) == 0 && lineNumber > location)))
                    )){
                        strcat(string, "\n");
                        strcat(string, buffer);
                        strcpy(buffer, string);
                    }
               
                // And then this one goes next.
                }else if(sscanf(cmd_line, "%d%c%d%c", &location, &rangeModifier, &locationB, &commandLetter) == 4
                    && (rangeModifier == ',' || rangeModifier == '~')){

                    // Same method as before for dealing with the different ranges.
                    if(commandLetter == CMD_PRINT && (
                        (rangeModifier == ',' && location <= lineNumber && lineNumber <= locationB)
                        || (rangeModifier == '~' && (location == lineNumber || (((lineNumber - location) % locationB) == 0 && lineNumber > location)))
                    )){
                        printf("%s", buffer);
                    }
                   
                    if(commandLetter == CMD_DELETE && (
                        (rangeModifier == ',' && location <= lineNumber && lineNumber <= locationB)
                        || (rangeModifier == '~' && (location == lineNumber || (((lineNumber - location) % locationB) == 0 && lineNumber > location)))
                    )){
                        skipPrint = 1;
                    }
               
                // This one's next but it doesn't have a range, just the not modifier.
                }else if(sscanf(cmd_line, "%d%c%c%s", &location, &notModifier, &commandLetter, string) == 4
                    && notModifier == '!'){
               
                    // So basically, because of the !, we only make sure that the line number DOESN'T match.
                    // We don't have to use the range detection here.
                    if(commandLetter == CMD_APPENDS && location != lineNumber){
                        strcat(buffer, string);
                        strcat(buffer, "\n");
                    }
                   
                    // And here.
                    if(commandLetter == CMD_REPLACE && location != lineNumber){
                        strcpy(buffer, string);
                        strcat(buffer, "\n");
                    }
                   
                    // And here.
                    if(commandLetter == CMD_INSERT && location == lineNumber){
                        strcat(string, "\n");
                        strcat(string, buffer);
                        strcpy(buffer, string);
                    }

                // We do have a not modifier here, so we need to not match everything.
                }else if(sscanf(cmd_line, "%d%c%c", &location, &notModifier, &commandLetter) == 3
                    && notModifier == '!'){
                       
                    // Same here.
                    if(commandLetter == CMD_PRINT && location != lineNumber){
                        printf("%s", buffer);
                    }
                   
                    // And here.
                    if(commandLetter == CMD_DELETE && location != lineNumber){
                        skipPrint = 1;
                    }
               
                // This time we don't have the not modifier.
                }else if(sscanf(cmd_line, "%d%c%s", &location, &commandLetter, string) == 3){
                   
                    // So we check that the line numbers DO match. Again, no worry about ranges.
                    if(commandLetter == CMD_APPENDS && location == lineNumber){
                        strcat(buffer, string);
                        strcat(buffer, "\n");
                    }
                   
                    // Same here.
                    if(commandLetter == CMD_REPLACE && location == lineNumber){
                        strcpy(buffer, string);
                        strcat(buffer, "\n");
                    }
                   
                    // And here.
                    if(commandLetter == CMD_INSERT && location == lineNumber){
                        strcat(string, "\n");
                        strcat(string, buffer);
                        strcpy(buffer, string);
                    }
                   
                // We don't really have to make sure location > 0, but it's better to
                // validate as much of the input as you can, to weed out falsely-matching
                // input.
                }else if(sscanf(cmd_line, "%d%c", &location, &commandLetter) == 2
                    && location > 0){
                   
                    // Again, it's a simple case of does the line number match?
                    if(commandLetter == CMD_PRINT && location == lineNumber){
                        printf("%s", buffer);
                    }
                   
                    // Here too.
                    if(commandLetter == CMD_QUIT && location == lineNumber){
                        appState = STATE_EXIT;
                    }
                   
                    // This one as well.
                    if(commandLetter == CMD_DELETE && location == lineNumber){
                        skipPrint = 1;
                    }

                // We have a not modifier here.
                }else if(sscanf(cmd_line, "%c%c", &notModifier, &commandLetter) == 2
                    && notModifier == '!'){
               
                    // But no line numbers, so it matches every line.
                    if(commandLetter == CMD_PRINT){
                        // well, if we DON'T (from the !) print every line an additional time,
                        // then it just does what it normally does so this doesn't
                        // actually need to do anything?
                    }
                   
                    /// Same here.
                    if(commandLetter == CMD_DELETE){
                        // likewise, if we don't delete every line, then it acts
                        // normally and again, this doesn't do anything.
                        // I don't actually understand the point in !p and !d.
                    }
               
                // We're back to a simple command that effects every line, but not ! modifier.
                }else if(sscanf(cmd_line, "%c%s", &commandLetter, string) == 2){
               
                    // So we don't need to worry about line matching.
                    if(commandLetter == CMD_APPENDS){
                        strcat(buffer, string);
                        strcat(buffer, "\n");
                    }
                   
                    // Or here.
                    if(commandLetter == CMD_REPLACE){
                        strcpy(buffer, string);
                        strcat(buffer, "\n");
                    }
                   
                    // Or here.
                    if(commandLetter == CMD_INSERT){
                        strcat(string, "\n");
                        strcat(string, buffer);
                        strcpy(buffer, string);
                    }  
               
                // Very simple one letter commands.
                }else if(sscanf(cmd_line, "%c", &commandLetter) == 1){
                   
                    // Which match every line.
                    if(commandLetter == CMD_PRINT){
                        printf("%s", buffer);
                    }
                   
                    // And here.
                    if(commandLetter == CMD_QUIT){
                        appState = STATE_EXIT;
                    }
                   
                    // Same here.
                    if(commandLetter == CMD_DELETE){
                        skipPrint = 1;
                    }
                   
                }
               
                // If nothing's told it not to print since the beginning of the loop,
                // print the buffer. By this point, the buffer may have been modified
                // by a replace, append, or insert. Doesn't matter, print it anyway as
                // long as nothing set skipPrint to 1.          
                if(skipPrint == 0){
                    printf("%s", buffer);
                }
            }
           
        }
    } while(appState != STATE_EXIT);
   
    return 0;
}


Categories: CategoryUni
Valid XHTML 1.0 Transitional :: Valid CSS :: Powered by WikkaWiki