diff options
| author | Dirk Engling <erdgeist@erdgeist.org> | 2014-02-24 04:38:09 +0100 |
|---|---|---|
| committer | Dirk Engling <erdgeist@erdgeist.org> | 2014-02-24 04:38:09 +0100 |
| commit | fcefe3e6d93c86b7491c9e5af8372173ae01ed03 (patch) | |
| tree | 935d9d0ef9c1c9ac5fb910bcfba7977c65cb7caf /el.c | |
| parent | 315a4eed93bc4e8c52b3974a556fd96870e8f95b (diff) | |
Allow for multiple files to be acted upon
Diffstat (limited to 'el.c')
| -rw-r--r-- | el.c | 160 |
1 files changed, 88 insertions, 72 deletions
| @@ -8,21 +8,29 @@ | |||
| 8 | #include <unistd.h> | 8 | #include <unistd.h> |
| 9 | #include <ctype.h> | 9 | #include <ctype.h> |
| 10 | 10 | ||
| 11 | // Our index into the already scanned lines. | 11 | typedef struct { |
| 12 | // memory buffer is estimated to 1/32th of the | 12 | // Our mmap()ed file, from mystlib |
| 13 | // indexed file's size, meaning each line | 13 | MAP map; |
| 14 | // containing approx 31 letters. If it hits the | 14 | |
| 15 | // top, we increase in 1/32th steps | 15 | // Our index into the already scanned lines. |
| 16 | static unsigned char **index = NULL; | 16 | // memory buffer is estimated to 1/32th of the |
| 17 | 17 | // indexed file's size, meaning each line | |
| 18 | // this denotes the number of fields, NOT the | 18 | // containing approx 31 letters. If it hits the |
| 19 | // memory occupied (would be a size_t, then!!!) | 19 | // top, we increase in 1/32th steps |
| 20 | static long indexsize = 0; | 20 | uint8_t **index; |
| 21 | 21 | ||
| 22 | // this specifies, how many lines have been indexed | 22 | // this denotes the number of fields, NOT the |
| 23 | // already, scanning always only happens to the | 23 | // memory occupied (would be a size_t, then!!!) |
| 24 | // last reqeusted line | 24 | long index_size; |
| 25 | static long indexfilled = 1; | 25 | |
| 26 | // this specifies, how many lines have been indexed | ||
| 27 | // already, scanning always only happens to the | ||
| 28 | // last reqeusted line | ||
| 29 | long index_filled; | ||
| 30 | |||
| 31 | // indicates that we've been through all lines in the file | ||
| 32 | int all_lines_scanned; | ||
| 33 | } EL_FILE; | ||
| 26 | 34 | ||
| 27 | // If set, the stream of linenums specified calls | 35 | // If set, the stream of linenums specified calls |
| 28 | // the first line number 0... *shiver* | 36 | // the first line number 0... *shiver* |
| @@ -59,66 +67,57 @@ static int nextchar( void ) { | |||
| 59 | // to prevent huge numbers from stdin to steal our | 67 | // to prevent huge numbers from stdin to steal our |
| 60 | // memory | 68 | // memory |
| 61 | 69 | ||
| 62 | static unsigned char * scanforline( MAP file, const long lineno, long *size ) { | 70 | static uint8_t * scanforline( EL_FILE *file, const long lineno, long *size ) { |
| 63 | unsigned char *scanline, *const e_o_f = file->addr + file->size; | 71 | uint8_t *scanline, *const e_o_f = file->map->addr + file->map->size; |
| 64 | static int alllinesscanned = 0; | ||
| 65 | *size = 0; | 72 | *size = 0; |
| 66 | 73 | ||
| 67 | // lines start at 1 | 74 | // lines start at 1 |
| 68 | if( lineno < 1 ) return NULL; | 75 | if( lineno < 1 ) return NULL; |
| 69 | 76 | ||
| 70 | // lines we already found can simply be returned | 77 | // lines we already found can simply be returned |
| 71 | if( lineno < indexfilled ) { | 78 | if( lineno < file->index_filled ) |
| 72 | *size = index[lineno] - index[lineno-1]; | 79 | goto return_line; |
| 73 | return index[lineno-1]; | ||
| 74 | } | ||
| 75 | 80 | ||
| 76 | // if alllines were scanned, were either on | 81 | // if all lines were scanned, were either on |
| 77 | // or behind last line | 82 | // or behind last line |
| 78 | if( alllinesscanned ) { | 83 | if( file->all_lines_scanned ) { |
| 79 | if( lineno == indexfilled ) { | 84 | if( lineno == file->index_filled ) |
| 80 | *size = e_o_f - index[lineno-1]; | 85 | goto return_line; |
| 81 | return index[lineno-1]; | ||
| 82 | } | ||
| 83 | return NULL; | 86 | return NULL; |
| 84 | } | 87 | } |
| 85 | 88 | ||
| 86 | // exploring undiscovered land... | 89 | // exploring undiscovered land... |
| 87 | scanline = index[indexfilled-1]; | 90 | scanline = file->index[file->index_filled-1]; |
| 88 | 91 | ||
| 89 | while( indexfilled <= lineno ) { | 92 | while( file->index_filled <= lineno ) { |
| 90 | // scan for next line | 93 | // scan for next line |
| 91 | while( ( scanline < e_o_f ) && ( *scanline++ != '\n' )); | 94 | while( ( scanline < e_o_f ) && ( *scanline++ != '\n' )); |
| 92 | 95 | ||
| 96 | file->index[file->index_filled++] = scanline; | ||
| 97 | |||
| 93 | // store pointer | 98 | // store pointer |
| 94 | if( scanline == e_o_f ) { | 99 | if( scanline == e_o_f ) { |
| 95 | alllinesscanned = 1; | 100 | file->all_lines_scanned = 1; |
| 96 | if( indexfilled == lineno ) { | 101 | if( file->index_filled == lineno + 1 ) |
| 97 | *size = e_o_f - index[lineno-1]; | 102 | goto return_line; |
| 98 | return index[lineno-1]; | 103 | return NULL; |
| 99 | } else | ||
| 100 | return NULL; | ||
| 101 | } | 104 | } |
| 102 | 105 | ||
| 103 | index[indexfilled++] = scanline; | ||
| 104 | |||
| 105 | // reallocate some memory | 106 | // reallocate some memory |
| 106 | if( indexfilled == indexsize ) { | 107 | if( file->index_filled == file->index_size ) { |
| 107 | unsigned char ** newblock = (unsigned char**) realloc( index, sizeof(char *) * ( indexsize + file->size / 32 ) ); | 108 | void *newblock = realloc( file->index, sizeof(uint8_t*) * ( file->index_size + file->map->size / 32 ) ); |
| 108 | if( !newblock ) { | 109 | if( !newblock ) { |
| 109 | fputs( "Could not allocate memory, exiting.\n", stderr); | 110 | fputs( "Could not allocate memory, exiting.\n", stderr); |
| 110 | // unmap file and zero pointer | ||
| 111 | unmap_file( &file ); | ||
| 112 | exit ( 1 ); | 111 | exit ( 1 ); |
| 113 | } | 112 | } |
| 114 | indexsize += file->size / 32; | 113 | file->index_size += file->map->size / 32; |
| 115 | index = newblock; | 114 | file->index = newblock; |
| 116 | } | 115 | } |
| 117 | |||
| 118 | } | 116 | } |
| 119 | 117 | ||
| 120 | *size = index[lineno] - index[lineno-1]; | 118 | return_line: |
| 121 | return index[lineno-1]; | 119 | *size = file->index[lineno] - file->index[lineno-1]; |
| 120 | return file->index[lineno-1]; | ||
| 122 | } | 121 | } |
| 123 | 122 | ||
| 124 | // Reads all characters up to the next white space | 123 | // Reads all characters up to the next white space |
| @@ -164,7 +163,7 @@ static int acquire_lineno( int c ) { | |||
| 164 | 163 | ||
| 165 | input[inputindex] = 0; | 164 | input[inputindex] = 0; |
| 166 | 165 | ||
| 167 | // Try to read | 166 | // Try to read |
| 168 | if( sscanf( input, g_scanfmodifier, &lineno ) != 1 ) | 167 | if( sscanf( input, g_scanfmodifier, &lineno ) != 1 ) |
| 169 | return 0; | 168 | return 0; |
| 170 | 169 | ||
| @@ -172,12 +171,12 @@ static int acquire_lineno( int c ) { | |||
| 172 | } | 171 | } |
| 173 | 172 | ||
| 174 | static void usage() { | 173 | static void usage() { |
| 175 | fputs( "Usage: el [-0Ggnxh] [-i linenums] filename < linenum_file\n", stderr); | 174 | fputs( "Usage: el [-0Ggnxh] [-i linenums] filename .. < linenum_file\n", stderr); |
| 176 | } | 175 | } |
| 177 | 176 | ||
| 178 | int main( int argc, char **argv ) { | 177 | int main( int argc, char **argv ) { |
| 179 | // Our handle to the mapped text file | 178 | EL_FILE *textfiles; |
| 180 | MAP textfile = NULL; | 179 | size_t i, textfiles_count; |
| 181 | int c; | 180 | int c; |
| 182 | 181 | ||
| 183 | while ((c = getopt(argc, argv, ":0i:gGnxh")) != -1) { | 182 | while ((c = getopt(argc, argv, ":0i:gGnxh")) != -1) { |
| @@ -209,34 +208,51 @@ int main( int argc, char **argv ) { | |||
| 209 | argc -= optind; | 208 | argc -= optind; |
| 210 | argv += optind; | 209 | argv += optind; |
| 211 | 210 | ||
| 212 | if( argc != 1 ) { usage(); exit(1); } | 211 | if( argc < 1 ) { usage(); exit(1); } |
| 212 | textfiles_count = argc; | ||
| 213 | if( ( textfiles = malloc( textfiles_count * sizeof( EL_FILE ) ) ) == NULL ) { | ||
| 214 | fputs( "Could not allocate memory, exiting.\n", stderr); | ||
| 215 | exit(1); | ||
| 216 | } | ||
| 213 | 217 | ||
| 214 | // Map text file read only | 218 | for( i=0; i<textfiles_count; ++i ) { |
| 215 | if( (textfile = map_file( argv[0], 1 )) == NULL ) exit(1); | 219 | // Map text file read only |
| 220 | if( (textfiles[i].map = map_file( argv[i], 1 )) == NULL ) | ||
| 221 | exit(1); | ||
| 216 | 222 | ||
| 217 | indexsize = textfile->size < 32 ? 32 : textfile->size / 32; | 223 | textfiles[i].index_size = textfiles[i].map->size < 32 ? 32 : textfiles[i].map->size / 32; |
| 218 | if( (index = malloc( sizeof(char *) * indexsize )) == NULL ) { | 224 | if( (textfiles[i].index = malloc( sizeof(uint8_t*) * textfiles[i].index_size )) == NULL ) { |
| 219 | fputs( "Could not allocate memory, exiting.\n", stderr); | 225 | fputs( "Could not allocate memory, exiting.\n", stderr); |
| 220 | // unmap file and zero pointer | 226 | exit ( 1 ); |
| 221 | unmap_file( &textfile ); | 227 | } |
| 222 | exit ( 1 ); | 228 | |
| 223 | } | 229 | // First line starts at begin of file. |
| 230 | textfiles[i].index[0] = textfiles[i].map->addr; | ||
| 231 | textfiles[i].index_filled = 1; | ||
| 232 | textfiles[i].all_lines_scanned = 0; | ||
| 233 | } | ||
| 224 | 234 | ||
| 225 | // First line starts at begin of file. | ||
| 226 | index[0] = textfile->addr; | ||
| 227 | 235 | ||
| 228 | while( (c = nextchar()) != EOF ) { | 236 | while( (c = nextchar()) != EOF ) { |
| 229 | // get linenumber, pass on eof test char | 237 | // get linenumber, pass on eof test char |
| 230 | long slen, lineno = acquire_lineno(c); | 238 | long lineno = acquire_lineno(c); |
| 231 | unsigned char *line = scanforline( textfile, lineno, &slen ); | 239 | |
| 232 | 240 | for( i=0; i<textfiles_count; ++i ) { | |
| 233 | if( line && slen ) | 241 | long slen; |
| 234 | fwrite( line, slen, 1, stdout ); | 242 | uint8_t *line = scanforline( textfiles + i, lineno, &slen ); |
| 235 | else | 243 | |
| 236 | putchar('\n'); | 244 | if( line && slen ) { |
| 245 | // chomp | ||
| 246 | if( line[slen-1] == '\n' ) --slen; | ||
| 247 | fwrite( line, slen, 1, stdout ); | ||
| 248 | } | ||
| 249 | putchar( ( i + 1 < textfiles_count ) ? '\t' : '\n' ); | ||
| 250 | } | ||
| 237 | } | 251 | } |
| 238 | 252 | ||
| 239 | // unmap file and zero pointer | 253 | // unmap file and zero pointer |
| 240 | unmap_file( &textfile ); | 254 | for( i=0; i<textfiles_count; ++i ) |
| 255 | unmap_file( &(textfiles[i].map) ); | ||
| 256 | |||
| 241 | return 0; | 257 | return 0; |
| 242 | } | 258 | } |
