119 lines
2.5 KiB
C
119 lines
2.5 KiB
C
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <math.h>
|
|
#include <assert.h>
|
|
|
|
int grep(char pattern[]);
|
|
|
|
/* grep with graceful buffer overflow */
|
|
/* parse and verify arg pattern, pass it to grep */
|
|
int main(int argc, char *argv[])
|
|
{
|
|
/* verify arg is given */
|
|
if (argc < 2) {
|
|
printf("error: excpected pattern\n");
|
|
return -1;
|
|
}
|
|
|
|
char *pattern = argv[1];
|
|
|
|
/* verify pattern */
|
|
char c;
|
|
int i;
|
|
for (i = 0; (c = pattern[i]) != '\0'; i++)
|
|
if (c == '\n') {
|
|
printf("error: newline in pattern\n");
|
|
return -2;
|
|
}
|
|
|
|
int found = grep(pattern);
|
|
printf("found = %d\n", found);
|
|
return found;
|
|
}
|
|
|
|
void println(void);
|
|
int flush_lnbuff(void);
|
|
int getch_lnbuff(void);
|
|
|
|
/* grep: prints lines containing pattern, returns number of matching lines */
|
|
int grep(char *pattern)
|
|
{
|
|
int found, i, c;
|
|
const int plen = strlen(pattern);
|
|
|
|
i = found = 0;
|
|
|
|
while ((c = getch_lnbuff()) != EOF)
|
|
if (c != pattern[i])
|
|
i = 0;
|
|
else if (++i == plen) { // found match
|
|
i = 0;
|
|
found++;
|
|
flush_lnbuff();
|
|
println();
|
|
}
|
|
return found;
|
|
}
|
|
|
|
/* println: prints next line from stdin
|
|
* prints newline on EOF */
|
|
void println()
|
|
{
|
|
int c;
|
|
while ((c = getchar()) != EOF && c != '\n')
|
|
putchar(c);
|
|
putchar(c);
|
|
}
|
|
|
|
/* ------------------------ line buffer ---------------------- */
|
|
|
|
#define LNBUFF_LEN 128
|
|
|
|
/* the line buffer lenght must be a power of two */
|
|
static_assert(!(LNBUFF_LEN % 2), "Line buffer length is not a power of two!");
|
|
|
|
/* line_buffer: global overflowing line buffer */
|
|
struct {
|
|
char self[LNBUFF_LEN];
|
|
unsigned len;
|
|
} lnbuff = {.len= 0};
|
|
|
|
/* LNBUFF_I: current index in line buffer */
|
|
#define LNBUFF_I (lnbuff.len & (LNBUFF_LEN - 1))
|
|
|
|
/* getch_lnbuff: getchar and add it to buffer */
|
|
int getch_lnbuff()
|
|
{
|
|
int c = getchar();
|
|
|
|
if (c == EOF || c == '\n') // new line
|
|
lnbuff.len = 0;
|
|
else {
|
|
lnbuff.self[LNBUFF_I] = c;
|
|
lnbuff.len++;
|
|
}
|
|
|
|
return c;
|
|
}
|
|
|
|
/* flush_lnbuff: print contents of line buffer, return length */
|
|
int flush_lnbuff()
|
|
{
|
|
int i;
|
|
|
|
/* handle overflowing chars */
|
|
if (lnbuff.len > LNBUFF_LEN) {
|
|
for (i = LNBUFF_LEN; i < lnbuff.len; i++)
|
|
putchar('.');
|
|
for (i = LNBUFF_I; i < LNBUFF_LEN; i++)
|
|
putchar(lnbuff.self[i]);
|
|
}
|
|
/* handle rest of chars */
|
|
for (i = 0; i < LNBUFF_I; i++)
|
|
putchar(lnbuff.self[i]);
|
|
|
|
i = lnbuff.len;
|
|
lnbuff.len = 0;
|
|
return i;
|
|
}
|