
/* 
 * $Copyright:	$
 * Copyright (c) 1984, 1985, 1986, 1987, 1988, 1989, 1990 
 * Sequent Computer Systems, Inc.   All rights reserved.
 *  
 * This software is furnished under a license and may be used
 * only in accordance with the terms of that license and with the
 * inclusion of the above copyright notice.   This software may not
 * be provided or otherwise made available to, or used by, any
 * other person.  No title to or ownership of the software is
 * hereby transferred.
 */

/*	Copyright (c) 1984 AT&T	*/
/*	  All Rights Reserved  	*/

/*	THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T	*/
/*	The copyright notice above does not evidence any   	*/
/*	actual or intended publication of such source code.	*/
#ident "$Header: act.c 1.1 90/01/19 $@(#)act.c	1.1 89/12/01"
#include "xs.h"
#include "names.h"
#include "stack.h"
#include "types.h"
#include "anal.h"
#include "xdefs.h"
#include "act.h"

/*
 * Build actions lists for the input file edition and perform them
 * all together.
 */
typedef struct act {
  long act_offset;
  int act_len;
  char act_act;
  bool act_intern;
  long act_r_offset;
  int  act_r_len;
  struct act *act_next;
} ACT;

static struct act_buf {
  struct act_buf *act_next;
} *act_st, *tab_start;

long act_find();
long act_find_first();

extern char *gettxt();

/*
 * Caution : actions values are sorted in order of execution
 */
#define ACT_REPLACE	0
#define ACT_INSERT	1
#define ACT_APPEND	2

static ACT **act_tab;
static char loc_buf[BUFSIZ];
static FILE *ext;

act_start()
{
  register int i;
  
  if (act_st != 0){
    act_tab = (ACT **)tab_start;
    tab_start = tab_start->act_next;
  } else {
    if ((act_tab = (ACT **)malloc(sizeof(ACT *) * ACT_TAB_LEN)) == 0)
      fatal(gettxt("xs:1","act_creat: malloc failed"));
  }
  for (i = 0 ; i < ACT_TAB_LEN ; i++)
    act_tab[i] = 0;

  if (ext != 0)
    fclose(ext);

  if ((ext = tmpfile()) == NULL)
    fatal(gettxt("xs:2","act_creat: tempfile() failed"));
}

act_free()
{
  register int i;
  struct act_buf *ptr2;

  if (act_tab == 0)
    return;
  
  for (i = 0 ; i < ACT_TAB_LEN ; i++){
    if (act_tab[i] != 0){
      ACT *ptr = act_tab[i];
      while (ptr != 0){
        ACT *old;
        old = ptr;
        ptr = ptr->act_next;
        ptr2 = (struct act_buf *)old;
        ptr2->act_next = act_st;
        act_st = ptr2;
      }
    }
  }
  ptr2 = (struct act_buf *)act_tab;
  ptr2->act_next = tab_start;
  tab_start = ptr2;
  fclose(ext);
  ext = 0;
}

act_e_replace(off, len, format, a, b, c, d, e, f)
  long off;
  int len;
  char *format, *a, *b, *c, *d, *e, *f;
{
  int r_len =  sprintf(loc_buf, format, a, b, c, d, e, f);

  act_new(off, len, ACT_REPLACE, 0L, r_len, FALSE);
}

act_e_insert(off, format, a, b, c, d, e, f)
  long off;
  char *format, *a, *b, *c, *d, *e, *f;
{
  int r_len =  sprintf(loc_buf, format, a, b, c, d, e, f);

  act_new(off, 0, ACT_INSERT, 0L, r_len, FALSE);
}

act_e_append(off, format, a, b, c, d, e, f)
  long off;
  char *format, *a, *b, *c, *d, *e, *f;
{
  int r_len =  sprintf(loc_buf, format, a, b, c, d, e, f);

  act_new(off, 0, ACT_APPEND, 0L, r_len, FALSE);
}

act_i_append(off, r_off, r_len)
  long off, r_off;
  int r_len;
{
  act_new(off, 0, ACT_APPEND, r_off, r_len, TRUE);
}

act_new(off, len, act, r_off, r_len, intern)
  long off, r_off;
  int len, r_len;
  char act;
  bool intern;
{
  ACT *new = (ACT *)malloc(sizeof(ACT));
  ACT *ptr, *prev;
  int pos;
  
  if (new == 0)
    fatal(gettxt("xs:3","act_new: malloc failed"));
  new->act_offset = off;
  new->act_len = len;
  new->act_act = act;
  new->act_next = 0;
  new->act_intern = intern;

  if (!intern){
    new->act_r_offset = ftell(ext);
    if (fwrite(loc_buf, 1, r_len, ext) != r_len)
      fatal(gettxt("xs:4","act_new: write error"));
    new->act_r_len = ftell(ext) - new->act_r_offset;
  } else {
    new->act_r_len = r_len;
    new->act_r_offset = r_off;
  }
  pos = off % ACT_TAB_LEN;

  prev = ptr = act_tab[pos];
  while (ptr != 0){
    long curoff;
    if ((curoff=ptr->act_offset) > off || curoff == off && (act == 0 || 
    	 ptr->act_act > act)){
      new->act_next = ptr;
      if (ptr == act_tab[pos])
        act_tab[pos] = new;
      else
        prev->act_next = new;
      return;
    } else {
      prev = ptr;
      ptr = ptr->act_next;
      continue;
    }
  }
  if (prev == 0)
    act_tab[pos] = new;
  else
    prev->act_next = new;
}  

act_do()
{
  act_do1(0L, lastoff);
}

act_do1(s_off, e_off)
  long s_off, e_off;
{
  long curoff = act_find_first(s_off);
  long nextoff;
  bool appendfirst, replace;
  ACT *ptr;
  
  if (curoff >= e_off){
#ifdef i386
    act_copy(fd_in, s_off, e_off - s_off - 1);
#else
    act_copy(fd_in, s_off, e_off - s_off);
#endif
    return;
  }
  act_copy(fd_in, s_off, curoff - s_off);
  
  while (curoff < e_off){
    appendfirst = TRUE;
    replace = FALSE;
    ptr = act_tab[curoff % ACT_TAB_LEN];
    while (ptr->act_offset != curoff)
      ptr = ptr->act_next;
    while (ptr != 0 && ptr->act_offset == curoff){
      switch(ptr->act_act){
      case ACT_REPLACE:
        act_copy(ext, ptr->act_r_offset, ptr->act_r_len);
        curoff += ptr->act_len;
        replace = TRUE;
        ptr->act_act = -1;
        break;
      case ACT_INSERT:
        act_copy(ext, ptr->act_r_offset, ptr->act_r_len);
        ptr->act_act = -1;
        ptr = ptr->act_next;
        continue;
      case ACT_APPEND:
        if (appendfirst){
          act_copy(fd_in, curoff, 1);
          appendfirst = FALSE;
        }
        if (ptr->act_intern){
          ptr->act_act = -1;
	  act_do1(ptr->act_r_offset, ptr->act_r_offset + ptr->act_r_len + 1);
	} else
	  act_copy(ext, ptr->act_r_offset, ptr->act_r_len);
        ptr->act_act = -1;
        ptr = ptr->act_next;
	continue;
      default:
        ptr = ptr->act_next;
        continue;
      }
      break;
    }
    nextoff = (*(replace ? act_find_first : act_find))(curoff);
    if (!appendfirst)
      curoff++;
    if (nextoff >= e_off){
      act_copy(fd_in, curoff, e_off - curoff - 1);
      return;
    } else
      act_copy(fd_in, curoff, nextoff - curoff);
    curoff = nextoff;
  }
}

static
act_copy(fd, off, len)
  FILE *fd;
  long off;
  int len;
{
  register int n;
  
  if (fseek(fd, off, 0) != 0)
    fatal(gettxt("xs:5","act_copy: seek error"));
  /*
   * Use n instead of slen only because last length in input file 
   * is one char too long (there was a getchar for the EOF)
   * Subtract slen from len anyway to avoid an infinite loop
   */
  while (len > 0){
    int slen;
    slen = len > BUFSIZ ? BUFSIZ : len;
    n = fread(loc_buf, 1, slen, fd);
    if (fwrite(loc_buf, 1, n, fd_out) != n)
      fatal(gettxt("xs:6","act_copy: write error"));
    len -= slen;
  }
}
    
static long
act_find(s_off)
  long s_off;
{
  long max = lastoff;
  register int i;
  
  for (i = 0 ; i < ACT_TAB_LEN ; i++){
    ACT *ptr;

    ptr = act_tab[i];
    while (ptr != 0 && (ptr->act_act == -1 || ptr->act_offset <= s_off))
      ptr = ptr->act_next;

    if (ptr == 0)
      continue;

    if (ptr->act_offset < max)
      max = ptr->act_offset;
  }
  return max;
}

static long
act_find_first(s_off)
  long s_off;
{
  long max = lastoff;
  register int i;
  
  for (i = 0 ; i < ACT_TAB_LEN ; i++){
    ACT *ptr;

    ptr = act_tab[i];
    while (ptr != 0 && (ptr->act_act == -1 || ptr->act_offset < s_off))
      ptr = ptr->act_next;

    if (ptr == 0)
      continue;

    if (ptr->act_offset < max)
      max = ptr->act_offset;
  }
  return max;
}
