summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--el.c160
1 files changed, 88 insertions, 72 deletions
diff --git a/el.c b/el.c
index 40dccbd..518b3a7 100644
--- a/el.c
+++ b/el.c
@@ -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. 11typedef 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.
16static 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
20static 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;
25static 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
62static unsigned char * scanforline( MAP file, const long lineno, long *size ) { 70static 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]; 118return_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
174static void usage() { 173static 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
178int main( int argc, char **argv ) { 177int 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}