Navigation Menu

Skip to content

Instantly share code, notes, and snippets.

@skeeto
Created August 1, 2022 22:14
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save skeeto/5cafad10171d6a757d45ef5268f24c43 to your computer and use it in GitHub Desktop.
Save skeeto/5cafad10171d6a757d45ef5268f24c43 to your computer and use it in GitHub Desktop.
Finder over a file descriptor
#include <stdio.h>
#include <string.h>
#include <unistd.h>
struct finder {
long long lineno;
unsigned char *needle;
size_t nlen, noff;
size_t hlen, hoff;
int fd;
unsigned char haystack[1<<14]; // may be smaller than the needle
};
static void
finder_init(struct finder *f, int fd, const void *needle, size_t len)
{
f->needle = (unsigned char *)needle;
f->nlen = len;
f->noff = 0;
f->hlen = 0;
f->hoff = 0;
f->lineno = 0;
f->fd = fd;
}
static unsigned char
xlower(unsigned char c)
{
return c + ((c >= 'A' && c <= 'Z') << 5);
}
// Return the line number of the next instance of the needle, zero for
// EOF, and -1 on error.
static long long
finder_next(struct finder *f)
{
for (;;) {
while (f->hoff < f->hlen) {
unsigned char c = xlower(f->haystack[f->hoff++]);
if (c == '\n') {
int ismatch = f->noff == f->nlen;
f->lineno++;
f->noff = 0;
if (ismatch) {
return f->lineno;
}
} else if (f->noff < f->nlen && c == xlower(f->needle[f->noff])) {
f->noff++;
} else {
f->noff = (size_t)-1;
}
}
int r = read(f->fd, f->haystack, sizeof(f->haystack));
switch (r) {
case -1: return -1;
case 0: return 0;
default: f->hoff = 0;
f->hlen = r;
}
}
}
int
main(int argc, char **argv)
{
struct finder f[1];
finder_init(f, 0, argv[argc-1], strlen(argv[argc-1]));
for (;;) {
long long lineno = finder_next(f);
switch (lineno) {
case -1: return 1;
case 0: fflush(stdout);
return ferror(stdout);
default: printf("%lld\n", lineno);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment