133 lines
4.1 KiB
C
133 lines
4.1 KiB
C
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <assert.h>
|
|
|
|
#define BUFF_BITS 10
|
|
#define BUFF_SIZE (1 << BUFF_BITS)
|
|
|
|
/* buffered_ln: structure for buffered input line */
|
|
struct buffered_ln {
|
|
unsigned long lineno; /* line number */
|
|
unsigned int len; /* line length */
|
|
|
|
char self[BUFF_SIZE]; /* line buffer */
|
|
int last_char; /* last read char of line
|
|
when equals to EOF or \n the line
|
|
has been read to completion */
|
|
};
|
|
|
|
void init_bln(struct buffered_ln *);
|
|
int get_bln(struct buffered_ln *);
|
|
void flush_bln(struct buffered_ln *);
|
|
int sub_of_bln(const char *pattern, struct buffered_ln *, unsigned plen);
|
|
|
|
/* find: finds occurences of pattern in input lines */
|
|
int find(char *pattern, char lineno_flag, char except_flag)
|
|
{
|
|
size_t plen = strlen(pattern);
|
|
if (plen-1 > BUFF_SIZE) {
|
|
printf("error: length of pattern > max line\n");
|
|
return -1;
|
|
}
|
|
|
|
struct buffered_ln bln;
|
|
init_bln(&bln);
|
|
|
|
while (get_bln(&bln))
|
|
if (sub_of_bln(pattern, &bln, plen) == !except_flag) {
|
|
if (lineno_flag)
|
|
printf("%ld:", bln.lineno);
|
|
flush_bln(&bln);
|
|
}
|
|
}
|
|
|
|
/* init_bln: initalizes buffered line struct */
|
|
void init_bln(struct buffered_ln *bln)
|
|
{
|
|
bln->lineno = 0;
|
|
bln->len = 0;
|
|
bln->last_char = '\n';
|
|
}
|
|
|
|
#define OVERFLOW_MASK (~0 << BUFF_BITS)
|
|
#define INDEX_MASK (~OVERFLOW_MASK)
|
|
#define bln_i(i) ((i) & INDEX_MASK) /* casts unsigned integer i to a valid bln index */
|
|
|
|
#define overflowed_bln(bln) (bln->len & OVERFLOW_MASK) /* 1 if bln is overflowed */
|
|
/* eol_bln: 1 if bln si finalized (last_char is \n or EOF) */
|
|
#define eol_bln(bln) (bln->last_char == EOF || bln->last_char == '\n')
|
|
#define bln_next_i(bln) bln_i(bln->len) /* next writable index of bln */
|
|
#define bln_start_i(bln) (overflowed_bln(bln) ? bln_next_i(bln) : 0) /* starting index of bln */
|
|
|
|
/* getchar_bln: gets char from input and writes it to bln, returns it */
|
|
#define getchar_bln(bln) \
|
|
(bln->self[bln_next_i(bln)] = bln->last_char, ++bln->len, bln->last_char = getchar())
|
|
|
|
/* get_bln: skips current line in buffer line bln, sets bln to next line of input
|
|
* returns 0 on EOF and a postivie value otherwise */
|
|
int get_bln(struct buffered_ln *bln)
|
|
{
|
|
/* finalize previous line */
|
|
while (!eol_bln(bln))
|
|
bln->last_char = getchar();
|
|
if (bln->last_char == EOF)
|
|
return 0;
|
|
/* init next line */
|
|
bln->lineno++;
|
|
bln->len = 0;
|
|
return (bln->last_char = getchar()) != EOF;
|
|
}
|
|
|
|
/* flush_bln: flushes buffered line bln to stdout */
|
|
void flush_bln(struct buffered_ln *bln)
|
|
{
|
|
unsigned i;
|
|
/* print overflowed chars */
|
|
if (overflowed_bln(bln)) {
|
|
for (i = BUFF_SIZE; i < bln->len; i++)
|
|
putchar('.');
|
|
for (i = bln_next_i(bln); i < BUFF_SIZE; i++)
|
|
putchar(bln->self[i]);
|
|
}
|
|
/* print buffered chars */
|
|
for (i = 0; i < bln_next_i(bln); i++)
|
|
putchar(bln->self[i]);
|
|
/* print not yet read chars */
|
|
for (; !eol_bln(bln); bln->last_char = getchar())
|
|
putchar(bln->last_char);
|
|
putchar('\n');
|
|
}
|
|
|
|
/* sub_of_bln: returns 0 if pattern with length plen is not a substring of
|
|
* buffered line bln and a positive value otherwise */
|
|
int sub_of_bln(const char *pattern, struct buffered_ln *bln, const unsigned plen)
|
|
{
|
|
/* buffered line must not be overflowed */
|
|
assert(!overflowed_bln(bln));
|
|
|
|
/* fill buffer with plen-1 chars */
|
|
for (; bln->len < plen-1; getchar_bln(bln))
|
|
if (eol_bln(bln))
|
|
return 0;
|
|
|
|
unsigned i, j;
|
|
int k;
|
|
/* handle buffered chars */
|
|
for (i = plen-1; i < bln->len; i++) {
|
|
for (j = i, k = plen-1; k >= 0 && bln->self[j] == pattern[k]; k--, j--)
|
|
;
|
|
if (k < 0)
|
|
return 1;
|
|
}
|
|
/* handle no yet read chars */
|
|
for (; !eol_bln(bln); getchar_bln(bln)) {
|
|
if (bln->last_char != pattern[plen-1])
|
|
continue;
|
|
for (j = bln_i(bln_next_i(bln)-1), k = plen-2; k >=0 && bln->self[j] == pattern[k]; k--, j = bln_i(j-1))
|
|
;
|
|
if (k < 0)
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|