diff options
-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 | } |