Advertisement
Shanix

Untitled

Mar 16th, 2016
73
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 14.81 KB | None | 0 0
  1. /* The spellcheck.c component will contain the main() function and any other
  2. supporting functions you decide to use.
  3.  
  4. It will be responsible for handling the command-line arguments, finding words in the text,
  5. checking to see if they're in the dictionary, and responding to user commands.
  6.  
  7. Other than main(), you're not required to define any specific functions in spellcheck.c,
  8. but you must decide on at least two additional functions you'd like to use to simplify your
  9. implementation. You can break the problem down however you'd like, but you must use at least
  10. two non-trivial functions in addition to main. You can use more if you want. */
  11.  
  12. #include <stdio.h>
  13. #include <stdbool.h>
  14. #include <ctype.h>
  15. #include <stdlib.h>
  16. #include <string.h>
  17. #include "text.h"
  18.  
  19. #define INPUT_SIZE 100
  20. #define LOCAL_LINES_MAX 3
  21. #define BAK_LENGTH 4
  22. #define MAX_ARGS 3
  23.  
  24. char **dictionary;
  25. int dictionarySize;
  26.  
  27. char **wordLines;
  28. int linesSize;
  29.  
  30. /**
  31. * qsort comparing
  32. */
  33. int compareStrings( const void* a, const void* b )
  34. {
  35. const char *str1 = *(const char **)a;
  36. const char *str2 = *(const char **)b;
  37. int str1Len = strlen( str1 );
  38. int str2Len = strlen( str2 );
  39.  
  40. if ( str1Len >= str2Len ) {
  41. return strncmp(str1, str2, str1Len);
  42. } else {
  43. return strncmp(str1, str2, str2Len);
  44. }
  45.  
  46. }
  47.  
  48. /**
  49. * Function to check if a word is in the dictionary. Can be
  50. * easily modded to take in a dictionary. Will loop through
  51. * the dictionary until it finds a word or until the given word
  52. * is smaller than current position - meaning it wasn't inDictionary.
  53. * @param word a char array to check if in dictionary.
  54. * @return 1 or 0 if inDictionary or not respectively.
  55. */
  56. int isInDictionary( char *word )
  57. {
  58. //word to be compared, must be made lowercase
  59. //but we don't want to modify the word itself.
  60. char lowercaseWord[ strlen( word ) + 1 ];
  61. for ( int i = 0; i < strlen( word ); i++ ) {
  62. lowercaseWord[i] = tolower( word[i] );
  63. }
  64.  
  65. lowercaseWord[ strlen( word ) ] = '\0';
  66. for ( int i = 0; i < dictionarySize; i++ ) {
  67. if ( strcmp( lowercaseWord, dictionary[i] ) == 0 ) {
  68. return 1;
  69. } else if ( strcmp( lowercaseWord, dictionary[i] ) < 0 ) {
  70. break;
  71. }
  72. }
  73.  
  74. return 0;
  75. }
  76.  
  77. /**
  78. * When called, markMisspelled will change color of output
  79. * to red. Once called again, standard color.
  80. */
  81. void markMisspelled( char *word )
  82. {
  83. printf( "\x1B[31m%s\x1B[0m", word );
  84. }
  85.  
  86. char *userCommand()
  87. {
  88. char *input;
  89. // hope this is big enough.
  90. input = (char *) malloc( INPUT_SIZE * sizeof( char ) );
  91.  
  92. // Prompt user for input
  93. printf( "(r)eplace, (a)dd word, (n)ext or (q)uit: ");
  94. scanf( "%s", input );
  95. input[0] = tolower( input[0] );
  96.  
  97. if ( input[0] == 'r' ) {
  98. // Go character by character and read in response
  99. char nextChar = 'a';
  100. int index = 1;
  101. scanf( "%c", &nextChar );
  102. while ( nextChar != '\n' ) {
  103. input[index++] = nextChar;
  104. scanf( "%c", &nextChar );
  105. }
  106. // Null terminate at index
  107. input[index] = '\0';
  108. }
  109.  
  110. return input;
  111. }
  112.  
  113. /**
  114. * Prints the lines above and below the line containing the word not in dictionary.
  115. * Finds the incorrect word and higlights it red.
  116. */
  117. void printNearbyLines( char *word, int index, int textSize )
  118. {
  119. printf("\n"); // always helpful. Probably needed.
  120.  
  121. char **nearest = malloc( LOCAL_LINES_MAX * sizeof( char * ) );
  122. for ( int i = 0; i < LOCAL_LINES_MAX; i++ ) {
  123. nearest[i] = ( char * ) malloc( INPUT_SIZE * sizeof ( char ) );
  124. }
  125. if ( index == 0 ) { // Word on top edge
  126. strcpy( nearest[0], wordLines[index] );
  127. strcpy( nearest[1], wordLines[index + 1] );
  128. strcpy( nearest[2], wordLines[index + 2] );
  129. } else if ( index == textSize - 1 ) { // Word on bottom edge
  130. strcpy( nearest[0], wordLines[index - 2] );
  131. strcpy( nearest[1], wordLines[index - 1] );
  132. strcpy( nearest[2], wordLines[index] );
  133. } else { // General case: word not on edge.
  134. strcpy( nearest[0], wordLines[index - 1] );
  135. strcpy( nearest[1], wordLines[index] );
  136. strcpy( nearest[2], wordLines[index + 1] );
  137. }
  138.  
  139. // Now we check for that word.
  140. for ( int i = 0; i < LOCAL_LINES_MAX; i++ ) {
  141. if ( strstr( nearest[i], word ) != NULL ) { // checking bigger string.
  142. char *token = strtok(nearest[i], " ");
  143. while ( token != NULL ) {
  144. if ( strstr( token, word ) != NULL ) { // Obama to public: We got 'im.
  145. markMisspelled( token );
  146. } else { // we got the wrong guy... er, word, so let's just print it.
  147. printf("%s ", token);
  148. }
  149. token = strtok( NULL, " " ); // seriously this threw me off so bad.
  150. }
  151. printf("\n");
  152. } else {
  153. printf( "%s\n", nearest[i] );
  154. }
  155. }
  156. }
  157.  
  158. void switchString( char *line, const char *checker, const char *replacement )
  159. {
  160. char *nullCheck; // should probably rename...
  161. // nah.
  162.  
  163. if ( ( nullCheck = strstr( line, checker ) ) == NULL ) { //disgusting, but works.
  164. return; //but seriously it should never happen.
  165. }
  166. //assuming it works.
  167.  
  168. int checkLength = strlen( checker );
  169. int replacementLength = strlen( replacement );
  170. int endLength = strlen( nullCheck + checkLength );
  171.  
  172. memmove( nullCheck + replacementLength, nullCheck + checkLength, endLength + 1 );
  173. memcpy( nullCheck, replacement, replacementLength );
  174.  
  175. }
  176.  
  177. /**
  178. * Program Start.
  179. */
  180. int main( int argc, char *argv[] )
  181. {
  182. // Check command-line arguments and open the input file.
  183. FILE *inFile = fopen( argv[ 1 ], "r" );
  184. FILE *dictionaryFile = fopen( "words.txt", "r" );;
  185.  
  186. if ( inFile == NULL ) {
  187. printf( "usage: spellcheck <textfile.txt> [words.txt]\n" );
  188. exit( EXIT_FAILURE );
  189. }
  190.  
  191. if ( argc == MAX_ARGS ) {
  192. fclose( dictionaryFile );
  193. dictionaryFile = fopen( argv[ 2 ], "r" );
  194. }
  195.  
  196. fclose( inFile );
  197. fclose( dictionaryFile );
  198.  
  199. if ( argc > MAX_ARGS || argc < 2 ) {
  200. printf( "usage: spellcheck <textfile.txt> [words.txt]\n" );
  201. exit( EXIT_FAILURE );
  202. }
  203.  
  204. //Words from text files.
  205. linesSize = 0;
  206. int *linePointer = &linesSize;
  207. wordLines = readLines( argv[ 1 ], linePointer );
  208.  
  209. //Dictionary.
  210. dictionarySize = 0;
  211. int *countPointer = &dictionarySize;
  212. if ( argc == 2 ) {
  213. dictionary = readLines( "words.txt", countPointer );
  214. } else {
  215. dictionary = readLines( argv[ 2 ], countPointer );
  216. }
  217.  
  218. // Check dictionary for errors.
  219. for ( int i = 0; i < dictionarySize; i++ ) {
  220. int stringLength = strlen( dictionary[i] );
  221. if ( dictionary[i][0] == 0 ) {
  222. printf( "Invalid word, line: %d\n", i + 1 );
  223. return EXIT_FAILURE;
  224. }
  225. for ( int j = 0; j < stringLength; j++ ) {
  226. if ( !isalpha( dictionary[i][j] ) ) {
  227. printf( "Invalid word, line: %d\n", i + 1 );
  228. return EXIT_FAILURE;
  229. }
  230. if ( dictionary[i][j] != tolower( dictionary[i][j] ) ) {
  231. printf( "Invalid word, line: %d\n", i + 1 );
  232. return EXIT_FAILURE;
  233. }
  234. }
  235. }
  236.  
  237. //sort.
  238. qsort( dictionary, dictionarySize, sizeof( dictionary[0] ), compareStrings );
  239.  
  240.  
  241. //Getting set up to do EVERYTHING.
  242. int capacity = INPUT_SIZE;
  243. char **wordsInLine = malloc( capacity * sizeof( char * ) );
  244.  
  245. /** backupArray wordLines */
  246. char **backupArray = (char **) malloc( linesSize * sizeof ( char * ) );
  247. for ( int i = 0; i < linesSize; i++ ) {
  248. backupArray[i] = malloc( INPUT_SIZE * sizeof( char ) );
  249. strcpy( backupArray[i], wordLines[i] );
  250. }
  251.  
  252. char *token = NULL;
  253. int index = 0;
  254. int lineLength = 0;
  255.  
  256. //tried doing a while loop and look what happens to me.
  257. for ( int i = 0; i < linesSize; i++ ) {
  258. token = strtok( backupArray[i], " " );
  259. while ( token != NULL ) {
  260.  
  261. // Trying to get rid of punctuation
  262. int tokenLen = strlen( token );
  263. if ( !isalpha( token[tokenLen - 1] ) ) {
  264. token[tokenLen - 1] = '\0';
  265. }
  266. wordsInLine[index] = token;
  267. index++;
  268. lineLength++;
  269. token = strtok(NULL, " "); // this annoys me to no end.
  270. }
  271.  
  272. // Now we get to find out if these words even exist!
  273. for (int j = 0; j < lineLength; j++ ) {
  274. int inDictionary = isInDictionary( wordsInLine[j] );
  275. if ( !inDictionary ) {
  276. printNearbyLines( wordsInLine[j], i, linesSize );
  277. // Getting rid of NULLs first.
  278.  
  279. // Get the user's command.
  280. char *decision = malloc( INPUT_SIZE * sizeof ( char ) );
  281. decision = userCommand();
  282.  
  283. // If it's not q, n, a, or r, make them enter it again.
  284. while ( decision[0] != 'q' && decision[0] != 'n'
  285. && decision[0] != 'a' && decision[0] != 'r' ) {
  286. printf( "Unknown command\n" );
  287. printNearbyLines( wordsInLine[j], i, linesSize );
  288. decision = (char *) malloc( INPUT_SIZE * sizeof ( char ) );
  289. decision = userCommand();
  290. }
  291.  
  292. // User command execution area.
  293.  
  294. //If they want to quit, free everything and quit.
  295. if ( decision[0] == 'q' ) {
  296. fprintf( stderr, "Discarding changes\n" );
  297. // Free memory
  298. freeLines( wordLines, linesSize );
  299. freeLines( dictionary, dictionarySize );
  300. // freeLines( backupArray, linesSize );
  301. // freeLines ( wordsInLine, INPUT_SIZE );
  302.  
  303. // Exit the program
  304. exit(EXIT_FAILURE);
  305. } else if ( decision[0] == 'n' ) { // move on, skip the word.
  306. break;
  307. } else if ( decision[0] == 'r' ) { // replace the word.
  308. // Length of word (minus the first two because user commands)
  309. int newWordLength = strlen( decision ) - 2;
  310. char *replacementWord = malloc( newWordLength * sizeof( char ) );
  311.  
  312. memcpy( replacementWord, &decision[2], newWordLength );
  313. // figuring this out took me like, an hour.
  314.  
  315. replacementWord[newWordLength] = '\0';
  316.  
  317. switchString( wordLines[i], wordsInLine[j], replacementWord );
  318.  
  319. // Do some replacement work.
  320. char *token = strtok( replacementWord, " " );
  321. int count = 1; // token count
  322. int position = j; // position
  323.  
  324. while ( token != NULL ) {
  325.  
  326. // Getting rid of punctuation
  327. int tokenLen = strlen( token );
  328. if ( !isalpha( token[tokenLen - 1] ) ) {
  329. token[tokenLen - 1] = '\0';
  330. }
  331. if ( count == 1 ) {
  332. wordsInLine[position] = token;
  333. count++;
  334. } else { // aw hell there's more of 'em
  335.  
  336. // Update wordsInLine to be each token
  337. lineLength++;
  338. // Capacity check
  339. if ( lineLength == capacity ) {
  340. capacity *= 2;
  341. wordsInLine = (char **) realloc( wordsInLine,
  342. capacity * sizeof( char * ) );
  343. wordsInLine[lineLength] = (char *)
  344. malloc( capacity * sizeof ( char ) );
  345. }
  346. position++;
  347. // Move position to keep working
  348. // Infinite loop count: 3 or 4.
  349.  
  350. // Move everything up.
  351. for ( int k = lineLength - 1; k > position; k-- ) {
  352. wordsInLine[k] = wordsInLine[k-1];
  353. }
  354. // Token assigning.
  355. // Some correctional folks would call it 'in processing'
  356. wordsInLine[position] = token;
  357. }
  358. token = strtok( NULL, " " );
  359. }
  360.  
  361. // Just making sure.
  362. j--;
  363. } else if ( decision[0] == 'a' ) { // add the word.
  364. // Updating size for adding.
  365. dictionarySize++;
  366. // Add new word by realloc memory.
  367. dictionary = ( char ** ) realloc( dictionary,
  368. dictionarySize * sizeof ( char * ) );
  369. dictionary[dictionarySize - 1] = ( char * )
  370. malloc( INPUT_SIZE * sizeof ( char ) );
  371. strcpy( dictionary[dictionarySize - 1], wordsInLine[j] );
  372. qsort( dictionary, dictionarySize, sizeof( dictionary[0] ), compareStrings );
  373. }
  374. }
  375. }
  376.  
  377. //reset stuff.
  378. wordsInLine = (char **) malloc( INPUT_SIZE * sizeof( char * ) );
  379. index = 0;
  380. lineLength = 0;
  381. }
  382.  
  383. //Final output stuff.
  384. printf( "Spellcheck complete.\n" );
  385. printf( "Backing up %s to %s.bak\n", argv[1], argv[1] );
  386. char *backupArrayFile = malloc( strlen( argv[1] ) + BAK_LENGTH );
  387. strcat( backupArrayFile, argv[1] );
  388. strcat( backupArrayFile, ".bak" );
  389. rename( argv[1], backupArrayFile );
  390. printf( "Writing updated %s\n", argv[1] );
  391.  
  392. //Print to file.
  393. inFile = fopen( argv[ 1 ], "w" );
  394.  
  395. // printf( "%d\n", wordLines[6][0] );
  396.  
  397. for ( int i = 0; i < linesSize; i++ ) {
  398. if ( wordLines[i] == 0 ) {
  399. fprintf( inFile, "\n" );
  400. } else {
  401. fprintf( inFile, "%s\n", wordLines[i] );
  402. }
  403. }
  404.  
  405. fclose( inFile );
  406.  
  407. //free it all up.
  408. freeLines( dictionary, dictionarySize );
  409. freeLines( wordLines, linesSize );
  410.  
  411. //oh ye and exit too
  412. return EXIT_SUCCESS;
  413.  
  414. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement