#include #include #include #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; }