typedef enum {
UNKNOWN, DOS_BINARY, DOS_TEXT, UNIX_TEXT
} File_type;
struct dos_map {
off_t pos;
off_t add;
};
static int dos_report_unix_offset = 0;
static File_type dos_file_type = UNKNOWN;
static File_type dos_use_file_type = UNKNOWN;
static off_t dos_stripped_crs = 0;
static struct dos_map *dos_pos_map;
static int dos_pos_map_size = 0;
static int dos_pos_map_used = 0;
static int inp_map_idx = 0, out_map_idx = 1;
static inline File_type
guess_type (char *buf, register size_t buflen)
{
int crlf_seen = 0;
register char *bp = buf;
while (buflen--)
{
if (!*bp)
return DOS_BINARY;
else if (*bp == '\r' && buflen && bp[1] == '\n')
crlf_seen = 1;
bp++;
}
return crlf_seen ? DOS_TEXT : UNIX_TEXT;
}
static inline int
undossify_input (register char *buf, size_t buflen)
{
int chars_left = 0;
if (totalcc == 0)
{
inp_map_idx = 0;
out_map_idx = 1;
dos_pos_map_used = 0;
dos_stripped_crs = 0;
dos_file_type = dos_use_file_type;
}
if (dos_file_type == UNKNOWN)
dos_file_type = guess_type(buf, buflen);
if (dos_file_type == DOS_TEXT)
{
char *destp = buf;
while (buflen--)
{
if (*buf != '\r')
{
*destp++ = *buf++;
chars_left++;
}
else
{
buf++;
if (out_byte && !dos_report_unix_offset)
{
dos_stripped_crs++;
while (buflen && *buf == '\r')
{
dos_stripped_crs++;
buflen--;
buf++;
}
if (inp_map_idx >= dos_pos_map_size - 1)
{
dos_pos_map_size = inp_map_idx ? inp_map_idx * 2 : 1000;
dos_pos_map =
(struct dos_map *)xrealloc((char *)dos_pos_map,
dos_pos_map_size *
sizeof(struct dos_map));
}
if (!inp_map_idx)
{
dos_pos_map[inp_map_idx].pos = 0;
dos_pos_map[inp_map_idx++].add = 0;
dos_pos_map[inp_map_idx].add = 0;
}
inp_map_idx++;
dos_pos_map[inp_map_idx-1].pos =
(*buf == '\n' ? destp + 1 : destp ) - bufbeg + totalcc;
dos_pos_map[inp_map_idx].add = dos_stripped_crs;
dos_pos_map_used = inp_map_idx;
dos_pos_map[inp_map_idx].pos = destp - bufbeg + totalcc + 1;
}
}
}
return chars_left;
}
return buflen;
}
static inline off_t
dossified_pos (off_t byteno)
{
off_t pos_lo;
off_t pos_hi;
if (dos_file_type != DOS_TEXT || dos_report_unix_offset)
return byteno;
pos_lo = dos_pos_map[out_map_idx-1].pos;
pos_hi = dos_pos_map[out_map_idx].pos;
if (byteno >= pos_hi)
{
out_map_idx++;
while (out_map_idx < dos_pos_map_used &&
byteno >= dos_pos_map[out_map_idx].pos)
out_map_idx++;
}
else if (byteno < pos_lo)
{
out_map_idx--;
while (out_map_idx > 1 && byteno < dos_pos_map[out_map_idx-1].pos)
out_map_idx--;
}
return byteno + dos_pos_map[out_map_idx].add;
}