ack/modules/src/em_code/insert.c
1988-07-08 15:31:32 +00:00

365 lines
6.3 KiB
C

/* $Header$ */
/* Implementation of C_insertpart, C_beginpart, and C_endpart.
Basic methodology: place the parts either in memory or on a temporary
file, in the order received, and remember this order. Then, in a second
"pass", write out the code.
An optimization is possible: as long as the order in which the parts
are received corresponds to the order in which they must be written,
they can be written immediately.
*/
#include <alloc.h>
#include "insert.h"
#ifndef INCORE
static int
getbyte(b)
long b;
{
/* Get the byte at offset "b" from the start of the
temporary file, and try to do so in an efficient way.
*/
static long start_core, curr_pos;
if (b < start_core || b >= curr_pos) {
/* the block wanted is not in core, so get it */
long nb = (b & ~(BUFSIZ - 1));
int n;
C_flush();
if (nb != curr_pos) {
if (sys_seek(C_tfr, nb, 0, &curr_pos) == 0) {
C_failed();
}
}
if (! C_ibuf) {
C_ibuf = Malloc(BUFSIZ);
}
if (sys_read(C_tfr, C_ibuf, BUFSIZ, &n) == 0) {
C_failed();
}
curr_pos += n;
start_core = nb;
}
return C_ibuf[(int) (b - start_core)];
}
#endif
static C_out_parts();
static Part *C_findpart();
outpart(id)
int id;
{
/* Output part "id", if present.
*/
Part *p = C_findpart(id);
if (p) C_out_parts(p->p_parts);
}
static
C_out_parts(pp)
register PartOfPart *pp;
{
/* Output the list of chunks started by "pp".
The list is build in reverse order, so this routine is
recursive.
*/
PartOfPart *prev = 0, *next;
while (pp) {
next = pp->pp_next;
pp->pp_next = prev;
prev = pp;
pp = next;
}
pp = prev;
while (pp) {
if (pp->pp_type == INSERT) {
(*C_outpart)(pp->pp_id);
}
else {
/* copy the chunk to output */
#ifdef INCORE
register char *s = C_BASE + pp->pp_begin;
char *se = C_BASE + pp->pp_end;
while (s < se) {
put(*s++);
}
#else
register long b = pp->pp_begin;
while (b < pp->pp_end) {
put(getbyte(b++));
}
#endif
}
pp = pp->pp_next;
}
}
static Part *
C_findpart(part)
int part;
{
/* Look for part "part" in the table.
Return 0 if not present,
*/
register Part *p = C_stable[part % TABSIZ];
while (p && p->p_id != part) {
p = p->p_next;
}
return p;
}
static
swttmp()
{
#ifndef INCORE
if (C_tmpfile == 0) {
static char tmpbuf[64];
register char *p = tmpbuf;
extern char *mktemp();
strcpy(p, C_tmpdir);
strcat(p, "/CodeXXXXXX");
C_tmpfile = mktemp(p);
if (! sys_open(p, OP_WRITE, &C_old_ofp)) {
C_failed();
}
if (! sys_open(p, OP_READ, &C_tfr)) {
C_failed();
}
}
if (! C_ontmpfile) {
File *p = C_ofp;
C_flush();
C_ofp = C_old_ofp;
C_old_ofp = p;
C_ontmpfile = 1;
}
#else
if (! C_ontmpfile) {
char *p;
p = C_opp;
C_opp = C_old_opp;
C_old_opp = p;
p = C_top;
C_top = C_old_top;
C_old_top = p;
C_ontmpfile = 1;
}
#endif
}
static
swtout()
{
#ifndef INCORE
if (C_ontmpfile) {
File *p = C_ofp;
C_flush();
C_ofp = C_old_ofp;
C_old_ofp = p;
C_ontmpfile = 0;
}
#else
if (C_ontmpfile) {
char *p;
p = C_opp;
C_opp = C_old_opp;
C_old_opp = p;
p = C_top;
C_top = C_old_top;
C_old_top = p;
C_ontmpfile = 0;
}
#endif
}
static int
available(part)
int part;
{
/* See if part "part", and all the parts it consists of,
are available. Return 1 if they are, 0 otherwize
*/
register Part *p = C_findpart(part);
register PartOfPart *pp;
int retval = 1;
if (p == 0) return 0;
if (p->p_flags & BUSY) {
/* recursive call ends up here, and this just should
not happen. It is an error of the programmer using
this module.
*/
C_internal_error();
}
p->p_flags |= BUSY;
pp = p->p_parts;
while (pp) {
if (pp->pp_type == INSERT && ! available(pp->pp_id)) {
retval = 0;
break;
}
else pp = pp->pp_next;
}
p->p_flags &= ~BUSY;
return retval;
}
static Part *
mkpart(part)
int part;
{
/* Create a Part structure with id "part", and return a
pointer to it, after checking that is does not exist
already.
*/
register Part *p = C_findpart(part);
register int index = part % TABSIZ;
if (p != 0) {
/* multiple defined part ... */
C_internal_error();
}
p = (Part *) Malloc(sizeof(Part));
p->p_id = part;
p->p_next = C_stable[index];
C_stable[index] = p;
p->p_parts = 0;
p->p_flags = 0;
p->p_prevpart = 0;
return p;
}
static
end_partofpart(p)
register Part *p;
{
/* End the current chunk of part *p.
*/
if (p) {
register PartOfPart *pp = p->p_parts;
pp->pp_end = C_current_out - C_BASE;
if (pp->pp_begin == pp->pp_end) {
/* nothing in this chunk, so give it back */
p->p_parts = pp->pp_next;
free((char *) pp);
}
}
}
static
resume(p)
register Part *p;
{
/* Resume part "p", by creating a new PartOfPart structure
for it.
*/
register PartOfPart *pp = (PartOfPart *) Malloc(sizeof(PartOfPart));
swttmp();
C_curr_part = p;
pp->pp_next = p->p_parts;
p->p_parts = pp;
pp->pp_type = TEXT;
pp->pp_begin = C_current_out - C_BASE;
}
C_insertpart(part)
int part;
{
/* Insert part "part" in the current part. If C_sequential is
still set and the part to be inserted is available now,
just write it out.
*/
register Part *p;
register PartOfPart *pp;
C_outpart = outpart;
C_swttmp = swttmp;
C_swtout = swtout;
if (C_sequential && available(part)) {
outpart(part);
return;
}
if (C_sequential) {
/* stop the sequential stuff, by creating a part */
C_sequential = 0;
p = mkpart(0);
C_curr_part = p;
}
else {
p = C_curr_part;
end_partofpart(p);
}
/* Now, add the insertion of "part" to the current part. */
pp = (PartOfPart *) Malloc(sizeof(PartOfPart));
pp->pp_next = p->p_parts;
p->p_parts = pp;
pp->pp_type = INSERT;
pp->pp_id = part;
resume(p);
}
C_beginpart(part)
int part;
{
/* Now follows the definition for part "part".
Suspend the current part, and add part "part" to the
table.
*/
register Part *p = mkpart(part);
C_outpart = outpart;
C_swttmp = swttmp;
C_swtout = swtout;
end_partofpart(C_curr_part);
p->p_prevpart = C_curr_part;
resume(p);
}
C_endpart(part)
int part;
{
/* End the current part. The parameter "part" is just there
for the checking. Do we really need it ???
*/
register Part *p = C_curr_part;
if (p->p_id != part) {
/* illegal C_endpart ... */
C_internal_error();
}
end_partofpart(p);
if (p->p_prevpart) resume(p->p_prevpart);
else {
C_curr_part = 0;
swtout();
}
}