Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /* The spellcheck.c component will contain the main() function and any other
- supporting functions you decide to use.
- It will be responsible for handling the command-line arguments, finding words in the text,
- checking to see if they're in the dictionary, and responding to user commands.
- Other than main(), you're not required to define any specific functions in spellcheck.c,
- but you must decide on at least two additional functions you'd like to use to simplify your
- implementation. You can break the problem down however you'd like, but you must use at least
- two non-trivial functions in addition to main. You can use more if you want. */
- #include <stdio.h>
- #include <stdbool.h>
- #include <ctype.h>
- #include <stdlib.h>
- #include <string.h>
- #include "text.h"
- #define INPUT_SIZE 100
- #define LOCAL_LINES_MAX 3
- #define BAK_LENGTH 4
- #define MAX_ARGS 3
- char **dictionary;
- int dictionarySize;
- char **wordLines;
- int linesSize;
- /**
- * qsort comparing
- */
- int compareStrings( const void* a, const void* b )
- {
- const char *str1 = *(const char **)a;
- const char *str2 = *(const char **)b;
- int str1Len = strlen( str1 );
- int str2Len = strlen( str2 );
- if ( str1Len >= str2Len ) {
- return strncmp(str1, str2, str1Len);
- } else {
- return strncmp(str1, str2, str2Len);
- }
- }
- /**
- * Function to check if a word is in the dictionary. Can be
- * easily modded to take in a dictionary. Will loop through
- * the dictionary until it finds a word or until the given word
- * is smaller than current position - meaning it wasn't inDictionary.
- * @param word a char array to check if in dictionary.
- * @return 1 or 0 if inDictionary or not respectively.
- */
- int isInDictionary( char *word )
- {
- //word to be compared, must be made lowercase
- //but we don't want to modify the word itself.
- char lowercaseWord[ strlen( word ) + 1 ];
- for ( int i = 0; i < strlen( word ); i++ ) {
- lowercaseWord[i] = tolower( word[i] );
- }
- lowercaseWord[ strlen( word ) ] = '\0';
- for ( int i = 0; i < dictionarySize; i++ ) {
- if ( strcmp( lowercaseWord, dictionary[i] ) == 0 ) {
- return 1;
- } else if ( strcmp( lowercaseWord, dictionary[i] ) < 0 ) {
- break;
- }
- }
- return 0;
- }
- /**
- * When called, markMisspelled will change color of output
- * to red. Once called again, standard color.
- */
- void markMisspelled( char *word )
- {
- printf( "\x1B[31m%s\x1B[0m", word );
- }
- char *userCommand()
- {
- char *input;
- // hope this is big enough.
- input = (char *) malloc( INPUT_SIZE * sizeof( char ) );
- // Prompt user for input
- printf( "(r)eplace, (a)dd word, (n)ext or (q)uit: ");
- scanf( "%s", input );
- input[0] = tolower( input[0] );
- if ( input[0] == 'r' ) {
- // Go character by character and read in response
- char nextChar = 'a';
- int index = 1;
- scanf( "%c", &nextChar );
- while ( nextChar != '\n' ) {
- input[index++] = nextChar;
- scanf( "%c", &nextChar );
- }
- // Null terminate at index
- input[index] = '\0';
- }
- return input;
- }
- /**
- * Prints the lines above and below the line containing the word not in dictionary.
- * Finds the incorrect word and higlights it red.
- */
- void printNearbyLines( char *word, int index, int textSize )
- {
- printf("\n"); // always helpful. Probably needed.
- char **nearest = malloc( LOCAL_LINES_MAX * sizeof( char * ) );
- for ( int i = 0; i < LOCAL_LINES_MAX; i++ ) {
- nearest[i] = ( char * ) malloc( INPUT_SIZE * sizeof ( char ) );
- }
- if ( index == 0 ) { // Word on top edge
- strcpy( nearest[0], wordLines[index] );
- strcpy( nearest[1], wordLines[index + 1] );
- strcpy( nearest[2], wordLines[index + 2] );
- } else if ( index == textSize - 1 ) { // Word on bottom edge
- strcpy( nearest[0], wordLines[index - 2] );
- strcpy( nearest[1], wordLines[index - 1] );
- strcpy( nearest[2], wordLines[index] );
- } else { // General case: word not on edge.
- strcpy( nearest[0], wordLines[index - 1] );
- strcpy( nearest[1], wordLines[index] );
- strcpy( nearest[2], wordLines[index + 1] );
- }
- // Now we check for that word.
- for ( int i = 0; i < LOCAL_LINES_MAX; i++ ) {
- if ( strstr( nearest[i], word ) != NULL ) { // checking bigger string.
- char *token = strtok(nearest[i], " ");
- while ( token != NULL ) {
- if ( strstr( token, word ) != NULL ) { // Obama to public: We got 'im.
- markMisspelled( token );
- } else { // we got the wrong guy... er, word, so let's just print it.
- printf("%s ", token);
- }
- token = strtok( NULL, " " ); // seriously this threw me off so bad.
- }
- printf("\n");
- } else {
- printf( "%s\n", nearest[i] );
- }
- }
- }
- void switchString( char *line, const char *checker, const char *replacement )
- {
- char *nullCheck; // should probably rename...
- // nah.
- if ( ( nullCheck = strstr( line, checker ) ) == NULL ) { //disgusting, but works.
- return; //but seriously it should never happen.
- }
- //assuming it works.
- int checkLength = strlen( checker );
- int replacementLength = strlen( replacement );
- int endLength = strlen( nullCheck + checkLength );
- memmove( nullCheck + replacementLength, nullCheck + checkLength, endLength + 1 );
- memcpy( nullCheck, replacement, replacementLength );
- }
- /**
- * Program Start.
- */
- int main( int argc, char *argv[] )
- {
- // Check command-line arguments and open the input file.
- FILE *inFile = fopen( argv[ 1 ], "r" );
- FILE *dictionaryFile = fopen( "words.txt", "r" );;
- if ( inFile == NULL ) {
- printf( "usage: spellcheck <textfile.txt> [words.txt]\n" );
- exit( EXIT_FAILURE );
- }
- if ( argc == MAX_ARGS ) {
- fclose( dictionaryFile );
- dictionaryFile = fopen( argv[ 2 ], "r" );
- }
- fclose( inFile );
- fclose( dictionaryFile );
- if ( argc > MAX_ARGS || argc < 2 ) {
- printf( "usage: spellcheck <textfile.txt> [words.txt]\n" );
- exit( EXIT_FAILURE );
- }
- //Words from text files.
- linesSize = 0;
- int *linePointer = &linesSize;
- wordLines = readLines( argv[ 1 ], linePointer );
- //Dictionary.
- dictionarySize = 0;
- int *countPointer = &dictionarySize;
- if ( argc == 2 ) {
- dictionary = readLines( "words.txt", countPointer );
- } else {
- dictionary = readLines( argv[ 2 ], countPointer );
- }
- // Check dictionary for errors.
- for ( int i = 0; i < dictionarySize; i++ ) {
- int stringLength = strlen( dictionary[i] );
- if ( dictionary[i][0] == 0 ) {
- printf( "Invalid word, line: %d\n", i + 1 );
- return EXIT_FAILURE;
- }
- for ( int j = 0; j < stringLength; j++ ) {
- if ( !isalpha( dictionary[i][j] ) ) {
- printf( "Invalid word, line: %d\n", i + 1 );
- return EXIT_FAILURE;
- }
- if ( dictionary[i][j] != tolower( dictionary[i][j] ) ) {
- printf( "Invalid word, line: %d\n", i + 1 );
- return EXIT_FAILURE;
- }
- }
- }
- //sort.
- qsort( dictionary, dictionarySize, sizeof( dictionary[0] ), compareStrings );
- //Getting set up to do EVERYTHING.
- int capacity = INPUT_SIZE;
- char **wordsInLine = malloc( capacity * sizeof( char * ) );
- /** backupArray wordLines */
- char **backupArray = (char **) malloc( linesSize * sizeof ( char * ) );
- for ( int i = 0; i < linesSize; i++ ) {
- backupArray[i] = malloc( INPUT_SIZE * sizeof( char ) );
- strcpy( backupArray[i], wordLines[i] );
- }
- char *token = NULL;
- int index = 0;
- int lineLength = 0;
- //tried doing a while loop and look what happens to me.
- for ( int i = 0; i < linesSize; i++ ) {
- token = strtok( backupArray[i], " " );
- while ( token != NULL ) {
- // Trying to get rid of punctuation
- int tokenLen = strlen( token );
- if ( !isalpha( token[tokenLen - 1] ) ) {
- token[tokenLen - 1] = '\0';
- }
- wordsInLine[index] = token;
- index++;
- lineLength++;
- token = strtok(NULL, " "); // this annoys me to no end.
- }
- // Now we get to find out if these words even exist!
- for (int j = 0; j < lineLength; j++ ) {
- int inDictionary = isInDictionary( wordsInLine[j] );
- if ( !inDictionary ) {
- printNearbyLines( wordsInLine[j], i, linesSize );
- // Getting rid of NULLs first.
- // Get the user's command.
- char *decision = malloc( INPUT_SIZE * sizeof ( char ) );
- decision = userCommand();
- // If it's not q, n, a, or r, make them enter it again.
- while ( decision[0] != 'q' && decision[0] != 'n'
- && decision[0] != 'a' && decision[0] != 'r' ) {
- printf( "Unknown command\n" );
- printNearbyLines( wordsInLine[j], i, linesSize );
- decision = (char *) malloc( INPUT_SIZE * sizeof ( char ) );
- decision = userCommand();
- }
- // User command execution area.
- //If they want to quit, free everything and quit.
- if ( decision[0] == 'q' ) {
- fprintf( stderr, "Discarding changes\n" );
- // Free memory
- freeLines( wordLines, linesSize );
- freeLines( dictionary, dictionarySize );
- // freeLines( backupArray, linesSize );
- // freeLines ( wordsInLine, INPUT_SIZE );
- // Exit the program
- exit(EXIT_FAILURE);
- } else if ( decision[0] == 'n' ) { // move on, skip the word.
- break;
- } else if ( decision[0] == 'r' ) { // replace the word.
- // Length of word (minus the first two because user commands)
- int newWordLength = strlen( decision ) - 2;
- char *replacementWord = malloc( newWordLength * sizeof( char ) );
- memcpy( replacementWord, &decision[2], newWordLength );
- // figuring this out took me like, an hour.
- replacementWord[newWordLength] = '\0';
- switchString( wordLines[i], wordsInLine[j], replacementWord );
- // Do some replacement work.
- char *token = strtok( replacementWord, " " );
- int count = 1; // token count
- int position = j; // position
- while ( token != NULL ) {
- // Getting rid of punctuation
- int tokenLen = strlen( token );
- if ( !isalpha( token[tokenLen - 1] ) ) {
- token[tokenLen - 1] = '\0';
- }
- if ( count == 1 ) {
- wordsInLine[position] = token;
- count++;
- } else { // aw hell there's more of 'em
- // Update wordsInLine to be each token
- lineLength++;
- // Capacity check
- if ( lineLength == capacity ) {
- capacity *= 2;
- wordsInLine = (char **) realloc( wordsInLine,
- capacity * sizeof( char * ) );
- wordsInLine[lineLength] = (char *)
- malloc( capacity * sizeof ( char ) );
- }
- position++;
- // Move position to keep working
- // Infinite loop count: 3 or 4.
- // Move everything up.
- for ( int k = lineLength - 1; k > position; k-- ) {
- wordsInLine[k] = wordsInLine[k-1];
- }
- // Token assigning.
- // Some correctional folks would call it 'in processing'
- wordsInLine[position] = token;
- }
- token = strtok( NULL, " " );
- }
- // Just making sure.
- j--;
- } else if ( decision[0] == 'a' ) { // add the word.
- // Updating size for adding.
- dictionarySize++;
- // Add new word by realloc memory.
- dictionary = ( char ** ) realloc( dictionary,
- dictionarySize * sizeof ( char * ) );
- dictionary[dictionarySize - 1] = ( char * )
- malloc( INPUT_SIZE * sizeof ( char ) );
- strcpy( dictionary[dictionarySize - 1], wordsInLine[j] );
- qsort( dictionary, dictionarySize, sizeof( dictionary[0] ), compareStrings );
- }
- }
- }
- //reset stuff.
- wordsInLine = (char **) malloc( INPUT_SIZE * sizeof( char * ) );
- index = 0;
- lineLength = 0;
- }
- //Final output stuff.
- printf( "Spellcheck complete.\n" );
- printf( "Backing up %s to %s.bak\n", argv[1], argv[1] );
- char *backupArrayFile = malloc( strlen( argv[1] ) + BAK_LENGTH );
- strcat( backupArrayFile, argv[1] );
- strcat( backupArrayFile, ".bak" );
- rename( argv[1], backupArrayFile );
- printf( "Writing updated %s\n", argv[1] );
- //Print to file.
- inFile = fopen( argv[ 1 ], "w" );
- // printf( "%d\n", wordLines[6][0] );
- for ( int i = 0; i < linesSize; i++ ) {
- if ( wordLines[i] == 0 ) {
- fprintf( inFile, "\n" );
- } else {
- fprintf( inFile, "%s\n", wordLines[i] );
- }
- }
- fclose( inFile );
- //free it all up.
- freeLines( dictionary, dictionarySize );
- freeLines( wordLines, linesSize );
- //oh ye and exit too
- return EXIT_SUCCESS;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement