Advertisement
Shanix

Untitled

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