Files
Arquivotheca.SunOS-4.1.4/usr.lib/libsuntool/text/es_util.c
seta75D ff309bfe1c Init
2021-10-11 18:37:13 -03:00

227 lines
5.9 KiB
C

#ifndef lint
#ifdef sccs
static char sccsid[] = "@(#)es_util.c 1.1 94/10/31";
#endif
#endif
/*
* Copyright (c) 1986, 1987 by Sun Microsystems, Inc.
*/
/*
* Utilities for use with entity streams.
*/
#include <suntool/primal.h>
#include <suntool/entity_stream.h>
extern Es_index
es_bounds_of_gap(esh, around, last_plus_one, flags)
register Es_handle esh;
Es_index around;
Es_index *last_plus_one;
int flags;
/* If there is no gap, then around == return value == *last_plus_one.
* Else, if not looking for the start of the gap (flags & 0x1 == 0),
* around < return value == *last_plus_one.
* Else, if looking for the start of the gap,
* return value <= around <= *last_plus_one
* (return value will be ES_CANNOT_SET if gap extends from 0 on).
*/
{
#define BUFSIZE 32
char buf[BUFSIZE+4];
int count_read;
register Es_index new_pos, low, high, probe;
low = es_set_position(esh, around);
new_pos = es_read(esh, 1, buf, &count_read);
if (count_read == 0) {
low = new_pos;
}
if (last_plus_one)
*last_plus_one = low;
if ((low != around) && (flags & 0x1) &&
!READ_AT_EOF(around, new_pos, count_read)) {
/* Try binary search to locate the start of the gap.
* Invariants for loop:
* 0 <= low <= start of gap <= high <= around
* low < probe = (high + low) / 2 < high
* Essentially, choose a probe point and try to read. 3 cases:
* 1) new_pos < around: null, partial or full read
* => low = new_pos;
* if low >=high, gap starts at probe+count_read
* 2) new_pos > around: null read
* => high = probe
* 3) new_pos > around: partial read
* => gap starts at probe+count_read
* "new_pos == around || (new_pos > around: full read)"
* impossible as there is gap
*/
low = 0;
high = around;
while (low+1 < high) {
probe = es_set_position(esh, (high+low)/2);
new_pos = es_read(esh, BUFSIZE, buf, &count_read);
if (new_pos < around) {
if (new_pos >= high) {
low = probe+count_read;
break;
} else {
low = new_pos;
}
} else if (count_read == 0) {
high = probe;
} else {
low = probe+count_read;
break;
}
}
if (low == 0) {
probe = es_set_position(esh, 0);
new_pos = es_read(esh, BUFSIZE, buf, &count_read);
if (count_read == 0)
low == ES_CANNOT_SET;
}
}
return(low);
#undef BUFSIZE
}
/* Caller must make sure that esbuf->last_plus_one is the current position
* in the entity stream.
*/
extern int
es_advance_buf(esbuf)
Es_buf_handle esbuf;
{
int read = 0;
register Es_index next = esbuf->last_plus_one;
while (read == 0) {
esbuf->first = next;
next = es_read(esbuf->esh, esbuf->sizeof_buf, esbuf->buf, &read);
esbuf->last_plus_one = esbuf->first + read;
if READ_AT_EOF(esbuf->first, next, read) {
return(1);
}
}
return(0);
}
extern Es_index
es_backup_buf(esbuf)
Es_buf_handle esbuf;
{
/* Move buffer back in stream (i.e., change so that esbuf->first is smaller).
* Backing the buffer up is complicated by possible gap before the current
* beginning of the buffer.
* This routine moves over such a gap.
*/
register Es_index prev;
register Es_index esi = esbuf->first-1;
Retry:
switch (es_make_buf_include_index(esbuf, esi, esbuf->sizeof_buf-1)) {
case 0:
break;
case 2:
prev = esi;
esi = es_bounds_of_gap(esbuf->esh, prev, 0, 0x1);
if (esi != ES_CANNOT_SET && esi < prev) {
goto Retry;
}
/* else gap extends back to 0 OR unexpected error
* => fall through.
*/
case 1:
default: /* Conservative in face of new cases */
esi = ES_CANNOT_SET;
break;
}
return(esi);
}
/* esbuf->first and ->last_plus_one are only adjusted when entities are
* actually read. This makes it easier for callers to figure out how to
* correct after failure to re-position a buffer.
* Returns:
* 0 iff it managed to align the buffer as requested,
* 1 if read at end of stream while trying to align,
* 2 if desired entity is in a "hole" in the stream.
*/
extern int
es_make_buf_include_index(esbuf, index, desired_prior_count)
register Es_buf_handle esbuf;
Es_index index;
int desired_prior_count;
{
register Es_index last_plus_one, next;
int read;
last_plus_one = (desired_prior_count > index) ? 0
: index - desired_prior_count;
es_set_position(esbuf->esh, last_plus_one);
FOREVER {
next = es_read(esbuf->esh, esbuf->sizeof_buf, esbuf->buf, &read);
if READ_AT_EOF(last_plus_one, next, read)
return(1);
esbuf->first = last_plus_one;
esbuf->last_plus_one = last_plus_one+read;
if (next > index) {
if (esbuf->last_plus_one < index) {
return(2);
} else
return(0);
}
last_plus_one = next;
}
}
extern Es_status
es_copy(from, to, newline_must_terminate)
register Es_handle from, to;
int newline_must_terminate;
{
#define BUFSIZE 2096
char buf[BUFSIZE+4];
register Es_status result;
int read, write;
Es_index new_pos, pos, to_pos;
/* Find start of "from" (it need not actually be 0, e.g. secondary
* pieces that compose a selection)
*/
pos = es_set_position(from, 0);
write = 0;
/* Cannot just "es_replace(to, ES_INFINITY, ...)" in case not copying
* at the end of "to", so get (and maintain) current position in "to".
*/
to_pos = es_get_position(to);
FOREVER {
new_pos = es_read(from, BUFSIZE, buf, &read);
if (read > 0) {
to_pos = es_replace(to, to_pos, read, buf, &write);
if (write < read) {
result = ES_SHORT_WRITE;
return(result);
}
} else if (pos == new_pos)
break;
pos = new_pos;
}
if (newline_must_terminate && (
(write <= 0) || (write > sizeof(buf)) ||
(buf[write-1] != '\n') )) {
buf[0] = '\n';
(void) es_replace(to, ES_INFINITY, 1, buf, &write);
if (write < 1) {
result = ES_SHORT_WRITE;
return(result);
}
}
result = es_commit(to);
return(result);
#undef BUFSIZE
}