/*
* 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 <ac/ctype.h>
#include <ac/string.h>
#include <fcheck.h>
#include <input/private.h>
#include <mem.h>
#include <trace.h>
#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 <cmalloc.h>
/*
* 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;
}
}
syntax highlighted by Code2HTML, v. 0.9.1