int main() { Password* fallout = new Password(); addWords(fallout); guessWords(fallout); delete fallout; }
bool findAnchorImpl(int* result, T& dict, int nrows, const char** rows, const int* lens, int ANCHOR, int last) { for (int start = 0; start <= last; start++) { if (addWords(result, dict, nrows, rows, lens, ANCHOR, start)) { return true; } } return false; }
// . set words from a string // . assume no HTML entities in the string "s" // . s must be NULL terminated // . NOTE: do not free "s" from under us cuz we reference it // . break up the string ,"s", into "words". // . doesn't do tags, only text nodes in "xml" // . our definition of a word is as close to English as we can get it // . BUT we also consider a string of punctuation characters to be a word bool Words::set( char *s, bool computeWordIds ) { reset(); // determine rough upper bound on number of words by counting // punct/alnum boundaries m_preCount = countWords ( s ); if ( !allocateWordBuffers( m_preCount ) ) { return false; } return addWords( s, 0x7fffffff, computeWordIds ); }
bool Words::setxi ( char *s , char *buf, long bufSize, long niceness ) { // prevent setting with the same string if ( m_s == s ) { char *xx=NULL;*xx=0; } reset(); m_version = TITLEREC_CURRENT_VERSION; // save for sanity check m_s = s; m_localBuf2 = buf; m_localBufSize2 = bufSize; // determine rough upper bound on number of words by counting // punct/alnum boundaries m_preCount = countWords ( s , niceness ); if (!allocateWordBuffers(m_preCount)) return false; bool computeWordIds = true; return addWords(s,0x7fffffff, computeWordIds, niceness ); }
// . set words from a string // . assume no HTML entities in the string "s" // . s must be NULL terminated // . NOTE: do not free "s" from under us cuz we reference it // . break up the string ,"s", into "words". // . doesn't do tags, only text nodes in "xml" // . our definition of a word is as close to English as we can get it // . BUT we also consider a string of punctuation characters to be a word bool Words::set ( char *s , long version, bool computeWordIds , long niceness ) { // prevent setting with the same string if ( m_s == s ) { char *xx=NULL;*xx=0; } reset(); m_version = version; // save for sanity check m_s = s; m_version = version; // determine rough upper bound on number of words by counting // punct/alnum boundaries m_preCount = countWords ( s , niceness ); if (!allocateWordBuffers(m_preCount)) return false; return addWords(s,0x7fffffff, computeWordIds, niceness ); }
bool Words::set11 ( char *s , char *send , long niceness ) { reset(); m_version = TITLEREC_CURRENT_VERSION; m_s = s; // this will make addWords() scan for tags m_hasTags = true; // save it char saved = *send; // null term *send = '\0'; // determine rough upper bound on number of words by counting // punct/alnum boundaries m_preCount = countWords ( s , niceness ); // true = tagIds bool status = allocateWordBuffers(m_preCount,true); // deal with error now if ( ! status ) { *send = saved; return false; } // and set the words status = addWords(s,0x7fffffff, true, niceness ); // bring it back *send = saved; // return error? return status; }
bool Words::set2 ( Xml *xml, bool computeWordIds , long niceness) { reset(); m_xml = xml; m_version = xml->getVersion(); m_version = xml->getVersion(); register char *p = (char *)xml->getContent(); if ( *p ) p++; register long x = 0; ploop: //if ( is_alnum(*(p-1)) ^ is_alnum(*p) ) x++; //if ( is_alnum(*p ) ) x++; //x += g_map_is_alpha[*p] ; if ( is_alnum_utf8(p) ) x++; //if ( isalnum(*p) ) x++; //if ( g_map_is_alpha[*p] ) x++; //x++; p++; if ( *p ) goto ploop; m_preCount = x; m_preCount = xml->getContentLen() / 2; //if ( m_preCount > 9000 ) m_preCount = 9000; //m_preCount = 9000; if (!allocateWordBuffers(m_preCount, true)) return false; long numNodes = xml->getNumNodes(); // are we done? for ( long k = 0 ; k < numNodes && m_numWords < m_preCount ; k++ ) { // get the kth node char *node = xml->getNode (k); long nodeLen = xml->getNodeLen(k); // is the kth node a tag? if ( xml->isTag(k) ) { m_words [m_numWords] = node; m_wordLens [m_numWords] = nodeLen; m_tagIds [m_numWords] = xml->getNodeId(k); m_wordIds [m_numWords] = 0LL; m_nodes [m_numWords] = k; // we have less than 127 HTML tags, so set // the high bit for back tags if ( xml->isBackTag(k)) { m_tagIds[m_numWords] |= BACKBIT; } //log(LOG_DEBUG, "Words: Word %ld: got tag %s%s (%d)", // m_numWords, // isBackTag(m_numWords)?"/":"", // g_nodes[getTagId(m_numWords)].m_nodeName, // getTagId(m_numWords)); m_numWords++; // used by XmlDoc.cpp m_numTags++; continue; } // otherwise it's a text node char c = node[nodeLen]; node[nodeLen] = '\0'; addWords(node, nodeLen,computeWordIds, niceness); node[nodeLen] = c; } return true; }
bool Words::set ( Xml *xml, bool computeWordIds , long niceness , long node1 , long node2 ) { // prevent setting with the same string if ( m_xml == xml ) { char *xx=NULL;*xx=0; } reset(); m_xml = xml; m_version = xml->getVersion(); //m_version = xml->getVersion(); // quick test if ( ! s_tested ) { // only do once s_tested = true; // set c to a curling quote in unicode long c = 0x201c; // 0x235e; // encode it into utf8 char dst[5]; // point to it char *p = dst; // put space in there *p++ = ' '; // "numBytes" is how many bytes it stored into 'dst" long numBytes = utf8Encode ( c , p ); // must be 2 bytes i guess if ( numBytes != 3 ) { char *xx=NULL; *xx=0; } // check it long size = getUtf8CharSize(p); if ( size != 3 ) { char *xx=NULL; *xx=0; } // is that punct if ( ! is_punct_utf8 ( p ) ) { char *xx=NULL;*xx=0; } // make sure can pair across //unsigned char bits = getPunctuationBits ( dst , 4 ); // must be able to pair across //if ( ! ( bits & D_CAN_PAIR_ACROSS ) ) { char *xx=NULL;*xx=0;} } // if xml is empty, bail if ( ! xml->getContent() ) return true; long numNodes = xml->getNumNodes(); if ( numNodes <= 0 ) return true; // . can be given a range, if node2 is -1 that means all! // . range is half-open: [node1, node2) if ( node2 < 0 ) node2 = numNodes; // sanity check if ( node1 > node2 ) { char *xx=NULL;*xx=0; } char *start = xml->getNode(node1); char *end = xml->getNode(node2-1) + xml->getNodeLen(node2-1); long size = end - start; m_preCount = countWords( start , size , niceness ); // allocate based on the approximate count if ( ! allocateWordBuffers(m_preCount, true)) return false; // are we done? for ( long k = node1 ; k < node2 && m_numWords < m_preCount ; k++ ){ // get the kth node char *node = xml->getNode (k); long nodeLen = xml->getNodeLen(k); // is the kth node a tag? if ( ! xml->isTag(k) ) { char c = node[nodeLen]; node[nodeLen] = '\0'; addWords(node,nodeLen,computeWordIds,niceness); node[nodeLen] = c; continue; } // it is a tag m_words [m_numWords] = node; m_wordLens [m_numWords] = nodeLen; m_tagIds [m_numWords] = xml->getNodeId(k); m_wordIds [m_numWords] = 0LL; m_nodes [m_numWords] = k; // we have less than 127 HTML tags, so set // the high bit for back tags if ( xml->isBackTag(k)) { m_tagIds[m_numWords] |= BACKBIT; } //log(LOG_DEBUG, "Words: Word %ld: got tag %s%s (%d)", // m_numWords, // isBackTag(m_numWords)?"/":"", // g_nodes[getTagId(m_numWords)].m_nodeName, // getTagId(m_numWords)); m_numWords++; // used by XmlDoc.cpp m_numTags++; continue; } return true; }
int main(int argc, char *const *argv) { FILE *data = NULL; struct parameters p; char o, *tok, tmp[256]; word_t word; struct d_entry *d_entry; p.delimiters = NULL; STAILQ_INIT(&p.dictionary); // Initialisation des parametres while((o = getopt (argc, argv, "a:A:d:D:w:W:hHvV")) != -1) switch(o) { case 'w': case 'W': tok = strtok(optarg, " "); do { if((d_entry = (struct d_entry *) malloc(sizeof(struct d_entry)))) if((d_entry->string = (char *) calloc((strlen(tok) + 1), sizeof(char)))) { strcpy(d_entry->string, tok); STAILQ_INSERT_TAIL(&p.dictionary, d_entry, entries); } else { fprintf( stderr, "%s: Unable to create a dictionary entry for the word \"%s\": %s\n", *argv, tok, strerror(errno) ); free(d_entry); } else fprintf( stderr, "%s: Unable to create a dictionary entry for the word \"%s\": %s\n", *argv, tok, strerror(errno) ); } while((tok = strtok(NULL, " "))); break; case 'd': case 'D': p.delimiters = optarg; break; case 'h': case 'H': switch(system("cat help.txt")) { case 1: fprintf(stderr, "%s: \"help.txt\" does not exist", *argv); case -1: return EXIT_FAILURE; default: return EXIT_SUCCESS; break; } break; case 'v': case 'V': verbose = true; break; case '?': default: fprintf(stderr, "Usage: %s %s\n", *argv, USAGE); return EXIT_FAILURE; break; } // Chargement des dictionnaires while(optind < argc - 1) { if(!(data = fopen(argv[optind], "r"))) fprintf(stderr, "%s: %s\n", *argv, strerror(errno)); else { addWords(data, &p.dictionary); } fclose(data); optind++; } if(optind >= argc) { fprintf(stderr, "Usage: %s %s\n", *argv, USAGE); return EXIT_FAILURE; } // Chargement de l'automate if(!(data = fopen(argv[optind], "r"))) { fprintf(stderr, "%s: %s: %s\n", *argv, argv[optind], strerror(errno)); return EXIT_FAILURE; } if(!parse(data, &(p.fsm))) { fprintf(stderr, "%s: Unable to parse the automaton file\n", *argv); fclose(data); return EXIT_FAILURE; } fclose(data); // Lecture de mots sur l'entree standard if(STAILQ_EMPTY(&p.dictionary)) { while(printf("> "), scanf("%255[^\n]s\n", tmp)) { word = mkword(tmp, p.delimiters); printf("%s - %srecognized by the automaton\n", tmp, recognize(&p.fsm, word) ? "" : "un"); wfree(word); getchar(); } } // Lecture du dictionnaire while((d_entry = STAILQ_FIRST(&p.dictionary))) { word = mkword(d_entry->string, p.delimiters); printf("%s - %srecognized by the automaton\n", d_entry->string, recognize(&p.fsm, word) ? "" : "un"); wfree(word); STAILQ_REMOVE_HEAD(&p.dictionary, entries); free(d_entry->string); free(d_entry); } freeFsm(&(p.fsm)); return EXIT_SUCCESS; }
bool Words::set( Xml *xml, bool computeWordIds, int32_t node1, int32_t node2 ) { // prevent setting with the same string if ( m_xml == xml ) gbshutdownLogicError(); reset(); m_xml = xml; // if xml is empty, bail if ( !xml->getContent() ) { return true; } int32_t numNodes = xml->getNumNodes(); if ( numNodes <= 0 ) { return true; } // . can be given a range, if node2 is -1 that means all! // . range is half-open: [node1, node2) if ( node2 < 0 ) { node2 = numNodes; } // sanity check if ( node1 > node2 ) gbshutdownLogicError(); char *start = xml->getNode(node1); char *end = xml->getNode( node2 - 1 ) + xml->getNodeLen( node2 - 1 ); int32_t size = end - start; m_preCount = countWords( start , size ); // allocate based on the approximate count if ( !allocateWordBuffers( m_preCount, true ) ) { return false; } // are we done? for ( int32_t k = node1; k < node2 && m_numWords < m_preCount; ++k ) { // get the kth node char *node = xml->getNode( k ); int32_t nodeLen = xml->getNodeLen( k ); // is the kth node a tag? if ( !xml->isTag( k ) ) { /// @todo ALC why are we adding NULL and restoring it after? /// addWords should be change to use nodeLen and not null terminated string char c = node[nodeLen]; node[nodeLen] = '\0'; addWords( node, nodeLen, computeWordIds ); node[nodeLen] = c; continue; } // it is a tag m_words [m_numWords] = node; m_wordLens [m_numWords] = nodeLen; m_tagIds [m_numWords] = xml->getNodeId(k); m_wordIds [m_numWords] = 0LL; m_nodes [m_numWords] = k; // we have less than 127 HTML tags, so set // the high bit for back tags if ( xml->isBackTag(k)) { m_tagIds[m_numWords] |= BACKBIT; } m_numWords++; // used by XmlDoc.cpp m_numTags++; continue; } return true; }
DirectionTypePtr Direction::createDirectionType( std::ostream& message, xml::XElementIterator& subIter, xml::XElementIterator& subIterEnd, bool& isSuccess ) { auto directionType = makeDirectionType(); if( subIter == subIterEnd ) { message << "Direction: well thats weird - should not get here" << std::endl; isSuccess = false; return directionType; } if( subIter->getName() == "wedge" ) { directionType->setChoice( DirectionType::Choice::wedge ); isSuccess &= directionType->getWedge()->fromXElement( message, *subIter ); return directionType; } if( subIter->getName() == "dashes" ) { directionType->setChoice( DirectionType::Choice::dashes ); isSuccess &= directionType->getDashes()->fromXElement( message, *subIter ); return directionType; } if( subIter->getName() == "bracket" ) { directionType->setChoice( DirectionType::Choice::bracket ); isSuccess &= directionType->getBracket()->fromXElement( message, *subIter ); return directionType; } if( subIter->getName() == "pedal" ) { directionType->setChoice( DirectionType::Choice::pedal ); isSuccess &= directionType->getPedal()->fromXElement( message, *subIter ); return directionType; } if( subIter->getName() == "metronome" ) { directionType->setChoice( DirectionType::Choice::metronome ); isSuccess &= directionType->getMetronome()->fromXElement( message, *subIter ); return directionType; } if( subIter->getName() == "octave-shift" ) { directionType->setChoice( DirectionType::Choice::octaveShift ); isSuccess &= directionType->getOctaveShift()->fromXElement( message, *subIter ); return directionType; } if( subIter->getName() == "harp-pedals" ) { directionType->setChoice( DirectionType::Choice::harpPedals ); isSuccess &= directionType->getHarpPedals()->fromXElement( message, *subIter ); return directionType; } if( subIter->getName() == "damp" ) { directionType->setChoice( DirectionType::Choice::damp ); isSuccess &= directionType->getDamp()->fromXElement( message, *subIter ); return directionType; } if( subIter->getName() == "damp-all" ) { directionType->setChoice( DirectionType::Choice::dampAll ); isSuccess &= directionType->getDampAll()->fromXElement( message, *subIter ); return directionType; } if( subIter->getName() == "eyeglasses" ) { directionType->setChoice( DirectionType::Choice::eyeglasses ); isSuccess &= directionType->getEyeglasses()->fromXElement( message, *subIter ); return directionType; } if( subIter->getName() == "string-mute" ) { directionType->setChoice( DirectionType::Choice::stringMute ); isSuccess &= directionType->getStringMute()->fromXElement( message, *subIter ); return directionType; } if( subIter->getName() == "scordatura" ) { directionType->setChoice( DirectionType::Choice::scordatura ); isSuccess &= directionType->getScordatura()->fromXElement( message, *subIter ); return directionType; } if( subIter->getName() == "image" ) { directionType->setChoice( DirectionType::Choice::image ); isSuccess &= directionType->getImage()->fromXElement( message, *subIter ); return directionType; } if( subIter->getName() == "principal-voice" ) { directionType->setChoice( DirectionType::Choice::principalVoice ); isSuccess &= directionType->getPrincipalVoice()->fromXElement( message, *subIter ); return directionType; } if( subIter->getName() == "accordion-registration" ) { directionType->setChoice( DirectionType::Choice::accordionRegistration ); isSuccess &= directionType->getAccordionRegistration()->fromXElement( message, *subIter ); return directionType; } if( subIter->getName() == "other-direction" ) { directionType->setChoice( DirectionType::Choice::otherDirection ); isSuccess &= directionType->getOtherDirection()->fromXElement( message, *subIter ); return directionType; } std::string name = "rehearsal"; if( subIter->getName() == name ) { directionType->setChoice( DirectionType::Choice::rehearsal ); bool isFirstSubItemAdded = false; while( subIter != subIterEnd ) { if( subIter->getName() != name ) { message << "Direction: createDirectionType encountered an unexpected element '" << subIter->getName() << "' while parsing a collection of '" << name << "' elements" << std::endl; isSuccess = false; return directionType; } auto itemToAdd = makeRehearsal(); isSuccess &= itemToAdd->fromXElement( message, *subIter ); if( !isFirstSubItemAdded && directionType->getRehearsalSet().size() == 1 ) { directionType->addRehearsal( itemToAdd ); directionType->removeRehearsal( directionType->getRehearsalSet().cbegin() ); } else { directionType->addRehearsal( itemToAdd ); } isFirstSubItemAdded = true; ++subIter; } // end loop return directionType; } // end rehearsal name = "segno"; if( subIter->getName() == name ) { directionType->setChoice( DirectionType::Choice::segno ); bool isFirstSubItemAdded = false; while( subIter != subIterEnd ) { if( subIter->getName() != name ) { message << "Direction: createDirectionType encountered an unexpected element '" << subIter->getName() << "' while parsing a collection of '" << name << "' elements" << std::endl; isSuccess = false; return directionType; } auto itemToAdd = makeSegno(); isSuccess &= itemToAdd->fromXElement( message, *subIter ); if( !isFirstSubItemAdded && directionType->getSegnoSet().size() == 1 ) { directionType->addSegno( itemToAdd ); directionType->removeSegno( directionType->getSegnoSet().cbegin() ); } else { directionType->addSegno( itemToAdd ); } isFirstSubItemAdded = true; ++subIter; } // end loop return directionType; } // end segno name = "words"; if( subIter->getName() == name ) { directionType->setChoice( DirectionType::Choice::words ); bool isFirstSubItemAdded = false; while( subIter != subIterEnd ) { if( subIter->getName() != name ) { message << "Direction: createDirectionType encountered an unexpected element '" << subIter->getName() << "' while parsing a collection of '" << name << "' elements" << std::endl; isSuccess = false; return directionType; } auto itemToAdd = makeWords(); isSuccess &= itemToAdd->fromXElement( message, *subIter ); if( !isFirstSubItemAdded && directionType->getWordsSet().size() == 1 ) { directionType->addWords( itemToAdd ); directionType->removeWords( directionType->getWordsSet().cbegin() ); } else { directionType->addWords( itemToAdd ); } isFirstSubItemAdded = true; ++subIter; } // end loop return directionType; } // end words name = "coda"; if( subIter->getName() == name ) { directionType->setChoice( DirectionType::Choice::coda ); bool isFirstSubItemAdded = false; while( subIter != subIterEnd ) { if( subIter->getName() != name ) { message << "Direction: createDirectionType encountered an unexpected element '" << subIter->getName() << "' while parsing a collection of '" << name << "' elements" << std::endl; isSuccess = false; return directionType; } auto itemToAdd = makeCoda(); isSuccess &= itemToAdd->fromXElement( message, *subIter ); if( !isFirstSubItemAdded && directionType->getCodaSet().size() == 1 ) { directionType->addCoda( itemToAdd ); directionType->removeCoda( directionType->getCodaSet().cbegin() ); } else { directionType->addCoda( itemToAdd ); } isFirstSubItemAdded = true; ++subIter; } // end loop return directionType; } // end coda name = "dynamics"; if( subIter->getName() == name ) { directionType->setChoice( DirectionType::Choice::dynamics ); bool isFirstSubItemAdded = false; while( subIter != subIterEnd ) { if( subIter->getName() != name ) { message << "Direction: createDirectionType encountered an unexpected element '" << subIter->getName() << "' while parsing a collection of '" << name << "' elements" << std::endl; isSuccess = false; return directionType; } auto itemToAdd = makeDynamics(); isSuccess &= itemToAdd->fromXElement( message, *subIter ); if( !isFirstSubItemAdded && directionType->getDynamicsSet().size() == 1 ) { directionType->addDynamics( itemToAdd ); directionType->removeDynamics( directionType->getDynamicsSet().cbegin() ); } else { directionType->addDynamics( itemToAdd ); } isFirstSubItemAdded = true; ++subIter; } // end loop return directionType; } // end dynamics name = "percussion"; if( subIter->getName() == name ) { directionType->setChoice( DirectionType::Choice::percussion ); bool isFirstSubItemAdded = false; while( subIter != subIterEnd ) { if( subIter->getName() != name ) { message << "Direction: createDirectionType encountered an unexpected element '" << subIter->getName() << "' while parsing a collection of '" << name << "' elements" << std::endl; isSuccess = false; return directionType; } auto itemToAdd = makePercussion(); isSuccess &= itemToAdd->fromXElement( message, *subIter ); if( !isFirstSubItemAdded && directionType->getPercussionSet().size() == 1 ) { directionType->addPercussion( itemToAdd ); directionType->removePercussion( directionType->getPercussionSet().cbegin() ); } else { directionType->addPercussion( itemToAdd ); } isFirstSubItemAdded = true; ++subIter; } // end loop return directionType; } // end percussion return directionType; }
int main (int argc, char **argv) { /* extensions must be allocated in the heap because strsep will mess with it inside buildFindCmd */ char *extensions = (char*)malloc(sizeof(char) * MAXLINELEN); bzero(extensions, MAXLINELEN); strcat(extensions, "txt:text"); char *dir = "."; char *output = NULL; int i; int c; if (argc < 2) { printf("%s -d <dir> -e <ext1:ext2:...> -o <output>\n", argv[0]); exit(1); } /* opterr = 0; /\* Turn off error msgs from getopt *\/ */ while ((c = getopt (argc, argv, "e::d:o::")) != -1) switch (c) { case 'e': free(extensions); extensions = optarg; break; case 'd': dir = optarg; break; case 'o': output = optarg; break; case '?': if (optopt == 'e' || optopt == 'd' || optopt == 'o') fprintf (stderr, "Option -%c requires an argument.\n", optopt); else if (isprint (optopt)) fprintf (stderr, "Unknown option `-%c'.\n", optopt); else fprintf (stderr, "Unknown option character `\\x%x'.\n", optopt); return 1; default: abort (); } /* fprintf(stderr, "extensions = %s, dir = %s, output = %s\n", */ /* extensions, dir, output); */ /* for (i = optind; i < argc; i++) */ /* fprintf(stderr, "Non-option argument %s\n", argv[i]); */ char* cmd = buildFindCmd(&extensions, dir); char* filelist = exec(cmd); char* savedFilelist = filelist; free(cmd); /* printf("%s", filelist); */ char** words = (char**)malloc(sizeof(char*) * MAXWORDS); unsigned long long int num_words = 0, num_words_turn; unsigned long long int threshold = STARTTHRESHOLD; int threshold_hit = 0; char *file; FILE *f; int numFiles = countFilelist(filelist); int numFilesDone = 0; while ((file = strsep(&filelist, "\n")) != NULL) { if (file[0] != '\0') { /* fprintf(stderr, "===== Opening %s\n", file); */ if (isDoc(file)) { makeTmpWithStrings(file); strcpy(file, "tmpfile"); } f = fopen(file, "r"); num_words_turn = addWords(f, words+num_words); /* fprintf(stderr, "===== Total: %llu - Added %llu words from file %s\n", num_words, num_words_turn, file); */ fprintf(stderr, "===== Total: %llu %d of %d files \r", num_words, numFilesDone, numFiles-1); num_words += num_words_turn; if (num_words >= MAXWORDS-1) { fprintf(stderr, " *********************** Numero maximo de palavras excedido. ***********************\n\n\n"); } #ifdef SHRINK if (num_words > threshold) { /* Whenever we've got more than THRESHOLD words */ /* fprintf(stderr, " *********************** Shrinking, Threshold: %llu ***********************\n\n", threshold); */ num_words = shrink(words, num_words); /* Eliminate duplicates */ threshold_hit++; if (threshold_hit > 2) { threshold *= 2; threshold_hit = 0; } } #endif fclose(f); numFilesDone++; } } num_words = shrink(words, num_words); /* fprintf(stderr, "===== Total words found: %llu\n", num_words); */ qsort(words, num_words, sizeof(char*), compare_case); if (output) { f = fopen(output, "w"); for (i = 0; i < num_words; i++) { fprintf(f, "%s\n", words[i]); free(words[i]); } fclose(f); } else { for (i = 0; i < num_words; i++) { printf("%s\n", words[i]); free(words[i]); } } fprintf(stderr, "===== Total words found: %llu\n", num_words); free(words); free(savedFilelist); if (extensions) free(extensions); return 0; }