/* * fhist - file history and comparison tools * Copyright (C) 2000-2002 Peter Miller; * All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA. * * MANIFEST: functions for reading input */ #include #include #include #include #include #include #ifdef input_name #undef input_name #endif const char * input_name(input_ty *fp) { const char *result; trace(("input_name(fp = %8.8lX)\n{\n", (long)fp)); result = fp->vptr->name(fp); trace(("return \"%s\";\n", result)); trace(("}\n")); return result; } #ifdef input_length #undef input_length #endif long input_length(input_ty *fp) { long result; trace(("input_length(fp = %8.8lX)\n{\n", (long)fp)); result = fp->vptr->length(fp); trace(("return %ld;\n", result)); trace(("}\n")); return result; } #ifdef input_ftell #undef input_ftell #endif long input_ftell(input_ty *fp) { long result; trace(("input_ftell(fp = %8.8lX)\n{\n", (long)fp)); result = fp->vptr->ftell(fp) - fp->pushback_len; trace(("return %ld;\n", result)); trace(("}\n")); return result; } #ifdef input_read #undef input_read #endif long input_read(input_ty *fp, void *data, long len) { long result; trace(("input_read(fp = %8.8lX, data = %8.8lX, len = %8.8lX)\n{\n", (long)fp, (long)data, len)); if (len <= 0) { result = 0; } else { if (fp->pushback_len > 0) { fp->pushback_len--; *(char *)data = fp->pushback_buf[fp->pushback_len]; result = 1; } else { result = fp->vptr->read(fp, data, len); } } trace(("return %ld;\n", result)); trace(("}\n")); return result; } #ifdef DEBUG static char * unctrl(int c) { static char buffer[10]; if (c < 0 || c >= 256) { snprintf(buffer, sizeof(buffer), "%d", c); return buffer; } switch (c) { case '\'': case '\\': escape: buffer[0] = '\''; buffer[1] = '\\'; buffer[2] = c; buffer[3] = '\''; buffer[4] = 0; break; case '\b': c = 'b'; goto escape; case '\f': c = 'f'; goto escape; case '\n': c = 'n'; goto escape; case '\r': c = 'r'; goto escape; case '\t': c = 't'; goto escape; default: if (isprint((unsigned char)c)) { buffer[0] = '\''; buffer[1] = c; buffer[2] = '\''; buffer[3] = 0; } else snprintf(buffer, sizeof(buffer), "'\\%o'", c); break; } return buffer; } #endif #ifdef input_getc #undef input_getc #endif int input_getc(input_ty *fp) { int result; trace(("input_getc(fp = %8.8lX)\n{\n", (long)fp)); if (fp->pushback_len > 0) { fp->pushback_len--; result = fp->pushback_buf[fp->pushback_len]; } else result = fp->vptr->get(fp); trace(("return %s;\n", unctrl(result))); trace(("}\n")); return result; } #ifdef input_ungetc #undef input_ungetc #endif void input_ungetc(input_ty *fp, int c) { trace(("input_ungetc(fp = %8.8lX, c = %s)\n{\n", (long)fp, unctrl(c))); if (c >= 0) { if (fp->pushback_len >= fp->pushback_max) { fp->pushback_max = 16 + 2 * fp->pushback_max; fp->pushback_buf = mem_change_size(fp->pushback_buf, fp->pushback_max); } fp->pushback_buf[fp->pushback_len++] = c; } trace(("}\n")); } void input_delete(input_ty *fp) { trace(("input_delete(fp = %8.8lX)\n{\n", (long)fp)); if (fp->vptr->destruct) fp->vptr->destruct(fp); if (fp->pushback_buf) mem_free(fp->pushback_buf); fp->pushback_buf = 0; fp->pushback_len = 0; fp->pushback_max = 0; fp->vptr = 0; /* paranoia */ mem_free(fp); trace(("}\n")); } #include /* * Routine to read in the next line from a file, no matter how long it is. * This returns a pointer to the string, and also indirectly its length. * The string is normally returned from a static string, which is reused * for each call. But if keep is non-zero, then the returned string * belongs to the caller and must later be freed. The returned line * is ended with a newline and null character, but the returned length * does not count the null character. Returns 0 on an error, with the * error stored in the fp structure. */ char * input_readline(input_ty *fp, long *retlen, int keep, int *is_bin_file) { char *dp; /* destination pointer */ size_t totallen; /* total length of data */ static char *linebuffer; /* common line buffer */ static size_t linelength; /* total length of line */ trace(("input_readline(fp = %8.8lX, retlen = %8.8lX, keep = %d)\n{\n", (long)fp, (long)retlen, keep)); if (linelength == 0) { /* allocate line buffer */ linelength = 16; linebuffer = r_alloc_and_check(linelength + 1); } totallen = 0; for (;;) { int c = input_getc(fp); if (c < 0) { if (totallen == 0) return 0; warning_last_line_unterminated(input_name(fp)); c = '\n'; } if (c == 0) { *is_bin_file = 1; c = 0x80; } if (totallen >= linelength) { /* * doubling gives O(1) behaviour * over the life of the prog */ linelength = linelength * 2 + 16; linebuffer = r_realloc_and_check(linebuffer, linelength + 1); } linebuffer[totallen++] = c; if (c == '\n') break; } linebuffer[totallen] = 0; if (retlen) *retlen = totallen; if (!keep) dp = linebuffer; else { dp = cm_alloc_and_check(totallen + 1); memcpy(dp, linebuffer, (size_t)totallen); } trace(("return %8.8lX;\n", (long)dp)); trace(("}\n")); return dp; } void input_skip_lines(input_ty *fp, int numlines) { while (numlines > 0) { int c = input_getc(fp); if (c < 0) break; if (c == '\n') --numlines; } }