-
-
Save Maxdamantus/2e344f688d9715490cb0ea6dd6ffb8bd to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdlib.h> | |
#include <stdio.h> | |
#include <string.h> | |
#include <unistd.h> | |
#include <fcntl.h> | |
#define BUFSZ 8192 | |
static const char *const less = "/usr/bin/less"; | |
static int unicodedatafd = -1; | |
static long datasize, dataseek, imaginaryseek; | |
static struct { | |
size_t s; | |
unsigned char v[BUFSZ]; | |
long dataoffset; | |
} buf; | |
static int ensureready(char *fn){ | |
unicodedatafd = open(fn, O_RDONLY); | |
if(unicodedatafd < 0) | |
exit(1); | |
return (dataseek = datasize = lseek(unicodedatafd, 0, SEEK_END)) > 0; | |
} | |
static int fillbuf(void){ | |
int rs; | |
if(dataseek != imaginaryseek) | |
if((dataseek = lseek(unicodedatafd, imaginaryseek, SEEK_SET)) < 0) | |
return 0; | |
buf.s = 0; | |
rs = read(unicodedatafd, buf.v, BUFSZ); | |
if(rs < 1) | |
return 0; | |
buf.s = rs; | |
buf.dataoffset = dataseek; | |
return 1; | |
} | |
static int getcurchar(void){ | |
if(!buf.s || imaginaryseek < buf.dataoffset || imaginaryseek >= buf.dataoffset + buf.s) | |
if(!fillbuf()) | |
return -1; | |
return buf.v[imaginaryseek - buf.dataoffset]; | |
} | |
static int readchar(void){ | |
int c = getcurchar(); | |
if(c < 0) | |
return -1; | |
imaginaryseek++; | |
return c; | |
} | |
static int skiptonextline(void){ | |
int c; | |
if(imaginaryseek == -1){ | |
imaginaryseek = 0; | |
return 1; | |
} | |
while((c = readchar()) > 0) | |
if(c == '\n') | |
return 1; | |
return 0; | |
} | |
int compare(char *key){ | |
for(;;){ | |
if(!*key) | |
return 0; | |
int c = readchar(); | |
if(c < 0) | |
return -1; | |
if(c != *(unsigned char *)key) | |
return *(unsigned char *)key - c; | |
else | |
key++; | |
} | |
} | |
int lookup(char *key, long *out){ | |
long min = 0, max; | |
max = datasize; | |
int ret = 0; | |
while(max >= min){ | |
long mid = (max + min)/2; | |
imaginaryseek = mid - 1; | |
skiptonextline(); | |
long linestart = imaginaryseek; | |
int cmp = compare(key); | |
//fprintf(stderr, "%li > %li; mid = %li; cmp = %i\n", max, min, mid, cmp); | |
ret = cmp == 0; | |
if(cmp > 0) | |
min = mid + 1; | |
else if(cmp < 0) | |
max = mid - 1; | |
else if(max != mid) | |
max = mid; | |
else{ | |
min = linestart; | |
break; | |
} | |
} | |
*out = min; | |
return ret; | |
} | |
int main(int argc, char **argv){ | |
if(argc < 1) | |
return -1; | |
int exact = 0; | |
int prefix = 0; | |
int printnotfound = 0; | |
int exit = 0; | |
int readstdin = 0; | |
int plainargs = 0; | |
int execless = 0; | |
int first = 1; | |
char *fn = 0; | |
for(int x = 1; x < argc + readstdin; x++){ | |
if(plainargs || x >= argc); | |
else if(!strcmp(argv[x], "-e")){ | |
exact = !exact; | |
continue; | |
}else if(!strcmp(argv[x], "-w")){ | |
printnotfound = !printnotfound; | |
continue; | |
}else if(!strcmp(argv[x], "-p")){ | |
prefix = !prefix; | |
continue; | |
}else if(!strcmp(argv[x], "-i")){ | |
readstdin = 1; | |
continue; | |
}else if(!strcmp(argv[x], "-l")){ | |
execless = 1; | |
continue; | |
}else if(!strcmp(argv[x], "--")){ | |
plainargs = 1; | |
continue; | |
} | |
if(first){ | |
if(x > argc){ | |
fprintf(stderr, "too few arguments\n"); | |
return -1; | |
} | |
if(!ensureready(fn = argv[x])) | |
return -1; | |
first = 0; | |
continue; | |
} | |
char *needle; | |
char buf[1024]; | |
if(x < argc) | |
needle = argv[x]; | |
else{ | |
if(!fgets(buf, sizeof buf, stdin)) | |
continue; | |
size_t len = strlen(buf); | |
if(buf[len - 1] != '\n'){ | |
fprintf(stderr, "line too long\n"); | |
int c; | |
do | |
c = getchar(); | |
while(c != EOF && c != '\n'); | |
if(c == '\n') | |
x--; | |
continue; | |
} | |
x--; | |
buf[len - 1] = '\0'; | |
needle = buf; | |
} | |
long pos; | |
int found = lookup(needle, &pos); | |
exit = exit || !found; | |
if(prefix){ | |
imaginaryseek = pos; | |
for(;;){ | |
int shouldbreak = 0; | |
long line = imaginaryseek; | |
int cmp = compare(needle); | |
if(cmp != 0) | |
break; | |
imaginaryseek = line; | |
for(;;){ | |
int c = readchar(); | |
shouldbreak = c <= 0; | |
if(shouldbreak || c == '\n') | |
break; | |
putchar(c); | |
} | |
if(shouldbreak) | |
break; | |
putchar('\n'); | |
} | |
}else if(found || !exact){ | |
if(execless){ | |
close(unicodedatafd); | |
char lesscmd[1024]; | |
snprintf(lesscmd, sizeof lesscmd, "++%liP", pos); | |
lesscmd[sizeof lesscmd - 1] = 0; | |
execv(less, (char *[]){ "less", "-n", lesscmd, fn, 0 }); | |
perror("execv"); | |
return 1; | |
} | |
imaginaryseek = pos; | |
for(;;){ | |
int c = readchar(); | |
if(c <= 0 || c == '\n') | |
break; | |
putchar(c); | |
} | |
putchar('\n'); | |
} | |
if(printnotfound && !found) | |
fprintf(stderr, "not found: %s\n", needle); | |
} | |
close(unicodedatafd); | |
return exit; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment