/* "make_kernel_string_pool.c" created by: grayspace aka J. Leveille for: UbixOS Project date: July 3, 2002 purpose: - tool to create string pools for in kernel use - will generate the source for including a global set of ASCII (for now) strings into the kernel to avoid memory wastage for kernel output strings for long lists of things such as device descriptions NOTEs: - for now only ASCII is supported TODO: - expand to support unicode - use huffman encoding instead $Id$ */ /* SubStringfile format: - each on it's own line, each unique substring */ #include <stdlib.h> #include <string.h> #include <stdio.h> typedef struct tagSUBSTRLIST { char ** pp_substrs; int numsubstrs; } SUBSTRLIST; // current open sub string file FILE * g_p_file_substrs = NULL; // main/current list of sub strings SUBSTRLIST g_mainsubstrs = { NULL, 0 }; // temporary lists of substrings SUBSTRLIST g_tempsubstrs1 = { NULL, 0 }; SUBSTRLIST g_tempsubstrs2 = { NULL, 0 }; // free all memory associated with the sub string list static void Free_SubStringList( SUBSTRLIST * p_ssl ) { int i; if( p_ssl->pp_substrs != NULL ) { for( i = 0; i < p_ssl->numsubstrs; i++ ) { if( p_ssl->pp_substrs[i] != NULL ) { free( p_ssl->pp_substrs[i] ); p_ssl->pp_substrs[i] = NULL; } } free( p_ssl->pp_substrs ); p_ssl->pp_substrs = NULL; p_ssl->numsubstrs = 0; } } // compare two pointers to strings static int CompareStringPtr( const void * p1, const void * p2 ) { return strcmp( *((const char **) p1), *((const char **) p2) ); } // sorts a sub string list into alphabetical order // list cannot be empty for success // returns 1 on success, 0 on failure static int Sort_SubStringList( SUBSTRLIST * p_ssl ) { if( p_ssl->numsubstrs && p_ssl->pp_substrs ) { // sort by pointer qsort( p_ssl->pp_substrs, p_ssl->numsubstrs, sizeof(char *), CompareStringPtr ); return 1; } return 0; } // given an open sub string file, creates a 'SUBSTRLIST' with its // contents (the file should contain a list of unique substrings // in alphabetical order) // // on failure: // - frees/empties the given list // - returns 0 // on success: // - returns 1 static int Create_SubStringList( SUBSTRLIST * p_ssl, FILE * p_file ) { int i; int numlines; char buff[1025]; // go to beginning of file if( fseek( p_file, 0L, SEEK_SET ) ) { goto failbail; } // count our lines: numlines = 0; while( fgets( buff, 1024, p_file ) != NULL ) { numlines++; } // go to beginning of file if( fseek( p_file, 0L, SEEK_SET ) ) { goto failbail; } // re-allocate our substring list: Free_SubStringList( p_ssl ); p_ssl->numsubstrs = numlines; p_ssl->pp_substrs = (char **) malloc( sizeof(char *) * p_ssl->numsubstrs ); // read each substring for( i = 0; i < p_ssl->numsubstrs; i++ ) { if( fgets( buff, 1024, p_file ) != NULL ) { p_ssl->pp_substrs[i] = (char *) malloc( sizeof(char) * (strlen( buff ) + 1) ); strcpy( p_ssl->pp_substrs[i], buff ); continue; } goto failbail; } // sort the substrings into alphabetical order if( Sort_SubStringList( p_ssl ) ) { // success: return 1; } failbail: Free_SubStringList( p_ssl ); printf( "[Create_SubStringList] Error" ); return 0; } // Given an open file which contains plain text, builds a sub string list // of unique sub strings into the list given as 'p_ssl' // NOTE: destroys/frees the contents of 'p_ssl' // regardless of success or failure const static char g_whitespace[] = " \t\n"; static int BuildFromFile_SubStrings( SUBSTRLIST * p_ssl, FILE * p_file ) { int i; int numwords; char buff[1025]; char * p_curbuff; // destroy the current list Free_SubStringList( p_ssl ); // go to beginning of file if( fseek( p_file, 0L, SEEK_SET ) ) { goto failbail; } // count our words: numwords = 0; while( (p_curbuff = fgets( buff, 1024, p_file )) != NULL ) { p_curbuff = strtok( p_curbuff, g_whitespace ); while( p_curbuff ) { numwords++; p_curbuff = strtok( NULL, g_whitespace ); } } // go to beginning of file if( fseek( p_file, 0L, SEEK_SET ) ) { goto failbail; } // read each substring from words in file p_ssl->numsubstrs = numwords; p_ssl->pp_substrs = (char **) malloc( sizeof(char *) * p_ssl->numsubstrs ); for( i = 0; i < p_ssl->numsubstrs; ) { if( (p_curbuff = fgets( buff, 1024, p_file )) != NULL ) { p_curbuff = strtok( p_curbuff, g_whitespace ); while( p_curbuff ) { p_ssl->pp_substrs[i] = (char *) malloc( sizeof(char) * (strlen( p_curbuff ) + 1) ); strcpy( p_ssl->pp_substrs[i], p_curbuff ); i++; p_curbuff = strtok( NULL, g_whitespace ); } continue; } goto failbail; } // sort the substrings into alphabetical order if( Sort_SubStringList( p_ssl ) ) { // success: return 1; } failbail: Free_SubStringList( p_ssl ); printf( "[Create_SubStringList] Error" ); return 0; } // creates a new 'SUBSTRLIST' into 'p_ssl_dst' by // combining the sub-strings in 'p_ssl_src1' and 'p_ssl_src2' // then it clears/frees both 'p_ssl_src1' and 'p_ssl_src2' // so that they are empty // NOTE: will destroy any contents in 'p_ssl_dst' safely static void Combine_SubStringLists( SUBSTRLIST * p_ssl_dst, SUBSTRLIST * p_ssl_src1, SUBSTRLIST * p_ssl_src2 ) { int src_idx_1; int src_idx_2; int src_idx; int dst_idx; SUBSTRLIST * p_ssl_src; // free the destination list Free_SubStringList( p_ssl_dst ); // set number of strings in dest list p_ssl_dst->numsubstrs = p_ssl_src1->numsubstrs + p_ssl_src2->numsubstrs; // allocate strings pointers p_ssl_dst->pp_substrs = (char **) malloc( sizeof(char *) * p_ssl_dst->numsubstrs ); // combine lists, preserving alphabetical order src_idx_1 = 0; src_idx_2 = 0; dst_idx = 0; while( src_idx_1 < p_ssl_src1->numsubstrs && src_idx_2 < p_ssl_src2->numsubstrs ) { if( strcmp( p_ssl_src1->pp_substrs[src_idx_1], p_ssl_src2->pp_substrs[src_idx_2] ) <= 0 ) { // move string from source 1 p_ssl_dst->pp_substrs[dst_idx] = p_ssl_src1->pp_substrs[src_idx_1]; p_ssl_src1->pp_substrs[src_idx_1] = NULL; dst_idx++; src_idx_1++; continue; } // move strings from source 2 p_ssl_dst->pp_substrs[dst_idx] = p_ssl_src2->pp_substrs[src_idx_2]; p_ssl_src2->pp_substrs[src_idx_2] = NULL; dst_idx++; src_idx_2++; } // find which source still has strings p_ssl_src = p_ssl_src1; src_idx = src_idx_1; if( src_idx_2 < p_ssl_src2->numsubstrs ) { p_ssl_src = p_ssl_src2; src_idx = src_idx_2; } // add remaining strings while( src_idx < p_ssl_src->numsubstrs ) { // move strings from source p_ssl_dst->pp_substrs[dst_idx] = p_ssl_src->pp_substrs[src_idx]; p_ssl_src->pp_substrs[src_idx] = NULL; dst_idx++; src_idx++; } // empty source strings p_ssl_src1->numsubstrs = 0; p_ssl_src2->numsubstrs = 0; Free_SubStringList( p_ssl_src1 ); Free_SubStringList( p_ssl_src2 ); } // removes duplicate sub strings in sub string list static void RemoveDuplicates_SubStrings( SUBSTRLIST * p_ssl ) { char * p_checkstr; int strsremoved; int idx; int dst_idx; int src_idx; // first pass, remove and free all duplicate strings // in their current position strsremoved = 0; idx = 0; while( idx < p_ssl->numsubstrs ) { // get new check string p_checkstr = p_ssl->pp_substrs[idx]; idx++; // remove all duplicates of check string while( idx < p_ssl->numsubstrs ) { if( strcmp( p_checkstr, p_ssl->pp_substrs[idx] ) == 0 ) { // remove duplicate free( p_ssl->pp_substrs[idx] ); p_ssl->pp_substrs[idx] = NULL; strsremoved++; idx++; // process next string continue; } // get new check string break; } } // second pass, re-order dst_idx = 0; src_idx = 0; while( src_idx < p_ssl->numsubstrs ) { // find next empty string section while( dst_idx < p_ssl->numsubstrs ) { if( p_ssl->pp_substrs[dst_idx] ) { dst_idx++; continue; } break; } // find next non-empty string section src_idx = dst_idx + 1; while( src_idx < p_ssl->numsubstrs ) { if( !p_ssl->pp_substrs[src_idx] ) { src_idx++; continue; } break; } // move all non-empty strings into empty space idx = src_idx; while( dst_idx < src_idx && idx < p_ssl->numsubstrs ) { if( p_ssl->pp_substrs[idx] ) { // move string p_ssl->pp_substrs[dst_idx] = p_ssl->pp_substrs[idx]; p_ssl->pp_substrs[idx] = NULL; dst_idx++; idx++; // process next string continue; } // start over break; } } // adjust number of strings in list p_ssl->numsubstrs -= strsremoved; } // moves one string list to another // (also cleans memory a little) // NOTES: // - this operation empties/frees 'p_ssl_src' // - this operation overwrites the contents of 'p_ssl_dst' static void Move_SubStrings( SUBSTRLIST * p_ssl_dst, SUBSTRLIST * p_ssl_src ) { int i; // free/clear the dest substrings Free_SubStringList( p_ssl_dst ); // allocate new dest sub-strings p_ssl_dst->numsubstrs = p_ssl_src->numsubstrs; p_ssl_dst->pp_substrs = (char **) malloc( sizeof(char *) * p_ssl_dst->numsubstrs ); // move the strings over for( i = 0; i < p_ssl_dst->numsubstrs; i++ ) { p_ssl_dst->pp_substrs[i] = p_ssl_src->pp_substrs[i]; p_ssl_src->pp_substrs[i] = NULL; } // clear/free the source string p_ssl_src->numsubstrs = 0; Free_SubStringList( p_ssl_src ); } // writes given sub string list into given file // on success: // - old file contents are destroyed // - returns 1 // on failure: // - old file contents are destroyed or mangled // - returns 0 static int Write_SubStrings( SUBSTRLIST * p_ssl, FILE * p_file ) { int i; // go to beginning of file if( fseek( p_file, 0L, SEEK_SET ) ) { goto failbail; } // write out all strings for( i = 0; i < p_ssl->numsubstrs; i++ ) { if( fputs( p_ssl->pp_substrs[i], p_file ) != EOF ) { if( fputs( "\n", p_file ) != EOF ) { continue; } } goto failbail; } // success: return 1; failbail: printf( "[Write_SubStrings] Error, cannot write to file\n" ); return 0; } // writes out and closes the current sub string file if possible // and frees the current sub string list // returns 1 on success, 0 on failure int WriteAndClose_SubStringFile() { if( g_p_file_substrs ) { if( Write_SubStrings( &g_mainsubstrs, g_p_file_substrs ) ) { // close the file if( fclose( g_p_file_substrs ) == 0 ) { // success g_p_file_substrs = NULL; return 1; } printf( "[WriteAndClose_SubStringFile] Error closing file\n" ); goto failbail; } printf( "[WriteAndClose_SubStringFile] Error, cannot write to file\n" ); goto failbail; } printf( "[WriteAndClose_SubStringFile] Error, never opened \n" ); failbail: if( fclose( g_p_file_substrs ) ) { g_p_file_substrs = NULL; } return 0; } // closes the current open sub string file and frees // the current sub string list // returns 1 on success, 0 on failure int Close_SubStringFile() { if( g_p_file_substrs ) { // close the file if( fclose( g_p_file_substrs ) == 0 ) { // success g_p_file_substrs = NULL; return 1; } printf( "[Close_SubStringFile] Error closing file\n" ); return 0; } printf( "[Close_SubStringFile] Error, never opened \n" ); return 0; } #if 0 void OpenStringFile( const char * p_path ) { } void CreateStringFile( const char * p_path ) { } void AddStringsFromFile( const char * p_path ) { } #endif // given a plain text files, extracts any unique sub strings // and adds them into the current sub string list // // returns 1 on success, 0 on failure int Add_SubStringsFromFile( const char * p_path ) { FILE * p_file = fopen( p_path, "rt" ); if( p_file ) { // build a new substring list from the file if( BuildFromFile_SubStrings( &g_tempsubstrs1, p_file ) ) { // combine new substrings with current list // into a new temporary list // NOTE: this operation empties/frees // both 'g_tempsubstrs1' and 'g_mainsubstrs' Combine_SubStringLists( &g_tempsubstrs2, &g_tempsubstrs1, &g_mainsubstrs ); // remove duplicates from new temporary list RemoveDuplicates_SubStrings( &g_tempsubstrs2 ); // move new temporary list into main list // (also cleans memory a little) // NOTE: this operation empties/frees 'g_tempsubstrs2' Move_SubStrings( &g_mainsubstrs, &g_tempsubstrs2 ); // close the file fclose( p_file ); // success return 1; } fclose( p_file ); printf( "[Add_SubStringsFromFile] Error" ); return 0; } printf( "[Add_SubStringsFromFile] Error, cannot open file: %s.\n", p_path ); return 0; } // given a path, opens an existing sub string file // (shoudl conatin an alphabetically sorted list of unique substrings) // reads in the contents as the current sub string list and sets // the file as the current open sub string file // // returns 1 on success, 0 on failure int Open_SubStringFile( const char * p_path ) { g_p_file_substrs = fopen( p_path, "r+t" ); if( g_p_file_substrs ) { if( Create_SubStringList( &g_mainsubstrs, g_p_file_substrs ) ) { // success return 1; } fclose( g_p_file_substrs ); printf( "[OpenSubStringFile] Error" ); return 0; } printf( "[OpenSubStringFile] Error, cannot open file: %s.\n", p_path ); return 0; } // given a path, creates a sub string file for writing to // as the current open sub string file // // returns 1 on success, 0 on failure int Create_SubStringFile( const char * p_path ) { g_p_file_substrs = fopen( p_path, "w+t" ); if( g_p_file_substrs ) { // free current list Free_SubStringList( &g_mainsubstrs ); // success return 1; } printf( "[Create_SubStringFile] Error, cannot create file: %s.\n", p_path ); return 0; } // Resets *everything*, frees all memory in use, closes all open files void MakeKSP_ResetAll() { Free_SubStringList( &g_mainsubstrs ); Free_SubStringList( &g_tempsubstrs1 ); Free_SubStringList( &g_tempsubstrs2 ); if( g_p_file_substrs ) { fclose( g_p_file_substrs ); g_p_file_substrs = NULL; } }