Category : C Source Code
Archive   : OLEO130S.ZIP
Filename : OLEO130S.TAR

 
Output of file : OLEO130S.TAR contained in archive : OLEO130S.ZIP
oleo-1.3/ 755 722 0 0 5356470565 10421 5ustar lordwheeloleo-1.3/parse.y 644 722 0 42503 5322364526 12021 0ustar lordwheel%{
/* Copyright (C) 1990, 1992, 1993 Free Software Foundation, Inc.

This file is part of Oleo, the GNU Spreadsheet.

Oleo 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, or (at your option)
any later version.

Oleo 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 Oleo; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
%}


%right '?' ':'
/* %left '|' */
%left '&'
%nonassoc '=' NE
%nonassoc '<' LE '>' GE
%left '+' '-'
%left '*' '/' '%'
%right '^'
%left NEG '!'

%token L_CELL L_RANGE
%token L_VAR

%token L_CONST
%token L_FN0 L_FN1 L_FN2 L_FN3 L_FN4 L_FNN
%token L_FN1R L_FN2R L_FN3R L_FN4R L_FNNR

%token L_LE L_NE L_GE

%{
#include "funcdef.h"

#include

#define obstack_chunk_alloc ck_malloc
#define obstack_chunk_free free
#include "obstack.h"
#include "sysdef.h"

#include "global.h"
#include "errors.h"
#include "node.h"
#include "eval.h"
#include "ref.h"

int yylex ();
#ifdef __STDC__
void yyerror (char *);
#else
void yyerror ();
#endif
VOIDSTAR parse_hash;
extern VOIDSTAR hash_find();

/* This table contains a list of the infix single-char functions */
unsigned char fnin[] = {
SUM, DIFF, DIV, PROD, MOD, /* AND, OR, */ POW, EQUAL, IF, CONCAT, 0
};

#define YYSTYPE _y_y_s_t_y_p_e
typedef struct node *YYSTYPE;
YYSTYPE parse_return;
#ifdef __STDC__
YYSTYPE make_list (YYSTYPE, YYSTYPE);
#else
YYSTYPE make_list ();
#endif

char *instr;
int parse_error = 0;
extern struct obstack tmp_mem;

%}
%%
line: exp
{ parse_return=$1; }
| error {
if(!parse_error)
parse_error=PARSE_ERR;
parse_return=0; }
;

exp: L_CONST
| cell
| L_FN0 '(' ')' {
$$=$1; }
| L_FN1 '(' exp ')' {
($1)->n_x.v_subs[0]=$3;
($1)->n_x.v_subs[1]=(struct node *)0;
$$=$1; }
| L_FN2 '(' exp ',' exp ')' {
($1)->n_x.v_subs[0]=$3;
($1)->n_x.v_subs[1]=$5;
$$=$1; }
| L_FN3 '(' exp ',' exp ',' exp ')' {
($1)->n_x.v_subs[0]=make_list($3,$5);
($1)->n_x.v_subs[1]=$7;
$$=$1;}
| L_FN4 '(' exp ',' exp ',' exp ',' exp ')' {
($1)->n_x.v_subs[0]=make_list($3,$5);
($1)->n_x.v_subs[1]=make_list($7,$9);
$$=$1;}
| L_FNN '(' exp_list ')' {
($1)->n_x.v_subs[0]=(struct node *)0;
($1)->n_x.v_subs[1]=$3;
$$=$1; }
| L_FN1R '(' L_RANGE ')' {
$1->n_x.v_subs[0]=$3;
$$=$1; }
| L_FN1R '(' L_VAR ')' {
$1->n_x.v_subs[0]=$3;
$$=$1; }

| L_FN2R '(' L_RANGE ',' exp ')' {
$1->n_x.v_subs[0]=$3;
$1->n_x.v_subs[1]=$5;
$$=$1; }
| L_FN2R '(' L_VAR ',' exp ')' {
$1->n_x.v_subs[0]=$3;
$1->n_x.v_subs[1]=$5;
$$=$1; }

/* JF: These should be FN2R, but I'm hacking this for SYLNK */
| L_FN2R '(' L_RANGE ',' exp ',' exp ')' {
if($1->comp_value!=F_INDEX)
parse_error=PARSE_ERR;
$1->comp_value=F_INDEX2;
$1->n_x.v_subs[0]=make_list($3,$5);
$1->n_x.v_subs[1]=$7;
$$=$1; }
| L_FN2R '(' L_VAR ',' exp ',' exp ')' {
if($1->comp_value!=F_INDEX)
parse_error=PARSE_ERR;
$1->comp_value=F_INDEX2;
$1->n_x.v_subs[0]=make_list($3,$5);
$1->n_x.v_subs[1]=$7;
$$=$1; }

| L_FN3R '(' L_RANGE ',' exp ',' exp ')' {
($1)->n_x.v_subs[0]=make_list($3,$5);
($1)->n_x.v_subs[1]=$7;
$$=$1;}
| L_FN3R '(' L_VAR ',' exp ',' exp ')' {
($1)->n_x.v_subs[0]=make_list($3,$5);
($1)->n_x.v_subs[1]=$7;
$$=$1;}

| L_FNNR '(' range_exp_list ')' {
($1)->n_x.v_subs[0]=(struct node *)0;
($1)->n_x.v_subs[1]=$3;
$$=$1; }
| exp '?' exp ':' exp {
$2->comp_value=IF;
$2->n_x.v_subs[0]=$4;
$2->n_x.v_subs[1]=$5;
$4->n_x.v_subs[0]=$1;
$4->n_x.v_subs[1]=$3;
$$=$2; }
/* | exp '|' exp {
$2->n_x.v_subs[0]=$1;
$2->n_x.v_subs[1]=$3;
$$ = $2; } */
| exp '&' exp {
$2->n_x.v_subs[0]=$1;
$2->n_x.v_subs[1]=$3;
$$ = $2; }
| exp '<' exp {
$2->n_x.v_subs[0]=$1;
$2->n_x.v_subs[1]=$3;
$$ = $2; }
| exp LE exp {
$2->n_x.v_subs[0]=$1;
$2->n_x.v_subs[1]=$3;
$$ = $2; }
| exp '=' exp {
$2->n_x.v_subs[0]=$1;
$2->n_x.v_subs[1]=$3;
$$ = $2; }
| exp NE exp {
$2->n_x.v_subs[0]=$1;
$2->n_x.v_subs[1]=$3;
$$ = $2; }
| exp '>' exp {
$2->n_x.v_subs[0]=$1;
$2->n_x.v_subs[1]=$3;
$$ = $2; }
| exp GE exp {
$2->n_x.v_subs[0]=$1;
$2->n_x.v_subs[1]=$3;
$$ = $2; }
| exp '+' exp {
$2->n_x.v_subs[0]=$1;
$2->n_x.v_subs[1]=$3;
$$ = $2; }
| exp '-' exp {
$2->n_x.v_subs[0]=$1;
$2->n_x.v_subs[1]=$3;
$$ = $2; }
| exp '*' exp {
$2->n_x.v_subs[0]=$1;
$2->n_x.v_subs[1]=$3;
$$ = $2; }
| exp '/' exp {
$2->n_x.v_subs[0]=$1;
$2->n_x.v_subs[1]=$3;
$$ = $2; }
| exp '%' exp {
$2->n_x.v_subs[0]=$1;
$2->n_x.v_subs[1]=$3;
$$ = $2; }
| exp '^' exp {
$2->n_x.v_subs[0]=$1;
$2->n_x.v_subs[1]=$3;
$$ = $2; }
| '-' exp %prec NEG {
if($2->comp_value==CONST_FLT) {
$2->n_x.v_float= -($2->n_x.v_float);
/* free($1); */
$$=$2;
} else if($2->comp_value==CONST_INT) {
$2->n_x.v_int= -($2->n_x.v_int);
/* free($1); */
$$=$2;
} else {
$1->comp_value = NEGATE;
$1->n_x.v_subs[0]=$2;
$1->n_x.v_subs[1]=(struct node *)0;
$$ = $1;
} }
| '!' exp {
$1->n_x.v_subs[0]=$2;
$1->n_x.v_subs[1]=(struct node *)0;
$$ = $1; }
| '(' exp ')'
{ $$ = $2; }
| '(' exp error {
if(!parse_error)
parse_error=NO_CLOSE;
}
/* | exp ')' error {
if(!parse_error)
parse_error=NO_OPEN;
} */
| '(' error {
if(!parse_error)
parse_error=NO_CLOSE;
}
;


exp_list: exp
{ $$ = make_list($1, 0); }
| exp_list ',' exp
{ $$ = make_list($3, $1); }
;

range_exp: L_RANGE
| exp
;

range_exp_list: range_exp
{ $$=make_list($1, 0); }
| range_exp_list ',' range_exp
{ $$=make_list($3,$1); }
;

cell: L_CELL
{ $$=$1; }
| L_VAR
;
%%

void
yyerror FUN1(char *, s)
{
if(!parse_error)
parse_error=PARSE_ERR;
}

YYSTYPE
make_list FUN2(YYSTYPE, car, YYSTYPE, cdr)
{
YYSTYPE ret;

ret=(YYSTYPE)obstack_alloc(&tmp_mem,sizeof(*ret));
ret->comp_value = 0;
ret->n_x.v_subs[0]=car;
ret->n_x.v_subs[1]=cdr;
return ret;
}

#define ERROR -1

extern struct node *yylval;

#ifdef __STDC__
unsigned char parse_cell_or_range (char **,struct rng *);
int str_to_col (char ** str);
#else
unsigned char parse_cell_or_range ();
#endif

int
yylex FUN0()
{
int ch;
struct node *new;
int isflt;
char *begin;
char *tmp_str;
unsigned char byte_value;
int n;

/* unsigned char *ptr; */
int nn;
struct function *fp;
int tmp_ch;

#ifdef TEST
if(!instr)
return ERROR;
#endif
while(isspace(*instr))
instr++;
ch = *instr++;
if(ch=='(' || ch==',' || ch==')')
return ch;

new=(struct node *)obstack_alloc(&tmp_mem,sizeof(struct node));
new->add_byte=0;
new->sub_value=0;
switch(ch) {
case 0:
return 0;

case '0': case '1': case '2': case '3': case '4': case '5': case '6':
case '7': case '8': case '9': case '.':
isflt = (ch=='.');

begin=instr-1;
tmp_str=instr;

while(isdigit(*tmp_str) || (!isflt && *tmp_str=='.' && ++isflt))
tmp_str++;
if(*tmp_str=='e' || *tmp_str=='E') {
isflt=1;
tmp_str++;
if(*tmp_str=='-' || *tmp_str=='+')
tmp_str++;
while(isdigit(*tmp_str))
tmp_str++;
}
if(isflt) {
new->n_x.v_float=astof((char **)(&begin));
byte_value=CONST_FLT;
} else {
new->n_x.v_int=astol((char **)(&begin));
if(begin!=tmp_str) {
begin=instr-1;
new->n_x.v_float=astof((char **)(&begin));
byte_value=CONST_FLT;
} else
byte_value=CONST_INT;
}
ch=L_CONST;
instr=begin;
break;

case '"':
begin=instr;
while(*instr && *instr!='"') {
if(*instr=='\\' && instr[1])
instr++;
instr++;
}
if(!*instr) {
parse_error=NO_QUOTE;
return ERROR;
}
tmp_str=new->n_x.v_string=(char *)ck_malloc(1+instr-begin);
while(begin!=instr) {
unsigned char n;

if(*begin=='\\') {
begin++;
if(begin[0]>='0' && begin[0]<='7') {
if(begin[1]>='0' && begin[1]<='7') {
if(begin[2]>='0' && begin[2]<='7') {
n=(begin[2]-'0') + (010 * (begin[1]-'0')) + ( 0100 * (begin[0]-'0'));
begin+=3;
} else {
n=(begin[1]-'0') + (010 * (begin[0]-'0'));
begin+=2;
}
} else {
n=begin[0]-'0';
begin++;
}
} else
n= *begin++;
*tmp_str++= n;
} else
*tmp_str++= *begin++;
}
*tmp_str='\0';
instr++;
byte_value=CONST_STR;
ch=L_CONST;
break;

case '+': case '-':

case '*': case '/': case '%': case '&':
/* case '|': */ case '^': case '=':

case '?':
{
unsigned char *ptr;

for(ptr= fnin;*ptr;ptr++)
if(the_funs[*ptr].fn_str[0]==ch)
break;
#ifdef TEST
if(!*ptr)
panic("Can't find fnin[] entry for '%c'",ch);
#endif
byte_value= *ptr;
}
break;

case ':':
byte_value=IF;
break;

case '!':
case '<':
case '>':
if(*instr!='=') {
byte_value = (ch=='<') ? LESS : (ch=='>') ? GREATER : NOT;
break;
}
instr++;
byte_value = (ch=='<') ? LESSEQ : (ch=='>') ? GREATEQ : NOTEQUAL;
ch = (ch=='<') ? LE : (ch=='>') ? GE : NE;
break;

case '\'':
case ';':
case '[':
case '\\':
case ']':
case '`':
case '{':
case '}':
case '~':
bad_chr:
parse_error=BAD_CHAR;
return ERROR;

case '#':
begin=instr-1;
while(*instr && (isalnum(*instr) || *instr=='_'))
instr++;
ch= *instr;
*instr=0;
if(!stricmp(begin,tname))
byte_value=F_TRUE;
else if(!stricmp(begin,fname))
byte_value=F_FALSE;
else if(!stricmp(begin,iname) && (begin[4]==0 || !stricmp(begin+4,"inity")))
byte_value=CONST_INF;
else if(!stricmp(begin,mname) ||
!stricmp(begin,"#ninf"))
byte_value=CONST_NINF;
else if(!stricmp(begin,nname) ||
!stricmp(begin,"#nan"))
byte_value=CONST_NAN;
else {
for(n=1;n<=ERR_MAX;n++)
if(!stricmp(begin,ename[n]))
break;
if(n>ERR_MAX)
n=BAD_CHAR;
new->n_x.v_int=n;
byte_value=CONST_ERR;
}
*instr=ch;
ch=L_CONST;
break;

default:
if(!a0 && (ch=='@' || ch=='$'))
goto bad_chr;

if(a0 && ch=='@') {
begin=instr;
while(*instr && (isalpha(*instr) || isdigit(*instr) || *instr=='_'))
instr++;
n=instr-begin;
} else {
begin=instr-1;
byte_value=parse_cell_or_range(&begin,&(new->n_x.v_rng));
if(byte_value) {
if((byte_value& ~0x3)==R_CELL)
ch=L_CELL;
else
ch=L_RANGE;
instr=begin;
break;
}

while(*instr && (isalpha(*instr) || isdigit(*instr) || *instr=='_'))
instr++;

n=instr-begin;
while(isspace(*instr))
instr++;

if(*instr!='(') {
ch=L_VAR;
byte_value=VAR;
new->n_x.v_var=find_or_make_var(begin,n);
break;
}
}
tmp_ch=begin[n];
begin[n]='\0';
fp=hash_find(parse_hash,begin);
begin[n]=tmp_ch;
byte_value= ERROR;
if(!fp) {
parse_error=BAD_FUNC;
return ERROR;
}

if(fp>=the_funs && fp<=&the_funs[USR1])
byte_value=fp-the_funs;
else {
for(nn=0;nn if(fp>=&usr_funs[nn][0] && fp<=&usr_funs[nn][usr_n_funs[nn]]) {
byte_value=USR1+nn;
new->sub_value=fp-&usr_funs[nn][0];
break;
}
}
#ifdef TEST
if(nn==n_usr_funs) {
io_error_msg("Couln't turn fp into a ##");
parse_error=BAD_FUNC;
return ERROR;
}
#endif
}

if(fp->fn_argn&X_J)
ch= byte_value==F_IF ? L_FN3 : L_FN2;
else if(fp->fn_argt[0]=='R' || fp->fn_argt[0]=='E')
ch=L_FN1R-1+fp->fn_argn-X_A0;
else
ch=L_FN0 + fp->fn_argn-X_A0;

break;
}
/* new->node_type=ch; */
new->comp_value=byte_value;
yylval=new;
return ch;
}

/* Return value is
0 if it doesn't look like a cell or a range,
R_CELL if it is a cell (ptr now points past the characters, lr and lc hold the row and col of the cell)
RANGE if it is a range (ptr points past the chars)
*/
unsigned char
parse_cell_or_range FUN2(char **,ptr, struct rng *,retp)
{
if(a0) {
unsigned tmpc,tmpr;
char *p;
int abz = ROWREL|COLREL;

p= *ptr;
tmpc=0;
if(*p=='$') {
abz-=COLREL;
p++;
}
if(!isalpha(*p))
return 0;
tmpc=str_to_col(&p);
if(tmpcMAX_COL)
return 0;
if(*p=='$') {
abz-=ROWREL;
p++;
}
if(!isdigit(*p))
return 0;
for(tmpr=0;isdigit(*p);p++)
tmpr=tmpr*10 + *p - '0';

if(tmprMAX_ROW)
return 0;

if(*p==':' || *p=='.') {
unsigned tmpc1,tmpr1;

abz = ((abz&COLREL) ? LCREL : 0)|((abz&ROWREL) ? LRREL : 0)|HRREL|HCREL;
p++;
if(*p=='$') {
abz-=HCREL;
p++;
}
if(!isalpha(*p))
return 0;
tmpc1=str_to_col(&p);
if(tmpc1MAX_COL)
return 0;
if(*p=='$') {
abz-=HRREL;
p++;
}
if(!isdigit(*p))
return 0;
for(tmpr1=0;isdigit(*p);p++)
tmpr1=tmpr1*10 + *p - '0';
if(tmpr1MAX_ROW)
return 0;

if(tmpr retp->lr=tmpr;
retp->hr=tmpr1;
} else {
retp->lr=tmpr1;
retp->hr=tmpr;
}
if(tmpc retp->lc=tmpc;
retp->hc=tmpc1;
} else {
retp->lc=tmpc1;
retp->hc=tmpc;
}
*ptr= p;
return RANGE | abz;
}
retp->lr = retp->hr = tmpr;
retp->lc = retp->hc = tmpc;
*ptr=p;
return R_CELL | abz;
} else {
char *p;
unsigned char retr;
unsigned char retc;
int ended;
long num;
CELLREF tmp;

#define CK_ABS_R(x) ((x)MAX_ROW)

#define CK_REL_R(x) (((x)>0 && MAX_ROW-(x) || ((x)<0 && MIN_ROW-(x)>cur_row))

#define CK_ABS_C(x) ((x)MAX_COL)

#define CK_REL_C(x) (((x)>0 && MAX_COL-(x) || ((x)<0 && MIN_COL-(x)>cur_col))

#define MAYBEREL(p) (*(p)=='[' && (isdigit((p)[1]) || (((p)[1]=='+' || (p)[1]=='-') && isdigit((p)[2]))))

p= *ptr;
retr=0;
retc=0;
ended=0;
while(ended==0) {
switch(*p) {
case 'r':
case 'R':
if(retr) {
ended++;
break;
}
p++;
retr=R_CELL;
if(isdigit(*p)) {
num=astol(&p);
if (CK_ABS_R(num))
return 0;
retp->lr= retp->hr=num;
} else if(MAYBEREL(p)) {
p++;
num=astol(&p);
if (CK_REL_R(num))
return 0;
retp->lr= retp->hr=num+cur_row;
retr|=ROWREL;
if(*p==':') {
retr=RANGE|LRREL|HRREL;
p++;
num=astol(&p);
if (CK_REL_R(num))
return 0;
retp->hr=num+cur_row;
}
if(*p++!=']')
return 0;
} else if(retc || *p=='c' || *p=='C') {
retr|=ROWREL;
retp->lr= retp->hr=cur_row;
} else
return 0;
if(*p==':' && retr!=(RANGE|LRREL|HRREL)) {
retr= (retr&ROWREL) ? RANGE|LRREL : RANGE;
p++;
if(isdigit(*p)) {
num=astol(&p);
if (CK_ABS_R(num))
return 0;
retp->hr=num;
} else if(MAYBEREL(p)) {
p++;
num=astol(&p);
if (CK_REL_R(num))
return 0;
retp->hr=num+cur_row;
retr|=HRREL;
if(*p++!=']')
return 0;
} else
return 0;
}

if(retc)
ended++;
break;

case 'c':
case 'C':
if(retc) {
ended++;
break;
}
p++;
retc=R_CELL;
if(isdigit(*p)) {
num=astol(&p);
if (CK_ABS_C(num))
return 0;
retp->lc= retp->hc=num;
} else if(MAYBEREL(p)) {
p++;
num=astol(&p);
if (CK_REL_C(num))
return 0;
retp->lc= retp->hc=num+cur_col;
retc|=COLREL;
if(*p==':') {
retc=RANGE|LCREL|HCREL;
p++;
num=astol(&p);
if (CK_REL_C(num))
return 0;
retp->hc=num+cur_col;
}
if(*p++!=']')
return 0;
} else if(retr || *p=='r' || *p=='R') {
retc|=COLREL;
retp->lc= retp->hc=cur_col;
} else
return 0;
if(*p==':' && retc!=(RANGE|LCREL|HCREL)) {
retc= (retc&COLREL) ? RANGE|LCREL : RANGE;
p++;
if(isdigit(*p)) {
num=astol(&p);
if (CK_ABS_C(num))
return 0;
retp->hc=num;
} else if(MAYBEREL(p)) {
p++;
num=astol(&p);
if (CK_REL_C(num))
return 0;
retp->hc=num+cur_col;
retc|=HCREL;
if(*p++!=']')
return 0;
} else
return 0;
}

if(retr)
ended++;
break;
default:
if(retr) {
*ptr=p;
retp->lc=MIN_COL;
retp->hc=MAX_COL;
if((retr|ROWREL)==(R_CELL|ROWREL))
return (retr&ROWREL) ? (RANGE|LRREL|HRREL) : RANGE;
else
return retr;
} else if(retc) {
*ptr=p;
retp->lr=MIN_ROW;
retp->hr=MAX_COL;
if((retc|COLREL)==(R_CELL|COLREL))
return (retc&COLREL) ? (RANGE|LCREL|HCREL) : RANGE;
else
return retc;
}
return 0;
}
}
if(!retr || !retc)
return 0;
*ptr=p;
if(retp->lr>retp->hr)
tmp=retp->lr,retp->lr=retp->hr,retp->hr=tmp;
if(retp->lc>retp->hc)
tmp=retp->lc,retp->lc=retp->hc,retp->hc=tmp;

if((retr|ROWREL)==(R_CELL|ROWREL)) {
if((retc|COLREL)==(R_CELL|COLREL))
return retr|retc;
return (retr&ROWREL) ? (retc|LRREL|HRREL) : retc;
}
if((retc|COLREL)==(R_CELL|COLREL))
return (retc&COLREL) ? (retr|LCREL|HCREL) : retr;
return retr|retc;
}
}

int
str_to_col FUN1(char **,str)
{
int ret;
char c,cc,ccc;
#if MAX_COL>702
char cccc;
#endif

ret=0;
c=str[0][0];
if(!isalpha((cc=str[0][1]))) {
(*str)++;
return MIN_COL + (isupper(c) ? c-'A' : c-'a');
}
if(!isalpha((ccc=str[0][2]))) {
(*str)+=2;
return MIN_COL+26 + (isupper(c) ? c-'A' : c-'a')*26 + (isupper(cc) ? cc-'A' : cc-'a');
}
#if MAX_COL>702
if(!isalpha((cccc=str[0][3]))) {
(*str)+=3;
return MIN_COL+702 + (isupper(c) ? c-'A' : c-'a')*26*26 + (isupper(cc) ? cc-'A' : cc-'a')*26 + (isupper(ccc) ? ccc-'A' : ccc-'a');
}
if(!isalpha(str[0][4])) {
(*str)+=4;
return MIN_COL+18278 + (isupper(c) ? c-'A' : c-'a')*26*26*26 + (isupper(cc) ? cc-'A' : cc-'a')*26*26 + (isupper(ccc) ? ccc-'A' : ccc-'a')*26 + (isupper(cccc) ? cccc-'A' : cccc-'a');
}
#endif
return 0;
}
oleo-1.3/byte-compile.c 644 722 0 53402 5352265345 13254 0ustar lordwheel/* Copyright (C) 1990, 1992, 1993 Free Software Foundation, Inc.

This file is part of Oleo, the GNU Spreadsheet.

Oleo 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, or (at your option)
any later version.

Oleo 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 Oleo; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */

#include "funcdef.h"
#include

#define obstack_chunk_alloc ck_malloc
#define obstack_chunk_free free
#include "obstack.h"

#include "sysdef.h"
#include "global.h"
#include "node.h"
#include "eval.h"
#include "math.h"
#include "hash.h"
#include "ref.h"


#ifdef __STDC__
extern int yyparse (void);
#else
extern int yyparse ();
#endif

extern struct function busi_funs[];
extern struct function string_funs[];
extern struct function cells_funs[];
extern char *instr;
extern int parse_error;
extern struct node *parse_return;
extern void sort ();


#ifdef __STDC__
static void add_backpatch (unsigned, unsigned);
#else
static void add_backpatch ();
#endif

struct backpatch
{
unsigned from, to;
};

static struct backpatch *patches;
static int patches_allocated;
static int patches_used;
static void *fn_stack;
static void *str_stack;
struct obstack tmp_mem;
void *tmp_mem_start;


#define V (void(*)())

/* These have to go in some file or other, so it is stuck in here (for now).
*/
struct function the_funs[] =
{
{0, X_A0, "", 0, ""},
{0, X_A0, "", 0, ""},

{C_IF | R | INF (1), X_A1 | X_J, "D", 0, "?"},
{C_IF | R | INF (1), X_A1 | X_JL, "D", 0, "?"},
{C_IF, X_A1 | X_J, "D", 0, "if"},
{C_IF, X_A1 | X_JL, "D", 0, "if"},
{C_ANDOR, X_A1 | X_J, "D", 0, "and"},
/* { C_ANDOR|L|INF(3), X_A1, "DD", 0, "&" }, */
{C_ANDOR, X_A1 | X_JL, "D", 0, "and"},
/* { C_ANDOR|L|INF(3), X_A1, "DD", 0, "&" }, */
{C_ANDOR, X_A1 | X_J, "D", 0, "or"},
/* { C_ANDOR|L|INF(2), X_A1, "DD", 0, "|" }, */
{C_ANDOR, X_A1 | X_JL, "D", 0, "or"},
/* { C_ANDOR|L|INF(2), X_A1, "DD", 0, "|" }, */
{C_STR, X_A0 | X_J, "", 0, "\"%s\""},
{C_STR, X_A0 | X_JL, "", 0, "\"%s\""},

{C_CELL, X_A0, "", 0, "$%s$%u"},
{C_CELL, X_A0, "", 0, "$%s%u"},
{C_CELL, X_A0, "", 0, "%s$%u"},
{C_CELL, X_A0, "", 0, "%s%u"},
{C_RANGE, X_A0, "", 0, "$%s$%u:$%s$%u"},
{C_RANGE, X_A0, "", 0, "$%s%u:$%s$%u"},
{C_RANGE, X_A0, "", 0, "$%s$%u:$%s%u"},
{C_RANGE, X_A0, "", 0, "$%s%u:$%s%u"},
{C_RANGE, X_A0, "", 0, "%s$%u:$%s$%u"},
{C_RANGE, X_A0, "", 0, "%s%u:$%s$%u"},
{C_RANGE, X_A0, "", 0, "%s$%u:$%s%u"},
{C_RANGE, X_A0, "", 0, "%s%u:$%s%u"},
{C_RANGE, X_A0, "", 0, "$%s$%u:%s$%u"},
{C_RANGE, X_A0, "", 0, "$%s%u:%s$%u"},
{C_RANGE, X_A0, "", 0, "$%s$%u:%s%u"},
{C_RANGE, X_A0, "", 0, "$%s%u:%s%u"},
{C_RANGE, X_A0, "", 0, "%s$%u:%s$%u"},
{C_RANGE, X_A0, "", 0, "%s%u:%s$%u"},
{C_RANGE, X_A0, "", 0, "%s$%u:%s%u"},
{C_RANGE, X_A0, "", 0, "%s%u:%s%u"},

{C_CONST, X_A0, "", 0, tname},
{C_CONST, X_A0, "", 0, fname},

{C_CONST, X_A0, "", 0, iname},
{C_CONST, X_A0, "", 0, mname},
{C_CONST, X_A0, "", 0, nname},
{C_ERR, X_A0 | X_J, "", 0, "%s"},
{C_FLT, X_A0, "", 0, "%.15g"},
{C_INT, X_A0, "", 0, "%ld"},

{C_VAR, X_A0, "", 0, "%s"},

{C_UNA, X_A1, "F", 0, "-"},
{C_UNA, X_A1, "B", 0, "!"},

{C_INF | L | INF (6), X_A2, "NN", 0, "-"},
{C_INF | L | INF (7), X_A2, "NN", 0, "/"},
{C_INF | L | INF (7), X_A2, "NN", 0, "%"},
{C_INF | L | INF (7), X_A2, "NN", 0, "*"},
{C_INF | L | INF (6), X_A2, "NN", 0, "+"},
{C_INF | L | INF (2), X_A2, "SS", 0, "&"},
{C_INF | N | INF (4), X_A2, "AA", 0, "="},
{C_INF | N | INF (5), X_A2, "AA", 0, ">="},
{C_INF | N | INF (5), X_A2, "AA", 0, ">"},
{C_INF | N | INF (5), X_A2, "AA", 0, "<"},
{C_INF | N | INF (5), X_A2, "AA", 0, "<="},
{C_INF | N | INF (4), X_A2, "AA", 0, "!="},
{C_INF | R | INF (8), X_A2, "FF", V pow, "^"},

{C_FN0, X_A0, "", 0, "pi"},
{C_FN0X, X_A0, "", 0, "row"},
{C_FN0X, X_A0, "", 0, "col"},
{C_FN0 | C_T, X_A0, "", 0, "now"},

{C_FN1, X_A1, "F", V fabs, "abs"},
{C_FN1, X_A1, "F", V acos, "acos"},
{C_FN1, X_A1, "F", V asin, "asin"},
{C_FN1, X_A1, "F", V atan, "atan"},
{C_FN1, X_A1, "F", V ceil, "ceil"},
{C_FN1, X_A1, "F", V to_int, "int"},
{C_FN1, X_A1, "F", V floor, "floor"},
{C_FN1, X_A1, "F", V cos, "cos"},
{C_FN1, X_A1, "F", V dtr, "dtr"},
{C_FN1, X_A1, "F", V exp, "exp"},
{C_FN1, X_A1, "F", V log, "log"},
{C_FN1, X_A1, "F", V log10, "log10"},
{C_FN1, X_A1, "F", V rtd, "rtd"},
{C_FN1, X_A1, "F", V sin, "sin"},
{C_FN1, X_A1, "F", V sqrt, "sqrt"},
{C_FN1, X_A1, "F", V tan, "tan"},
{C_FN1, X_A1, "I", 0, "ctime"},
{C_FN1, X_A1, "A", 0, "negate"},
{C_FN1, X_A1, "A", 0, "not"},
{C_FN1, X_A1, "A", 0, "iserr"},
{C_FN1, X_A1, "A", 0, "isnum"},

{C_FN1 | C_T, X_A1, "I", 0, "rnd"},
{C_FN1, X_A1, "R", 0, "rows"},
{C_FN1, X_A1, "R", 0, "cols"},
{C_FN2, X_A2, "FF", V atan2, "atan2"},
{C_FN2, X_A2, "FF", V hypot, "hypot"},
{C_FN2, X_A2, "FI", 0, "fixed"},
{C_FN2, X_A2, "AA", 0, "iferr"},
{C_FN2, X_A2, "RI", 0, "index"},
{C_FN3, X_A3, "RII", 0, "index"},
{C_FNN, X_AN, "IAAA", 0, "oneof"},

{C_FNN, X_AN, "SIIA", 0, "file"},
{C_FNN, X_AN, "EEEE", 0, "sum"},
{C_FNN, X_AN, "EEEE", 0, "prod"},
{C_FNN, X_AN, "EEEE", 0, "avg"},
{C_FNN, X_AN, "EEEE", 0, "std"},
{C_FNN, X_AN, "EEEE", 0, "max"},
{C_FNN, X_AN, "EEEE", 0, "min"},
{C_FNN, X_AN, "EEEE", 0, "count"},
{C_FNN, X_AN, "EEEE", 0, "var"},

};

#ifdef USE_DLD
int n_usr_funs;
struct function **usr_funs;
int *usr_n_funs;
#else
int n_usr_funs = 3;
static struct function *__usr_funs[] =
{
busi_funs,
string_funs,
cells_funs,
};
static int __usr_n_funs[] =
{
18, 11, 10
};

struct function **usr_funs = __usr_funs;
int *usr_n_funs = __usr_n_funs;
#endif

/* ... A whole huge empty space, then ... */
struct function skip_funs[] =
{
{C_SKIP, X_A0 | X_J, "", 0, ""},
{C_SKIP, X_A0 | X_JL, "", 0, ""},
};

/* The memory allocated here is used for several things, but byte_compile
is a small file, so it might as well be here */
void
init_mem ()
{
int n;

parse_hash = hash_new ();
hash_insert (parse_hash, the_funs[F_IF].fn_str, &the_funs[F_IF]);
hash_insert (parse_hash, the_funs[AND].fn_str, &the_funs[AND]);
hash_insert (parse_hash, the_funs[OR].fn_str, &the_funs[OR]);
for (n = F_PI; n < USR1; n++)
hash_insert (parse_hash, the_funs[n].fn_str, &the_funs[n]);
#ifndef USE_DLD
for (n = 0; n < n_usr_funs; n++)
{
int nn;

for (nn = 0; usr_funs[n][nn].fn_str; nn++)
hash_insert (parse_hash, usr_funs[n][nn].fn_str, &usr_funs[n][nn]);
#ifdef TEST
if (usr_n_funs[n] != nn)
{
fprintf (stderr, "Usr_n_funs[%d]%d!=%d", n, usr_n_funs[n], nn);
usr_n_funs[n] = nn;

}
#endif
}
#endif
fn_stack = init_stack ();
str_stack = init_stack ();
obstack_begin (&tmp_mem, 400);
tmp_mem_start = obstack_alloc (&tmp_mem, 0);
}

#ifdef USE_DLD
void
add_usr_funs (new_funs)
struct function *new_funs;
{
int n;

n_usr_funs++;
usr_funs = usr_funs ? ck_realloc (usr_funs, n_usr_funs * sizeof (struct function *)) : ck_malloc (sizeof (struct function *));
usr_n_funs = usr_n_funs ? ck_realloc (usr_n_funs, n_usr_funs * sizeof (int)) : ck_malloc (sizeof (int));

usr_funs[n_usr_funs - 1] = new_funs;
for (n = 0; new_funs[n].fn_str; n++)
hash_insert (parse_hash, new_funs[n].fn_str, &new_funs[n]);
usr_n_funs[n_usr_funs - 1] = n;
}

#endif

/* Stash away a backpatch for future editing. */
static void
add_backpatch (from, to)
unsigned from;
unsigned to;
{
if (!patches)
{
patches_allocated = 5;
patches = (struct backpatch *) ck_malloc (patches_allocated * sizeof (struct backpatch));
patches_used = 0;
}
if (patches_allocated == patches_used)
{
patches_allocated *= 2;
patches = (struct backpatch *) ck_realloc (patches, patches_allocated * sizeof (struct backpatch));
}
patches[patches_used].from = from;
patches[patches_used].to = to;
patches_used++;
}

static int
cmp_patch (n1, n2)
int n1;
int n2;
{
int ret;

ret = (patches[n1].from == patches[n2].from) ? patches[n1].to - patches[n2].to : patches[n1].from - patches[n2].from;
return ret;
}

static void
swp_patch (n1, n2)
int n1;
int n2;
{
struct backpatch tmp;

tmp = patches[n1];
patches[n1] = patches[n2];
patches[n2] = tmp;
}

static void
rot_patch (n1, n2)
int n1;
int n2;
{
struct backpatch tmp;
tmp = patches[n2];
while (n2 > n1)
{
patches[n2] = patches[n2 - 1];
--n2;
}
patches[n2] = tmp;
}


/* This takes an ascii string and returns a pointer to the byte-compiled
result. It calls yyparse() to do the actual parsing. This is complicated
only because yyparse returns a parse tree which needs to be turned into
postfix compiled bytes. This is further complicated by the presence of
forward branches in the byte-compiled code. That's what the backpatch
stuff is for.

It'd be nice if oneof() could compile into
arg1
ONEOF n_possibilities
JUMP poss1
JUMP poss2
JUMP poss3
...
JUMP error
{poss 1}
JUMP end
{poss 2}
JUMP end
...
end: {rest of expression}
instead of the simplistic (and slow-to-execute) version currently used

It'd also be nice if byte-compiled expressions could have *BIG*
subexpressions, instead of silently failing as they do now. Error checking
and a way to encode longer branches would be a *good* idea.
*/
unsigned char *
parse_and_compile (string)
char *string;
{
struct node *new_node;
struct node *node;
const struct function *f;
unsigned char *ret;
int n;
unsigned buf_siz;
int need_relax;
int byte;

instr = string;
parse_error = 0;
patches_used = 0;
if (yyparse () || parse_error)
{
ret = ck_malloc (strlen (string) + 5);
ret[0] = CONST_ERR;
ret[1] = 2;
ret[2] = parse_error;
ret[3] = ENDCOMP;
strcpy ((char *) &ret[4], string);
(void) obstack_free (&tmp_mem, tmp_mem_start);
return ret;
}

node = parse_return;
if (!node)
return 0;

loop:
if (node->comp_value < USR1)
{
f = &the_funs[node->comp_value];
}
else if (node->comp_value < SKIP)
{
n = node->sub_value;
f = &usr_funs[node->comp_value - USR1][n];
}
else
{
f = &skip_funs[node->comp_value - SKIP];
}
byte = node->comp_value;

#ifdef TEST
if (!f)
panic ("f is zero in byte_compile!");
#endif
switch (GET_COMP (f->fn_comptype))
{
case C_IF:
/* if compiles to
test-code IF amt-to-skip-on-false true-code SKIP
amt-to-skip-on-true false-code */
if (node->n_x.v_subs[0])
{
if (node->n_x.v_subs[0]->n_x.v_subs[0])
{
/* Put out the test-code */
push_stack (fn_stack, node);
new_node = node->n_x.v_subs[0]->n_x.v_subs[0];
node->n_x.v_subs[0]->n_x.v_subs[0] = 0;
node = new_node;
goto loop;
}
/* Put out IF, null-byte to backpatch */
(void) obstack_1grow (&tmp_mem, byte);
node->add_byte = obstack_object_size (&tmp_mem);
(void) obstack_1grow (&tmp_mem, 0);

/* put out true-code */
push_stack (fn_stack, node);
new_node = node->n_x.v_subs[0]->n_x.v_subs[1];
node->n_x.v_subs[0] = 0;
node = new_node;
goto loop;
}
if (node->n_x.v_subs[1])
{

(void) obstack_1grow (&tmp_mem, (char)SKIP);
(void) obstack_1grow (&tmp_mem, 0);
add_backpatch (node->add_byte, obstack_object_size (&tmp_mem));
node->add_byte = obstack_object_size (&tmp_mem) - 1;

push_stack (fn_stack, node);
new_node = node->n_x.v_subs[1];
node->n_x.v_subs[1] = 0;
node = new_node;
goto loop;
}
add_backpatch (node->add_byte, obstack_object_size (&tmp_mem));
break;

case C_ANDOR:
if (node->n_x.v_subs[0])
{
push_stack (fn_stack, node);
new_node = node->n_x.v_subs[0];
node->n_x.v_subs[0] = 0;
node = new_node;
goto loop;
}
if (node->n_x.v_subs[1])
{
(void) obstack_1grow (&tmp_mem, byte);
node->add_byte = obstack_object_size (&tmp_mem);
(void) obstack_1grow (&tmp_mem, 0); /* for backpatching */
push_stack (fn_stack, node);
new_node = node->n_x.v_subs[1];
node->n_x.v_subs[1] = 0;
node = new_node;
goto loop;
}
add_backpatch (node->add_byte, obstack_object_size (&tmp_mem));
break;

case C_ERR:
(void) obstack_1grow (&tmp_mem, byte);
node->add_byte = obstack_object_size (&tmp_mem);
(void) obstack_1grow (&tmp_mem, 0);
(void) obstack_1grow (&tmp_mem, node->n_x.v_int);
node->n_x.v_string = ename[node->n_x.v_int];
push_stack (str_stack, node);
break;

case C_FLT:
(void) obstack_1grow (&tmp_mem, byte);
(void) obstack_grow (&tmp_mem, &(node->n_x.v_float), sizeof (double));
break;

case C_INT:
(void) obstack_1grow (&tmp_mem, byte);
(void) obstack_grow (&tmp_mem, &(node->n_x.v_int), sizeof (long));
break;

case C_STR:
(void) obstack_1grow (&tmp_mem, byte);
node->add_byte = obstack_object_size (&tmp_mem);
(void) obstack_1grow (&tmp_mem, 0);
push_stack (str_stack, node);
break;

case C_VAR:
add_ref_to (obstack_object_size (&tmp_mem));
add_var_ref (node->n_x.v_var);
(void) obstack_1grow (&tmp_mem, byte);
(void) obstack_grow (&tmp_mem, &(node->n_x.v_var), sizeof (struct var *));
break;

case C_CELL:
add_ref_to (obstack_object_size (&tmp_mem));
add_ref (node->n_x.v_rng.lr, node->n_x.v_rng.lc);
(void) obstack_1grow (&tmp_mem, byte);
#if BITS_PER_CELLREF==16
(void) obstack_1grow (&tmp_mem, node->n_x.v_rng.lr >> 8);
(void) obstack_1grow (&tmp_mem, node->n_x.v_rng.lr);
(void) obstack_1grow (&tmp_mem, node->n_x.v_rng.lc >> 8);
(void) obstack_1grow (&tmp_mem, node->n_x.v_rng.lc);
#else
#if BITS_PER_CELLREF==8
(void) obstack_1grow (&tmp_mem, node->n_x.v_rng.lr);
(void) obstack_1grow (&tmp_mem, node->n_x.v_rng.lc);
#else
Insert appropriate code here
#endif
#endif
break;

case C_RANGE:
add_ref_to (obstack_object_size (&tmp_mem));
add_range_ref (&(node->n_x.v_rng));
(void) obstack_1grow (&tmp_mem, byte);
(void) obstack_grow (&tmp_mem, &(node->n_x.v_rng), sizeof (struct rng));
break;

case C_FN0X:
add_ref_to (obstack_object_size (&tmp_mem));
/* FALLTHROUGH */
case C_FN0:
case C_CONST:
add_byte:
if (f->fn_comptype & C_T)
add_timer_ref (obstack_object_size (&tmp_mem));
(void) obstack_1grow (&tmp_mem, byte);
if (byte >= USR1 && byte < SKIP)
(void) obstack_1grow (&tmp_mem, (int) node->sub_value);
break;

case C_FN1:
case C_UNA:
if (node->n_x.v_subs[0])
{
push_stack (fn_stack, node);
new_node = node->n_x.v_subs[0];
node->n_x.v_subs[0] = 0;
node = new_node;
goto loop;
}
goto add_byte;

case C_FN2:
case C_INF:
if (node->n_x.v_subs[0])
{
push_stack (fn_stack, node);
new_node = node->n_x.v_subs[0];
node->n_x.v_subs[0] = 0;
node = new_node;
goto loop;
}
if (node->n_x.v_subs[1])
{
push_stack (fn_stack, node);
new_node = node->n_x.v_subs[1];
node->n_x.v_subs[1] = 0;
node = new_node;
goto loop;
}
goto add_byte;

case C_FN3:
if (node->n_x.v_subs[0])
{
if (node->n_x.v_subs[0]->n_x.v_subs[0])
{
push_stack (fn_stack, node);
new_node = node->n_x.v_subs[0]->n_x.v_subs[0];
node->n_x.v_subs[0]->n_x.v_subs[0] = 0;
node = new_node;
goto loop;
}
push_stack (fn_stack, node);
new_node = node->n_x.v_subs[0]->n_x.v_subs[1];
node->n_x.v_subs[0] = 0;
node = new_node;
goto loop;
}
if (node->n_x.v_subs[1])
{
push_stack (fn_stack, node);
new_node = node->n_x.v_subs[1];
node->n_x.v_subs[1] = 0;
node = new_node;
goto loop;
}
goto add_byte;

case C_FN4:
if (node->n_x.v_subs[0])
{
if (node->n_x.v_subs[0]->n_x.v_subs[0])
{
push_stack (fn_stack, node);
new_node = node->n_x.v_subs[0]->n_x.v_subs[0];
node->n_x.v_subs[0]->n_x.v_subs[0] = 0;
node = new_node;
goto loop;
}
push_stack (fn_stack, node);
new_node = node->n_x.v_subs[0]->n_x.v_subs[1];
node->n_x.v_subs[0] = 0;
node = new_node;
goto loop;
}
if (node->n_x.v_subs[1])
{
if (node->n_x.v_subs[1]->n_x.v_subs[0])
{
push_stack (fn_stack, node);
new_node = node->n_x.v_subs[1]->n_x.v_subs[0];
node->n_x.v_subs[1]->n_x.v_subs[0] = 0;
node = new_node;
goto loop;
}
push_stack (fn_stack, node);
new_node = node->n_x.v_subs[1]->n_x.v_subs[1];
node->n_x.v_subs[1] = 0;
node = new_node;
goto loop;
}
goto add_byte;

case C_FNN:
if (node->n_x.v_subs[1])
{
if (node->add_byte == 0)
for (new_node = node; new_node->n_x.v_subs[1]; new_node = new_node->n_x.v_subs[1])
node->add_byte++;
for (new_node = node; new_node->n_x.v_subs[1]->n_x.v_subs[1]; new_node = new_node->n_x.v_subs[1])
;
push_stack (fn_stack, node);
node = new_node->n_x.v_subs[1]->n_x.v_subs[0];
new_node->n_x.v_subs[1] = 0;
goto loop;
}
(void) obstack_1grow (&tmp_mem, byte);
if (byte >= USR1 && byte < SKIP)
(void) obstack_1grow (&tmp_mem, (int) node->sub_value);
(void) obstack_1grow (&tmp_mem, node->add_byte);
break;

default:
panic ("Bad comptype %d", f->fn_comptype);
}
node = (struct node *) pop_stack (fn_stack);
if (node)
goto loop;

(void) obstack_1grow (&tmp_mem, 0);

while (node = pop_stack (str_stack))
{
add_backpatch (node->add_byte, obstack_object_size (&tmp_mem));
(void) obstack_grow (&tmp_mem, node->n_x.v_string, strlen (node->n_x.v_string) + 1);
}

buf_siz = obstack_object_size (&tmp_mem);
ret = (unsigned char *) ck_malloc (buf_siz);
bcopy (obstack_finish (&tmp_mem), ret, buf_siz);

need_relax = 0;
for (n = 0; n < patches_used; n++)
{
long offset;

offset = (patches[n].to - patches[n].from) - 1;
if (offset < 0 || offset > 255)
need_relax++;
else
ret[patches[n].from] = offset;
}
if (need_relax)
{
int n_lo;
long offset;
int start;

/* ... Sort the patches list ... */
sort (patches_used, cmp_patch, swp_patch, rot_patch);

while (need_relax)
{
ret = ck_realloc (ret, buf_siz + need_relax);
for (n_lo = 0; n_lo < patches_used; n_lo++)
{
offset = (patches[n_lo].to - patches[n_lo].from) - 1;
if (offset < 0 || offset > 255 - need_relax)
break;
}

/* n_lo points to the first jump that may need to be relaxed */
for (n = n_lo; n < patches_used; n++)
{
offset = (patches[n].to - patches[n].from) - 1;
if (offset < 0 || offset > 255)
{
int nn;

start = patches[n].from;

ret[start - 1]++; /* Translate insn to LONG */
ret[start] = offset;
bcopy (&ret[start + 1], &ret[start + 2], buf_siz - start);
ret[start + 1] = offset >> 8;
need_relax--;
buf_siz++;
for (nn = 0; nn < patches_used; nn++)
{
if (patches[nn].from > start)
patches[nn].from++;
if (patches[nn].to > start)
patches[nn].to++;
if (patches[nn].from < start && patches[nn].to > start && ret[patches[nn].from]++ == 255)
{
if (ret[patches[nn].from - 1] & 01)
ret[patches[nn].from + 1]++;
else
need_relax++;
}
}
}
}
}
}

(void) obstack_free (&tmp_mem, tmp_mem_start);

patches_used = 0;

return ret;
}

/* Back when strings stored a char*, they needed to be freed when a
byte-compiled expression was freed. Now that they're appended to the end,
they don't need to be specially freed anymore.
*/
void
byte_free (form)
unsigned char *form;
{
/* no longer needed
unsigned char *f;

for(f=form;*f;f++) {
switch(*f) {
case IF:
case F_IF:
case SKIP:
case AND:
case OR:
case CONST_STR:
f++;
break;
case CONST_INT:
f+=sizeof(long);
break;
case CONST_FLT:
f+=sizeof(double);
break;
case VAR:
f+=sizeof(struct var *);
break;
case R_CELL:
case R_CELL|ROWREL:
case R_CELL|COLREL:
case R_CELL|ROWREL|COLREL:
f+=EXP_ADD;
break;
case RANGE:
case RANGE|LRREL:
case RANGE|LRREL|LCREL:
case RANGE|LRREL|LCREL|HCREL:
case RANGE|LRREL|HCREL:
case RANGE|LRREL|HRREL:
case RANGE|LRREL|HRREL|LCREL:
case RANGE|LRREL|HRREL|LCREL|HCREL:
case RANGE|LRREL|HRREL|HCREL:
case RANGE|HRREL:
case RANGE|HRREL|LCREL:
case RANGE|HRREL|LCREL|HCREL:
case RANGE|HRREL|HCREL:
case RANGE|LCREL:
case RANGE|LCREL|HCREL:
case RANGE|HCREL:
f+=EXP_ADD_RNG;
break;
case F_PRINTF:
case F_CONCAT:
case F_ONEOF:
case F_STRSTR:
case F_EDIT:
case AREA_SUM:
case AREA_PROD:
case AREA_AVG:
case AREA_STD:
case AREA_MAX:
case AREA_MIN:
case AREA_CNT:
case AREA_VAR:
f++;
break;
default:
break;
}
} */
free (form);
}

/* This tries to tell if a byte-compiled expression is a constant. If it
is a constant, we can free it, and never try to recompute its value.
This returns non-zero if the expression is constant.*/
int
is_constant (bytes)
unsigned char *bytes;
{
/* It's constant, but it's already been dealt with.
Pretend it isn't. */
if (!bytes)
return 0;

switch (bytes[0])
{
case CONST_ERR:
return (bytes[3] == 0 && !strcmp ((char *) bytes + 4, ename[bytes[2]]));
case CONST_INT:
return bytes[sizeof (long) + 1] == ENDCOMP;
case CONST_FLT:
return bytes[sizeof (double) + 1] == ENDCOMP;
case CONST_STR:
return bytes[2] == ENDCOMP;
case F_TRUE:
case F_FALSE:
case CONST_INF:
case CONST_NINF:
case CONST_NAN:
return bytes[1] == ENDCOMP;
default:
return 0;
}
}
oleo-1.3/eval.c 644 722 0 102156 5355776315 11642 0ustar lordwheel/* Copyright (C) 1990, 1992, 1993 Free Software Foundation, Inc.

This file is part of Oleo, the GNU Spreadsheet.

Oleo 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, or (at your option)
any later version.

Oleo 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 Oleo; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */

#include
#include
#include

#ifdef __TURBOC__
#define SMALLEVAL
#endif

#include "funcdef.h"

#if defined(HAVE_RINT)
#ifdef __STDC__
extern double rint (double);
extern long random (void);
#else
extern double rint ();
extern long random ();
#endif
#else
#define rint(x) (((x)<0) ? ceil((x)-.5) : floor((x)+.5))
#endif

#define obstack_chunk_alloc ck_malloc
#define obstack_chunk_free free
#include "obstack.h"

#include "sysdef.h"
#include "global.h"
#include "cell.h"
#include "eval.h"
#include "errors.h"


extern int n_usr_funs;




double to_int ();
static int deal_area ();
static void add_int ();
static void add_flt ();
#ifndef __TURBOC__
RETSIGTYPE math_sig ();
#endif

#ifdef __STDC__
int fls (long);
#else
int fls ();
#endif
#ifdef SMALLEVAL
int __to_flt (struct value *);
int __to_int (struct value *);
int __to_num (struct value *);
int __to_str (struct value *);
int __to_bol (struct value *);
int __to_rng (struct value *);
#endif



struct value
{
int type;
union vals x;
};

#define Float x.c_d
#define String x.c_s
#define Int x.c_l
#define Value x.c_i
#define Rng x.c_r

#undef PI
#define PI (3.14159265358979326848)

static struct value *stack;
static int stackmax;
static int curstack;

unsigned short current_cycle;

CELLREF cur_row;
CELLREF cur_col;

static double exp10_arr[] =
{
1E0, 1E1, 1E2, 1E3, 1E4,
1E5, 1E6, 1E7, 1E8, 1E9,
1E10, 1E11, 1E12, 1E13, 1E14,
1E15, 1E16, 1E17, 1E18, 1E19,
1E20, 1E21, 1E22, 1E23, 1E24,
1E25, 1E26, 1E27, 1E28, 1E29
};

/* Various math conversions with error checking */
#define I_ADD(i1,i2) { itmp=(i1)+(i2); \
if((i1>0)==(i2>0) && (itmp>0)!=(i1>0)) { \
p->Float=(double)(i1)+(double)(i2); \
p->type=TYP_FLT; \
} else \
p->Int=itmp; }

#define I_SUB(i1,i2) { itmp=(i1)-(i2); \
if(((i1)<0)==((i2)>0) && ((itmp)>0)!=((i2)<0)) {\
p->Float=(double)(i1)-(double)(i2); \
p->type=TYP_FLT; \
} else \
p->Int=itmp; }

#define I_DIV(i1,i2) { ftmp=(double)(i1)/(double)(i2); \
/* ... */; \
p->Float=ftmp; \
p->type=TYP_FLT; }

#define I_MOD(i1,i2) {itmp=(i1)%(i2);/* ... */;p->Int=itmp;}

#define I_MUL(i1,i2) { if(fls(i1)+fls(i2)>32) { \
p->Float=(double)(i1)*(double)(i2); \
p->type=TYP_FLT; \
} else \
p->Int=(i1)*(i2); }

#define F_ADD(f1,f2) { ftmp=(f1)+(f2);/* ... */;p->Float=ftmp; }

#define F_SUB(f1,f2) { ftmp=(f1)-(f2);/* ... */;p->Float=ftmp;}

#define F_DIV(f1,f2) { ftmp=(f1)/(f2);/* ... */;p->Float=ftmp;}

#define F_MOD(f1,f2) { itmp=(long)(f1)%(long)(f2);/* ... */;p->Int=itmp;p->type=TYP_INT;}

#define F_MUL(f1,f2) { ftmp=(f1)*(f2);/* ... */;p->Float=ftmp;}

double ftmp;
long itmp;
int overflow;

/* You may ask: Why not jsut put the value in stack[0] and goto break_out
The answer is that ERROR is a valid input type for several operators, so
we want to work if we're feeding an error into one of these operators. . .
*/
#define ERROR(cause) \
{ \
p->type=TYP_ERR;\
p->Value=cause; \
goto next_byte; \
}

#ifdef SMALLEVAL

#define TO_FLT(val) \
if((tmp=__to_flt(val))!=0) \
ERROR(tmp);

#define TO_INT(val) \
if((tmp=__to_int(val))!=0) \
ERROR(tmp);

#define TO_NUM(val) \
if((tmp=__to_num(val))!=0) \
ERROR(tmp);

#define TO_STR(val) \
if((tmp=__to_str(val))!=0) \
ERROR(tmp);

#define TO_BOL(val) \
if((tmp=__to_bol(val))!=0) \
ERROR(tmp);

#define TO_RNG(val) \
if((tmp=__to_rng(val))!=0) \
ERROR(tmp);

#else
#define TO_FLT(val) \
if((val)->type==TYP_FLT) \
; \
else if((val)->type==TYP_INT) { \
(val)->type=TYP_FLT; \
(val)->Float=(double)(val)->Int; \
} else if((val)->type==TYP_STR) { \
(val)->type=TYP_FLT; \
strptr=(val)->String; \
(val)->Float=astof(&strptr); \
if(*strptr) \
ERROR(NON_NUMBER); \
} else if((val)->type==TYP_ERR) {\
ERROR((val)->Value); \
} else if((val)->type==0) { \
(val)->type=TYP_FLT; \
(val)->Float=0.0; \
} else \
ERROR(NON_NUMBER);

#define TO_INT(val) \
if((val)->type==TYP_INT) \
; \
else if((val)->type==TYP_FLT) { \
(val)->type=TYP_INT; \
(val)->Int=(long)(val)->Float; \
} else if((val)->type==TYP_STR) { \
(val)->type=TYP_INT; \
strptr=(val)->String; \
(val)->Int=astol(&strptr); \
if(*strptr) \
ERROR(NON_NUMBER); \
} else if((val)->type==TYP_ERR) {\
ERROR((val)->Value); \
} else if((val)->type==0) { \
(val)->type=TYP_INT; \
(val)->Int=0; \
} else \
ERROR(NON_NUMBER);

#define TO_NUM(val) \
if((val)->type==TYP_INT || (val)->type==TYP_FLT) \
; \
else if((val)->type==TYP_STR) { \
(val)->type=TYP_FLT; \
strptr=(val)->String; \
(val)->Float=astof(&strptr); \
if(*strptr) \
ERROR(NON_NUMBER); \
} else if((val)->type==TYP_ERR) {\
ERROR((val)->Value); \
} else if((val)->type==0) { \
(val)->type=TYP_INT; \
(val)->Int=0; \
} else \
ERROR(NON_NUMBER);

#define TO_STR(val) \
if((val)->type==TYP_STR) \
; \
else if((val)->type==TYP_INT) { \
char *s; \
(val)->type=TYP_STR; \
s=obstack_alloc(&tmp_mem,30); \
sprintf(s,"%ld",(val)->Int); \
(val)->String=s; \
} else if((val)->type==TYP_FLT) { \
char *s; \
s=flt_to_str((val)->Float); \
(void)obstack_grow(&tmp_mem,s,strlen(s)+1); \
(val)->String=obstack_finish(&tmp_mem); \
(val)->type=TYP_STR; \
} else if((val)->type==TYP_ERR) { \
ERROR((val)->Value); \
} else if((val)->type==0) { \
(val)->type=TYP_STR; \
(val)->String=obstack_alloc(&tmp_mem,1); \
(val)->String[0]='\0'; \
} else \
ERROR(NON_STRING);

#define TO_BOL(val) \
if((val)->type==TYP_BOL) \
; \
else if((val)->type==TYP_ERR) { \
ERROR((val)->Value); \
} else \
ERROR(NON_BOOL);


#define TO_RNG(val) \
if((val)->type==TYP_RNG) \
; \
else if((val)->type==TYP_ERR) {\
ERROR((val)->Value); \
} else \
ERROR(NON_RANGE);

#endif

#define TO_ANY(val) \
if((val)->type==TYP_RNG) \
ERROR(BAD_INPUT); \

#define PUSH_ANY(cp) \
if(!cp || !GET_TYP(cp)) { \
p->type=0; \
p->Int=0; \
} else { \
p->type=GET_TYP(cp); \
p->x=cp->c_z; \
}

void
init_eval ()
{
stack = (struct value *) ck_malloc (20 * sizeof (struct value));
stackmax = 20;
curstack = 0;
current_cycle++;
#ifndef __TURBOC__
(void) signal (SIGFPE, math_sig);
#endif
}

/* This huge function takes a byte-compiled expression and executes it. */
struct value *
eval_expression (expr)
unsigned char *expr;
{
unsigned char byte;
unsigned numarg;
unsigned jumpto;
struct function *f;
struct value *p;
char *strptr;
int tmp;

CELLREF lrow, hrow, crow;
CELLREF lcol, hcol, ccol;

struct cell *cell_ptr;

if (!expr)
return 0;
jumpto = 0;
numarg = 0;
p = 0;
curstack = 0;
while ((byte = *expr++) != ENDCOMP)
{
if (byte < USR1)
f = &the_funs[byte];
else if (byte < SKIP)
{
#ifdef TEST
if (byte - USR1 >= n_usr_funs)
panic ("Only have %d usr-function slots, but found byte for slot %d", n_usr_funs, 1 + byte - USR1);
#endif
tmp = *expr++;
f = &usr_funs[byte - USR1][tmp];
}
else
f = &skip_funs[byte - SKIP];

if (f->fn_argn & X_J)
jumpto = *expr++;
else if (f->fn_argn & X_JL)
{
jumpto = expr[0] + ((unsigned) (expr[1]) << 8);
expr += 2;
}

switch (f->fn_argn & X_ARGS)
{
/* A0 is special, since it makes the stack grow, while
all the others make the stack the same size or
less. . . */
case X_A0:
numarg = 0;
if (curstack == stackmax)
{
stackmax *= 2;
stack = (struct value *) ck_realloc (stack, sizeof (struct value) * stackmax);
}
p = &stack[curstack];
curstack++;
break;

case X_A1:
numarg = 1;
break;

case X_A2:
numarg = 2;
break;
case X_A3:
numarg = 3;
break;
case X_A4:
numarg = 4;
break;
case X_AN:
numarg = *expr++;
break;
default:
numarg = 0;
p = 0;
#ifdef TEST
panic ("Unknown arg_num %d", f->fn_argn);
#endif
}
if (numarg > 0)
{
int xt;

#ifdef TEST
if (curstack < numarg)
panic ("Only %u values on stack, not %u", curstack, numarg);
#endif
p = &stack[curstack - numarg];
curstack -= (numarg - 1);
for (xt = 0; xt < numarg; xt++)
{
switch (f->fn_argt[xt <= 3 ? xt : 3])
{
/* A is for anything */
/* Any non-range value */
case 'A':
TO_ANY (p + xt);
break;
/* B is for boolean */
case 'B':
TO_BOL (p + xt);
break;
/* D is for Don't check */
case 'D':
break;
/* E is for Everything */
case 'E':
break;
/* F is for Float */
case 'F':
TO_FLT (p + xt);
break;
/* I is for Int */
case 'I':
TO_INT (p + xt);
break;
/* N is for Number (int or float) */
case 'N':
TO_NUM (p + xt);
break;
/* R is for Range */
case 'R':
TO_RNG (p + xt);
break;
/* S is for String */
case 'S':
TO_STR (p + xt);
break;
#ifdef TEST
default:
io_error_msg ("YIKE! Unknown argtype for Fun %u arg #%u", byte, xt);
break;
#endif
}
}
}

switch (byte)
{
case IF_L:
case F_IF_L:
case IF:
case F_IF:
if (p->type != TYP_BOL)
{
if (p->type != TYP_ERR)
{
p->type = TYP_ERR;
p->Value = NON_BOOL;
}
expr += jumpto;
if (expr[-2] != SKIP)
jumpto = expr[-1] + (((unsigned) expr[-2]) << 8);
else
jumpto = expr[-1];
expr += jumpto; /* Skip both branches of the if */

}
else if (p->Value == 0)
{
expr += jumpto;
--curstack;
}
else
--curstack;
break;

case SKIP_L:
case SKIP:
--curstack;
expr += jumpto;
break;

case AND_L:
case AND:
if (p->type == TYP_ERR)
expr += jumpto;
else if (p->type != TYP_BOL)
{
p->type = TYP_ERR;
p->Value = NON_BOOL;
expr += jumpto;
}
else if (p->Value == 0)
expr += jumpto;
else
--curstack;
break;

case OR_L:
case OR:
if (p->type == TYP_ERR)
expr += jumpto;
else if (p->type != TYP_BOL)
{
p->type = TYP_ERR;
p->Value = NON_BOOL;
expr += jumpto;
}
else if (p->Value)
expr += jumpto;
else
--curstack;
break;

case CONST_FLT:
p->type = TYP_FLT;
bcopy ((VOIDSTAR) expr, (VOIDSTAR) (&(p->Float)), sizeof (double));
expr += sizeof (double);
break;

case CONST_INT:
p->type = TYP_INT;
bcopy ((VOIDSTAR) expr, (VOIDSTAR) (&(p->Int)), sizeof (long));
expr += sizeof (long);
break;

case CONST_STR:
case CONST_STR_L:
p->type = TYP_STR;
p->String = (char *) expr + jumpto;
break;

case CONST_ERR:
p->type = TYP_ERR;
p->Value = *expr++;
/* expr+=sizeof(char *); */
break;

case CONST_INF:
case CONST_NINF:
case CONST_NAN:
p->type = TYP_FLT;
p->Float = (byte == CONST_INF) ? __plinf : ((byte == CONST_NINF) ? __neinf : __nan);
break;

case VAR:
{
struct var *varp;

bcopy ((VOIDSTAR) expr, (VOIDSTAR) (&varp), sizeof (struct var *));
expr += sizeof (struct var *);
switch (varp->var_flags)
{
case VAR_UNDEF:
p->type = TYP_ERR;
p->Value = BAD_NAME;
break;

case VAR_CELL:
cell_ptr = find_cell (varp->v_rng.lr, varp->v_rng.lc);
PUSH_ANY (cell_ptr);
break;

case VAR_RANGE:
if (varp->v_rng.lr == varp->v_rng.hr && varp->v_rng.lc == varp->v_rng.hc)
{
cell_ptr = find_cell (varp->v_rng.lr, varp->v_rng.lc);
PUSH_ANY (cell_ptr);
}
else
{
p->type = TYP_RNG;
p->Rng = varp->v_rng;
}
break;
#ifdef TEST
default:
panic ("Unknown var type %d", varp->var_flags);
#endif
}
}
break;

/* Cell refs */
case R_CELL:
case R_CELL | COLREL:
case R_CELL | ROWREL:
case R_CELL | ROWREL | COLREL:
{
CELLREF torow, tocol;

torow = GET_ROW (expr);
tocol = GET_COL (expr);
expr += EXP_ADD;
cell_ptr = find_cell ((CELLREF) torow, (CELLREF) tocol);
PUSH_ANY (cell_ptr);
}
break;

case RANGE:
case RANGE | LRREL:
case RANGE | LRREL | LCREL:
case RANGE | LRREL | LCREL | HCREL:
case RANGE | LRREL | HCREL:
case RANGE | LRREL | HRREL:
case RANGE | LRREL | HRREL | LCREL:
case RANGE | LRREL | HRREL | LCREL | HCREL:
case RANGE | LRREL | HRREL | HCREL:
case RANGE | HRREL:
case RANGE | HRREL | LCREL:
case RANGE | HRREL | LCREL | HCREL:
case RANGE | HRREL | HCREL:
case RANGE | LCREL:
case RANGE | LCREL | HCREL:
case RANGE | HCREL:
p->type = TYP_RNG;
GET_RNG (expr, &(p->Rng));
expr += EXP_ADD_RNG;
break;

case F_TRUE:
case F_FALSE:
p->type = TYP_BOL;
p->Value = (byte == F_TRUE);
break;

case F_PI:
p->type = TYP_FLT;
p->Float = PI;
break;

case F_ROW:
case F_COL:
p->type = TYP_INT;
p->Int = ((byte == F_ROW) ? cur_row : cur_col);
break;

case F_NOW:
p->type = TYP_INT;
p->Int = time ((VOIDSTAR) 0);
break;

/* Single operand instrs */
case F_ABS:
case F_ACOS:
case F_ASIN:
case F_ATAN:
case F_CEIL:
case F_COS:
case F_DTR:
case F_EXP:
case F_FLOOR:
case F_INT:
case F_LOG:
case F_LOG10:
case F_RTD:
case F_SIN:
case F_SQRT:
case F_TAN:
{
#ifdef __STDC__
double (*funp1) (double);
funp1 = (double (*)(double)) (f->fn_fun);
#else
double (*funp1) ();
funp1 = (double (*)()) (f->fn_fun);
#endif

p->Float = (*funp1) (p->Float);
if (p->Float != p->Float)
ERROR (OUT_OF_RANGE);
}
break;

case F_CTIME:
p->type = TYP_STR;
strptr = ctime ((time_t*) &p->Int);
p->String = obstack_alloc (&tmp_mem, 25);
strncpy (p->String, strptr, 24);
p->String[24] = '\0';
break;

case NEGATE:
case F_NEG:
if (p->type == TYP_ERR)
break;
if (p->type == TYP_INT)
p->Int = -(p->Int);
else if (p->type == TYP_FLT)
p->Float = -(p->Float);
else
ERROR (NON_NUMBER);
break;

case F_RND:
p->Int = (random () % (p->Int)) + 1;
break;

case NOT:
case F_NOT:
p->Value = !(p->Value);
break;

case F_ISERR:
p->Value = (p->type == TYP_ERR);
p->type = TYP_BOL;
break;

case F_ISNUM:
if (p->type == TYP_FLT || p->type == TYP_INT)
p->Value = 1;
else if (p->type == TYP_STR)
{
strptr = p->String;
(void) astof (&strptr);
p->Value = (*strptr == '\0');
}
else
p->Value = 0;
p->type = TYP_BOL;
break;

case F_ROWS:
case F_COLS:
p->type = TYP_INT;
p->Int = 1 + (byte == F_ROWS ? (p->Rng.hr - p->Rng.lr) : (p->Rng.hc - p->Rng.lc));
break;

/* Two operand cmds */
case F_ATAN2:
case F_HYPOT:
case POW:
{
#ifdef __STDC__
double (*funp2) (double, double);
funp2 = (double (*)(double, double)) (f->fn_fun);
#else
double (*funp2) ();
funp2 = (double (*)()) (f->fn_fun);
#endif

p->Float = (*funp2) (p->Float, (p + 1)->Float);
if (p->Float != p->Float)
ERROR (OUT_OF_RANGE);
}
break;

case DIFF:
case DIV:
case MOD:
case PROD:
case SUM:

if (p->type != (p + 1)->type)
{
if (p->type == TYP_INT)
{
p->type = TYP_FLT;
p->Float = (double) p->Int;
}
if ((p + 1)->type == TYP_INT)
{
(p + 1)->type = TYP_FLT;
(p + 1)->Float = (double) ((p + 1)->Int);
}
}
if (p->type == TYP_INT)
{
switch (byte)
{
case DIFF:
I_SUB (p->Int, (p + 1)->Int);
break;
case DIV:
if ((p + 1)->Int == 0)
ERROR (DIV_ZERO);
I_DIV (p->Int, (p + 1)->Int);
break;
case MOD:
if ((p + 1)->Int == 0)
ERROR (DIV_ZERO);
I_MOD (p->Int, (p + 1)->Int);
break;
case PROD:
I_MUL (p->Int, (p + 1)->Int);
break;
case SUM:
I_ADD (p->Int, (p + 1)->Int);
break;
#ifdef TEST
default:
panic ("Evaluator confused by byte-value %d", byte);
#endif
}
}
else
{
switch (byte)
{
case DIFF:
F_SUB (p->Float, (p + 1)->Float);
break;
case DIV:
if ((p + 1)->Float == 0)
ERROR (DIV_ZERO);
F_DIV (p->Float, (p + 1)->Float);
break;
case MOD:
if ((p + 1)->Float == 0)
ERROR (DIV_ZERO);
F_MOD (p->Float, (p + 1)->Float);
break;
case PROD:
F_MUL (p->Float, (p + 1)->Float);
break;
case SUM:
F_ADD (p->Float, (p + 1)->Float);
break;
#ifdef TEST
default:
panic ("Unknown operation %d", byte);
#endif
}
}
if (overflow)
ERROR (OUT_OF_RANGE);
break;

case EQUAL:
case NOTEQUAL:

case GREATEQ:
case GREATER:
case LESS:
case LESSEQ:
if (p->type == TYP_ERR)
break;
if ((p + 1)->type == TYP_ERR)
ERROR ((p + 1)->Value);

if (p->type == TYP_BOL || (p + 1)->type == TYP_BOL)
{
if (p->type != (p + 1)->type || (byte != EQUAL && byte != NOTEQUAL))
ERROR (BAD_INPUT);
if (byte == EQUAL)
p->Value = p->Value == (p + 1)->Value;
else
p->Value = p->Value != (p + 1)->Value;
break;
}
if (p->type != (p + 1)->type)
{
if (p->type == 0)
{
if ((p + 1)->type == TYP_STR)
{
p->type = TYP_STR;
p->String = "";
}
else if ((p + 1)->type == TYP_INT)
{
p->type = TYP_INT;
p->Int = 0;
}
else
{
p->type = TYP_FLT;
p->Float = 0.0;
}
}
else if ((p + 1)->type == 0)
{
if (p->type == TYP_STR)
{
(p + 1)->type = TYP_STR;
(p + 1)->String = "";
}
else if (p->type == TYP_INT)
{
(p + 1)->type = TYP_INT;
(p + 1)->Int = 0;
}
else
{
(p + 1)->type = TYP_FLT;
(p + 1)->Float = 0.0;
}
}
else if (p->type == TYP_STR)
{
strptr = p->String;
if ((p + 1)->type == TYP_INT)
{
p->type = TYP_INT;
p->Int = astol (&strptr);
}
else
{
p->type = TYP_FLT;
p->Float = astof (&strptr);
}
if (*strptr)
{
p->type = TYP_BOL;
p->Value = (byte == NOTEQUAL);
break;
}
}
else if ((p + 1)->type == TYP_STR)
{
strptr = (p + 1)->String;
if (p->type == TYP_INT)
(p + 1)->Int = astol (&strptr);
else
(p + 1)->Float = astof (&strptr);
if (*strptr)
{
p->type = TYP_BOL;
p->Value = (byte == NOTEQUAL);
break;
}

/* If we get here, one is INT, and the other
is FLT Make them both FLT */
}
else if (p->type == TYP_INT)
{
p->type = TYP_FLT;
p->Float = (double) p->Int;
}
else
(p + 1)->Float = (double) (p + 1)->Int;
}
if (p->type == TYP_STR)
tmp = strcmp (p->String, (p + 1)->String);
else if (p->type == TYP_FLT)
tmp = (p->Float < (p + 1)->Float) ? -1 : ((p->Float > (p + 1)->Float) ? 1 : 0);
else if (p->type == TYP_INT)
tmp = (p->Int < (p + 1)->Int ? -1 : ((p->Int > (p + 1)->Int) ? 1 : 0));
else if (p->type == 0)
tmp = 0;
else
{
tmp = 0;
panic ("Bad type value %d", p->type);
}
p->type = TYP_BOL;
if (tmp < 0)
p->Value = (byte == NOTEQUAL || byte == LESS || byte == LESSEQ);
else if (tmp == 0)
p->Value = (byte == EQUAL || byte == GREATEQ || byte == LESSEQ);
else
p->Value = (byte == NOTEQUAL || byte == GREATER || byte == GREATEQ);
break;

case F_FIXED:
tmp = (p + 1)->Int;
if (tmp < -29 || tmp > 29)
ERROR (OUT_OF_RANGE);
if (tmp < 0)
p->Float = rint ((p->Float) / exp10_arr[-tmp]) * exp10_arr[-tmp];
else
p->Float = rint ((p->Float) * exp10_arr[tmp]) / exp10_arr[tmp];
break;

case F_IFERR:
if (p->type == TYP_ERR)
*p = *(p + 1);
break;

case F_INDEX:
tmp = (p + 1)->Int - 1;
if (tmp < 0)
ERROR (OUT_OF_RANGE);
lrow = p->Rng.lr;
lcol = p->Rng.lc;
hrow = p->Rng.hr;
hcol = p->Rng.hc;
if (lrow != hrow && lcol != hcol)
{
int dex;

dex = 1 + hrow - lrow;
if (tmp >= dex * (1 + hcol - lcol))
ERROR (OUT_OF_RANGE);
crow = tmp % dex;
ccol = tmp / dex;
lrow += crow;
lcol += ccol;
}
else if (lrow != hrow)
{
if (tmp > (hrow - lrow))
ERROR (OUT_OF_RANGE);
lrow += tmp;
}
else
{
if (tmp > (hcol - lcol))
ERROR (OUT_OF_RANGE);
lcol += tmp;
}
cell_ptr = find_cell (lrow, lcol);
PUSH_ANY (cell_ptr);
break;

case F_INDEX2:
crow = (p + 1)->Int - 1;
ccol = (p + 2)->Int - 1;
lrow = p->Rng.lr;
lcol = p->Rng.lc;
hrow = p->Rng.hr;
hcol = p->Rng.hc;
if (crow > (hrow - lrow) || ccol > (hcol - lcol))
ERROR (OUT_OF_RANGE);
cell_ptr = find_cell (lrow + crow, lcol + ccol);
PUSH_ANY (cell_ptr);
break;

/* case F_PRINTF:
panic("no printf yet");
break; */

case CONCAT:
strptr = (char *) obstack_alloc (&tmp_mem, strlen (p->String) + strlen ((p + 1)->String) + 1);
strcpy (strptr, p->String);
strcat (strptr, (p + 1)->String);
p->String = strptr;
break;

case F_ONEOF:
if (numarg < 2)
ERROR (NO_VALUES);
--numarg;
tmp = p->Int;
if (tmp < 1 || tmp > numarg)
ERROR (OUT_OF_RANGE);
/* Can never happen? */
TO_ANY (p + tmp);
p[0] = p[tmp];
break;

case F_FILE:
{
FILE *fp;
char buf[128];
int num;

if (numarg < 1)
ERROR (NO_VALUES);
fp = fopen (p->String, "r");
if (!fp)
ERROR (BAD_INPUT);
switch (numarg)
{
case 2:
fseek (fp, (p + 1)->Int, 0);
/* Fallthrough */

case 1:
while ((num = fread (buf, sizeof (char), sizeof (buf), fp)) > 0)
(void) obstack_grow (&tmp_mem, buf, num);
break;

case 3:
fseek (fp, (p + 1)->Int, 0);
for (;;)
{
num = ((p + 2)->Int < sizeof (buf)) ? (p + 2)->Int : sizeof (buf);
(p + 2)->Int -= num;
num = fread (buf, sizeof (char), num, fp);
(void) obstack_grow (&tmp_mem, buf, num);
if (num == 0 || (p + 2)->Int == 0)
break;
}
break;

default:
ERROR (BAD_INPUT);
}
fclose (fp);
(void) obstack_1grow (&tmp_mem, 0);
p->String = obstack_finish (&tmp_mem);
break;
}

case AREA_SUM:
case AREA_PROD:
case AREA_AVG:
case AREA_STD:
case AREA_MAX:
case AREA_MIN:
case AREA_CNT:
case AREA_VAR:
tmp = deal_area (byte, numarg, p);
if (tmp)
ERROR (tmp);
break;

/* This is now a fallthrough for all the USRmumble codes */
case USR1:
default:
if ((f->fn_argn & X_ARGS) == X_AN)
{
#ifdef __STDC__
void (*funp) (int, struct value *);
funp = (void (*)(int, struct value *)) f->fn_fun;
#else
void (*funp) ();
funp = (void (*)()) f->fn_fun;
#endif
(*funp) (numarg, p);
}
else
{
#ifdef __STDC__
void (*funp) (struct value *);
funp = (void (*)(struct value *)) f->fn_fun;
#else
void (*funp) ();
funp = (void (*)()) f->fn_fun;
#endif
(*funp) (p);
}
break;

/* #ifdef TEST
default:
panic("Unknown byte-value %d",byte);
break;
#endif */
}
/* Goto next-byte is the equiv of a multi-level break, which
C doesn't allow. */
next_byte:
;
}
#ifdef TEST
if (curstack != 1)
io_error_msg ("%d values on stack", curstack);
#endif
return stack;
}

/* These helper functions were split out so that eval_expression would compile
under Turbo C 2.0 on my PC.
*/


static int cnt_flt;
static int cnt_int;

static long int_tmp;
static double flt_tmp;

static long sqr_int_tmp; /* for AREA_STD */
static double sqr_flt_tmp;

static unsigned char area_cmd;

static int
deal_area (cmd, num_args, p)
unsigned char cmd;
unsigned char num_args;
struct value *p;
{
double flt_cnt_flt;
CELL *cell_ptr;
char *strptr;

area_cmd = cmd;
cnt_flt = 0;
cnt_int = 0;
for (; num_args--;)
{
switch (p[num_args].type)
{
case TYP_INT:
add_int (p[num_args].Int);
break;

case TYP_FLT:
add_flt (p[num_args].Float);
break;

case TYP_STR:
strptr = p[num_args].String;
flt_cnt_flt = astof (&strptr);
if (*strptr)
return NON_NUMBER;
add_flt (flt_cnt_flt);
break;

case TYP_RNG:
find_cells_in_range (&(p[num_args].Rng));
while (cell_ptr = next_cell_in_range ())
{
if (GET_TYP (cell_ptr) == TYP_FLT)
add_flt (cell_ptr->cell_flt);
else if (GET_TYP (cell_ptr) == TYP_INT)
add_int (cell_ptr->cell_int);
else if (GET_TYP (cell_ptr) == TYP_STR)
{
strptr = cell_ptr->cell_str;
flt_cnt_flt = astof (&strptr);
if (!*strptr)
add_flt (flt_cnt_flt);
}
}
break;

case 0:
break;

case TYP_ERR:
return p[num_args].Value;

default:
return NON_NUMBER;
}
}
if (!cnt_flt && !cnt_int && area_cmd != AREA_CNT)
return NO_VALUES;

switch (area_cmd)
{
case AREA_SUM:
if (cnt_flt && cnt_int)
{
flt_tmp += (double) int_tmp;
cnt_int = 0;
}
break;
case AREA_PROD:
if (cnt_flt && cnt_int)
{
flt_tmp *= (double) int_tmp;
cnt_int = 0;
}
break;
case AREA_AVG:
if (cnt_flt && cnt_int)
{
flt_tmp += (double) int_tmp;
flt_tmp /= (double) ((cnt_flt + cnt_int));
cnt_int = 0;
}
else if (cnt_flt)
flt_tmp /= (double) cnt_flt;
else
{
flt_tmp = (double) int_tmp / (double) cnt_int;
cnt_int = 0;
}
break;
case AREA_STD:
if (cnt_int && cnt_flt)
{
flt_tmp += (double) int_tmp;
sqr_flt_tmp += (double) sqr_int_tmp;
cnt_flt += cnt_int;
cnt_int = 0;
}
else if (cnt_int)
{
flt_tmp = (double) int_tmp;
sqr_flt_tmp = (double) sqr_int_tmp;
cnt_flt = cnt_int;
cnt_int = 0;
}
flt_cnt_flt = (double) cnt_flt;
flt_tmp = sqrt (((flt_cnt_flt * sqr_flt_tmp) -
(flt_tmp * flt_tmp)) /
(flt_cnt_flt * (flt_cnt_flt - 1)));
break;
case AREA_VAR:
if (cnt_int && cnt_flt)
{
flt_tmp += (double) int_tmp;
sqr_flt_tmp += (double) sqr_int_tmp;
cnt_flt += cnt_int;
cnt_int = 0;
}
else if (cnt_int)
{
flt_tmp = (double) int_tmp;
sqr_flt_tmp = (double) sqr_int_tmp;
cnt_flt = cnt_int;
cnt_int = 0;
}
flt_cnt_flt = (double) cnt_flt;
flt_tmp = ((flt_cnt_flt * sqr_flt_tmp) -
(flt_tmp * flt_tmp)) /
(flt_cnt_flt * flt_cnt_flt);
break;

case AREA_MAX:
if (cnt_flt && cnt_int && flt_tmp > (double) int_tmp)
cnt_int = 0;
break;

case AREA_MIN:
if (cnt_flt && cnt_int && flt_tmp < (double) int_tmp)
cnt_int = 0;
break;

case AREA_CNT:
int_tmp = cnt_int + cnt_flt;
cnt_int = 1;
break;

#ifdef TEST
default:
panic ("Unknown AREA command %d", area_cmd);
#endif
}
if (cnt_int)
{
p->type = TYP_INT;
p->Int = int_tmp;
}
else
{
p->type = TYP_FLT;
p->Float = flt_tmp;
}
return 0;
}

static void
add_flt (value)
double value;
{
if (cnt_flt++ == 0)
{
flt_tmp = value;
sqr_flt_tmp = value * value;
return;
}

switch (area_cmd)
{
case AREA_STD:
case AREA_VAR:
sqr_flt_tmp += value * value;
/* Fall through */
case AREA_SUM:
case AREA_AVG:
flt_tmp += value;
return;
case AREA_PROD:
flt_tmp *= value;
return;
case AREA_MAX:
if (flt_tmp < value)
flt_tmp = value;
return;
case AREA_MIN:
if (flt_tmp > value)
flt_tmp = value;
return;
case AREA_CNT:
return;
#ifdef TEST
default:
panic ("Unknown area command %d in add_flt(%g)", area_cmd, value);
#endif
}
}

static void
add_int (value)
long value;
{
if (cnt_int++ == 0)
{
int_tmp = value;
sqr_int_tmp = value * value;
return;
}

switch (area_cmd)
{
case AREA_STD:
case AREA_VAR:
sqr_int_tmp += value * value;
/* Fall through */
case AREA_SUM:
case AREA_AVG:
int_tmp += value;
return;
case AREA_PROD:
int_tmp *= value;
return;
case AREA_MAX:
if (int_tmp < value)
int_tmp = value;
return;
case AREA_MIN:
if (int_tmp > value)
int_tmp = value;
return;
case AREA_CNT:
return;
#ifdef TEST
default:
panic ("Unknown Area command %d in add_int(%ld)", area_cmd, value);
#endif
}
}

#ifdef __STDC__
double
dtr (double x)
#else
double
dtr (x)
double x;
#endif
{
return x * (PI / (double) 180.0);
}

#ifdef __STDC__
double
rtd (double x)
#else
double
rtd (x)
double x;
#endif
{
return x * (180.0 / (double) PI);
}

#ifdef __STDC__
double
to_int (double x)
#else
double
to_int (x)
double x;
#endif
{
return (x < 0 ? ceil (x) : floor (x));
}

/* Various methods of dealing with arithmatic overflow. They don't work well.
Someone should really convince this thing to properly deal with it.
*/
#ifdef __TURBOC__
int
matherr (exc)
struct exception *exc;
{
stack[curstack].type = TYP_ERR;
stack[curstack].Value = BAD_INPUT;
write (2, "MATHERR\n", 8);
return 1;
}

#endif

#ifndef __TURBOC__
RETSIGTYPE
math_sig (sig)
int sig;
{
stack[curstack].type = TYP_ERR;
stack[curstack].Value = BAD_INPUT;
}

#endif

/* Here's the entry point for this module. */
void
update_cell (cell)
CELL *cell;
{
struct value *new;
int new_val;

new = eval_expression (cell->cell_formula);
if (!new)
{
push_refs (cell->cell_refs_from);
return;
}
cell->cell_cycle = current_cycle;

if (new->type != GET_TYP (cell))
{
if (GET_TYP (cell) == TYP_STR)
free (cell->cell_str);
SET_TYP (cell, new->type);
new_val = 1;
if (new->type == TYP_STR)
new->String = strdup (new->String);
}
else
switch (new->type)
{
case 0:
new_val = 0;
break;
case TYP_FLT:
new_val = new->Float != cell->cell_flt;
break;
case TYP_INT:
new_val = new->Int != cell->cell_int;
break;
case TYP_STR:
new_val = strcmp (new->String, cell->cell_str);
if (new_val)
{
free (cell->cell_str);
new->String = strdup (new->String);
}
break;
case TYP_BOL:
new_val = new->Value != cell->cell_bol;
break;
case TYP_ERR:
new_val = new->Value != cell->cell_err;
break;
default:
new_val = 0;
#ifdef TEST
panic ("Unknown type %d in update_cell", new->type);
#endif
}
if (new_val)
{
cell->c_z = new->x;
push_refs (cell->cell_refs_from);
}
(void) obstack_free (&tmp_mem, tmp_mem_start);
}

int
fls (num)
long num;
{
int ret = 1;

if (!num)
return 0;
if (num < 0)
num = -num;
if (num & 0xffff0000)
{
ret += 16;
num = (num >> 16) & 0xffff;
}
if (num & 0xff00)
{
ret += 8;
num >>= 8;
}
if (num & 0xf0)
{
ret += 4;
num >>= 4;
}
if (num & 0x0c)
{
ret += 2;
num >>= 2;
}
if (num & 2)
ret++;
return ret;
}

#ifdef SMALLEVAL
int
__to_flt (p)
struct value *p;
{
char *strptr;

switch (p->type)
{
case 0:
p->type = TYP_FLT;
p->Float = 0;
/* Fallthrough */
case TYP_FLT:
return 0;
case TYP_INT:
p->Float = (double) p->Int;
p->type = TYP_FLT;
return 0;
case TYP_STR:
p->type = TYP_FLT;
strptr = p->String;
p->Float = astof (&strptr);
if (*strptr)
return NON_NUMBER;
return 0;
case TYP_ERR:
return p->Value;
default:
return NON_NUMBER;
}
}

int
__to_int (p)
struct value *p;
{
char *strptr;

switch (p->type)
{
case 0:
p->type = TYP_INT;
p->Int = 0;
case TYP_INT:
return 0;
case TYP_FLT:
p->type = TYP_INT;
p->Int = (long) p->Float;
return 0;
case TYP_STR:
p->type = TYP_INT;
strptr = p->String;
p->Int = astol (&strptr);
if (*strptr)
return NON_NUMBER;
return 0;
case TYP_ERR:
return p->Value;
default:
return NON_NUMBER;
}
}

int
__to_num (p)
struct value *p;
{
char *strptr;

switch (p->type)
{
case 0:
p->type = TYP_INT;
p->Int = 0;
return 0;
case TYP_FLT:
case TYP_INT:
return 0;
case TYP_STR:
p->type = TYP_FLT;
strptr = p->String;
p->Float = astof (&strptr);
if (*strptr)
return NON_NUMBER;
return 0;
case TYP_ERR:
return p->Value;
default:
return NON_NUMBER;
}
}

int
__to_str (p)
struct value *p;
{
char *strptr;

switch (p->type)
{
case 0:
p->type = TYP_STR;
p->String = obstack_alloc (&tmp_mem, 1);
p->String[0] = '\0';
return 0;

case TYP_STR:
return 0;

case TYP_INT:
p->type = TYP_STR;
strptr = obstack_alloc (&tmp_mem, 30);
sprintf (strptr, "%ld", p->Int);
p->String = strptr;
return 0;

case TYP_FLT:
p->type = TYP_STR;
strptr = flt_to_str (p->Float);
(void) obstack_grow (&tmp_mem, strptr, strlen (strptr) + 1);
p->String = obstack_finish (&tmp_mem);
return 0;

case TYP_ERR:
return p->Value;

default:
return NON_STRING;
}
}

int
__to_bol (p)
struct value *p;
{
switch (p->type)
{
case TYP_BOL:
return 0;
case TYP_ERR:
return p->Value;
default:
return NON_BOOL;
}
}

int
__to_rng (p)
struct value *p;
{
switch (p->type)
{
case TYP_RNG:
return 0;
case TYP_ERR:
return p->Value;
default:
return NON_BOOL;
}
}

#endif
oleo-1.3/ref.c 644 722 0 207632 5356453361 11466 0ustar lordwheel/* Copyright (C) 1990, 1992, 1993 Free Software Foundation, Inc.

This file is part of Oleo, the GNU Spreadsheet.

Oleo 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, or (at your option)
any later version.

Oleo 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 Oleo; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */

#include "funcdef.h"
#include
#include
#include
#include
#include "sysdef.h"
#include "global.h"
#include "cell.h"
#include "eval.h"
#include "io-abstract.h"
#include "io-generic.h"
#include "hash.h"
#include "byte-compile.h"
#include "parse.h"
#include "ref.h"
#include "cmd.h"


#ifdef __STDC__
static void add_ref_fm (struct ref_fm **, CELLREF, CELLREF);
static void flush_ref_fm (struct ref_fm **, CELLREF, CELLREF);
static void flush_range_ref (struct rng *, CELLREF, CELLREF);
extern void shift_formula (int r, int c, int dn, int ov);
#ifdef SPLIT_REFS
/* These two are tunable paramaters */
#define REF_START 3
#define REF_INC *=2
#else
static void flush_ref_to (struct ref_to **);
static void flush_fm_ref (struct ref_fm *);
#endif /* SPLIT_REFS */

#else /* !__STDC__ */

static void add_ref_fm ();
static void flush_ref_fm ();
static void flush_range_ref ();
extern void shift_formula ();

#ifdef SPLIT_REFS
/* These two are tunable paramaters */
#define REF_START 3
#define REF_INC *=2
#else
static void flush_ref_to ();
static void flush_fm_ref ();
#endif /* SPLIT_REFS */
#endif /* __STDC__ */

/* More tunable paramaters */

#define FIFO_START 40
#define FIFO_INC *=2

#define TO_MAGIC(row,col) (((long)(row)< #define MAGIC_ROW(magic) (((magic)>>BITS_PER_CELLREF)&CELLREF_MASK)
#define MAGIC_COL(magic) ((magic)&CELLREF_MASK)

#define BETWEEN(mid,lo,hi) ((mid>=lo)&&(mid<=hi))

static VOIDSTAR moving;

int timer_active = 0;
struct ref_fm *timer_cells;

CELL *my_cell;

#ifdef TEST
extern int debug;
#endif

/* Functions for dealing exclusively with variables */
struct hash_control *the_vars;

struct value
{
int type;
union vals c_z;
};

/* For the fifo-buffer */
struct pos
{
CELLREF row;
CELLREF col;
};

struct cell_buf
{
unsigned int size;
struct pos *buf;
struct pos *push_to_here;
struct pos *pop_frm_here;
};


/* Set the cell ROW,COL to STRING, parsing string as needed */
#ifdef __STDC__
void
set_cell (CELLREF row, CELLREF col, char *string)
#else
void
set_cell (row, col, string)
CELLREF row;
CELLREF col;
char *string;
#endif
{
unsigned char *ret;

cur_row = row;
cur_col = col;

#ifdef TEST
if (!string)
{
io_error_msg ("Null string to set_cell %s", cell_name (row, col));
return;
}
#endif
while (*string == ' ')
string++;

if (!*string)
{
my_cell = find_cell (cur_row, cur_col);
if (!my_cell)
return;
flush_old_value ();
return;
}

my_cell = find_or_make_cell (cur_row, cur_col);
flush_old_value ();

ret = parse_and_compile (string);
my_cell->cell_formula = ret;
}

extern int default_lock;

/* new_value() calls set_cell, but refuses to change locked cells, and
updates and prints the results. It returns an error msg on error. . .
*/
#ifdef __STDC__
char *
new_value (CELLREF row, CELLREF col, char *string)
#else
char *
new_value (row, col, string)
CELLREF row;
CELLREF col;
char *string;
#endif
{
CELL *cp;

cp = find_cell (row, col);
if (((!cp || GET_LCK (cp) == LCK_DEF) && default_lock == LCK_LCK) || (cp && GET_LCK (cp) == LCK_LCK))
{
return "cell is locked";
}

set_cell (row, col, string);
if (my_cell)
{
update_cell (my_cell);
if (is_constant (my_cell->cell_formula))
{
byte_free (my_cell->cell_formula);
my_cell->cell_formula = 0;
}
io_pr_cell (row, col, my_cell);
my_cell = 0;
}
return 0;
}

/* This sets the cell to a constant, stored in VALUE, whose type is in TYPE */
#ifdef __STDC__
char *
set_new_value (CELLREF row, CELLREF col, int type, union vals *value)
#else
char *
set_new_value (row, col, type, value)
CELLREF row;
CELLREF col;
int type;
union vals *value;
#endif
{
CELL *cp;
extern int default_lock;

if (type == TYP_ERR)
type = 0;
cur_row = row;
cur_col = col;
if (type == 0)
{
cp = find_cell (row, col);
if (cp && GET_TYP (cp))
{
if ((GET_LCK (cp) == LCK_DEF && default_lock == LCK_LCK) || GET_LCK (cp) == LCK_LCK)
return "cell is locked";
my_cell = cp;
flush_old_value ();
SET_TYP (cp, 0);
}
my_cell = 0;
return 0;
}
else
{
cp = find_or_make_cell (row, col);
if ((GET_LCK (cp) == LCK_DEF && default_lock == LCK_LCK) || GET_LCK (cp) == LCK_LCK)
return "cell is locked";
my_cell = cp;
flush_old_value ();
SET_TYP (cp, type);
/* cp->c_z= *value; */
switch (type)
{
case TYP_FLT:
cp->cell_flt = value->c_d;
cp->cell_formula = 0;
break;

case TYP_INT:
cp->cell_int = value->c_l;
cp->cell_formula = 0;
break;

case TYP_STR:
cp->cell_str = strdup (value->c_s);
cp->cell_formula = 0;
break;

case TYP_BOL:
cp->cell_bol = value->c_i;
cp->cell_formula = 0;
break;

case TYP_ERR:
cp->cell_err = value->c_i;
cp->cell_formula = 0;
break;
#ifdef TEST
default:
panic ("Unknown type %d in set_new_value", GET_TYP (cp));
#endif
}
}
push_refs (cp->cell_refs_from);
io_pr_cell (row, col, cp);
my_cell = 0;
return 0;
}

/* We're reading in a cell, whose formula is FORM, and whose current value
is VAL. Parse both of them. . . (Parsing of VAL is quite primitive)
*/
#ifdef __STDC__
char *
read_new_value (CELLREF row, CELLREF col, char *form, char *val)
#else
char *
read_new_value (row, col, form, val)
CELLREF row;
CELLREF col;
char *form;
char *val;
#endif
{
unsigned char *new_bytes;
extern double __plinf, __neinf, __nan;

cur_row = row;
cur_col = col;
my_cell = find_or_make_cell (cur_row, cur_col);
flush_old_value ();
SET_TYP (my_cell, 0);

if (form)
{
new_bytes = parse_and_compile (form);
my_cell->cell_formula = new_bytes;
}

if (val)
{
if (val[0] == '"')
{
char *sp, *nsp;

sp = val + 1;
SET_TYP (my_cell, TYP_STR);
while (*sp)
sp++;
if (*--sp != '"')
{
if (*sp == '\r' && sp[-1] == '"')
--sp;
else
panic ("Can't find \" in read_new value");
}
*sp = '\0';
nsp = my_cell->cell_str = ck_malloc (sp - val);
for (sp = val + 1; *sp;)
*nsp++ = *sp++;
*nsp++ = '\0';
}
else if (isdigit (val[0]) || val[0] == '.' || val[0] == '-' || val[0] == '+')
{
char *v;

v = val;
SET_TYP (my_cell, TYP_INT);
my_cell->cell_int = astol (&v);
if (*v)
{
SET_TYP (my_cell, TYP_FLT);
v = val;
my_cell->cell_flt = astof (&v);
if (*v)
return "unknown number";
}
}
else if (val[0] == '#')
{
char **en;

if (!stricmp (tname, val))
{
SET_TYP (my_cell, TYP_BOL);
my_cell->cell_bol = 1;
}
else if (!stricmp (fname, val))
{
SET_TYP (my_cell, TYP_BOL);
my_cell->cell_bol = 0;
}
else if (!stricmp (iname, val))
{
SET_TYP (my_cell, TYP_FLT);
my_cell->cell_flt = __plinf;
}
else if (!stricmp (iname, val))
{
SET_TYP (my_cell, TYP_FLT);
my_cell->cell_flt = __plinf;
}
else if (!stricmp (mname, val))
{
SET_TYP (my_cell, TYP_FLT);
my_cell->cell_flt = __neinf;
}
else if (!stricmp (nname, val))
{
SET_TYP (my_cell, TYP_FLT);
my_cell->cell_flt = __nan;
}
else
{
SET_TYP (my_cell, TYP_ERR);
for (en = ename; *en; en++)
if (!stricmp (*en, val))
break;
if (*en)
my_cell->cell_err = en - &ename[0];
else
my_cell->cell_err = 1;
}
}
else
panic ("What is a '%s'?", val);
}

my_cell = 0;
return 0;
}

/* This moves the contents, format, etc from RF,CF to RT,CT RF or RT may be
NON_ROW, in which case the cell's contents are moved to/from a static
storage area. Moving anything from NON_ROW before moving anything into it
or moving two things at a time into NON_ROW are both bad ideas. . .

Also note that move_cell does not call move_outside, which may or may not
be a bug. . . Move_cell is only called as part of sorting, which is why
we may *not* want to call move_outside. . .
*/

#ifdef __STDC__
void
move_cell (CELLREF rf, CELLREF cf, CELLREF rt, CELLREF ct)
#else
void
move_cell (rf, cf, rt, ct)
CELLREF rf;
CELLREF cf;
CELLREF rt;
CELLREF ct;
#endif
{
CELL *cpf;

static CELLREF non_rf, non_cf;
static struct cell non_cell;

if (rf == NON_ROW)
{
cur_row = rt;
cur_col = ct;
my_cell = find_cell (cur_row, cur_col);
if (my_cell)
flush_old_value ();
else if (!non_cell.cell_flags && !non_cell.cell_formula
&& !non_cell.cell_font)
return;
else
my_cell = find_or_make_cell (cur_row, cur_col);

my_cell->cell_flags = non_cell.cell_flags;
my_cell->cell_refs_to = non_cell.cell_refs_to;
my_cell->cell_formula = non_cell.cell_formula;
my_cell->cell_cycle = non_cell.cell_cycle;
my_cell->cell_font = non_cell.cell_font;
my_cell->c_z = non_cell.c_z;
push_refs (my_cell->cell_refs_from);
if (my_cell->cell_refs_to)
shift_formula (cur_row, cur_col, rt - non_rf, ct - non_cf);
my_cell = 0;
return;
}

cpf = find_cell (rf, cf);

if (rt == NON_ROW)
{
non_rf = rf;
non_cf = cf;
if (!cpf)
bzero (&non_cell, sizeof (non_cell));
else
{
non_cell.cell_flags = cpf->cell_flags;
non_cell.cell_refs_to = cpf->cell_refs_to;
non_cell.cell_formula = cpf->cell_formula;
non_cell.cell_cycle = cpf->cell_cycle;
non_cell.cell_font = cpf->cell_font;
non_cell.c_z = cpf->c_z;
cpf->cell_flags = 0;
cpf->cell_refs_to = 0;
cpf->cell_formula = 0;
cpf->cell_cycle = 0;
cpf->cell_font = 0;
}
return;
}

cur_row = rt;
cur_col = ct;
my_cell = find_cell (cur_row, cur_col);
if ((!cpf || (!cpf->cell_flags && !cpf->cell_formula && !cpf->cell_font))
&& !my_cell)
return;
if (!my_cell)
{
my_cell = find_or_make_cell (cur_row, cur_col);
cpf = find_cell (rf, cf); /* FOO */
}
else
flush_old_value ();

if (!cpf)
return;

my_cell->cell_flags = cpf->cell_flags;
my_cell->cell_refs_to = cpf->cell_refs_to;
my_cell->cell_formula = cpf->cell_formula;
my_cell->cell_cycle = cpf->cell_cycle;
my_cell->cell_font = cpf->cell_font;
my_cell->c_z = cpf->c_z;

cpf->cell_flags = 0;
cpf->cell_refs_to = 0;
cpf->cell_formula = 0;
cpf->cell_cycle = 0;
cpf->cell_font = 0;

push_refs (my_cell->cell_refs_from);
if (my_cell->cell_refs_to)
shift_formula (cur_row, cur_col, rt - rf, ct - cf);
my_cell = 0;
}

#ifdef __STDC__
void
copy_cell (CELLREF rf, CELLREF cf, CELLREF rt, CELLREF ct)
#else
void
copy_cell (rf, cf, rt, ct)
CELLREF rf;
CELLREF cf;
CELLREF rt;
CELLREF ct;
#endif
{
CELL *cpf;

cpf = find_cell (rf, cf);
cur_row = rt;
cur_col = ct;
my_cell = find_cell (cur_row, cur_col);
if ((!cpf || (!cpf->cell_flags && !cpf->cell_formula && !cpf->cell_font))
&& !my_cell)
return;
if (!my_cell)
{
my_cell = find_or_make_cell (cur_row, cur_col);
cpf = find_cell (rf, cf); /* FOO */
}
else
flush_old_value ();

if (!cpf)
return;

my_cell->cell_flags = cpf->cell_flags;
my_cell->cell_cycle = cpf->cell_cycle;
my_cell->cell_font = cpf->cell_font;
my_cell->cell_refs_to = cpf->cell_refs_to;

if (my_cell->cell_refs_to)
my_cell->cell_refs_to->refs_refcnt++;

if (GET_TYP (my_cell) == TYP_STR)
my_cell->cell_str = strdup (cpf->cell_str);
else
my_cell->c_z = cpf->c_z;

if (cpf->cell_formula)
{
unsigned char *fp;
unsigned char *hi;
unsigned char byte;
CELLREF trr, tcc;
struct rng trng;
struct function *f;
size_t len;
struct var *v;
CELL *tcp;

fp = cpf->cell_formula;
hi = 0;
if (!moving)
moving = init_stack ();
while ((byte = *fp++) != ENDCOMP)
{
unsigned char * refloc = fp - 1;
if (byte < USR1)
f = &the_funs[byte];
else if (byte < SKIP)
{
int tmp;
#ifdef TEST
if (byte - USR1 >= n_usr_funs)
panic ("Only have %d usr-function slots, but found byte for slot %d", n_usr_funs, 1 + byte - USR1);
#endif
tmp = *fp++;
f = &usr_funs[byte - USR1][tmp];
}
else
f = &skip_funs[byte - SKIP];

if (f->fn_argn & X_J)
fp++;
else if (f->fn_argn & X_JL)
fp += 2;

if ((f->fn_argn & X_ARGS) == X_AN)
fp++;

switch (byte)
{
case CONST_FLT:
fp += sizeof (double);
break;

case CONST_INT:
fp += sizeof (long);
break;

case CONST_STR:
if (!hi)
hi = fp + fp[-1];
break;

case CONST_STR_L:
if (!hi)
hi = fp + fp[-2] + ((unsigned) (fp[-1]) << 8);
break;

case CONST_ERR:
fp += 1 /* +sizeof(char *) */ ;
break;

case VAR:
bcopy (fp, &v, sizeof (struct var *));
fp += sizeof (struct var *);
add_ref_fm (&(v->var_ref_fm), cur_row, cur_col);
switch (v->var_flags)
{
case VAR_UNDEF:
break;
case VAR_CELL:
tcp = find_cell (v->v_rng.lr, v->v_rng.lc);
add_ref_fm (&(tcp->cell_refs_from), cur_row, cur_col);
break;
case VAR_RANGE:
add_range_ref (&(v->v_rng));
/* sparse array bug fixed here */
my_cell = find_cell (cur_row, cur_col);
cpf = find_cell (rf, cf);
break;
}
break;

case R_CELL:
case R_CELL | COLREL:
case R_CELL | ROWREL:
case R_CELL | ROWREL | COLREL:
push_stack (moving, fp);
fp += EXP_ADD;
break;

case RANGE:
case RANGE | LRREL:
case RANGE | LRREL | LCREL:
case RANGE | LRREL | LCREL | HCREL:
case RANGE | LRREL | HCREL:
case RANGE | LRREL | HRREL:
case RANGE | LRREL | HRREL | LCREL:
case RANGE | LRREL | HRREL | LCREL | HCREL:
case RANGE | LRREL | HRREL | HCREL:
case RANGE | HRREL:
case RANGE | HRREL | LCREL:
case RANGE | HRREL | LCREL | HCREL:
case RANGE | HRREL | HCREL:
case RANGE | LCREL:
case RANGE | LCREL | HCREL:
case RANGE | HCREL:
push_stack (moving, fp);
fp += EXP_ADD_RNG;
break;

default:
{
struct function *fun;

if (byte >= SKIP)
break;

if (byte < USR1)
fun = &the_funs[byte];
else
fun = &usr_funs[byte - USR1][refloc[1]];

if (fun->fn_comptype & C_T)
{
add_ref_fm (&timer_cells, rt, ct);
++timer_active;
}
break;
}
}
}
if (!hi)
hi = fp;
else
hi += strlen ((char *) hi);
hi++;
len = hi - cpf->cell_formula;
my_cell->cell_formula = cpf->cell_formula;
cpf->cell_formula = ck_malloc (hi - cpf->cell_formula);
bcopy (my_cell->cell_formula, cpf->cell_formula, len);
while (fp = pop_stack (moving))
{
byte = fp[-1];
if ((byte | ROWREL | COLREL) == (R_CELL | ROWREL | COLREL))
{
trr = GET_ROW (fp);
tcc = GET_COL (fp);
if (byte & ROWREL)
{
trr += rt - rf;
PUT_ROW (fp, trr);
}
if (byte & COLREL)
{
tcc += ct - cf;
PUT_COL (fp, tcc);
}
tcp = find_or_make_cell (trr, tcc);
add_ref_fm (&(tcp->cell_refs_from), cur_row, cur_col);
}
#ifdef TEST
else if ((byte | LRREL | HRREL | LCREL | HCREL) !=
(RANGE | LRREL | HRREL | LCREL | HCREL))
panic ("Unknown byte %x in copy_cell", byte);
#endif
else
{
GET_RNG (fp, &trng);
if (byte & LRREL)
trng.lr += rt - rf;
if (byte & HRREL)
trng.hr += rt - rf;
if (byte & LCREL)
trng.lc += ct - cf;
if (byte & HCREL)
trng.hc += ct - cf;
PUT_RNG (fp, &trng);
add_range_ref (&trng);
/* sparse array bug fixed here */
my_cell = find_cell (cur_row, cur_col);
cpf = find_cell (rf, cf);
}
}
update_cell (my_cell);
}
else
{
my_cell->cell_formula = 0;
}
io_pr_cell (cur_row, cur_col, my_cell);

push_refs (my_cell->cell_refs_from);
my_cell = 0;
}

/* Take away the value of CP. This means getting rid of all the references
to it, etc.
*/
#ifdef __STDC__
void
flush_old_value (void)
#else
void
flush_old_value ()
#endif
{
struct ref_to *ref;
unsigned char *refloc;
int n;
unsigned char byte;
CELL *other_cell;
struct var *varp;

ref = my_cell->cell_refs_to;
if (ref)
{
for (n = 0; n < ref->refs_used; n++)
{
/* Switch on formula[ref->to_refs[n]] */
refloc = &(my_cell->cell_formula[ref->to_refs[n]]);
byte = refloc[0];
switch (byte)
{
case F_ROW:
case F_COL:
break;

case R_CELL:
case R_CELL | ROWREL:
case R_CELL | COLREL:
case R_CELL | ROWREL | COLREL:
other_cell = find_cell (GET_ROW (refloc + 1), GET_COL (refloc + 1));
if (other_cell)
flush_ref_fm (&(other_cell->cell_refs_from), cur_row, cur_col);
#ifdef TEST
else
io_error_msg ("Can't find other_cell in flush_old_value");
#endif
break;
case RANGE:
case RANGE | LRREL:
case RANGE | LRREL | LCREL:
case RANGE | LRREL | LCREL | HCREL:
case RANGE | LRREL | HCREL:
case RANGE | LRREL | HRREL:
case RANGE | LRREL | HRREL | LCREL:
case RANGE | LRREL | HRREL | LCREL | HCREL:
case RANGE | LRREL | HRREL | HCREL:
case RANGE | HRREL:
case RANGE | HRREL | LCREL:
case RANGE | HRREL | LCREL | HCREL:
case RANGE | HRREL | HCREL:
case RANGE | LCREL:
case RANGE | LCREL | HCREL:
case RANGE | HCREL:
{
struct rng rng;

GET_RNG (refloc + 1, &rng);
flush_range_ref (&rng, cur_row, cur_col);
}
break;

case VAR:
bcopy (&refloc[1], &varp, sizeof (struct var *));
flush_ref_fm (&(varp->var_ref_fm), cur_row, cur_col);
if (varp->var_flags == VAR_CELL)
{
other_cell = find_cell (varp->v_rng.lr, varp->v_rng.lc);
if (other_cell)
flush_ref_fm (&(other_cell->cell_refs_from), cur_row, cur_col);
}
else if (varp->var_flags == VAR_RANGE)
flush_range_ref (&(varp->v_rng), cur_row, cur_col);
#ifdef TEST
else if (varp->var_flags != VAR_UNDEF)
panic ("Unknown var type %d", varp->var_flags);
#endif
break;

default:
{
struct function *fun;

if (byte < USR1)
fun = &the_funs[byte];
#ifdef TEST
else if (byte >= SKIP)
fun = 0, panic ("SKIP? in flush_old_value()");
#endif
else
fun = &usr_funs[byte - USR1][refloc[1]];

if (fun->fn_comptype & C_T)
{
#ifdef TEST
if (!timer_cells || !timer_cells->refs_used)
panic ("No timer cells in flush_timer_cell");
#endif
flush_ref_fm (&timer_cells, cur_row, cur_col);
--timer_active;
break;
}
else
io_error_msg ("Bad ref_to of %d.%x ignored", ref->to_refs[n], byte);
}
break;
}
}
#ifdef SPLIT_REFS
ref->refs_used = 0;
#else
flush_ref_to (&(my_cell->cell_refs_to));
#endif
}
if (my_cell->cell_formula)
{
byte_free (my_cell->cell_formula);
my_cell->cell_formula = 0;
}
if (GET_TYP (my_cell) == TYP_STR)
free (my_cell->cell_str);
SET_TYP (my_cell, 0);
}

/* --------- Routines for dealing with cell references to other cells ------ */

#ifdef __STDC__
void
add_ref (CELLREF row, CELLREF col)
#else
void
add_ref (row, col)
CELLREF row;
CELLREF col;
#endif
{
CELL *other_cell;

other_cell = find_or_make_cell (row, col);
add_ref_fm (&(other_cell->cell_refs_from), cur_row, cur_col);
}

#ifdef __STDC__
void
add_range_ref (struct rng *rng)
#else
void
add_range_ref (rng)
struct rng *rng;
#endif
{
CELL *other_cell;
struct ref_fm *oldref, *newref;
struct ref_fm nonref;


make_cells_in_range (rng);

/* Be efficient: If cells in the range currently have the same
* references, they'll have the same references afterward, so just
* adjust the refcounts
*/
nonref.refs_refcnt = 1;
other_cell = next_cell_in_range ();
oldref = other_cell->cell_refs_from;
if (oldref && oldref->refs_refcnt == 1)
oldref = &nonref;

add_ref_fm (&(other_cell->cell_refs_from), cur_row, cur_col);
newref = other_cell->cell_refs_from;
while (other_cell = next_cell_in_range ())
{
if (other_cell->cell_refs_from == oldref)
{
if (oldref)
{
if (oldref->refs_refcnt == 1)
{
flush_fm_ref (oldref);
oldref = &nonref;
}
else
oldref->refs_refcnt--;
}
other_cell->cell_refs_from = newref;
newref->refs_refcnt++;
}
else if (oldref == &nonref && (!other_cell->cell_refs_from || other_cell->cell_refs_from->refs_refcnt > 1))
{
oldref = other_cell->cell_refs_from;
add_ref_fm (&(other_cell->cell_refs_from), cur_row, cur_col);
newref = other_cell->cell_refs_from;
}
else
add_ref_fm (&(other_cell->cell_refs_from), cur_row, cur_col);
}
/* if(oldref && oldref->refs_refcnt==0) {
oldref->refs_refcnt=1;
flush_fm_ref(oldref);
} */
}

#ifdef __STDC__
static void
flush_range_ref (struct rng *rng, CELLREF rr, CELLREF cc)
#else
static void
flush_range_ref (rng, rr, cc)
struct rng *rng;
CELLREF rr;
CELLREF cc;
#endif
{
CELL *other_cell;
#ifndef SPLIT_REFS
struct ref_fm *oldref, *newref;
struct ref_fm nonref;
#endif
/* This is horribly inefficient: Simply referencing a cell makes
it appear. On the other hand, there is no other easy way to deal
with the references to the cells (That I know of, anyway) */
find_cells_in_range (rng);
#ifndef SPLIT_REFS
/* Be efficient: If cells in the range currently have the same
references, they'll have the same references afterward, so just
adjust the refcounts */
nonref.refs_refcnt = 1;
other_cell = next_cell_in_range ();
if (!other_cell)
return;
oldref = other_cell->cell_refs_from;
if (oldref && oldref->refs_refcnt == 1)
oldref = &nonref;

flush_ref_fm (&(other_cell->cell_refs_from), rr, cc);
newref = other_cell->cell_refs_from;
while (other_cell = next_cell_in_range ())
{
if (other_cell->cell_refs_from == oldref)
{
if (oldref)
{
if (oldref->refs_refcnt == 1)
{
flush_fm_ref (oldref);
oldref = &nonref;
}
else
oldref->refs_refcnt--;
}
other_cell->cell_refs_from = newref;
if (newref)
newref->refs_refcnt++;
}
else if (oldref == &nonref && (!other_cell->cell_refs_from || other_cell->cell_refs_from->refs_refcnt > 1))
{
oldref = other_cell->cell_refs_from;
flush_ref_fm (&(other_cell->cell_refs_from), rr, cc);
newref = other_cell->cell_refs_from;
}
else
flush_ref_fm (&(other_cell->cell_refs_from), rr, cc);
}
#else
while (other_cell = next_cell_in_range ())
flush_ref_fm (&(other_cell->cell_refs_from), rr, cc);
#endif
}

/* SPLIT_REFS should probably go away, since it is a performance loss.
When it is defined, we allocate a a reference structure for each cell with
references, and update them individually.

The default is to allocate one reference structure for each *different*
reference, and have multiple cells point to it. We use reference counts
to keep track of when to delete the reference structure. This would
appear to be a performance loss, but because of the increased efficiency
in referencing ranges, it may actually be faster. It also uses *far* less
memory than SPLIT_REFS */


#ifndef SPLIT_REFS
#ifdef __TURBOC__
#define FM_HASH_NUM 51
#define TO_HASH_NUM 13
#else
#define FM_HASH_NUM 503
#define TO_HASH_NUM 29
#endif
#ifdef TEST
static int fm_misses = 0;
static int to_misses = 0;
#endif

static struct ref_fm *fm_list[FM_HASH_NUM];
static struct ref_fm *fm_tmp_ref;
static unsigned fm_tmp_ref_alloc;

static struct ref_to *to_list[TO_HASH_NUM];
static struct ref_to *to_tmp_ref;
static unsigned to_tmp_ref_alloc;

#ifdef __STDC__
void
flush_refs (void)
#else
void
flush_refs ()
#endif
{
int n;
struct ref_fm *ftmp, *oftmp;
struct ref_to *ttmp, *ottmp;

for (n = 0; n < FM_HASH_NUM; n++)
{
for (ftmp = fm_list[n]; ftmp; ftmp = oftmp)
{
oftmp = ftmp->refs_next;
free (ftmp);
}
fm_list[n] = 0;
}
for (n = 0; n < TO_HASH_NUM; n++)
{
for (ttmp = to_list[n]; ttmp; ttmp = ottmp)
{
ottmp = ttmp->refs_next;
free (ttmp);
}
to_list[n] = 0;
}
}

#ifdef __STDC__
static struct ref_fm *
find_fm_ref (void)
#else
static struct ref_fm *
find_fm_ref ()
#endif
{
struct ref_fm *tmp;
int n;
unsigned long hash;

#if 1
for (hash = 0, n = 0; n < fm_tmp_ref->refs_used; n++)
{
hash += (n + 1) * (((fm_tmp_ref->fm_refs[n].ref_row) << BITS_PER_CELLREF) +
fm_tmp_ref->fm_refs[n].ref_col);
}
hash %= FM_HASH_NUM;
#else
hash = fm_tmp_ref->refs_used;
#endif
for (tmp = fm_list[hash]; tmp; tmp = tmp->refs_next)
{
if (tmp->refs_used != fm_tmp_ref->refs_used)
continue;
if (!bcmp (tmp->fm_refs, fm_tmp_ref->fm_refs, fm_tmp_ref->refs_used * sizeof (struct ref_array)))
{
tmp->refs_refcnt++;
return tmp;
}
#ifdef TEST
else
fm_misses++;
#endif
}

tmp = ck_malloc (sizeof (struct ref_fm) + (fm_tmp_ref->refs_used - 1) * sizeof (struct ref_array));
tmp->refs_next = fm_list[hash];
fm_list[hash] = tmp;
tmp->refs_refcnt = 1;
tmp->refs_used = fm_tmp_ref->refs_used;
bcopy (fm_tmp_ref->fm_refs, tmp->fm_refs, tmp->refs_used * sizeof (struct ref_array));

return tmp;
}

#ifdef __STDC__
static void
flush_fm_ref (struct ref_fm *old)
#else
static void
flush_fm_ref (old)
struct ref_fm *old;
#endif
{
struct ref_fm *tmp;
int n;
unsigned long hash;

--(old->refs_refcnt);

#ifdef DEFER_FREE
return;
#endif
if (!old->refs_refcnt)
{
#if 1
for (hash = 0, n = 0; n < old->refs_used; n++)
{
hash += (n + 1) * (((old->fm_refs[n].ref_row) << BITS_PER_CELLREF) +
old->fm_refs[n].ref_col);
}
hash %= FM_HASH_NUM;
#else
hash = old->refs_used;
#endif
if (fm_list[hash] == old)
fm_list[hash] = old->refs_next;
else
{
for (tmp = fm_list[hash]; tmp && tmp->refs_next != old; tmp = tmp->refs_next)
;
#ifdef TEST
if (!tmp)
{
io_error_msg ("Old not in refs_list in flush_fm_ref(%p)", old);
return;
}
#endif
tmp->refs_next = old->refs_next;
}
free (old);
}
}

/* This adds a from reference to a cells reference list.
* Note that the ref_fm structures themselves are hash-consed.
*/
#ifdef __STDC__
static void
add_ref_fm (struct ref_fm **where, CELLREF r, CELLREF c)
#else
static void
add_ref_fm (where, r, c)
struct ref_fm **where;
CELLREF r;
CELLREF c;
#endif
{
struct ref_fm *from;
int n;

from = *where;
if (!from)
{
if (!fm_tmp_ref)
{
fm_tmp_ref = ck_malloc (sizeof (struct ref_fm));
fm_tmp_ref_alloc = 1;
}
fm_tmp_ref->refs_used = 1;
fm_tmp_ref->fm_refs[0].ref_row = r;
fm_tmp_ref->fm_refs[0].ref_col = c;
}
else
{
if (fm_tmp_ref_alloc <= from->refs_used)
{
fm_tmp_ref =
ck_realloc (fm_tmp_ref, sizeof (struct ref_fm)
+ from->refs_used * sizeof (struct ref_array)) ;
fm_tmp_ref_alloc = from->refs_used + 1;
}
fm_tmp_ref->refs_used = from->refs_used + 1;
n = 0;
while (n < from->refs_used
&& (from->fm_refs[n].ref_row < r
|| (from->fm_refs[n].ref_row == r && from->fm_refs[n].ref_col <= c)))
{
fm_tmp_ref->fm_refs[n] = from->fm_refs[n];
n++;
}
fm_tmp_ref->fm_refs[n].ref_row = r;
fm_tmp_ref->fm_refs[n].ref_col = c;
while (n < from->refs_used)
{
fm_tmp_ref->fm_refs[n + 1] = from->fm_refs[n];
n++;
}
}
*where = find_fm_ref ();
if (from)
flush_fm_ref (from);
}

#ifdef __STDC__
static void
flush_ref_fm (struct ref_fm **where, CELLREF r, CELLREF c)
#else
static void
flush_ref_fm (where, r, c)
struct ref_fm **where;
CELLREF r;
CELLREF c;
#endif
{
struct ref_fm *from;
int n;

from = *where;
#ifdef TEST
if (!from)
{
io_error_msg ("No refs in flush_ref_fm(%p,%u,%u)", where, r, c);
return;
}
#endif
if (!from)
return;
if (from->refs_used == 1)
{
*where = 0;
flush_fm_ref (from);
return;
}
fm_tmp_ref->refs_used = from->refs_used - 1;
n = 0;
while (n < from->refs_used
&& (from->fm_refs[n].ref_row < r
|| (from->fm_refs[n].ref_row == r && from->fm_refs[n].ref_col < c)))
{
fm_tmp_ref->fm_refs[n] = from->fm_refs[n];
n++;
}
#ifdef TEST
if (n == from->refs_used)
{
io_error_msg ("No refs from %u,%u in %p in flush_refs_fm", r, c, where);
return;
}
#endif
while (n < fm_tmp_ref->refs_used)
{
fm_tmp_ref->fm_refs[n] = from->fm_refs[n + 1];
n++;
}
*where = find_fm_ref ();
flush_fm_ref (from);
}

#ifdef TEST

void
dbg_print_ref_fm (rf)
struct ref_fm *rf;
{
int nr;
char *bufp;

if (rf)
{
io_text_line ("fm %p: refcnt %u next %p used %u",
rf, rf->refs_refcnt, rf->refs_next, rf->refs_used);
for (nr = 0, bufp = print_buf; nr < rf->refs_used; nr++)
{
(void) sprintf (bufp, " %s", cell_name (rf->fm_refs[nr].ref_row, rf->fm_refs[nr].ref_col));
if (nr % 10 == 9)
{
io_text_line (print_buf);
bufp = print_buf;
}
else
bufp += strlen (bufp);
}
if (nr % 10)
io_text_line (print_buf);
}
}

#endif

#ifdef __STDC__
static struct ref_to *
find_to_ref (void)
#else
static struct ref_to *
find_to_ref ()
#endif
{
struct ref_to *tmp;
int n;
unsigned long hash;

/* io_error_msg("find_to_ref %u %u",to_tmp_ref->refs_used,to_tmp_ref->to_refs[0]); */
#if 1
for (hash = 0, n = 0; n < to_tmp_ref->refs_used; n++)
hash += (n + 1) * to_tmp_ref->to_refs[n];

hash %= TO_HASH_NUM;
#else
hash = to_tmp_ref->refs_used;
#endif
for (tmp = to_list[hash]; tmp; tmp = tmp->refs_next)
{
/* io_error_msg("%p(%u)->%p %u %u",tmp,tmp->refs_refcnt,
tmp->refs_next,tmp->refs_used,tmp->to_refs[0]); */
if (tmp->refs_used != to_tmp_ref->refs_used)
continue;
if (!bcmp (tmp->to_refs, to_tmp_ref->to_refs, to_tmp_ref->refs_used))
{
/* io_error_msg("Hit!"); */
tmp->refs_refcnt++;
return tmp;
}
#ifdef TEST
else
to_misses++;
#endif
}

/* io_error_msg("Miss. .."); */
tmp = ck_malloc (sizeof (struct ref_to) + to_tmp_ref->refs_used - 1);
tmp->refs_next = to_list[hash];
to_list[hash] = tmp;
tmp->refs_refcnt = 1;
tmp->refs_used = to_tmp_ref->refs_used;
bcopy (to_tmp_ref->to_refs, tmp->to_refs, tmp->refs_used);

return tmp;
}

#ifdef __STDC__
void
add_ref_to (int whereto)
#else
void
add_ref_to (whereto)
int whereto;
#endif
{
struct ref_to *from;
int n;

from = my_cell->cell_refs_to;
if (!from)
{
if (!to_tmp_ref)
{
to_tmp_ref = ck_malloc (sizeof (struct ref_to));
to_tmp_ref_alloc = 1;
}
to_tmp_ref->refs_used = 1;
to_tmp_ref->to_refs[0] = whereto;
}
else
{
if (to_tmp_ref_alloc <= from->refs_used)
{
to_tmp_ref = ck_realloc (to_tmp_ref, sizeof (struct ref_to) + from->refs_used);
to_tmp_ref_alloc = from->refs_used + 1;
}
to_tmp_ref->refs_used = from->refs_used + 1;
n = 0;
while (n < from->refs_used && from->to_refs[n] < whereto)
{
to_tmp_ref->to_refs[n] = from->to_refs[n];
n++;
}
to_tmp_ref->to_refs[n] = whereto;
while (n < from->refs_used)
{
to_tmp_ref->to_refs[n + 1] = from->to_refs[n];
n++;
}
flush_ref_to (&(my_cell->cell_refs_to));
}
my_cell->cell_refs_to = find_to_ref ();
}

#ifdef __STDC__
static void
flush_ref_to (struct ref_to **where)
#else
static void
flush_ref_to (where)
struct ref_to **where;
#endif
{
struct ref_to *tmp;
struct ref_to *old;
int n;
unsigned long hash;

#ifdef TEST
if (!where || !*where)
{
io_error_msg ("null flush_ref_to(%p)", where);
return;
}
#endif
old = *where;
*where = 0;
--(old->refs_refcnt);

#ifdef DEFER_FREE
return;
#endif
if (!old->refs_refcnt)
{
#if 1
for (hash = 0, n = 0; n < old->refs_used; n++)
hash += (n + 1) * old->to_refs[n];

hash %= TO_HASH_NUM;
#else
hash = old->refs_used;
#endif
if (to_list[hash] == old)
to_list[hash] = old->refs_next;
else
{
for (tmp = to_list[hash]; tmp && tmp->refs_next != old; tmp = tmp->refs_next)
;
#ifdef TEST
if (!tmp)
{
io_error_msg ("Old not in refs_list in flush_to_ref(%p)", old);
return;
}
#endif
tmp->refs_next = old->refs_next;
}
free (old);
}
}

#ifdef TEST
void
dbg_print_ref_to (rt, form)
struct ref_to *rt;
unsigned char *form;
{
int nr;
char *bufp;

if (rt)
{
io_text_line ("to %p: refcnt %u next %p used %u",
rt, rt->refs_refcnt, rt->refs_next, rt->refs_used);
for (nr = 0, bufp = print_buf; nr < rt->refs_used; nr++)
{
(void) sprintf (bufp, " %3d (%#4x)", rt->to_refs[nr], form[rt->to_refs[nr]]);
if (nr % 7 == 6)
{
io_text_line (print_buf);
bufp = print_buf;
}
else
bufp += strlen (bufp);
}
if (nr % 7)
io_text_line (print_buf);
}
}

void
ref_stats ()
{
int n;
int cur;
struct ref_fm *rf;
struct ref_to *rt;

int rf_max = 0;
int rf_num = 0;
int rf_shared = 0;
int rf_saved = 0;
int rf_zero = 0;

int rt_max = 0;
int rt_num = 0;
int rt_shared = 0;
int rt_saved = 0;
int rt_zero = 0;

for (n = 0; n < FM_HASH_NUM; n++)
{
cur = 0;
for (rf = fm_list[n]; rf; rf = rf->refs_next)
{
if (rf->refs_refcnt == 0)
rf_zero++;
if (rf->refs_refcnt > 1)
{
rf_shared++;
rf_saved += rf->refs_refcnt - 1;
}
rf_num++;
cur++;
}
if (cur > rf_max)
rf_max = cur;
}
for (n = 0; n < TO_HASH_NUM; n++)
{
cur = 0;
for (rt = to_list[n]; rt; rt = rt->refs_next)
{
if (rt->refs_refcnt == 0)
rt_zero++;
if (rt->refs_refcnt > 1)
{
rt_shared++;
rt_saved += rt->refs_refcnt - 1;
}
rt_num++;
cur++;
}
if (cur > rt_max)
rt_max = cur;
}
io_text_line ("from: %d refs, max_length %d, shared %d, saved %d, zero_ref %d, missed %d\n", rf_num, rf_max, rf_shared, rf_saved, rf_zero, fm_misses);
io_text_line ("to: %d refs, max_length %d, shared %d, saved %d, zero_ref %d, missed %d\n", rt_num, rt_max, rt_shared, rt_saved, rt_zero, to_misses);
}

#endif
#else

#ifdef __STDC__
static void
add_ref_fm (struct ref_fm **where, CELLREF r, CELLREF c)
#else
static void
add_ref_fm (where, r, c)
struct ref_fm **where;
CELLREF r;
CELLREF c;
#endif
{
struct ref_fm *ref;

ref = *where;
if (!ref)
{
*where = ref = ck_malloc (sizeof (struct ref_fm) + (REF_START - 1) * sizeof (struct ref_array));
ref->refs_alloc = REF_START;
ref->refs_used = 0;
}
else if (ref->refs_alloc == ref->refs_used)
{
ref->refs_alloc REF_INC;
*where = ref = ck_realloc (ref, sizeof (struct ref_fm) + (ref->refs_alloc - 1) * sizeof (struct ref_array));
}
ref->fm_refs[ref->refs_used].ref_row = r;
ref->fm_refs[ref->refs_used].ref_col = c;
ref->refs_used++;
}

#ifdef __STDC__
static void
flush_ref_fm (struct ref_fm **where, CELLREF r, CELLREF c)
#else
static void
flush_ref_fm (where, r, c)
struct ref_fm **where;
CELLREF r;
CELLREF c;
#endif
{
int n;
struct ref_fm *ref;

ref = *where;
#ifdef TEST
if (!ref)
{
io_error_msg ("%s->No refs in flush_ref_fm(%d,%d)", cell_name (cur_row, cur_col), r, c);
return;
}
#endif
for (n = 0; n < ref->refs_used; n++)
if (ref->fm_refs[n].ref_row == r && ref->fm_refs[n].ref_col == c)
{
ref->fm_refs[n] = ref->fm_refs[ref->refs_used - 1];
--(ref->refs_used);
return;
}
#ifdef TEST
io_error_msg ("%s->Can't flush_ref_fm(%d,%d)", cell_name (cur_row, cur_col), r, c);
return;
#endif
}

#ifdef __STDC__
void
add_ref_to (int whereto)
#else
void
add_ref_to (whereto)
int whereto;
#endif
{
struct ref_to *ref;

ref = my_cell->cell_refs_to;
if (!ref)
{
my_cell->cell_refs_to = ref = ck_malloc (sizeof (struct ref_to) + (REF_START - 1) * sizeof (unsigned char));
ref->refs_alloc = REF_START;
ref->refs_used = 0;
}
else if (ref->refs_alloc == ref->refs_used)
{
ref->refs_alloc REF_INC;
my_cell->cell_refs_to = ref = ck_realloc (ref, sizeof (struct ref_to) +
(ref->refs_alloc - 1) * sizeof (unsigned char));
}
ref->to_refs[ref->refs_used] = whereto;
ref->refs_used++;
}

#ifdef TEST

void
dbg_print_ref_fm (rf)
struct ref_fm *rf;
{
int nr;
char *bufp;

if (rf)
{
io_text_line ("fm %p: alloc %u used %u",
rf, rf->refs_alloc, rf->refs_used);
for (nr = 0, bufp = print_buf; nr < rf->refs_used; nr++)
{
(void) sprintf (bufp, " %s", cell_name (rf->fm_refs[nr].ref_row, rf->fm_refs[nr].ref_col));
if (nr % 10 == 9)
{
io_text_line (print_buf);
bufp = print_buf;
}
else
bufp += strlen (bufp);
}
if (nr % 10)
io_text_line (print_buf);
}
}

void
dbg_print_ref_to (rt, form)
struct ref_to *rt;
unsigned char *form;
{
int nr;
char *bufp;

if (rt)
{
io_text_line ("to %p: alloc %u used %u",
rt, rt->refs_alloc, rt->refs_used);
for (nr = 0, bufp = print_buf; nr < rt->refs_used; nr++)
{
(void) sprintf (bufp, " %3d (%#4x)", rt->to_refs[nr], form[rt->to_refs[nr]]);
if (nr % 7 == 6)
{
io_text_line (print_buf);
bufp = print_buf;
}
else
bufp += strlen (bufp);
}
if (nr % 7)
io_text_line (print_buf);
}
}

void
ref_stats ()
{
CELL *cp;

int rf_num = 0;
int rf_zero = 0;
int rf_biggest = 0;

int rt_num = 0;
int rt_zero = 0;
int rt_biggest = 0;

find_cells_in_range (&all_rng);
while (cp = next_cell_in_range ())
{
if (cp->cell_refs_from)
{
if (cp->cell_refs_from->refs_used > rf_biggest)
rf_biggest = cp->cell_refs_from->refs_used;
if (cp->cell_refs_from->refs_used == 0)
rf_zero++;
rf_num++;
}
if (cp->cell_refs_to)
{
if (cp->cell_refs_to->refs_used > rt_biggest)
rt_biggest = cp->cell_refs_to->refs_used;
if (cp->cell_refs_to->refs_used == 0)
rt_zero++;
rt_num++;
}
}
io_text_line ("from: %d refs, biggest %d, zero_ref %d\n", rf_num, rf_biggest, rf_zero);
io_text_line ("to: %d refs, biggest %d,zero_ref %d\n", rt_num, rt_biggest, rt_zero);
}

#endif

#endif

/* ------------- Routines for dealing with moving cells -------------------- */

static struct rng *shift_fm;
static int shift_ov;
static int shift_dn;

/* This removes all the CELL_REF_FM links associated with a
* variable, and adjusts the variables value.
* After calling this function, one must also call
* finish_shift_var to install the new CELL_REF_FM links.
*/
#ifdef __STDC__
static void
start_shift_var (char *name, struct var *v)
#else
static void
start_shift_var (name, v)
char *name;
struct var *v;
#endif
{
int n;
int nn;


n = (BETWEEN (v->v_rng.hc, shift_fm->lc, shift_fm->hc) << 3)
+ (BETWEEN (v->v_rng.lc, shift_fm->lc, shift_fm->hc) << 2)
+ (BETWEEN (v->v_rng.hr, shift_fm->lr, shift_fm->hr) << 1)
+ BETWEEN (v->v_rng.lr, shift_fm->lr, shift_fm->hr);
switch (n)
{
case 0:
case 1:
case 2:
case 3:
case 4:
case 8:
case 12:
/* Null intersection, ignore it */
break;

case 5: /* The bottom and right */
case 6: /* The bottom and left */
case 9: /* The top and right */
case 10: /* The top and left */
/* The var sticks out of the range we're moving */
/* on two sides. what should we do? */
io_error_msg ("'%s' can't be adjusted", v->var_name);
break;

case 7: /* v->hc sticks out the right */
case 11: /* v->lc sticks out the left */
case 13: /* v->hr sticks out the bottom */
case 14: /* v->lr sticks out the top */
/* It only sticks out on one side. We can
(try to) adjust it */

case 15: /* var is completely inside the range */
if (v->var_ref_fm)
{
for (nn = 0; nn < v->var_ref_fm->refs_used; nn++)
{
flush_range_ref (&(v->v_rng),
v->var_ref_fm->fm_refs[nn].ref_row,
v->var_ref_fm->fm_refs[nn].ref_col);
}
}
if (n != 7)
v->v_rng.hc += shift_ov;
if (n != 11)
v->v_rng.lc += shift_ov;
if (n != 13)
v->v_rng.hr += shift_dn;
if (n != 14)
v->v_rng.lr += shift_dn;
v->var_flags = VAR_DANGLING_RANGE;
}
}


#ifdef __STDC__
static void
finish_shift_var (char *name, struct var *v)
#else
static void
finish_shift_var (name, v)
char *name;
struct var *v;
#endif
{
int n;
if (!v->var_ref_fm || v->var_flags != VAR_DANGLING_RANGE)
return;

v->var_flags = VAR_RANGE;

for (n = 0; n < v->var_ref_fm->refs_used; n++)
{
cur_row = v->var_ref_fm->fm_refs[n].ref_row;
cur_col = v->var_ref_fm->fm_refs[n].ref_col;
add_range_ref (&(v->v_rng));
}
}

#define RIGHT 8
#define LEFT 4
#define BOTTOM 2
#define TOP 1

/*
* This iterates over the region FM, preparing the cells there to be shifted
* OV(er) and D(ow)N.
*
* After this, the ref_fm and ref_to lists of a cell within the region should
* be appropriate to the location that cell will be shifted to.
*
* Variables and references to variables are also shifted.
*/
#ifdef __STDC__
void
shift_outside (struct rng *fm, int dn, int ov)
#else
void
shift_outside (fm, dn, ov)
struct rng *fm;
int dn;
int ov;
#endif
{
CELL *cp;
CELL *fcp;
CELL *tcp;
int n;
int fn;
CELLREF rr, cc;
CELLREF frr, fcc;
CELLREF trr, tcc;
unsigned char *ffp;
unsigned char *fp;
struct rng orng;

char *ptr;
unsigned long val;
static char DEF_REF[] = "DEFREF";
static char DEF_RNG[] = "DEFRNG";

/* Variables and references to variables are also shifted. */
shift_fm = fm;
shift_dn = dn;
shift_ov = ov;
for_all_vars (start_shift_var);

/* This stack is used to defer adjustments to references that are entirely
* within FM. Intra-FM references are adjusted after references into and
* out of FM.
*/

if (!moving)
moving = init_stack ();

find_cells_in_range (fm);

while (cp = next_row_col_in_range (&rr, &cc))
{
/* cp/rr/cc is a cell in FM. */

/* First, adjust references FROM the region */
if (cp->cell_refs_to)
{
for (n = 0; n < cp->cell_refs_to->refs_used; n++)
{
fp = &(cp->cell_formula[cp->cell_refs_to->to_refs[n]]);
switch (*fp)
{
case R_CELL:
case R_CELL | ROWREL:
case R_CELL | COLREL:
case R_CELL | ROWREL | COLREL:
/* Trr/cc/cp is the cell being referenced */
trr = GET_ROW (fp + 1);
tcc = GET_COL (fp + 1);
tcp = find_cell (trr, tcc);

/* Get rid of the backpointer to this reference. */
flush_ref_fm (&(tcp->cell_refs_from), rr, cc);

/* frr/fcc is the new address of the referenced cell.
* The address will change if Trr/cc happens to be
* in the region that is moving, or if the reference
* is a relative reference.
*/
fn = (BETWEEN (trr, fm->lr, fm->hr)
&& BETWEEN (tcc, fm->lc, fm->hc));
frr = (fn || (((*fp) & ROWREL))) ? trr + dn : trr;
fcc = (fn || (((*fp) & COLREL))) ? tcc + ov : tcc;

PUT_ROW (fp + 1, frr); /* Adjust the formula byte-code. */
PUT_COL (fp + 1, fcc); /* This might even be a noop. */

/* Reinstall the backreference, unless the new address of the
* referenced cell is w/in the region being moved. (In which
* case, defer making the backreference).
*/
if (BETWEEN(frr, fm->lr, fm->hr) && BETWEEN(fcc, fm->lc, fm->hc))
{
push_stack (moving, (VOIDSTAR) TO_MAGIC (rr + dn, cc + ov));
push_stack (moving, (VOIDSTAR) TO_MAGIC (frr, fcc));
push_stack (moving, DEF_REF);
}
else
{
tcp = find_or_make_cell (frr, fcc);
add_ref_fm (&(tcp->cell_refs_from), rr + dn, cc + ov);
cp = find_cell (rr, cc);
}

break;

case VAR:
{
struct var * varp;
bcopy ((VOIDSTAR) (fp + 1),
(VOIDSTAR)&varp, sizeof (struct var *));
flush_ref_fm (&varp->var_ref_fm, rr, cc);
add_ref_fm (&varp->var_ref_fm, rr + dn, cc + ov);
break;
}

case RANGE:
case RANGE | LRREL:
case RANGE | HRREL:
case RANGE | LCREL:
case RANGE | HCREL:
case RANGE | LRREL | HRREL:
case RANGE | LRREL | LCREL:
case RANGE | LRREL | HCREL:
case RANGE | HRREL | LCREL:
case RANGE | HRREL | HCREL:
case RANGE | LCREL | HCREL:
case RANGE | LRREL | LCREL | HCREL:
case RANGE | LRREL | HRREL | LCREL:
case RANGE | LRREL | HRREL | HCREL:
case RANGE | HRREL | LCREL | HCREL:
case RANGE | LRREL | HRREL | LCREL | HCREL:
/* orng is the range being referenced. */
GET_RNG (fp + 1, &orng);

/* Get rid of backpointers to this reference. */
flush_range_ref (&orng, rr, cc);

/* This asks -- does the referenced region
* intersect the region being moved at the:
*/
fn = ((BETWEEN (orng.hc, fm->lc, fm->hc) << 3) /* right? 8 */
| (BETWEEN (orng.lc, fm->lc, fm->hc) << 2) /* left? 4 */
| (BETWEEN (orng.hr, fm->lr, fm->hr) << 1) /* bottom? 2 */
| BETWEEN (orng.lr, fm->lr, fm->hr)); /* top? 1 */

/* In this switch, a union of masks represents a conjunction
* of intersections. So, LEFT | TOP means `interects at left
* and top'.
*/
switch (fn)
{
/* Most of the time, the referenced region is moved only
* if the reference is relative.
*/
case LEFT | TOP:
case LEFT | BOTTOM:
case RIGHT | TOP:
case RIGHT | BOTTOM:

/* There used to be a warning given to the user here, but
* that seems silly, no?
*/

case 0:
case TOP:
case BOTTOM:
case TOP | BOTTOM:
case LEFT:
case RIGHT:
case LEFT | RIGHT:
if ((*fp) & LRREL)
orng.lr += dn;
if ((*fp) & HRREL)
orng.hr += dn;
if ((*fp) & LCREL)
orng.lc += ov;
if ((*fp) & HCREL)
orng.hc += ov;
break;

/* If the referenced range contains rows or columns that
* are entirely within the region being moved, then
* the region is moved, shrunk or stretched.
*/
case LEFT | BOTTOM | TOP:
case RIGHT | BOTTOM | TOP:
case RIGHT | LEFT | TOP:
case RIGHT | LEFT | BOTTOM:
case RIGHT | LEFT | BOTTOM | TOP:
if (fn != (LEFT | BOTTOM | TOP))
orng.hc += ov;
if (fn != (RIGHT | BOTTOM | TOP))
orng.lc += ov;
if (fn != (RIGHT | LEFT | TOP))
orng.hr += dn;
if (fn != (RIGHT | LEFT | BOTTOM))
orng.lr += dn;
break;
}
PUT_RNG (fp + 1, &orng); /* Patch the bytecode. */

push_stack (moving, (VOIDSTAR) fp);
push_stack (moving, (VOIDSTAR) TO_MAGIC (rr + dn, cc + ov));
push_stack (moving, DEF_RNG);
break;

default:
{
struct function *fun;

if (*fp < USR1)
fun = &the_funs[*fp];
else
fun = &usr_funs[*fp - USR1][fp[1]];

if (fun->fn_comptype & C_T)
{
flush_ref_fm (&timer_cells, rr, cc);
add_ref_fm (&timer_cells, rr + dn, cc + ov);
}
}
break;
}

}
}

/* Next, adjust references TO the region */
for (n = 0; cp->cell_refs_from && n < cp->cell_refs_from->refs_used; n++)
{
/* The second enclosed loop over the bytecode will fix all of the
* references to this cell. This loop is here because a
* refs_fm structure may contain more than one occurence of the
* referencing cell. We don't want to adjust the same bytecode
* twice.
*/
while ((n < cp->cell_refs_from->refs_used - 1)
&& (cp->cell_refs_from->fm_refs[n].ref_row ==
cp->cell_refs_from->fm_refs[n + 1].ref_row)
&& (cp->cell_refs_from->fm_refs[n].ref_col ==
cp->cell_refs_from->fm_refs[n + 1].ref_col))
++n;

/* For each cell that referenced this one, look
* at the type of reference involved
*/
frr = cp->cell_refs_from->fm_refs[n].ref_row;
fcc = cp->cell_refs_from->fm_refs[n].ref_col;

/* Unless the reference is from inside the region we're moving, in
* which case, it has already been adjusted.
*
* (This test seems unnecessary but harmless. -tl)
*/
if (BETWEEN (frr, fm->lr, fm->hr) && BETWEEN (fcc, fm->lc, fm->hc))
continue;

/* Find the cell that references cp. */
fcp = find_cell (frr, fcc);

/* Search the byte-code for the reference. */
for (fn = 0; fcp->cell_refs_to && fn < fcp->cell_refs_to->refs_used; fn++)
{

ffp = &(fcp->cell_formula[fcp->cell_refs_to->to_refs[fn]]);
switch (*ffp)
{
case R_CELL:
case R_CELL | ROWREL:
case R_CELL | COLREL:
case R_CELL | ROWREL | COLREL:

trr = GET_ROW (ffp + 1);
tcc = GET_COL (ffp + 1);

if (trr != rr || tcc != cc)
continue;

{
CELLREF old_tr = trr;
CELLREF old_tc = tcc;
/* Find the cell that fcp should reference now. */
if (!((*ffp) & ROWREL))
{
trr += dn;
PUT_ROW (ffp + 1, trr);
}
if (!((*ffp) & COLREL))
{
tcc += ov;
PUT_COL (ffp + 1, tcc);
}
else
/* If this is an abs reference, it doesn't change. */
continue;
/* Get rid of the now-invalid backpointer */
{
CELL * old_reffed = find_cell (old_tr, old_tc);
flush_ref_fm (&(old_reffed->cell_refs_from), frr, fcc);
}
}

if (BETWEEN (trr, fm->lr, fm->hr) && BETWEEN (tcc, fm->lc, fm->hc))
{
push_stack (moving, (VOIDSTAR) TO_MAGIC (frr, fcc));
push_stack (moving, (VOIDSTAR) TO_MAGIC (trr, tcc));
push_stack (moving, DEF_REF);
}
else
{
cp = find_or_make_cell (trr, tcc);
add_ref_fm (&(cp->cell_refs_from), frr, fcc);
}


case VAR:
/* This case is taken care of by {start,finish}_shift_vars */
continue;

case RANGE:
case RANGE | LRREL:
case RANGE | LRREL | LCREL:
case RANGE | LRREL | LCREL | HCREL:
case RANGE | LRREL | HCREL:
case RANGE | LRREL | HRREL:
case RANGE | LRREL | HRREL | LCREL:
case RANGE | LRREL | HRREL | LCREL | HCREL:
case RANGE | LRREL | HRREL | HCREL:
case RANGE | HRREL:
case RANGE | HRREL | LCREL:
case RANGE | HRREL | LCREL | HCREL:
case RANGE | HRREL | HCREL:
case RANGE | LCREL:
case RANGE | LCREL | HCREL:
case RANGE | HCREL:
GET_RNG (ffp + 1, &orng);

if (!BETWEEN (rr, orng.lr, orng.hr) || !BETWEEN (cc, orng.lc, orng.hc))
break;

val = ((BETWEEN (orng.hc, fm->lc, fm->hc) << 3) /* right */
+ (BETWEEN (orng.lc, fm->lc, fm->hc) << 2) /* left */
+ (BETWEEN (orng.hr, fm->lr, fm->hr) << 1) /* bottom */
+ BETWEEN (orng.lr, fm->lr, fm->hr)); /* top */

/* If the reference is absolute, or relative only in directions
* that aren't changing, there's nothing to do.
*/
if (!(*ffp == RANGE
|| (!dn && ((*ffp) | LRREL | HRREL) == (RANGE | LRREL | HRREL))
|| (!ov && ((*ffp) | LCREL | HCREL) == (RANGE | LCREL | HCREL))))
continue;

/* If it's a case we don't know how to adjust, there's
* nothing to do. If there is no overlap, there's nothing to
* do.
*/
if ((val != (LEFT | BOTTOM | TOP))
&& (val != (RIGHT | BOTTOM | TOP))
&& (val != (RIGHT | LEFT | TOP))
&& (val != (RIGHT | LEFT | BOTTOM))
&& (val != (RIGHT | LEFT | BOTTOM | TOP)))
continue;

flush_range_ref (&orng, frr, fcc);

if (val != (RIGHT | LEFT | BOTTOM))
orng.lr += dn;
if (val != (RIGHT | LEFT | TOP))
orng.hr += dn;
if (val != (RIGHT | BOTTOM | TOP))
orng.lc += ov;
if (val != (LEFT | BOTTOM | TOP))
orng.hc += ov;
PUT_RNG (ffp + 1, &orng);
push_stack (moving, (VOIDSTAR) ffp);
push_stack (moving, (VOIDSTAR) TO_MAGIC (frr, fcc));
push_stack (moving, DEF_RNG);
continue;
#ifdef TEST
default:
{ struct function *fun; if (*ffp < USR1) fun =
&the_funs[*ffp]; else if (*ffp >= SKIP) fun = 0, panic
("SKIP? in shift_outside()"); else fun =
&usr_funs[*ffp][ffp[1]];
if ((fun->fn_comptype & C_T) == 0) io_error_msg
("Unknown byte (%d) for reference_to #%d %d",
*ffp, fn, fcp->cell_refs_to->to_refs[fn]);
}
break;
#endif
}
}
}
}

while (ptr = pop_stack (moving))
{
if (ptr == DEF_REF)
{
val = (unsigned long) pop_stack (moving);
trr = MAGIC_ROW (val);
tcc = MAGIC_COL (val);
val = (unsigned long) pop_stack (moving);
cp = find_or_make_cell (trr, tcc);
add_ref_fm (&(cp->cell_refs_from), MAGIC_ROW (val), MAGIC_COL (val));
}
else if (ptr == DEF_RNG)
{
val = (unsigned long) pop_stack (moving);
cur_row = MAGIC_ROW (val);
cur_col = MAGIC_COL (val);
ffp = (unsigned char *) pop_stack (moving);

GET_RNG (ffp + 1, &orng);
add_range_ref (&orng);
if (my_cell)
panic ("shift_outside: my_cell lost.");
/* If this panic occurs, the caller should be recomputing
* my_cell after shift_outside returns (and this useful panic
* will have to be removed or my_cell set temporarily to 0).
*/
}
#ifdef TEST
else
panic ("Now what (%p)?", ptr);
#endif
}
for_all_vars (finish_shift_var);
/* flush_stack(moving); */
}

/* The formula in cell my_cell has moved by DN down and OV over, adjust
everything so it'll still work */
#ifdef __STDC__
void
shift_formula (int r, int c, int dn, int ov)
#else
void
shift_formula (r, c, dn, ov)
int r; /* Address of my_cell. */
int c;
int dn;
int ov;
#endif
{
int n;
unsigned char *fp;

for (n = 0; n < my_cell->cell_refs_to->refs_used; n++)
{
fp = &(my_cell->cell_formula[my_cell->cell_refs_to->to_refs[n]]);
switch (*fp)
{
case F_ROW:
case F_COL:
push_cell (cur_row, cur_col);
break;

case R_CELL:
case R_CELL | ROWREL:
case R_CELL | COLREL:
case R_CELL | ROWREL | COLREL:
{
CELLREF trr, tcc;
CELL *tcp;

/* These are more difficult */
trr = GET_ROW (fp + 1);
tcc = GET_COL (fp + 1);
tcp = find_cell (trr, tcc);
#ifdef TEST
if (!tcp)
panic ("Can't find_cell(%s) in shift_formula", cell_name (trr, tcc));
#endif
flush_ref_fm (&(tcp->cell_refs_from), cur_row - dn, cur_col - ov);

if (((*fp) & ROWREL) && dn)
{
trr += dn;
PUT_ROW (fp + 1, trr);
}
if (((*fp) & COLREL) && ov)
{
tcc += ov;
PUT_COL (fp + 1, tcc);
}
tcp = find_or_make_cell (trr, tcc);
add_ref_fm (&(tcp->cell_refs_from), cur_row, cur_col);
}
break;

case RANGE:
case RANGE | LRREL:
case RANGE | LRREL | LCREL:
case RANGE | LRREL | LCREL | HCREL:
case RANGE | LRREL | HCREL:
case RANGE | LRREL | HRREL:
case RANGE | LRREL | HRREL | LCREL:
case RANGE | LRREL | HRREL | LCREL | HCREL:
case RANGE | LRREL | HRREL | HCREL:
case RANGE | HRREL:
case RANGE | HRREL | LCREL:
case RANGE | HRREL | LCREL | HCREL:
case RANGE | HRREL | HCREL:
case RANGE | LCREL:
case RANGE | LCREL | HCREL:
case RANGE | HCREL:
{
struct rng orng;
GET_RNG (fp + 1, &orng);

flush_range_ref (&orng, cur_row - dn, cur_col - ov);

if ((*fp) & LRREL)
orng.lr += dn;
if ((*fp) & HRREL)
orng.hr += dn;
if ((*fp) & LCREL)
orng.lc += ov;
if ((*fp) & HCREL)
orng.hc += ov;
PUT_RNG (fp + 1, &orng);
add_range_ref (&orng);
/* sparse array bug fixed here */
my_cell = find_cell (r, c);
}
break;

case VAR:
{
struct var *v;
struct cell *tcp;

bcopy (&fp[1], &v, sizeof (struct var *));
flush_ref_fm (&(v->var_ref_fm), cur_row - dn, cur_col - ov);
add_ref_fm (&(v->var_ref_fm), cur_row, cur_col);
switch (v->var_flags)
{
case VAR_UNDEF:
break;

case VAR_CELL:
tcp = find_cell (v->v_rng.lr, v->v_rng.lc);
#ifdef TEST
if (!tcp)
panic ("Can't find_cell(%s) in shift_formula", cell_name (v->v_rng.lr, v->v_rng.lc));
#endif
flush_ref_fm (&(tcp->cell_refs_from), cur_row - dn, cur_col - ov);
add_ref_fm (&(tcp->cell_refs_from), cur_row, cur_col);
break;

case VAR_RANGE:
flush_range_ref (&(v->v_rng), cur_row - dn, cur_col - ov);
add_range_ref (&(v->v_rng));
/* sparse array bug fixed here */
my_cell = find_cell (r, c);
break;

#ifdef TEST
default:
panic ("Unknown var type %d", v->var_flags);
#endif
}
}
break;

default:
{
struct function *fun;

if (*fp < USR1)
fun = &the_funs[*fp];
#ifdef TEST
else if (*fp >= SKIP)
fun = 0, panic ("SKIP? in shift_formula?");
#endif
else
fun = &usr_funs[*fp][fp[1]];
/* These are easy */
if (fun->fn_comptype & C_T)
{
flush_ref_fm (&timer_cells, cur_row - dn, cur_col - ov);
add_ref_fm (&timer_cells, cur_row, cur_col);
}
#ifdef TEST
else
panic ("How do I deal with byte %d in shift_formula()?", *fp);
#endif
}
break;
}
}
}


/* ---------------- Routines for dealing with async functions -------------- */


/* This function is called when the alarm has gone off (but not from inside
* the signal handler!). It schedules timer_cells->fm_refs for recalc.
*/
#ifdef __STDC__
void
cell_alarm (void)
#else
void
cell_alarm ()
#endif
{
int n;
static time_t last_time = 0;
if (timer_active)
{
time_t this_time = time(0);
if ((this_time - last_time) < cell_timer_seconds)
return;
last_time = this_time;
current_cycle++;
for (n = 0; n < timer_cells->refs_used; n++)
push_cell (timer_cells->fm_refs[n].ref_row,
timer_cells->fm_refs[n].ref_col);
}
}

/* All the timer_cells are going away, 'cuz everything is going away. . . */
#ifdef __STDC__
void
flush_all_timers (void)
#else
void
flush_all_timers ()
#endif
{
if (timer_active)
{
#ifdef SPLIT_REFS
timer_cells->refs_used = 0;
#else
flush_fm_ref (timer_cells);
timer_cells = 0;
#endif
timer_active = 0;
}
}

/* Add CUR_ROW, CUR_COL to the list of active timer-cells, turning on
the timer_active, if it isn't already */
#ifdef __STDC__
void
add_timer_ref (int whereto)
#else
void
add_timer_ref (whereto)
int whereto;
#endif
{
add_ref_to (whereto);
add_ref_fm (&timer_cells, cur_row, cur_col);
++timer_active;
}

/* ---------- Routines and vars for dealing with the eval FIFO ------------ */
static struct cell_buf cell_buffer;

/* Start up the FIFO of cells to update */
#ifdef __STDC__
void
init_refs (void)
#else
void
init_refs ()
#endif
{
cell_buffer.size = FIFO_START;
cell_buffer.buf = (struct pos *) ck_malloc (cell_buffer.size * sizeof (struct pos));
bzero (cell_buffer.buf, cell_buffer.size * sizeof (struct pos));
cell_buffer.push_to_here = cell_buffer.buf;
cell_buffer.pop_frm_here = cell_buffer.buf;
the_vars = hash_new ();
}

/* Push the cells in REF onto the FIFO. This calls push_cell to do the
actual work. . . */
#ifdef __STDC__
void
push_refs (struct ref_fm *ref)
#else
void
push_refs (ref)
struct ref_fm *ref;
#endif
{
int n;

if (!ref || !ref->refs_used)
return;
n = ref->refs_used;
while (n--)
{
#ifdef TEST
CELL *cp;

if (debug & 04)
io_error_msg ("Push %s", cell_name (ref->fm_refs[n].ref_row, ref->fm_refs[n].ref_col));
cp = find_cell (ref->fm_refs[n].ref_row, ref->fm_refs[n].ref_col);
if (cp->cell_cycle == current_cycle)
{
if (debug & 01)
io_error_msg ("Cycle detected from %s to %s",
cell_name (cur_row, cur_col),
cell_name (ref->fm_refs[n].ref_row, ref->fm_refs[n].ref_col));
push_cell (ref->fm_refs[n].ref_row,
ref->fm_refs[n].ref_col);
}
else
#endif
push_cell (ref->fm_refs[n].ref_row, ref->fm_refs[n].ref_col);
}
}

/* Push a cell onto the FIFO of cells to evaluate, checking for cells
that are already on the FIFO, etc.

This does not implement best-order recalculation, since there may be
intersecting branches in the dependency tree, however, it's close enough
for most people.
*/
#ifdef __STDC__
void
push_cell (CELLREF row, CELLREF col)
#else
void
push_cell (row, col)
CELLREF row;
CELLREF col;
#endif
{
struct pos *dup;
CELL *cp;
struct ref_fm *rf;

if (cell_buffer.push_to_here + 1 == cell_buffer.pop_frm_here || (cell_buffer.pop_frm_here == cell_buffer.buf && cell_buffer.push_to_here == cell_buffer.buf + (cell_buffer.size - 1)))
{
int f, t, from_num;

f = cell_buffer.pop_frm_here - cell_buffer.buf;
t = cell_buffer.push_to_here - cell_buffer.buf;
from_num = cell_buffer.size - f;

cell_buffer.size FIFO_INC;
cell_buffer.buf = (struct pos *) ck_realloc ((VOIDSTAR) cell_buffer.buf, cell_buffer.size * sizeof (struct pos));
if (t == 0)
{
cell_buffer.push_to_here = cell_buffer.buf + f + from_num;
cell_buffer.pop_frm_here = cell_buffer.buf + f;
}
else if (t > f)
{
cell_buffer.push_to_here = cell_buffer.buf + t;
cell_buffer.pop_frm_here = cell_buffer.buf + f;
}
else
{
cell_buffer.push_to_here = cell_buffer.buf + t;
cell_buffer.pop_frm_here = cell_buffer.buf + (cell_buffer.size - from_num);
if (from_num)
bcopy (cell_buffer.buf + f,
cell_buffer.pop_frm_here,
from_num * sizeof (struct pos));
}
}

#if 1
if (cell_buffer.pop_frm_here != cell_buffer.push_to_here)
{
dup = cell_buffer.pop_frm_here;

cp = find_cell (row, col);
if (!cp)
{
return;
}
rf = cp->cell_refs_from;
for (; dup != cell_buffer.push_to_here;)
{
if (dup->row == row && dup->col == col)
{
#ifdef TEST
if (debug & 010)
io_error_msg ("Flushed dup ref to %s", cell_name (row, col));
#endif
*dup = *(cell_buffer.pop_frm_here);
cell_buffer.pop_frm_here++;
if (cell_buffer.pop_frm_here == cell_buffer.buf + cell_buffer.size)
cell_buffer.pop_frm_here = cell_buffer.buf;
break;
}
#if 0
if (rf)
{
for (n = 0; n < rf->refs_used; n++)
if (rf->fm_refs[n].ref_row == dup->row && rf->fm_refs[n].ref_col == dup->col)
{
#ifdef TEST
if (debug & 01)
io_error_msg ("Swapped %s and %s", cell_name (row, col), cell_name (dup->row, dup->col));
#endif
dup->row = row;
dup->col = col;
row = rf->fm_refs[n].ref_row;
col - rf->fm_refs[n].ref_col;
goto breakout;
}
}
#endif

if (++dup == cell_buffer.buf + cell_buffer.size)
dup = cell_buffer.buf;
}
}
#endif

cell_buffer.push_to_here->row = row;
cell_buffer.push_to_here->col = col;
cell_buffer.push_to_here++;
if (cell_buffer.push_to_here == cell_buffer.buf + cell_buffer.size)
cell_buffer.push_to_here = cell_buffer.buf;
}

/* Pop a cell off CELL_BUFFER, and evaluate it, displaying the result. . .
This returns 0 if there are no more cells to update, or if it gets
an error. */

#ifdef __STDC__
int
eval_next_cell (void)
#else
int
eval_next_cell ()
#endif
{
CELL *cp;
static loop_counter = 40;

if (cell_buffer.pop_frm_here == cell_buffer.push_to_here)
return 0;

cur_row = cell_buffer.pop_frm_here->row;
cur_col = cell_buffer.pop_frm_here->col;
cell_buffer.pop_frm_here++;
if (cell_buffer.pop_frm_here == cell_buffer.buf + cell_buffer.size)
cell_buffer.pop_frm_here = cell_buffer.buf;

cp = find_cell (cur_row, cur_col);
if (cp)
{
if (cp->cell_cycle == current_cycle)
--loop_counter;
else
loop_counter = 40;
update_cell (cp);
io_pr_cell (cur_row, cur_col, cp);
return loop_counter;
}
else
return 0;
}

#ifdef TEST
void
cell_buffer_contents ()
{
struct pos *ptr;

if (cell_buffer.pop_frm_here != cell_buffer.push_to_here)
{
ptr = cell_buffer.pop_frm_here;
for (;;)
{
printf ("Ref to %s\r\n", cell_name (ptr->row, ptr->col));
if (++ptr == cell_buffer.buf + cell_buffer.size)
ptr = cell_buffer.buf;
if (ptr == cell_buffer.push_to_here)
break;
}
}
printf ("End of buffer\r\n");
}

#endif

/* ----------------- Routines for dealing with variables ------------------ */

/* This sets the variable V_NAME to V_NEWVAL
It returns error msg, or 0 on success.
All the appropriate cells have their ref_fm arrays adjusted appropriatly
This could be smarter; when changing a range var, only the cells that
were in the old value but not in the new one need their references flushed,
and only the cells that are new need references added.
This might also be changed to use add_range_ref()?
*/
#ifdef __STDC__
char *
new_var_value (char *v_name, int v_namelen, char *v_newval)
#else
char *
new_var_value (v_name, v_namelen, v_newval)
char *v_name;
int v_namelen;
char *v_newval;
#endif
{
struct var *var;
int n;
int newflag;
struct rng tmp_rng;

cur_row = MIN_ROW;
cur_col = MIN_COL;
if (v_newval && *v_newval)
{
n = parse_cell_or_range (&v_newval, &tmp_rng);
if (!n)
return "Can't parse cell or range";
if (*v_newval)
return "Junk after cell or range";
newflag = ((n | ROWREL | COLREL) == (R_CELL | ROWREL | COLREL)) ? VAR_CELL : VAR_RANGE;
}
else
{
tmp_rng.lr = tmp_rng.hr = NON_ROW;
tmp_rng.lc = tmp_rng.hc = NON_COL;
newflag = VAR_UNDEF;
}

var = find_or_make_var (v_name, v_namelen);

if (var->var_ref_fm)
{
if (var->var_flags != VAR_UNDEF)
{
for (n = 0; n < var->var_ref_fm->refs_used; n++)
{
flush_range_ref (&(var->v_rng),
var->var_ref_fm->fm_refs[n].ref_row,
var->var_ref_fm->fm_refs[n].ref_col);
}
}
var->v_rng = tmp_rng;

if (var->v_rng.lr != NON_ROW)
{
for (n = 0; n < var->var_ref_fm->refs_used; n++)
{
cur_row = var->var_ref_fm->fm_refs[n].ref_row;
cur_col = var->var_ref_fm->fm_refs[n].ref_col;
add_range_ref (&(var->v_rng));
}
}
for (n = 0; n < var->var_ref_fm->refs_used; n++)
push_cell (var->var_ref_fm->fm_refs[n].ref_row,
var->var_ref_fm->fm_refs[n].ref_col);
}
else
var->v_rng = tmp_rng;

var->var_flags = newflag;

return 0;
}

#ifdef __STDC__
void
for_all_vars (void (*func) (char *, struct var *))
#else
void
for_all_vars (func)
void (*func) ();
#endif
{
hash_apply (the_vars, func);
}

/* Find a variable in the list of variables, or create it if it doesn't
exist. Takes a name and a length so the name doesn't have to be
null-terminated
*/
#ifdef __STDC__
struct var *
find_or_make_var (char *string, int len)
#else
struct var *
find_or_make_var (string, len)
char *string;
int len;
#endif
{
struct var *ret;
int ch;

ch = string[len];
string[len] = '\0';

ret = (struct var *) hash_find (the_vars, string);
if (ret)
{
string[len] = ch;
return ret;
}

ret = (struct var *) ck_malloc (sizeof (struct var) + len);
bcopy (string, ret->var_name, len + 1);
ret->var_flags = VAR_UNDEF;
ret->v_rng.lr = 0;
ret->v_rng.lc = 0;
ret->v_rng.hr = 0;
ret->v_rng.hc = 0;
ret->var_ref_fm = 0;
hash_insert (the_vars, ret->var_name, ret);
string[len] = ch;
return ret;
}

/* Like find-or-make-var except returns 0 if it doesn't exist */
#ifdef __STDC__
struct var *
find_var (char *string, int len)
#else
struct var *
find_var (string, len)
char *string;
int len;
#endif
{
int ch;
struct var *ret;

ch = string[len];
string[len] = '\0';
ret = (struct var *) hash_find (the_vars, string);
string[len] = ch;
return ret;
}

/* This adds a reference from CUR_ROW,CUR_COL to the variable VAR
It calls add_ref or add_range_ref to have the cell(s) in VAR be
referenced by CUR_ROW,CUR_COL
*/
#ifdef __STDC__
void
add_var_ref (void * vvar)
#else
void
add_var_ref (vvar)
void * vvar;
#endif
{
struct var *var = (struct var *)vvar;
add_ref_fm (&(var->var_ref_fm), cur_row, cur_col);
switch (var->var_flags)
{
case VAR_UNDEF:
break;
case VAR_CELL:
add_ref (var->v_rng.lr, var->v_rng.lc);
break;
case VAR_RANGE:
add_range_ref (&(var->v_rng));
break;
#ifdef TEST
default:
panic ("Unknown var type %d in add_var_ref", var->var_flags);
#endif
}
}

#ifdef __STDC__
static void
flush_var (char *name, struct var *var)
#else
static void
flush_var (name, var)
char *name;
struct var *var;
#endif
{
#ifdef SPLIT_REFS
if (var->var_ref_fm)
free (var->var_ref_fm);
#endif
free (var);
}


/* Free up all the variables, and (if SPLIT_REFS) the ref_fm structure
associated with each variable. Note that this does not get rid of
the struct var *s in cell expressions, so it can only be used when all
the cells are being freed also
*/
#ifdef __STDC__
void
flush_variables (void)
#else
void
flush_variables ()
#endif
{
for_all_vars (flush_var);
hash_die (the_vars);
the_vars = hash_new ();
}
oleo-1.3/decompile.c 644 722 0 44704 5355700425 12625 0ustar lordwheel/* Copyright (C) 1990, 1992, 1993 Free Software Foundation, Inc.

This file is part of Oleo, the GNU Spreadsheet.

Oleo 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, or (at your option)
any later version.

Oleo 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 Oleo; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */

#include "global.h"
#include "decompile.h"
#include "eval.h"
#include "cell.h"
#include "io-utils.h"



struct pr_node
{
int tightness;
int len;
char string[1];
};


static VOIDSTAR save_decomp;
static CELLREF decomp_row;
static CELLREF decomp_col;

/* These #defines are so that we don't have to duplicate code below */
/* JF: now obsolete, and should be trashed. */

#define F0 a0?"@%s()":"%s()"
#define F1 a0?"@%s(%s)":"%s(%s)"
#define F2 a0?"@%s(%s, %s)":"%s(%s, %s)"
#define F3 a0?"@%s(%s, %s, %s)":"%s(%s, %s, %s)"
#define F4 a0?"@%s(%s, %s, %s, %s)":"%s(%s, %s, %s, %s)"
#define FN1 a0?"@%s(%s":"%s(%s"

/* We decompile things with these wierd node-things. It's ugly, but it works.
*/
#ifdef __STDC__
static struct pr_node *
n_alloc (int size, int tightness, char *fmt,...)
#else
static struct pr_node *
n_alloc (size, tightness, fmt, va_alist)
int size;
int tightness;
char *fmt;
va_dcl
#endif
{
struct pr_node *ret;
va_list args;

ret = ck_malloc (sizeof (struct pr_node) + size + 1);
ret->len = size;
ret->tightness = tightness;
var_start (args, fmt);
vsprintf (ret->string, fmt, args);
va_end (args);
return ret;
}

#define n_free(x) free(x)

static struct pr_node *
byte_decompile (expr)
unsigned char *expr;
{
unsigned char byte;
double tmp_flt;
long tmp_lng;
char *tmp_str;
struct var *v;
unsigned long_skp;
unsigned char save_val;
unsigned jumpto;

struct pr_node *new = 0;
int pri;
int aso;
char *chr;

static struct pr_node **the_line;
static int line_alloc;

static struct pr_node **c_node;
struct function *f;

if (!the_line)
{
the_line = (struct pr_node **) ck_malloc (20 * sizeof (struct pr_node *));
line_alloc = 20;
c_node = the_line;
}

#ifdef TEST
if (!expr)
panic ("No expression to decompile");
#endif
next_byte:
byte = *expr++;
if (byte < USR1)
f = &the_funs[byte];
else if (byte < SKIP)
{
tmp_lng = *expr++;
f = &usr_funs[byte - USR1][tmp_lng];
}
else
f = &skip_funs[byte - SKIP];

if (f->fn_argn & X_J)
jumpto = *expr++;
else if (f->fn_argn & X_JL)
{
jumpto = expr[0] + ((unsigned) (expr[1]) << 8);
expr += 2;
}
else
jumpto = 0;

switch (GET_COMP (f->fn_comptype))
{
case C_IF:
if (expr[jumpto - 2] != SKIP)
{
long_skp = 1;
save_val = expr[jumpto - 3];
expr[jumpto - 3] = 0;
}
else
{
long_skp = 0;
save_val = expr[jumpto - 2];
expr[jumpto - 2] = 0;
}
c_node[0] = byte_decompile (expr);
c_node++;

if (long_skp)
{
expr[jumpto - 3] = save_val;
expr += jumpto;
jumpto = expr[-2] + ((unsigned) (expr[-1]) << 8);
}
else
{
expr[jumpto - 2] = save_val;
expr += jumpto;
jumpto = expr[-1];
}
save_val = expr[jumpto];
expr[jumpto] = 0;
c_node[0] = byte_decompile (expr);
c_node -= 2;
expr[jumpto] = save_val;
expr += jumpto;
if (byte == IF || byte == IF_L)
{
if (c_node[0]->tightness <= 1)
new = n_alloc (8 + c_node[0]->len + c_node[1]->len + c_node[2]->len,
1,
"(%s) ? %s : %s", c_node[0]->string, c_node[1]->string, c_node[2]->string);
else
new = n_alloc (6 + c_node[0]->len + c_node[1]->len + c_node[2]->len,
1,
"%s ? %s : %s", c_node[0]->string, c_node[1]->string, c_node[2]->string);
}
else
new = n_alloc (6 + c_node[0]->len + c_node[1]->len + c_node[2]->len + strlen (f->fn_str),
1000,
F3, f->fn_str, c_node[0]->string, c_node[1]->string, c_node[2]->string);
n_free (c_node[0]);
n_free (c_node[1]);
n_free (c_node[2]);
break;

case C_ANDOR:
save_val = expr[jumpto];
expr[jumpto] = 0;
c_node[0] = byte_decompile (expr);
expr[jumpto] = save_val;
expr += jumpto;
c_node++;
if (ISINFIX (f->fn_comptype))
{
pri = GET_IN (f->fn_comptype);
aso = GET_ASO (f->fn_comptype);
chr = f->fn_str;
goto do_infix;
}
else
goto do_fn2;

case C_STR:
tmp_str = backslash_a_string ((char *) expr + jumpto, 1);
new = n_alloc (strlen (tmp_str) + 1,
1000,
tmp_str);
break;

case C_CELL:
{
int num1, num2;
char *str;
CELLREF row, col;

row = GET_ROW (expr);
col = GET_COL (expr);
expr += EXP_ADD;

if (a0)
{
new = n_alloc (30, 1000, f->fn_str, col_to_str (col), row);
}
else
{
if (byte & ROWREL)
{
num1 = row - decomp_row;
if (byte & COLREL)
{
num2 = col - decomp_col;
if (row == decomp_row && col == decomp_col)
str = "rc";
else if (row == decomp_row)
{
str = "rc[%+d]";
num1 = num2;
}
else if (col == decomp_col)
str = "r[%+d]c";
else
str = "r[%+d]c[%+d]";
}
else if (row == decomp_row)
{
str = "rc%u";
num1 = num2 = col;
}
else
{
str = "r[%+d]c%u";
num2 = col;
}
}
else if (byte & COLREL)
{
num1 = row;
num2 = col - decomp_col;
if (col == decomp_col)
str = "r%uc";
else
str = "r%uc[%+d]";
}
else
{
str = "r%uc%u";
num1 = row;
num2 = col;
}
new = n_alloc (30, 1000, str, num1, num2);
}
new->len = strlen (new->string);
}
break;

case C_RANGE:
{
char tmprbuf[40];
char tmpcbuf[40];
struct rng rng;

GET_RNG (expr, &rng);
expr += EXP_ADD_RNG;

if (a0)
new = n_alloc (40, 1000, f->fn_str, col_to_str (rng.lc), rng.lr, col_to_str (rng.hc), rng.hr);
else
{
/* Check for special cases */
if (rng.lr == rng.hr && ((byte & LRREL) ? 1 : 0) == ((byte & HRREL) ? 1 : 0))
{
if (byte & LRREL)
{
if (rng.lr == decomp_row)
{
tmprbuf[0] = 'r';
tmprbuf[1] = '\0';
}
else
(void) sprintf (tmprbuf, "r[%+d]", rng.lr - decomp_row);
}
else
sprintf (tmprbuf, "r%u", rng.lr);
}
else if ((byte & LRREL) && (byte & HRREL))
{
int r1, r2, rtmp;

r1 = rng.lr - decomp_row;
r2 = rng.hr - decomp_row;
if (r1 < r2)
rtmp = r1, r1 = r2, r2 = rtmp;
(void) sprintf (tmprbuf, "r[%+d:%+d]", r1, r2);
}
else if ((byte & LRREL))
(void) sprintf (tmprbuf, "r[%+d]:%u", rng.lr - decomp_row, rng.hr);
else if (byte & HRREL)
(void) sprintf (tmprbuf, "r%u:[%+d]", rng.lr, rng.hr - decomp_row);
else if (rng.lr < rng.hr)
(void) sprintf (tmprbuf, "r%u:%u", rng.lr, rng.hr);
else
(void) sprintf (tmprbuf, "r%u:%u", rng.hr, rng.lr);

if (rng.lc == rng.hc && ((byte & LCREL) ? 1 : 0) == ((byte & HCREL) ? 1 : 0))
{
if (byte & LCREL)
{
if (rng.lc == decomp_col)
{
tmpcbuf[0] = 'c';
tmpcbuf[1] = '\0';
}
else
sprintf (tmpcbuf, "c[%+d]", rng.lc - decomp_col);
}
else
sprintf (tmpcbuf, "c%u", rng.lc);
}
else if ((byte & LCREL) && (byte & HCREL))
{
int c1, c2, ctmp;

c1 = rng.lc - decomp_col;
c2 = rng.hc - decomp_col;
if (c1 < c2)
ctmp = c1, c1 = c2, c2 = ctmp;
(void) sprintf (tmpcbuf, "c[%+d:%+d]", c1, c2);
}
else if ((byte & LCREL))
(void) sprintf (tmpcbuf, "c[%+d]:%u", rng.lc - decomp_col, rng.hc);
else if (byte & HCREL)
(void) sprintf (tmpcbuf, "c%u:[%+d]", rng.lc, rng.hc - decomp_col);
else if (rng.lc < rng.hc)
(void) sprintf (tmpcbuf, "c%u:%u", rng.lc, rng.hc);
else
(void) sprintf (tmpcbuf, "c%u:%u", rng.hc, rng.lc);

new = n_alloc (40, 1000, "%s%s", tmprbuf, tmpcbuf);
}
new->len = strlen (new->string);
}
break;

case C_CONST:
new = n_alloc (strlen (f->fn_str) + 1, 1000, f->fn_str);
break;

case C_FN0:
case C_FN0X:
case C_FN0 | C_T:
new = n_alloc (strlen (f->fn_str) + 3,
1000,
F0,
f->fn_str);
break;

case C_FN1:
--c_node;
new = n_alloc (c_node[0]->len + strlen (f->fn_str) + 3,
1000,
F1, f->fn_str, c_node[0]->string);
n_free (*c_node);
break;

case C_UNA:
--c_node;
if (c_node[0]->tightness < 9)
{
new = n_alloc (3 + c_node[0]->len,
9,
"%s(%s)", f->fn_str, c_node[0]->string);
}
else
{
new = n_alloc (1 + c_node[0]->len,
9,
"%s%s", f->fn_str, c_node[0]->string);
}
n_free (*c_node);
break;

case C_INF:
pri = GET_IN (f->fn_comptype);
aso = GET_ASO (f->fn_comptype);
chr = f->fn_str;

do_infix:
c_node -= 2;
if (c_node[0]->tightness < pri || (c_node[0]->tightness == pri && aso != 1))
{
if (c_node[1]->tightness < pri || (c_node[1]->tightness == pri && aso != -1))
new = n_alloc (7 + c_node[0]->len + c_node[1]->len,
pri,
"(%s) %s (%s)", c_node[0]->string, chr, c_node[1]->string);
else
new = n_alloc (5 + c_node[0]->len + c_node[1]->len,
pri,
"(%s) %s %s", c_node[0]->string, chr, c_node[1]->string);
}
else if (c_node[1]->tightness < pri || (c_node[1]->tightness == pri && aso != -1))
new = n_alloc (5 + c_node[0]->len + c_node[1]->len,
pri,
"%s %s (%s)", c_node[0]->string, chr, c_node[1]->string);
else
new = n_alloc (3 + c_node[0]->len + c_node[1]->len,
pri,
"%s %s %s", c_node[0]->string, chr, c_node[1]->string);

n_free (c_node[0]);
n_free (c_node[1]);
break;

case C_FN2:
do_fn2:
c_node -= 2;
new = n_alloc (c_node[0]->len + c_node[1]->len + strlen (f->fn_str) + 5,
1000,
F2, f->fn_str, c_node[0]->string, c_node[1]->string);
n_free (c_node[0]);
n_free (c_node[1]);
break;

case C_FN3:
c_node -= 3;
new = n_alloc (c_node[0]->len + c_node[1]->len + c_node[2]->len + strlen (f->fn_str) + 7,
1000,
F3,
f->fn_str,
c_node[0]->string,
c_node[1]->string,
c_node[2]->string);
n_free (c_node[0]);
n_free (c_node[1]);
n_free (c_node[2]);
break;

case C_FNN:
aso = *expr++;
c_node -= aso;

if (aso == 1)
new = n_alloc (3 + c_node[0]->len + strlen (f->fn_str),
1000,
F1, f->fn_str, c_node[0]->string);
else
{
new = n_alloc (2 + c_node[0]->len + strlen (f->fn_str),
1000,
FN1, f->fn_str, c_node[0]->string);
--aso;
for (pri = 1; pri < aso; pri++)
{
n_free (c_node[0]);
c_node[0] = new;
new = n_alloc (2 + new->len + c_node[pri]->len,
1000,
"%s, %s", new->string, c_node[pri]->string);
}
n_free (c_node[0]);
c_node[0] = new;
new = n_alloc (3 + new->len + c_node[aso]->len,
1000,
"%s, %s)", new->string, c_node[aso]->string);
}
n_free (c_node[0]);
break;

case C_FN4:
c_node -= 4;
new = n_alloc (c_node[0]->len + c_node[1]->len + c_node[2]->len + c_node[3]->len + strlen (f->fn_str) + 6,
1000,
F4,
f->fn_str,
c_node[0]->string,
c_node[1]->string,
c_node[2]->string,
c_node[3]->string);
n_free (c_node[0]);
n_free (c_node[1]);
n_free (c_node[2]);
n_free (c_node[3]);
break;

case C_ERR:
tmp_str = (char *) expr + jumpto;
expr++;
new = n_alloc (strlen (tmp_str) + 1, 1000, tmp_str);
/* bcopy((VOIDSTAR)expr,(VOIDSTAR)&tmp_str,sizeof(char *));
expr+=sizeof(char *);
new=n_alloc(strlen(tmp_str)+1,1000,f->fn_str,tmp_str); */
break;

case C_FLT:
bcopy ((VOIDSTAR) expr, (VOIDSTAR) & tmp_flt, sizeof (double));
expr += sizeof (double);
new = n_alloc (20, 1000, f->fn_str, tmp_flt);
new->len = strlen (new->string);
break;

case C_INT:
bcopy ((VOIDSTAR) expr, (VOIDSTAR) & tmp_lng, sizeof (long));
expr += sizeof (long);
new = n_alloc (20, 1000, f->fn_str, tmp_lng);
new->len = strlen (new->string);
break;

case C_VAR:
bcopy ((VOIDSTAR) expr, (VOIDSTAR) & v, sizeof (struct var *));
expr += sizeof (struct var *);
new = n_alloc (strlen (v->var_name) + 1,
1000,
f->fn_str, v->var_name);
break;


default:
panic ("Bad decompile %d", f->fn_comptype);
}
*c_node++ = new;
if (c_node == &the_line[line_alloc])
{
line_alloc *= 2;
the_line = ck_realloc (the_line, line_alloc * sizeof (struct pr_node *));
c_node = &the_line[line_alloc / 2];
}

if (*expr)
goto next_byte;

/* if(c_node != &the_line[1]) {
io_error_msg("%d values on decompile stack!",c_node - the_line);
return the_line[0];
} */
new = *--c_node;
/* free(the_line); */
return new;
}

/* Actual entry points to this file */
/* decomp(row, col, cell) returns a string that can be byte_compiled to create
cell->formula decomp_free() frees up the allocated string */
#if __STDC__
char *
decomp (CELLREF r, CELLREF c, CELL *cell)
#else
char *
decomp (r, c, cell)
CELLREF r;
CELLREF c;
CELL *cell;
#endif
{
struct pr_node *ret;
char *str;
extern char *bname[];

if (!cell)
return "";
decomp_row = r;
decomp_col = c;
if (cell->cell_formula == 0)
{
switch (GET_TYP (cell))
{
case 0:
str = ck_malloc (1);
str[0] = '\0';
break;
case TYP_FLT:
str = strdup (flt_to_str (cell->cell_flt));
break;
case TYP_INT:
str = ck_malloc (20);
sprintf (str, "%ld", cell->cell_int);
break;
case TYP_STR:
str = strdup (backslash_a_string (cell->cell_str, 1));
break;
case TYP_BOL:
str = strdup (bname[cell->cell_bol]);
break;
case TYP_ERR:
str = strdup (ename[cell->cell_bol]);
break;
default:
str = 0;
#ifdef TEST
panic ("Unknown type %d in decomp", GET_TYP (cell));
#endif
}
save_decomp = (VOIDSTAR) str;
return str;
}
else
ret = byte_decompile (cell->cell_formula);
save_decomp = (VOIDSTAR) ret;
return &(ret->string[0]);
}

#ifdef __STDC__
void
decomp_free (void)
#else
void
decomp_free ()
#endif
{
#ifdef TEST
if (!save_decomp)
panic ("No save decomp");
n_free (save_decomp);
save_decomp = (VOIDSTAR) 0;
#else
n_free (save_decomp);
#endif
}

/* This takes a string and returns a backslashed form suitable for printing.
Iff add_quote is true, it'll add "s at the beginning and end.
Note that this returns a pointer to a static area that is overwritten with
each call. . .
*/
#ifdef __STDC__
char *
backslash_a_string (char *string, int add_quote)
#else
char *
backslash_a_string (string, add_quote)
char *string;
int add_quote;
#endif
{
char *pf;
char *pt;
int ch;
int size;
int len;

static char *cbuf;
static int s_cbuf;

#define ALLOC_PT() \
len=strlen(pf); \
size=pf-string; \
if(s_cbuf<3+size+4*len) { \
s_cbuf=3+size+4*len; \
cbuf= (cbuf) ? ck_realloc(cbuf,s_cbuf) : ck_malloc(s_cbuf); \
} \
if(size) \
bcopy(string,cbuf,size); \
pt=cbuf+size; \


pt = 0;
pf = string;
if (add_quote)
{
ALLOC_PT ()
* pt++ = '"';
}
for (; *pf; pf++)
{
ch = *pf;
if (ch >= ' ' && ch <= '~' && ch != '\\' && (ch != '"' || !add_quote))
{
if (pt)
*pt++ = ch;
continue;
}

if (!pt)
{
ALLOC_PT ()
}
if (ch == '\\')
{
*pt++ = '\\';
*pt++ = '\\';
}
else if (ch == '"')
{
*pt++ = '\\';
*pt++ = ch;
}
else
{
*pt++ = '\\';
*pt++ = ((ch >> 6) & 0x3) + '0';
*pt++ = ((ch >> 3) & 0x7) + '0';
*pt++ = (ch & 0x7) + '0';
}
}
if (add_quote)
*pt++ = '"';
if (pt)
{
*pt++ = '\0';
return cbuf;
}
return string;
}

#ifdef TEST
void
dbg_print_formula (expr)
unsigned char *expr;
{
unsigned char byte;
struct function *f;
double tmp_flt;
char *tmp_str;
long tmp_int;
struct var *v;
struct rng rng;
char *buf;
unsigned jumpto;
extern char print_buf[];
extern char *strcpy ();

if (!expr)
return;
strcpy (print_buf, "Formula: ");
buf = print_buf + 9;
while (*expr)
{
byte = *expr++;

if (byte < USR1)
f = &the_funs[byte];
else if (byte < SKIP)
{
tmp_int = *expr++;
f = &usr_funs[byte - USR1][tmp_int];
}
else
f = &skip_funs[byte - SKIP];

if (f->fn_argn & X_J)
jumpto = *expr++;
else if (f->fn_argn & X_JL)
{
jumpto = expr[0] + ((unsigned) (expr[1]) << 8);
expr += 2;
}
else
jumpto = 0;

switch (GET_COMP (f->fn_comptype))
{
case C_IF:
sprintf (buf, " if%d.%u", byte, jumpto);
break;
case C_ANDOR:
sprintf (buf, " andor%d.%u", byte, jumpto);
break;
case C_ERR:
tmp_str = (char *) (expr + jumpto);
byte = *expr++;
sprintf (buf, " err%d.%p(%s)", byte, tmp_str, tmp_str);
break;
case C_FLT:
bcopy ((VOIDSTAR) expr, (VOIDSTAR) & tmp_flt, sizeof (double));
expr += sizeof (double);
sprintf (buf, " flt.%.15g", tmp_flt);
break;
case C_INT:
bcopy ((VOIDSTAR) expr, (VOIDSTAR) & tmp_int, sizeof (long));
expr += sizeof (long);
sprintf (buf, " int.%ld", tmp_int);
break;
case C_STR:
tmp_str = (char *) (expr + jumpto);
sprintf (buf, " str.%p.%s", tmp_str, tmp_str);
break;
case C_VAR:
bcopy ((VOIDSTAR) expr, (VOIDSTAR) & v, sizeof (struct var *));
expr += sizeof (struct var *);
sprintf (buf, " var.%p.%s", v, v->var_name);
break;
case C_CELL:
sprintf (buf, " ref%d.%u.%u", byte, GET_ROW (expr), GET_COL (expr));
expr += EXP_ADD;
break;
case C_RANGE:
GET_RNG (expr, &rng);
sprintf (buf, " rng%d.%u-%u,%u-%u", byte, rng.lr, rng.hr, rng.lc, rng.hc);
expr += EXP_ADD_RNG;
break;
case C_FN0:
case C_FN0X:
case C_FN1:
case C_FN2:
case C_FN3:
case C_FN4:
case C_UNA:
case C_INF:
sprintf (buf, " fun%d.%s.%p", byte, f->fn_str, f->fn_fun);
break;

case C_FNN:
sprintf (buf, " funn%d.%s.%p.%d", byte, f->fn_str, f->fn_fun, *expr++);
break;
case C_CONST:
sprintf (buf, " const%s", f->fn_str);
break;
case C_SKIP:
sprintf (buf, " skip.%d", jumpto);
break;
case 0:
sprintf (buf, " ???%d", byte);
break;
default:
io_error_msg ("Unknown decompile type %d", f->fn_comptype);
}
buf += strlen (buf);
}
io_text_line (print_buf);
}

#endif
oleo-1.3/sort.c 644 722 0 20525 5321115423 11635 0ustar lordwheel/* Copyright (C) 1990, 1992, 1993 Free Software Foundation, Inc.

This file is part of Oleo, the GNU Spreadsheet.

Oleo 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, or (at your option)
any later version.

Oleo 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 Oleo; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */

/* Plug-compatible replacement for UNIX qsort.
Copyright (C) 1989,1990, 1992, 1993 Free Software Foundation, Inc.
Written by Douglas C. Schmidt ([email protected])
Modified by Jay Fenlason for use in the spreadsheet. */

/* The modifications for the spreadsheet consist of calling functions to
compare, swap, and rotate array elements. This allows it to work
on sparse arrays, where some or all of the elements may not exist
*/

/* Envoke the comparison function, returns either 0, < 0, or > 0. */
#define CMP(A,B) ((*cmp)((A),(B)))

/* Byte-wise swap two items of size SIZE. */
/* #define SWAP(A,B,SIZE) do {int sz = (SIZE); char *a = (A); char *b = (B); \
do { char _temp = *a;*a++ = *b;*b++ = _temp;} while (--sz);} while (0) */
#define SWAP(A,B) ((*swap)((A),(B)))

#define ROT(a,b) ((*rot)((a),(b)))

/* Copy SIZE bytes from item B to item A. */
/* #define COPY(A,B,SIZE) {int sz = (SIZE); do { *(A)++ = *(B)++; } while (--sz); } */

/* This should be replaced by a standard ANSI macro. */
#define BYTES_PER_WORD 8

/* The next 4 #defines implement a very fast in-line stack abstraction. */
#define STACK_SIZE (BYTES_PER_WORD * sizeof (long))
#define PUSH(LOW,HIGH) do {top->lo = LOW;top++->hi = HIGH;} while (0)
#define POP(LOW,HIGH) do {LOW = (--top)->lo;HIGH = top->hi;} while (0)
#define STACK_NOT_EMPTY (stack < top)

/* Discontinue quicksort algorithm when partition gets below this size.
This particular magic number was chosen to work best on a Sun 4/260. */
#define MAX_THRESH 4

/* Stack node declarations used to store unfulfilled partition obligations. */
typedef struct
{
int lo;
int hi;
}

stack_node;

/* Order size using quicksort. This implementation incorporates
four optimizations discussed in Sedgewick:

1. Non-recursive, using an explicit stack of pointer that store the
next array partition to sort. To save time, this maximum amount
of space required to store an array of MAX_INT is allocated on the
stack. Assuming a 32-bit integer, this needs only 32 *
sizeof (stack_node) == 136 bits. Pretty cheap, actually.

2. Chose the pivot element using a median-of-three decision tree.
This reduces the probability of selecting a bad pivot value and
eliminates certain extraneous comparisons.

3. Only quicksorts TOTAL_ELEMS / MAX_THRESH partitions, leaving
insertion sort to order the MAX_THRESH items within each partition.
This is a big win, since insertion sort is faster for small, mostly
sorted array segements.

4. The larger of the two sub-partitions is always pushed onto the
stack first, with the algorithm then concentrating on the
smaller partition. This *guarantees* no more than log (n)
stack size is needed (actually O(1) in this case)! */

int
sort (total_elems, cmp, swap, rot)
int total_elems;
int (*cmp) ();
void (*swap) ();
void (*rot) ();
{
/* Allocating SIZE bytes for a pivot buffer facilitates a better
algorithm below since we can do comparisons directly on the pivot. */
int max_thresh = MAX_THRESH;

if (total_elems > MAX_THRESH)
{
int lo = 0;
int hi = lo + (total_elems - 1);
stack_node stack[STACK_SIZE]; /* Largest size needed for 32-bit int!!! */
stack_node *top = stack + 1;

while (STACK_NOT_EMPTY)
{
int left_ptr;
int right_ptr;
{
int pivot;
{
/* Select median value from among LO, MID, and HI. Rearrange
LO and HI so the three values are sorted. This lowers the
probability of picking a pathological pivot value and
skips a comparison for both the LEFT_PTR and RIGHT_PTR. */

int mid = lo + ((hi - lo) >> 1);

if (CMP (mid, lo) < 0)
SWAP (mid, lo);
if (CMP (hi, mid) < 0)
SWAP (mid, hi);
else
goto jump_over;
if (CMP (mid, lo) < 0)
SWAP (mid, lo);
jump_over:
/* COPY (pivot, mid); */
pivot = mid;
/* pivot = pivot_buffer; */
}
left_ptr = lo + 1;
right_ptr = hi - 1;

/* Here's the famous ``collapse the walls'' section of quicksort.
Gotta like those tight inner loops! They are the main reason
that this algorithm runs much faster than others. */
do
{
while (CMP (left_ptr, pivot) < 0)
left_ptr += 1;

while (CMP (pivot, right_ptr) < 0)
right_ptr -= 1;

if (left_ptr < right_ptr)
{
SWAP (left_ptr, right_ptr);
left_ptr += 1;
right_ptr -= 1;
}
else if (left_ptr == right_ptr)
{
left_ptr += 1;
right_ptr -= 1;
break;
}
}
while (left_ptr <= right_ptr);

}

/* Set up pointers for next iteration. First determine whether
left and right partitions are below the threshold size. If so,
ignore one or both. Otherwise, push the larger partition's
bounds on the stack and continue sorting the smaller one. */

if ((right_ptr - lo) <= max_thresh)
{
if ((hi - left_ptr) <= max_thresh) /* Ignore both small partitions. */
POP (lo, hi);
else /* Ignore small left partition. */
lo = left_ptr;
}
else if ((hi - left_ptr) <= max_thresh) /* Ignore small right partition. */
hi = right_ptr;
else if ((right_ptr - lo) > (hi - left_ptr)) /* Push larger left partition indices. */
{
PUSH (lo, right_ptr);
lo = left_ptr;
}
else
/* Push larger right partition indices. */
{
PUSH (left_ptr, hi);
hi = right_ptr;
}
}
}

/* Once the BASE_PTR array is partially sorted by quicksort the rest
is completely sorted using insertion sort, since this is efficient
for partitions below MAX_THRESH size. BASE_PTR points to the beginning
of the array to sort, and END_PTR points at the very last element in
the array (*not* one beyond it!). */

#define MIN(X,Y) ((X) < (Y) ? (X) : (Y))

{
int end_ptr = 0 + (total_elems - 1);
int run_ptr;
int tmp_ptr = 0;
int thresh = MIN (end_ptr, 0 + max_thresh);

/* Find smallest element in first threshold and place it at the
array's beginning. This is the smallest array element,
and the operation speeds up insertion sort's inner loop. */

for (run_ptr = tmp_ptr + 1; run_ptr <= thresh; run_ptr += 1)
if (CMP (run_ptr, tmp_ptr) < 0)
tmp_ptr = run_ptr;

if (tmp_ptr != 0)
SWAP (tmp_ptr, 0);

/* Insertion sort, running from left-hand-side up to `right-hand-side.'
Pretty much straight out of the original GNU qsort routine. */

for (run_ptr = 0 + 1; (tmp_ptr = run_ptr += 1) <= end_ptr;)
{

while (CMP (run_ptr, tmp_ptr -= 1) < 0)
;

if ((tmp_ptr += 1) != run_ptr)
{
ROT (tmp_ptr, run_ptr);
/* int trav;

for (trav = run_ptr + 1; --trav >= run_ptr;)
{
char c = *trav;
char *hi, *lo;

for (hi = lo = trav; (lo -= 1) >= tmp_ptr; hi = lo)
*hi = *lo;
*hi = c;
} */
}

}
}
return 1;
}


#ifdef TEST_ME
int buf[25] =
{
1, 15, 37, 9, 100, 3, 14, 2, 88,
6, 97, 12, 34, 8, 92, 11, 15, 38,
16, 6, 93, 42, 45, 55, 64};
main ()
{
int com ();
void swa ();
void rot ();
int n;

sort (25, com, swa, rot);
for (n = 0; n < 25; n++)
printf ("%d ", buf[n]);
}

com (n1, n2)
{
printf ("Cmp %d,%d\n", n1, n2);
return buf[n1] - buf[n2];
}

void
swa (n1, n2)
{
int t;

printf ("Swap %d,%d\n", n1, n2);
t = buf[n1];
buf[n1] = buf[n2];
buf[n2] = t;
}

void
rot (n1, n2)
{
int t;

printf ("Rot %d,%d\n", n1, n2);
t = buf[n2];
while (n2 > n1)
{
buf[n2] = buf[n2 - 1];
--n2;
}
buf[n2] = t;
}

#endif
oleo-1.3/regions.c 644 722 0 51017 5355700420 12320 0ustar lordwheel/* Copyright (C) 1990, 1992, 1993 Free Software Foundation, Inc.

This file is part of Oleo, the GNU Spreadsheet.

Oleo 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, or (at your option)
any later version.

Oleo 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 Oleo; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */

#include "funcdef.h"
#include
#include "sysdef.h"
#include "global.h"
#include "cell.h"
#include "io-generic.h"
#include "io-abstract.h"
#include "io-utils.h"
#include "lists.h"
#include "ref.h"
#include "regions.h"
#include "io-term.h"
#include "window.h"
#include "cmd.h"


struct rng all_rng = {MIN_ROW, MIN_COL, MAX_ROW, MAX_COL};

/* Take a struct rng (R) and init its elements to R1 C1 R2 C2, making sure
they are put in in the right order.
*/
#ifdef __STDC__
void
set_rng (struct rng *r, CELLREF r1, CELLREF c1, CELLREF r2, CELLREF c2)
#else
void
set_rng (r, r1, c1, r2, c2)
struct rng *r;
CELLREF r1;
CELLREF c1;
CELLREF r2;
CELLREF c2;
#endif
{
if (r1 <= r2)
{
r->lr = r1;
r->hr = r2;
}
else
{
r->lr = r2;
r->hr = r1;
}
if (c1 <= c2)
{
r->lc = c1;
r->hc = c2;
}
else
{
r->lc = c2;
r->hc = c1;
}
}

/* Flush all the cells in a region */
#ifdef __STDC__
void
delete_region (struct rng *where)
#else
void
delete_region (where)
struct rng *where;
#endif
{
CELLREF rr, cc;
CELL *pp;

modified = 1;

find_cells_in_range (where);
while (pp = next_row_col_in_range (&rr, &cc))
{
if (!pp->cell_formula && !GET_TYP (pp))
{
pp->cell_flags = 0;
pp->cell_font = 0;
continue;
}
cur_row = rr;
cur_col = cc;
my_cell = pp;
flush_old_value ();
pp->cell_formula = 0;
pp->cell_flags = 0;
pp->cell_font = 0;
push_refs (pp->cell_refs_from);
io_pr_cell (rr, cc, pp);
}
my_cell = 0;
}

/* Turn on/off the locked bits in a region */
#ifdef __STDC__
void
lock_region (struct rng *where, int locked)
#else
void
lock_region (where, locked)
struct rng *where;
int locked;
#endif
{
CELL *cp;

modified = 1;
make_cells_in_range (where);
while (cp = next_cell_in_range ())
SET_LCK (cp, locked);
}

#ifdef __STDC__
void
format_region (struct rng *where, int fmt, int just)
#else
void
format_region (where, fmt, just)
struct rng *where;
int fmt;
int just;
#endif
{
CELL *cp;
CELLREF rr, cc;

modified = 1;
make_cells_in_range (where);
while (cp = next_row_col_in_range (&rr, &cc))
{
if (fmt != -1)
SET_FMT (cp, fmt);
if (just != -1)
SET_JST (cp, just);
io_pr_cell (rr, cc, cp);
}
}

unsigned int print_width;

#ifdef __STDC__
void
print_region (FILE *fp, struct rng *print)
#else
void
print_region (fp, print)
FILE *fp;
struct rng *print;
#endif
{
CELLREF rr, cc;
CELL *cp;
char *ptr;
int w;
int j;
int lenstr;
int spaces;
CELLREF c_lo, c_hi;

for (c_lo = print->lc, c_hi = 0; c_hi != print->hc; c_lo = c_hi + 1)
{
w = 0;
for (w = get_width (cc = c_lo); w <= print_width && cc <= print->hc; w += get_width (++cc))
;
if (cc != c_lo)
--cc;
c_hi = cc;

for (rr = print->lr; rr <= print->hr; rr++)
{
spaces = 0;
for (cc = c_lo; cc <= c_hi; cc++)
{
w = get_width (cc);
if (!w)
continue;
cp = find_cell (rr, cc);
if (!cp || !GET_TYP (cp))
{
spaces += w;
continue;
}
ptr = print_cell (cp);
lenstr = strlen (ptr);
if (lenstr == 0)
{
spaces += w;
continue;
}
if (spaces)
{
fprintf (fp, "%*s", spaces, "");
spaces = 0;
}
j = GET_JST (cp);
if (j == JST_DEF)
j = default_jst;
if (lenstr <= w - 1)
{
if (j == JST_LFT)
{
fprintf (fp, "%s", ptr);
spaces = w - lenstr;
}
else if (j == JST_RGT)
{
fprintf (fp, "%*s", w - 1, ptr);
spaces = 1;
}
else if (j == JST_CNT)
{
w = (w - 1) - lenstr;
fprintf (fp, "%*s", w / 2 + lenstr, ptr);
spaces = (w + 3) / 2;
}
#ifdef TEST
else
{
panic ("What just %d", j);
}
#endif
}
else
{
CELLREF ccc = cc;
CELL *ccp;
int tmp_wid;
unsigned int ww;

for (ww = w;; tmp_wid = get_width (ccc), w += tmp_wid, spaces -= tmp_wid)
{
if (lenstr < w - 1)
break;
if (++ccc > c_hi)
break;
ccp = find_cell (rr, ccc);
if (!ccp || !GET_TYP (ccp) || GET_FMT (ccp) == FMT_HID)
continue;
if (GET_FMT (ccp) == FMT_DEF && default_fmt == FMT_HID)
continue;
break;
}
if (lenstr > w - 1)
{
if (GET_TYP (cp) == TYP_FLT)
{
ptr = adjust_prc (ptr, cp, w - 1, ww - 1, j);
lenstr = strlen (ptr);
}
else if (GET_TYP (cp) == TYP_INT)
{
ptr = numb_oflo;
lenstr = 80;
}
fprintf (fp, "%.*s", w - 1, ptr);
if (lenstr < w)
spaces += w - lenstr;
else
spaces++;
}
else
{
fprintf (fp, "%s", ptr);
spaces += w - lenstr;
}
}
}
(void) putc ('\n', fp);
}
}
}


/*
Set up regions for the move/copy functions. This deals with default
sizing of the target region, regions that don't fit, etc.

This returns
-1 if the regions overlap
0 if there is a *real* error
1 if the target is a multiple of the source
2 if everything is OK.
*/

#ifdef __STDC__
static int
set_to_region (struct rng *fm, struct rng *to)
#else
static int
set_to_region (fm, to)
struct rng *fm;
struct rng *to;
#endif
{
/* Delta {row,col} {from,to} */
int drf, dcf;
int drt, dct;
int ret = 2;

drf = fm->hr - fm->lr;
drt = to->hr - to->lr;
if (drt == 0)
{
if (to->lr > MAX_ROW - drf)
{
io_error_msg ("The range won't fit this far down!");
return 0;
}
to->hr = to->lr + drf;
}
else if (drf != drt)
{
if ((drt + 1) % (drf + 1) == 0)
ret = 1;
else
{
io_error_msg ("Rows %u:%u and %u:%u don't fit", fm->lr, fm->hr, to->lr, to->hr);
return 0;
}
}
dcf = fm->hc - fm->lc;
dct = to->hc - to->lc;
if (dct == 0)
{
if (to->lc > MAX_COL - dcf)
{
io_error_msg ("The range won't fit this far over!");
return 0;
}
to->hc = to->lc + dcf;
}
else if (dcf != dct)
{
if ((dct + 1) % (dcf + 1) == 0)
ret = 1;
else
{
io_error_msg ("Cols %u:%u and %u:%u don't fit", fm->lc, fm->hc, to->lc, to->hc);
return 0;
}
}

if (fm->lr == to->lr && fm->lc == to->lc)
{
io_error_msg ("Regions are in the same place");
return 0;
}

if (((fm->lr <= to->lr && to->lr <= fm->hr) || (fm->lr <= to->hr && to->hr <= fm->hr))
&& ((fm->lc <= to->lc && to->lc <= fm->hc) || (fm->lc <= to->hc && to->hc <= fm->hc)))
return -1;
modified = 1;
return ret;
}

/* This is only complicated because it must deal with overlap, and it wants
to be smart about copying empty space. . .
*/
#ifdef __STDC__
void
move_region (struct rng *fm, struct rng *to)
#else
void
move_region (fm, to)
struct rng *fm;
struct rng *to;
#endif
{
/* Delta {row,col} */
int dr, dc;
int nr, nc;
int ov, dn;
struct rng del_to_1, del_to_2;
int do_2, dirs[2];
int maxr, maxc;
CELLREF cmax, rmax;
int cdmax, rdmax;
int must_repaint = 0; /* If this move changes cell widths/heights */

switch (set_to_region (fm, to))
{
case 0:
return;

case 1:
io_error_msg ("Can't move source to multiple targets");
return;

case 2:
del_to_1 = *to;

do_2 = 0;
dirs[0] = 1;
dirs[1] = 1;

/* del_fm_1= *fm; */
break;

default:
/* They overlap. There are eight ways that
they can overlap. */
if (to->lc == fm->lc && to->lr < fm->lr)
{
/* State 1: 'from' on bottom */
del_to_1.lr = to->lr;
del_to_1.lc = to->lc;
del_to_1.hr = fm->lr - 1;
del_to_1.hc = to->hc;

do_2 = 0;
dirs[0] = 1;
dirs[1] = 1;

/* del_fm_1.lr=to->hr+1; del_fm_1.lc=fm->lc;
del_fm_1.hr=fm->hr; del_fm_1.hc=fm->hc; */
}
else if (to->lc == fm->lc)
{
/* State 2: 'from' on top */
del_to_1.lr = fm->hr + 1;
del_to_1.lc = to->lc;
del_to_1.hr = to->hr;
del_to_1.hc = to->hc;

do_2 = 0;
dirs[0] = -1;
dirs[1] = 1;

/* del_fm_1.lr=fm->lr; del_fm_1.lc=fm->lc;
del_fm_1.hr=to->lr-1; del_fm_1.hc=fm->hc; */
}
else if (to->lr == fm->lr && to->lc < fm->lc)
{
/* State 3: 'from' on right */
del_to_1.lr = to->lr;
del_to_1.lc = to->lc;
del_to_1.hr = to->hr;
del_to_1.hc = fm->lc - 1;

do_2 = 0;
dirs[0] = 1;
dirs[1] = 1;

/* del_fm_1.lr=fm->lr; del_fm_1.lc=to->hc+1;
del_fm_1.hr=fm->hr; del_fm_1.hc=fm->hc; */
}
else if (to->lr == fm->lr)
{
/* State 4: 'from' on left */
del_to_1.lr = to->lr;
del_to_1.lc = fm->hc + 1;
del_to_1.hr = to->hr;
del_to_1.hc = to->hc;

do_2 = 0;
dirs[0] = 1;
dirs[1] = -1;

/* del_fm_1.lr=fm->lr; del_fm_1.lc=fm->lc;
del_fm_1.hr=fm->hr; del_fm_1.hc=to->lc-1; */
}
else if (fm->lr < to->lr && fm->lc < to->lc)
{
/* State 5: From on topleft */

del_to_1.lr = to->lr;
del_to_1.lc = fm->hc + 1;
del_to_1.hr = fm->hr;
del_to_1.hc = to->hc;

del_to_2.lr = fm->hr + 1;
del_to_2.lc = to->lc;
del_to_2.hr = to->hr;
del_to_2.hc = to->hc;

do_2 = 1;
dirs[0] = -1;
dirs[1] = -1;

/* del_fm_1.lr=fm->lr; del_fm_1.lc=fm->lc;
del_fm_1.hr=to->lr-1; del_fm_1.hc=fm->hc;

del_fm_2.lr=to->lr; del_fm_2.lc=fm->lc;
del_fm_2.hr=fm->hr; del_fm_2.hc=to->lc-1; */
}
else if (fm->lr < to->lr)
{
/* State 6: 'from' on topright */
del_to_1.lr = to->lr;
del_to_1.lc = to->lc;
del_to_1.hr = fm->hr;
del_to_1.hc = fm->lc - 1;

del_to_2.lr = fm->hr + 1;
del_to_2.lc = to->lc;
del_to_2.hr = to->hr;
del_to_2.hc = to->hc;

do_2 = 1;
dirs[0] = -1;
dirs[1] = 1;

/* del_fm_1.lr=fm->lr; del_fm_1.lc=fm->lc;
del_fm_1.hr=to->lr-1; del_fm_1.hc=fm->hc;

del_fm_2.lr=to->lr; del_fm_2.lc=to->hc+1;
del_fm_2.hr=fm->hr; del_fm_2.hc=fm->hc; */
}
else if (fm->lc < to->lc)
{
/* State 7: 'from on bottomleft */
del_to_1.lr = to->lr;
del_to_1.lc = to->lc;
del_to_1.hr = fm->lr - 1;
del_to_1.hc = to->hc;

del_to_2.lr = fm->lr;
del_to_2.lc = fm->hc;
del_to_2.hr = to->hr;
del_to_2.hc = to->hc;

do_2 = 1;
dirs[0] = 1;
dirs[1] = -1;

/* del_fm_1.lr=fm->lr; del_fm_1.lc=fm->lc;
del_fm_1.hr=to->hr; del_fm_1.hc=to->lc-1;

del_fm_2.lr=to->hr+1; del_fm_2.lc=fm->lc;
del_fm_2.hr=to->hr+1; del_fm_2.hc=to->lc-1; */
}
else
{
/* State 8: 'from' on bottomright */
del_to_1.lr = to->lr;
del_to_1.lc = to->lc;
del_to_1.hr = fm->lr - 1;
del_to_1.hc = to->hc;

del_to_2.lr = fm->lr;
del_to_2.lc = to->lc;
del_to_2.hr = to->hr;
del_to_2.hc = fm->lc - 1;

do_2 = 1;
dirs[0] = 1;
dirs[1] = 1;

/* del_fm_1.lr=fm->lr; del_fm_1.lc=to->hc+1;
del_fm_1.hr=to->hr; del_fm_1.hc=fm->hc;

del_fm_2.lr=to->hr+1; del_fm_2.lc=fm->lc;
del_fm_2.hr=fm->hr; del_fm_2.hc=fm->hc; */
}
}
dn = to->hr - fm->hr;
ov = to->hc - fm->hc;

dr = fm->hr - fm->lr;
dc = fm->hc - fm->lc;

delete_region (&del_to_1);
if (do_2)
delete_region (&del_to_2);

if (to->lr == MIN_ROW && to->hr == MAX_ROW)
{
shift_widths (ov, fm->lc, fm->hc);
must_repaint = 1;
}

if (to->lc == MIN_COL && to->hc == MAX_COL)
{
shift_heights (dn, fm->lr, fm->hr);
must_repaint = 1;
}

shift_outside (fm, dn, ov);

rmax = highest_row ();
if (rmax < fm->lr)
rdmax = -1;
else if (rmax > fm->hr)
rdmax = dr;
else
rdmax = rmax - fm->lr;
nr = (dirs[0] > 0) ? 0 : rdmax;
maxr = (dirs[0] > 0) ? rdmax + 1 : -1;
for (; nr != maxr; nr += dirs[0])
{
cmax = max_col (fm->lr + nr);
if (cmax < fm->lc)
cdmax = -1;
else if (cmax > fm->hc)
cdmax = dc;
else
{
cdmax = cmax - fm->lc;
}
nc = (dirs[1] > 0) ? 0 : cdmax;
maxc = (dirs[1] > 0) ? cdmax + 1 : -1;
for (; nc != maxc; nc += dirs[1])
{
CELLREF rf, cf, rt, ct;
CELL *cpf;

rf = fm->lr + nr;
cf = fm->lc + nc;
rt = to->lr + nr;
ct = to->lc + nc;

cpf = find_cell (rf, cf);
cur_row = rt;
cur_col = ct;
my_cell = find_cell (cur_row, cur_col);
if ((!cpf
|| (!cpf->cell_font && !cpf->cell_flags && !cpf->cell_formula))
&& !my_cell)
continue;

if (!cpf)
{
my_cell->cell_flags = 0;
my_cell->cell_font = 0;
my_cell->cell_refs_to = 0;
my_cell->cell_formula = 0;
my_cell->cell_cycle = 0;
my_cell = 0;
continue;
}
if (!my_cell)
{
my_cell = find_or_make_cell (cur_row, cur_col);
cpf = find_cell (rf, cf);
}
else
flush_old_value ();

my_cell->cell_flags = cpf->cell_flags;
my_cell->cell_font = cpf->cell_font;
my_cell->cell_refs_to = cpf->cell_refs_to;
my_cell->cell_formula = cpf->cell_formula;
my_cell->cell_cycle = cpf->cell_cycle;
my_cell->c_z = cpf->c_z;

cpf->cell_flags = 0;
cpf->cell_font = 0;
cpf->cell_refs_to = 0;
cpf->cell_formula = 0;
cpf->cell_cycle = 0;

push_cell (cur_row, cur_col);

if (!must_repaint)
{
if (cpf)
io_pr_cell (rf, cf, cpf);
if (my_cell)
io_pr_cell (rt, ct, my_cell);
}
my_cell = 0;
}
}
if (must_repaint)
io_repaint ();
return;
}

#ifdef __STDC__
void
copy_region (struct rng *fm, struct rng *to)
#else
void
copy_region (fm, to)
struct rng *fm;
struct rng *to;
#endif
{
CELLREF rf, rt, cf, ct;

if (set_to_region (fm, to) < 1)
return;

for (rf = fm->lr, rt = to->lr; (rt > 0) && (rt <= to->hr); rt++, rf++)
{
for (cf = fm->lc, ct = to->lc; (ct > 0) && (ct <= to->hc); ct++, cf++)
{
copy_cell (rf, cf, rt, ct);

if (cf == fm->hc)
cf = fm->lc - 1;
}
if (rf == fm->hr)
rf = fm->lr - 1;
}
}

#ifdef __STDC__
void
copy_values_region (struct rng *fm, struct rng *to)
#else
void
copy_values_region (fm, to)
struct rng *fm;
struct rng *to;
#endif
{
CELLREF rf, rt, cf, ct;
union vals dummy;
CELL *cpf;

if (set_to_region (fm, to) < 1)
return;

for (rf = fm->lr, rt = to->lr; rt <= to->hr; rt++, rf++)
{
for (cf = fm->lc, ct = to->lc; ct <= to->hc; ct++, cf++)
{
cpf = find_cell (rf, cf);
set_new_value (rt, ct, cpf ? GET_TYP (cpf) : 0, cpf ? &(cpf->c_z) : &dummy);

if (cf == fm->hc)
cf = fm->lc - 1;
}
if (rf == fm->hr)
rf = fm->lr - 1;
}
}

struct rng sort_rng;
struct rng sort_ele;
struct cmp *sort_keys;
int sort_keys_alloc;
int sort_keys_num = 0;

static int srdiff, erdiff, scdiff, ecdiff;

#ifdef TEST
extern int debug;
#endif

#ifdef __STDC__
void
sort_region (void)
#else
void
sort_region ()
#endif
{
srdiff = 1 + sort_rng.hr - sort_rng.lr;
erdiff = 1 + sort_ele.hr - sort_ele.lr;

scdiff = 1 + sort_rng.hc - sort_rng.lc;
ecdiff = 1 + sort_ele.hc - sort_ele.lc;

if (srdiff != erdiff && srdiff % erdiff != 0)
{
io_error_msg ("Rows %u:%u and %u:%u don't fit", sort_rng.lr, sort_rng.hr, sort_ele.lr, sort_ele.hr);
return;
}
if (scdiff != ecdiff && scdiff % ecdiff != 0)
{
io_error_msg ("Cols %u:%u and %u:%u don't fit", sort_rng.lc, sort_rng.hc, sort_ele.lc, sort_ele.hc);
return;
}
if (scdiff != ecdiff && srdiff != erdiff)
{
io_error_msg ("Can't sort this region!");
return;
}
modified = 1;
if (scdiff != ecdiff)
{
erdiff = 0;
sort (scdiff / ecdiff, cmp_cells, swp_cells, rot_cells);
}
else
{
ecdiff = 0;
sort (srdiff / erdiff, cmp_cells, swp_cells, rot_cells);
}
}

#ifdef __STDC__
int
cmp_cells (int n1, int n2)
#else
int
cmp_cells (n1, n2)
int n1;
int n2;
#endif
{
CELL *c1, *c2;
int t1, t2;
union vals v1, v2;
CELLREF row1, row2, col1, col2;
int keyn;
int cmpval;

if (n1 == n2)
return 0;

for (keyn = 0; keyn < sort_keys_num; keyn++)
{
row1 = sort_rng.lr + (n1 * erdiff) + sort_keys[keyn].row;
col1 = sort_rng.lc + (n1 * ecdiff) + sort_keys[keyn].col;
row2 = sort_rng.lr + (n2 * erdiff) + sort_keys[keyn].row;
col2 = sort_rng.lc + (n2 * ecdiff) + sort_keys[keyn].col;
#ifdef TEST
if (debug & 04)
io_error_msg ("Cmp %u %u r%uc%u <-%u-> r%uc%u", n1, n2, row1, col1, sort_keys[keyn].mult, row2, col2);
#endif
c1 = find_cell (row1, col1);
c2 = find_cell (row2, col2);
if (!c1 && !c2)
continue;

if (c1)
{
t1 = GET_TYP (c1);
v1 = c1->c_z;
}
else
t1 = 0;
if (c2)
{
t2 = GET_TYP (c2);
v2 = c2->c_z;
}
else
t2 = 0;

if (t1 == TYP_ERR || t1 == TYP_BOL)
{
t1 = TYP_STR;
v1.c_s = print_cell (c1);
}
if (t2 == TYP_ERR || t2 == TYP_BOL)
{
t2 = TYP_STR;
v2.c_s = print_cell (c2);
}
if (t1 != t2)
{
if (t1 == 0)
{
if (t2 == TYP_STR)
{
t1 = TYP_STR;
v1.c_s = "";
}
else if (t2 == TYP_INT)
{
t1 = TYP_INT;
v1.c_l = 0;
}
else
{
t1 = TYP_FLT;
v1.c_d = 0.0;
}
}
else if (t2 == 0)
{
if (t1 == TYP_STR)
{
t2 = TYP_STR;
v2.c_s = "";
}
else if (t1 == TYP_INT)
{
t2 = TYP_INT;
v2.c_l = 0;
}
else
{
t2 = TYP_FLT;
v2.c_d = 0.0;
}
}
else if (t1 == TYP_STR)
{
t2 = TYP_STR;
v2.c_s = print_cell (c2);
}
else if (t2 == TYP_STR)
{
t1 = TYP_STR;
v1.c_s = print_cell (c1);
/* If we get here, one is INT, and the other
is FLT Make them both FLT */
}
else if (t1 == TYP_INT)
{
t1 = TYP_FLT;
v1.c_d = (double) v1.c_l;
}
else
{
t2 = TYP_FLT;
v2.c_d = (double) v2.c_l;
}
}
if (t1 == TYP_STR)
cmpval = strcmp (v1.c_s, v2.c_s);
else if (t1 == TYP_FLT)
cmpval = (v1.c_d < v2.c_d) ? -1 : ((v1.c_d > v2.c_d) ? 1 : 0);
else if (t1 == TYP_INT)
cmpval = (v1.c_l < v2.c_l) ? -1 : ((v1.c_l > v2.c_l) ? 1 : 0);
else
cmpval = 0;
if (cmpval)
return cmpval * sort_keys[keyn].mult;
}

return 0;
}

#ifdef __STDC__
void
swp_cells (int n1, int n2)
#else
void
swp_cells (n1, n2)
int n1;
int n2;
#endif
{
int rn, cn;
CELLREF r1, r2, c1, c2;

#ifdef TEST
if (debug & 04)
io_error_msg ("Swap %u<-->%u", n1, n2);
#endif
for (rn = sort_ele.lr; rn <= sort_ele.hr; rn++)
for (cn = sort_ele.lc; cn <= sort_ele.hc; cn++)
{
r1 = sort_rng.lr + (n1 * erdiff) + rn;
r2 = sort_rng.lr + (n2 * erdiff) + rn;
c1 = sort_rng.lc + (n1 * ecdiff) + cn;
c2 = sort_rng.lc + (n2 * ecdiff) + cn;
#ifdef TEST
if (debug & 04)
io_error_msg ("Save r%uc%u", r1, c1);
#endif
move_cell (r1, c1, NON_ROW, NON_COL);
#ifdef TEST
if (debug & 04)
io_error_msg ("Copy r%uc%u --> r%uc%u", r2, c2, r1, c1);
#endif
move_cell (r2, c2, r1, c1);

#ifdef TEST
if (debug & 04)
io_error_msg ("Restore r%uc%u", r2, c2);
#endif
move_cell (NON_ROW, NON_COL, r2, c2);

/* push_cell(r1,c1);
push_cell(r2,c2); */
}
}

#ifdef __STDC__
void
rot_cells (int n1, int n2)
#else
void
rot_cells (n1, n2)
int n1;
int n2;
#endif
{
int rn, cn;
int nn;
CELLREF r1, r2, c1, c2;

if (n1 + 1 == n2 || n2 + 1 == n1)
{
swp_cells (n1, n2);
return;
}
#ifdef TEST
if (debug & 04)
io_error_msg ("Rot cells %u -- %u", n1, n2);
#endif
for (rn = sort_ele.lr; rn <= sort_ele.hr; rn++)
for (cn = sort_ele.lc; cn <= sort_ele.hc; cn++)
{

/* store a copy of cell # n2 */
r2 = sort_rng.lr + (n2 * erdiff) + rn;
c2 = sort_rng.lc + (n2 * ecdiff) + cn;
move_cell (r2, c2, NON_ROW, NON_COL);

#ifdef TEST
if (debug & 04)
io_error_msg ("Save r%uc%u", r2, c2);
#endif
/* Copy each cell from n1 to n2-1 up one */
for (nn = n2; nn > n1; --nn)
{
r2 = sort_rng.lr + (nn * erdiff) + rn;
c2 = sort_rng.lc + (nn * ecdiff) + cn;

r1 = sort_rng.lr + ((nn - 1) * erdiff) + rn;
c1 = sort_rng.lc + ((nn - 1) * ecdiff) + cn;

move_cell (r1, c1, r2, c2);
#ifdef TEST
if (debug & 04)
io_error_msg ("Copy r%uc%u --> r%uc%u", r1, c1, r2, c2);
#endif
/* push_cell(r2,c2); */
}

r1 = sort_rng.lr + (nn * erdiff) + rn;
c1 = sort_rng.lc + (nn * ecdiff) + cn;
#ifdef TEST
if (debug & 04)
io_error_msg ("Restore r%uc%u", r1, c1);
#endif
move_cell (NON_ROW, NON_COL, r1, c1);

/* push_cell(r1,c1); */
}
}

/* End of functions for sort_region() */
oleo-1.3/utils.c 644 722 0 47420 5354752772 12035 0ustar lordwheel/* Copyright (C) 1990, 1992, 1993 Free Software Foundation, Inc.

This file is part of Oleo, the GNU Spreadsheet.

Oleo 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, or (at your option)
any later version.

Oleo 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 Oleo; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */

#include
#include
#include "sysdef.h"


/* unistd.h defines _POSIX_VERSION on POSIX.1 systems. */
#if defined(DIRENT) || defined(_POSIX_VERSION)
#include
#define NLENGTH(dirent) (strlen((dirent)->d_name))
#else /* not (DIRENT or _POSIX_VERSION) */
#define dirent direct
#define NLENGTH(dirent) ((dirent)->d_namlen)
#ifdef SYSNDIR
#include
#endif /* SYSNDIR */
#ifdef SYSDIR
#include
#endif /* SYSDIR */
#ifdef NDIR
#include
#endif /* NDIR */
#endif /* not (DIRENT or _POSIX_VERSION) */

#ifdef __STDC__
#define CONST const
#undef NULL
#else
#define CONST
#endif

#include
#include "utils.h"

#ifndef F_OK
#define F_OK 0
#endif
#ifndef _IOSTRG
#define _IOSTRG 0
#endif

#ifdef __STDC__
extern void abort (void);
extern void *malloc (size_t);
extern void *calloc (size_t, size_t);
extern void *realloc (void *, size_t);
#else
extern void abort ();
extern void *malloc ();
extern void *calloc ();
extern void *realloc ();
#endif

extern int sys_nerr;
extern char *sys_errlist[];

struct id
{
int flag;
FILE *fp;
char *name;
};

struct id *__id_s;
int __id_n;
int __id_f;

int __make_backups;
int __backup_by_copying;

/* Stash argv[0] here so panic will know what the program is called */
char *argv_name = 0;

/* Blow chunks! */
#ifdef __STDC__
void
panic (const char *s,...)
#else
void
panic (s, va_alist)
char *s;
va_dcl
#endif
{
va_list iggy;

var_start (iggy, s);
if (argv_name)
fprintf (stderr, "%s:", argv_name);
vfprintf (stderr, s, iggy);
putc ('\n', stderr);
va_end (iggy);
exit (2);
}

/* Given a file name, come up with a backup file name. . . */
#ifdef __STDC__
char *
backup_file_name (char *file_name)
#else
char *
backup_file_name (file_name)
char *file_name;
#endif
{
char *dir_name, *dir_end;

DIR *dir;
register struct dirent *dp;
int len;
int max_fnum;
int cur_fnum;

char *tmp_ptr;

char *return_value;

dir_end = (char *)rindex (file_name, '/');
if (dir_end)
{
dir_name = file_name;
file_name = dir_end + 1;
*dir_end = '\0';
}
else
{
dir_name = ".";
}
len = strlen (file_name);

dir = opendir (dir_name);
if (dir == 0)
{
if (dir_end)
*dir_end = '/';
return (char *) 0;
}

max_fnum = 0;
while (dp = readdir (dir))
{
if (!dp->d_ino
|| NLENGTH (dp) <= len
|| strncmp (dp->d_name, file_name, len)
|| dp->d_name[len] != '.'
|| dp->d_name[len + 1] != '~'
|| dp->d_name[NLENGTH(dp) - 1] != '~')
continue;

tmp_ptr = &(dp->d_name[len + 2]);
for (cur_fnum = 0; isdigit (*tmp_ptr); tmp_ptr++)
cur_fnum = cur_fnum * 10 + *tmp_ptr - '0';
if (tmp_ptr != &(dp->d_name[NLENGTH(dp) - 1]) || cur_fnum < max_fnum)
continue;
max_fnum = cur_fnum;
}
closedir (dir);
max_fnum++;
return_value = (char *) malloc (strlen (dir_name) + len + 12);
if (!return_value)
return (char *) 0;
sprintf (return_value, "%s/%s.~%d~", dir_name, file_name, max_fnum);
if (dir_end)
*dir_end = '/';
return return_value;
}


char *
__fp_name (fp)
FILE *fp;
{
int n;

for (n = 0; n < __id_n; n++)
{
if (__id_s[n].fp == fp)
return __id_s[n].name;
}
return "{Unknown file pointer}";
}

void
__set_fp (fp, name, flag)
FILE *fp;
CONST char *name;
int flag;
{
if (__id_s == 0)
{
__id_s = ck_malloc (20 * sizeof (struct id));
__id_n = 0;
__id_f = 20;
}
else
{
int n;

for (n = 0; n < __id_n; n++)
if (__id_s[n].fp == fp)
{
free (__id_s[n].name);
__id_s[n] = __id_s[--__id_n];
__id_f++;
break;
}
}
if (__id_f == 0)
{
__id_f = 20;
__id_s = ck_realloc (__id_s, (__id_f + __id_n) * sizeof (struct id));
}
__id_s[__id_n].flag = flag;
__id_s[__id_n].name = strdup (name);
__id_s[__id_n].fp = fp;
__id_n++;
__id_f--;
}

/* Open a file or a pipe */
FILE *
xopen (name, mode)
CONST char *name;
CONST char *mode;
{
int flag = 0;
FILE *ret;

while (*name == ' ')
name++;
if (*name == '!')
{
name++;
ret = popen (name, mode);
flag = 1;
}
else
ret = fopen (name, mode);
if (ret == 0)
return ret;
__set_fp (ret, name, flag);
return ret;
}

/* Open a file, creating a backup file if needed. . . */
FILE *
fopen_with_backup (name, mode)
char *name;
CONST char *mode;
{
char *newname;
struct stat stat_buf;
int old_file = 0;

old_file = (stat (name, &stat_buf) >= 0);

if (__make_backups && *mode == 'w' && access (name, F_OK) == 0)
{
newname = backup_file_name (name);
if (!newname)
return (FILE *) 0;
if (__backup_by_copying)
{
FILE *c_in, *c_out;
int n_read;
char buf[4096];
c_in = fopen (name, "r");
if (!c_in)
return 0;
c_out = fopen (newname, "w");
{
int fd;
if (!old_file || (stat (name, &stat_buf) < 0))
{
fclose (c_in);
return 0;
}
fd = creat (newname, stat_buf.st_mode);
if (fd < 0)
{
fclose (c_in);
return 0;
}
fchmod (fd, stat_buf.st_mode);
c_out = fdopen (fd, "w");
if (!c_out)
{
fclose (c_in);
close (fd);
return 0;
}
}
while ((n_read = fread (buf, 1, sizeof (buf), c_in)) > 0)
if (fwrite (buf, 1, n_read, c_out) != n_read)
{
fclose (c_in);
fclose (c_out);
return (FILE *) 0;
}
if (fclose (c_in) == EOF || fclose (c_out) == EOF)
return (FILE *) 0;
}
else
#if defined(HAVE_RENAME)
if (rename (name, newname) < 0)
#else
if (link (name, newname) || unlink (name))
#endif
return (FILE *) 0;
free (newname);
}

{
FILE * ret = fopen (name, mode);
if (ret && old_file)
fchmod (fileno (ret), stat_buf.st_mode);
return ret;
}
}

/* Open a file or a pipe, creating a backup file if it's a file */
FILE *
xopen_with_backup (name, mode)
CONST char *name;
CONST char *mode;
{
int flag;
FILE *ret;

while (*name == ' ')
name++;
if (*name == '|')
{
ret = popen (name + 1, mode);
flag = 1;
}
else
{
ret = fopen_with_backup (name, mode);
flag = 0;
}
if (ret == 0)
return ret;
__set_fp (ret, name, flag);
return ret;
}

/* Close something opened with xopen. . . */
int
xclose (fp)
FILE *fp;
{
int ret;
int n;

for (n = 0; n < __id_n; n++)
{
if (__id_s[n].fp == fp)
break;
}
if (n == __id_n)
panic ("Unknown file pointer %p given to xclose", fp);
if (__id_s[n].flag)
ret = pclose (fp);
else
ret = fclose (fp);
return ret;
}

/* Fclose or panic */
void
ck_fclose (stream)
FILE *stream;
{
if (fclose (stream) == EOF)
panic ("Couldn't close %s", __fp_name (stream));
}

/* fopen or panic */
void *
ck_malloc (size)
size_t size;
{
void *ret;

ret = malloc (size);
if (ret == (void *) 0)
panic ("Couldn't allocate %u bytes", size);
return ret;
}

#ifdef __STDC__
char *
ck_savestr (char *str)
#else
char *
ck_savestr (str)
char *str;
#endif
{
char *newstr = 0;
if (str)
{
int len = strlen (str) + 1;
newstr = (char *) ck_malloc (len);
bcopy (str, newstr, len);
}
return newstr;
}


#ifdef __STDC__
char *
ck_savestrn (char *str, int n)
#else
char *
ck_savestrn (str, n)
char *str;
int n;
#endif
{
char *newstr = 0;
if (str)
{
newstr = (char *) ck_malloc (n + 1);
bcopy (str, newstr, n);
newstr[n] = '\0';
}
return newstr;
}

#ifdef __STDC__
void *
ck_calloc (size_t size)
#else
void *
ck_calloc (size)
size_t size;
#endif
{
void *ret;

ret = calloc (size, 1);
if (ret == (void *) 0)
panic ("Couldn't allocate %u bytes", size);
return ret;
}

/* Realloc or panic */
#ifdef __STDC__
void *
ck_realloc (void *ptr, size_t size)
#else
void *
ck_realloc (ptr, size)
void *ptr;
size_t size;
#endif
{
void *ret;

if (!ptr)
ret = malloc (size);
else
ret = realloc (ptr, size);
if (ret == (void *) 0)
panic ("Couldn't re-allocate %u bytes from %p", size, ptr);
return ret;
}

/* Do a sprintf into an allocated buffer. */
char *
#ifdef __STDC__
mk_sprintf (char *str,...)
{
va_list iggy;
#ifdef __TURBOC__
static
#endif
char tmpbuf[1024 * 8];
char *ret;

va_start (iggy, str);
vsprintf (tmpbuf, str, iggy);
va_end (iggy);
ret = (char *) ck_malloc (strlen (tmpbuf) + 1);
strcpy (ret, tmpbuf);
return ret;
}

#else

mk_sprintf (str, va_alist)
char *str;
va_dcl
{
va_list iggy;
#ifdef __TURBOC__
static
#endif
char tmpbuf[1024 * 8];
char *ret;

va_start (iggy);
vsprintf (tmpbuf, str, iggy);
va_end (iggy);

ret = (char *) ck_malloc (strlen (tmpbuf) + 1);
strcpy (ret, tmpbuf);
return ret;
}

#endif

/* Implement a variable sized LIFO stack of pointers to void */

struct stack
{
int allocated;
int used;
void **buf;
};

#define MIN_STACK 20

void *
init_stack ()
{
struct stack *b;

b = (struct stack *) ck_malloc (sizeof (struct stack));
b->allocated = MIN_STACK;
b->used = 0;
b->buf = (void **) ck_malloc (MIN_STACK * sizeof (void *));
return (void *) b;
}

void
flush_stack (bb)
void *bb;
{
struct stack *b;

b = (struct stack *) bb;
free (b->buf);
b->buf = 0;
b->allocated = 0;
b->used = 0;
free (b);
}

void
push_stack (bb, add)
void *bb;
void *add;
{
struct stack *b;

b = (struct stack *) bb;
if (b->allocated == b->used)
{
b->allocated *= 2;
b->buf = (void **) ck_realloc (b->buf, b->allocated * sizeof (void *));
}
b->buf[(b->used)++] = add;
}

void *
pop_stack (bb)
void *bb;
{
struct stack *b;

b = (struct stack *) bb;
if (b->used == 0)
return (void *) 0;
return b->buf[--(b->used)];
}

int
size_stack (bb)
void *bb;
{
struct stack *b;

b = (struct stack *) bb;
return b->used;
}

#ifndef HAVE_STRDUP
char *
strdup (str)
CONST char *str;
{
char *ret;

ret = (char *) ck_malloc (strlen (str) + 2);
strcpy (ret, str);
return ret;
}
#endif

#ifndef HAVE_STRICMP
/*
* stricmp - compare string s1 to s2, ignoring case
*/

#ifdef __STDC__
int
stricmp (const char * s1, const char * s2)
#else
int
stricmp (s1, s2)
CONST char *s1;
CONST char *s2;
#endif
{
register CONST char *scan1;
register CONST char *scan2;
register char chr1, chr2;

scan1 = s1;
scan2 = s2;
do
{
chr1 = isupper (*scan1) ? tolower (*scan1) : *scan1;
chr2 = isupper (*scan2) ? tolower (*scan2) : *scan2;
scan1++;
scan2++;
}
while (chr1 && chr1 == chr2);

/*
* The following case analysis is necessary so that characters
* which look negative collate low against normal characters but
* high against the end-of-string NUL.
*/
if (chr1 == '\0' && chr2 == '\0')
return 0;
else if (chr1 == '\0')
return -1;
else if (chr2 == '\0')
return 1;
else
return chr1 - chr2;
}
#endif

#ifndef HAVE_STRINCMP
/* strincmp - compare first N chars of strings S1 and S2 */
#ifdef __STDC__
int
strincmp (const char * s1, const char * s2, size_t n)
#else
int
strincmp (s1, s2, n)
CONST char *s1;
CONST char *s2;
size_t n;
#endif
{
register CONST char *scan1;
register CONST char *scan2;
register size_t count;
register char chr1, chr2;

scan1 = s1;
scan2 = s2;
count = n;
do
{
chr1 = isupper (*scan1) ? tolower (*scan1) : *scan1;
chr2 = isupper (*scan2) ? tolower (*scan2) : *scan2;
scan1++;
scan2++;
}
while (--count != 0 && chr1 && chr1 == chr2);

/* if (count == (size_t)-1)
return 0; */

/*
* The following case analysis is necessary so that characters
* which look negative collate low against normal characters but
* high against the end-of-string NUL.
*/
if (chr1 == '\0' && chr2 == '\0')
return 0;
else if (chr1 == '\0')
return -1;
else if (chr2 == '\0')
return 1;
else
return chr1 - chr2;
}
#endif

#ifndef HAVE_STRSTR
CONST char *
strstr (s, wanted)
CONST char *s;
CONST char *wanted;
{
register CONST char *scan;
register size_t len;
register char firstc;

/*
* The odd placement of the two tests is so "" is findable.
* Also, we inline the first char for speed.
* The ++ on scan has been moved down for optimization.
*/
firstc = *wanted;
len = strlen (wanted);
for (scan = s; *scan != firstc || strncmp (scan, wanted, len) != 0;)
if (*scan++ == '\0')
return (char *) 0;
return scan;
}
#endif

#ifdef __STDC__
char *
err_msg (void)
#else
char *
err_msg ()
#endif
{
int n;
static char buf[80];

n = errno;

if (n < sys_nerr)
return sys_errlist[n];
sprintf (buf, "Unknown error code %d (%#x)", n, n);
return buf;
}


/* Take a quoted string and return the character it represents */
#ifdef __STDC__
int
string_to_char (char ** ptr)
#else
int
string_to_char (ptr)
char **ptr;
#endif
{
char *str;
int i;
char c1, c2;

str = *ptr;
if (str[0] == '\\')
{
switch (str[1])
{
case ' ':
i = ' ';
break;
case '\\':
i = '\\';
break;
case 'b':
i = '\b';
break;
case 'f':
i = '\f';
break;
case 'n':
i = '\n';
break;
case 'r':
i = '\r';
break;
case 't':
i = '\t';
break;
case 'x':
c1 = str[2];
c2 = str[3];
if (isxdigit (c1))
{
if (isdigit (c1))
c1 -= '0';
else if (isupper (c1))
c1 -= 'A';
else
c1 -= 'a';
if (isxdigit (c2))
{
if (isdigit (c2))
c2 -= '0';
else if (isupper (c2))
c2 -= 'A';
else
c2 -= 'a';
i = c1 * 0x10 + c2;
str++;
}
else
i = c1;
}
else
i = 'x';
break;

case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
if (str[2] >= '0' && str[2] <= '7')
{
if (str[3] >= '0' && str[3] <= '7')
{
i = (str[1] - '0') * 0100 + (str[2] - '0') * 010 + (str[3] - '0');
str += 2;
}
else
{
i = (str[1] - '0') * 010 + (str[2] - '0');
str++;
}
}
else
i = str[1] - '0';
break;
default:
i = str[0];
--str;
break;
}
str += 2;
*ptr = str;
return i;
}

if (str[0] == 'M' && str[1] == '-')
{
i = 0x80;
str += 2;
}
else
i = 0;

if (str[0] == '^')
{
if (str[1] == '?')
i += 0x7f;
else if (str[1] >= '@' && str[1] <= '_')
i |= str[1] - '@';
else if (str[1] >= 'a' && str[1] <= 'z')
i = str[1] - 'a' + 1;
else if (str[1] == '\0' || isspace (str[1]))
i = '^';
else
return -1;
str += 2;
}
else
{
i |= str[0];
str++;
}
*ptr = str;
return i;
}

/* Take a char and turn it into a readable string */
#ifdef __STDC__
char *
char_to_string (int ch)
#else
char *
char_to_string (ch)
int ch;
#endif
{
static char buf[5] = "M-";

if (ch >= ' ' && ch <= '~')
{
buf[3] = ch;
return &buf[3];
}
if (ch & 0x80)
{
ch &= 0x7f;
if (ch == 0x7f || ch < ' ')
{
buf[2] = '^';
buf[3] = (ch == 0x7f ? '?' : ch + '@');
}
else
{
buf[2] = ch;
buf[3] = '\0';
}
return &buf[0];
}
if (ch == 0x7f || ch < ' ')
{
buf[2] = '^';
buf[3] = (ch == 0x7f ? '?' : ch + '@');
return &buf[2];
}
return "huh";
}


#ifdef __STDC__
long
astol (char **ptr)
#else
long
astol (ptr)
char **ptr;
#endif
{
register long i = 0;
register int c;
int sign = 1;
char *s;

s = *ptr;
/* Skip whitespace */
while (isspace (*s))
if (*s++ == '\0')
{
*ptr = s;
return (0);
}
/* Check for - or + */
if (*s == '-')
{
s++;
sign = -1;
}
else if (*s == '+')
s++;

/* Read in the digits */
for (; c = *s; s++)
{
if (!isdigit (c) || i > 214748364 || (i == 214748364 && c > (sign > 0 ? '7' : '8')))
break;
i = i * 10 + c - '0';
}
*ptr = s;
return i * sign;
}

/*
* astof - accept a number of the form:
* (and ignores leading white space)
*
* null ::=
* digit ::= 0|1|2|3|4|5|6|7|8|9
* digits ::= *
* DIGITS ::= +
* sign ::= | + | -
* -------------------------------
* accepted:
* -------------------------------
* integer ::=
* real ::= . | .
* epart ::= e | E
* float ::= |
*
* Always returned as a double
*
* There is no particular attempt to reduce mpys/divs
* those machines that are still out there (eg. PDP11/Small)
* that shun floating point arithmetic might rethink this routine.
*/

static double exps0[10] =
{1E0, 1E1, 1E2, 1E3, 1E4, 1E5, 1E6, 1E7, 1E8, 1E9};
static double exps1[10] =
{1E00, 1E10, 1E20, 1E30
#ifndef vax
,1E40, 1E50, 1E60, 1E70, 1E80, 1E90
#endif
};

#define REGISTER register

#ifdef __STDC__
double
astof (char **sp)
#else
double
astof (sp)
char **sp;
#endif
{
REGISTER char *s;
REGISTER char *cp;
long ipart, epart;
int neg = 0;
double res;
int n;

s = *sp;
while (isspace (*s))
{
s++;
if (*s == '\0')
{
*sp = s;
return (0.0);
}
}
/*
* Need to handle sign here due to '-.3' or '-0.3'
*/
if (*s == '-')
{
++neg;
++s;
}
else if (*s == '+')
++s;
cp = s;
/*
* get ipart handling '.n' case
*/
res = 0.0;
while (isdigit (*s))
{
for (n = 0, ipart = 0; n < 6 && isdigit (*s); n++)
ipart = ipart * 10 + *s++ - '0';
res = res * exps0[n] + (double) ipart;
}
if (s == cp)
{
if (*s == '.')
ipart = 0;
else
{
*sp = s;
return (0.0);
}
}
/*
* either we find a '.' or e|E or done
*/
if (*s == '.')
{
int m;
++s;

m = 0;
while (isdigit (*s))
{
for (n = 0, ipart = 0; n < 6 && isdigit (*s); n++)
ipart = ipart * 10 + *s++ - '0';
m += n;
if (m >= 100)
continue;
if (m >= 10)
res += ((double) ipart) / (exps1[m / 10] * exps0[m % 10]);
else
res += ((double) ipart) / exps0[m];
}
}
/*
* In either case (.) handle E part
*/
if (*s == 'e' || *s == 'E')
{
int eneg;

++s;
epart = 0;
eneg = 0;
if (*s == '-')
{
eneg++;
s++;
}
else if (*s == '+')
s++;
while (isdigit (*s))
epart = epart * 10 + *s++ - '0';
if (eneg)
{
#ifndef vax
while (epart >= 100)
{
res /= 1E100;
epart -= 100;
}
#endif
if (epart > 9)
{
res /= exps1[epart / 10];
epart %= 10;
}
if (epart)
res /= exps0[epart];
}
else
{
#ifndef vax
while (epart >= 100)
{
res *= 1E100;
epart -= 100;
}
#endif
if (epart > 9)
{
res *= exps1[epart / 10];
epart %= 10;
}
if (epart)
res *= exps0[epart];
}
}
/*
* fix sign
*/
if (neg)
res = -res;
*sp = s;
return (res);
}

#ifdef TEST_ASTOF
main ()
{
char buf[80];
char *ptr;
double at, ast;
double atof ();

while (gets (buf))
{
at = atof (buf);
ptr = buf;
ast = astof (&ptr);
printf ("%15.6f %15.6f %s ", at, ast, at == ast ? "eq" : "NEQ");
if (*ptr)
printf ("%s->'%s'\n", buf, ptr);
else
printf ("%s\n", buf);
}
}
char *
ck_savestr (str)
char *str;
{
char *newstr = 0;
if (str)
{
int len = strlen (str) + 1;
newstr = (char *) ck_malloc (len);
bcopy (str, newstr, len);
}
return newstr;
}

#endif
oleo-1.3/obstack.c 644 722 0 31726 5321115437 12306 0ustar lordwheel/* obstack.c - subroutines used implicitly by object stack macros
Copyright (C) 1988, 1992, 1993 Free Software Foundation, Inc.

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, 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, 675 Mass Ave, Cambridge, MA 02139, USA. */

#include "obstack.h"

#ifdef __STDC__
#define POINTER void *
#else
#define POINTER char *
#endif

/* Determine default alignment. */
struct fooalign {char x; double d;};
#define DEFAULT_ALIGNMENT \
((PTR_INT_TYPE) ((char *)&((struct fooalign *) 0)->d - (char *)0))
/* If malloc were really smart, it would round addresses to DEFAULT_ALIGNMENT.
But in fact it might be less smart and round addresses to as much as
DEFAULT_ROUNDING. So we prepare for it to do that. */
union fooround {long x; double d;};
#define DEFAULT_ROUNDING (sizeof (union fooround))

/* When we copy a long block of data, this is the unit to do it with.
On some machines, copying successive ints does not work;
in such a case, redefine COPYING_UNIT to `long' (if that works)
or `char' as a last resort. */
#ifndef COPYING_UNIT
#define COPYING_UNIT int
#endif

/* The non-GNU-C macros copy the obstack into this global variable
to avoid multiple evaluation. */

struct obstack *_obstack;

/* Define a macro that either calls functions with the traditional malloc/free
calling interface, or calls functions with the mmalloc/mfree interface
(that adds an extra first argument), based on the state of use_extra_arg.
For free, do not use ?:, since some compilers, like the MIPS compilers,
do not allow (expr) ? void : void. */

#define CALL_CHUNKFUN(h, size) \
(((h) -> use_extra_arg) \
? (*(h)->chunkfun) ((h)->extra_arg, (size)) \
: (*(h)->chunkfun) ((size)))

#define CALL_FREEFUN(h, old_chunk) \
do { \
if ((h) -> use_extra_arg) \
(*(h)->freefun) ((h)->extra_arg, (old_chunk)); \
else \
(*(h)->freefun) ((old_chunk)); \
} while (0)


/* Initialize an obstack H for use. Specify chunk size SIZE (0 means default).
Objects start on multiples of ALIGNMENT (0 means use default).
CHUNKFUN is the function to use to allocate chunks,
and FREEFUN the function to free them. */

void
_obstack_begin (h, size, alignment, chunkfun, freefun)
struct obstack *h;
int size;
int alignment;
POINTER (*chunkfun) ();
void (*freefun) ();
{
register struct _obstack_chunk* chunk; /* points to new chunk */

if (alignment == 0)
alignment = DEFAULT_ALIGNMENT;
if (size == 0)
/* Default size is what GNU malloc can fit in a 4096-byte block. */
{
/* 12 is sizeof (mhead) and 4 is EXTRA from GNU malloc.
Use the values for range checking, because if range checking is off,
the extra bytes won't be missed terribly, but if range checking is on
and we used a larger request, a whole extra 4096 bytes would be
allocated.

These number are irrelevant to the new GNU malloc. I suspect it is
less sensitive to the size of the request. */
int extra = ((((12 + DEFAULT_ROUNDING - 1) & ~(DEFAULT_ROUNDING - 1))
+ 4 + DEFAULT_ROUNDING - 1)
& ~(DEFAULT_ROUNDING - 1));
size = 4096 - extra;
}

h->chunkfun = (struct _obstack_chunk * (*)()) chunkfun;
h->freefun = freefun;
h->chunk_size = size;
h->alignment_mask = alignment - 1;
h->use_extra_arg = 0;

chunk = h->chunk = CALL_CHUNKFUN (h, h -> chunk_size);
h->next_free = h->object_base = chunk->contents;
h->chunk_limit = chunk->limit
= (char *) chunk + h->chunk_size;
chunk->prev = 0;
/* The initial chunk now contains no empty object. */
h->maybe_empty_object = 0;
}

void
_obstack_begin_1 (h, size, alignment, chunkfun, freefun, arg)
struct obstack *h;
int size;
int alignment;
POINTER (*chunkfun) ();
void (*freefun) ();
POINTER arg;
{
register struct _obstack_chunk* chunk; /* points to new chunk */

if (alignment == 0)
alignment = DEFAULT_ALIGNMENT;
if (size == 0)
/* Default size is what GNU malloc can fit in a 4096-byte block. */
{
/* 12 is sizeof (mhead) and 4 is EXTRA from GNU malloc.
Use the values for range checking, because if range checking is off,
the extra bytes won't be missed terribly, but if range checking is on
and we used a larger request, a whole extra 4096 bytes would be
allocated.

These number are irrelevant to the new GNU malloc. I suspect it is
less sensitive to the size of the request. */
int extra = ((((12 + DEFAULT_ROUNDING - 1) & ~(DEFAULT_ROUNDING - 1))
+ 4 + DEFAULT_ROUNDING - 1)
& ~(DEFAULT_ROUNDING - 1));
size = 4096 - extra;
}

h->chunkfun = (struct _obstack_chunk * (*)()) chunkfun;
h->freefun = freefun;
h->chunk_size = size;
h->alignment_mask = alignment - 1;
h->extra_arg = arg;
h->use_extra_arg = 1;

chunk = h->chunk = CALL_CHUNKFUN (h, h -> chunk_size);
h->next_free = h->object_base = chunk->contents;
h->chunk_limit = chunk->limit
= (char *) chunk + h->chunk_size;
chunk->prev = 0;
/* The initial chunk now contains no empty object. */
h->maybe_empty_object = 0;
}

/* Allocate a new current chunk for the obstack *H
on the assumption that LENGTH bytes need to be added
to the current object, or a new object of length LENGTH allocated.
Copies any partial object from the end of the old chunk
to the beginning of the new one. */

void
_obstack_newchunk (h, length)
struct obstack *h;
int length;
{
register struct _obstack_chunk* old_chunk = h->chunk;
register struct _obstack_chunk* new_chunk;
register long new_size;
register int obj_size = h->next_free - h->object_base;
register int i;
int already;

/* Compute size for new chunk. */
new_size = (obj_size + length) + (obj_size >> 3) + 100;
if (new_size < h->chunk_size)
new_size = h->chunk_size;

/* Allocate and initialize the new chunk. */
new_chunk = h->chunk = CALL_CHUNKFUN (h, new_size);
new_chunk->prev = old_chunk;
new_chunk->limit = h->chunk_limit = (char *) new_chunk + new_size;

/* Move the existing object to the new chunk.
Word at a time is fast and is safe if the object
is sufficiently aligned. */
if (h->alignment_mask + 1 >= DEFAULT_ALIGNMENT)
{
for (i = obj_size / sizeof (COPYING_UNIT) - 1;
i >= 0; i--)
((COPYING_UNIT *)new_chunk->contents)[i]
= ((COPYING_UNIT *)h->object_base)[i];
/* We used to copy the odd few remaining bytes as one extra COPYING_UNIT,
but that can cross a page boundary on a machine
which does not do strict alignment for COPYING_UNITS. */
already = obj_size / sizeof (COPYING_UNIT) * sizeof (COPYING_UNIT);
}
else
already = 0;
/* Copy remaining bytes one by one. */
for (i = already; i < obj_size; i++)
new_chunk->contents[i] = h->object_base[i];

/* If the object just copied was the only data in OLD_CHUNK,
free that chunk and remove it from the chain.
But not if that chunk might contain an empty object. */
if (h->object_base == old_chunk->contents && ! h->maybe_empty_object)
{
new_chunk->prev = old_chunk->prev;
CALL_FREEFUN (h, old_chunk);
}

h->object_base = new_chunk->contents;
h->next_free = h->object_base + obj_size;
/* The new chunk certainly contains no empty object yet. */
h->maybe_empty_object = 0;
}

/* Return nonzero if object OBJ has been allocated from obstack H.
This is here for debugging.
If you use it in a program, you are probably losing. */

int
_obstack_allocated_p (h, obj)
struct obstack *h;
POINTER obj;
{
register struct _obstack_chunk* lp; /* below addr of any objects in this chunk */
register struct _obstack_chunk* plp; /* point to previous chunk if any */

lp = (h)->chunk;
/* We use >= rather than > since the object cannot be exactly at
the beginning of the chunk but might be an empty object exactly
at the end of an adjacent chunk. */
while (lp != 0 && ((POINTER)lp >= obj || (POINTER)(lp)->limit < obj))
{
plp = lp->prev;
lp = plp;
}
return lp != 0;
}

/* Free objects in obstack H, including OBJ and everything allocate
more recently than OBJ. If OBJ is zero, free everything in H. */

#undef obstack_free

/* This function has two names with identical definitions.
This is the first one, called from non-ANSI code. */

void
_obstack_free (h, obj)
struct obstack *h;
POINTER obj;
{
register struct _obstack_chunk* lp; /* below addr of any objects in this chunk */
register struct _obstack_chunk* plp; /* point to previous chunk if any */

lp = h->chunk;
/* We use >= because there cannot be an object at the beginning of a chunk.
But there can be an empty object at that address
at the end of another chunk. */
while (lp != 0 && ((POINTER)lp >= obj || (POINTER)(lp)->limit < obj))
{
plp = lp->prev;
CALL_FREEFUN (h, lp);
lp = plp;
/* If we switch chunks, we can't tell whether the new current
chunk contains an empty object, so assume that it may. */
h->maybe_empty_object = 1;
}
if (lp)
{
h->object_base = h->next_free = (char *)(obj);
h->chunk_limit = lp->limit;
h->chunk = lp;
}
else if (obj != 0)
/* obj is not in any of the chunks! */
abort ();
}

/* This function is used from ANSI code. */

void
obstack_free (h, obj)
struct obstack *h;
POINTER obj;
{
register struct _obstack_chunk* lp; /* below addr of any objects in this chunk */
register struct _obstack_chunk* plp; /* point to previous chunk if any */

lp = h->chunk;
/* We use >= because there cannot be an object at the beginning of a chunk.
But there can be an empty object at that address
at the end of another chunk. */
while (lp != 0 && ((POINTER)lp >= obj || (POINTER)(lp)->limit < obj))
{
plp = lp->prev;
CALL_FREEFUN (h, lp);
lp = plp;
/* If we switch chunks, we can't tell whether the new current
chunk contains an empty object, so assume that it may. */
h->maybe_empty_object = 1;
}
if (lp)
{
h->object_base = h->next_free = (char *)(obj);
h->chunk_limit = lp->limit;
h->chunk = lp;
}
else if (obj != 0)
/* obj is not in any of the chunks! */
abort ();
}

#if 0
/* These are now turned off because the applications do not use it
and it uses bcopy via obstack_grow, which causes trouble on sysV. */

/* Now define the functional versions of the obstack macros.
Define them to simply use the corresponding macros to do the job. */

#ifdef __STDC__
/* These function definitions do not work with non-ANSI preprocessors;
they won't pass through the macro names in parentheses. */

/* The function names appear in parentheses in order to prevent
the macro-definitions of the names from being expanded there. */

POINTER (obstack_base) (obstack)
struct obstack *obstack;
{
return obstack_base (obstack);
}

POINTER (obstack_next_free) (obstack)
struct obstack *obstack;
{
return obstack_next_free (obstack);
}

int (obstack_object_size) (obstack)
struct obstack *obstack;
{
return obstack_object_size (obstack);
}

int (obstack_room) (obstack)
struct obstack *obstack;
{
return obstack_room (obstack);
}

void (obstack_grow) (obstack, pointer, length)
struct obstack *obstack;
POINTER pointer;
int length;
{
obstack_grow (obstack, pointer, length);
}

void (obstack_grow0) (obstack, pointer, length)
struct obstack *obstack;
POINTER pointer;
int length;
{
obstack_grow0 (obstack, pointer, length);
}

void (obstack_1grow) (obstack, character)
struct obstack *obstack;
int character;
{
obstack_1grow (obstack, character);
}

void (obstack_blank) (obstack, length)
struct obstack *obstack;
int length;
{
obstack_blank (obstack, length);
}

void (obstack_1grow_fast) (obstack, character)
struct obstack *obstack;
int character;
{
obstack_1grow_fast (obstack, character);
}

void (obstack_blank_fast) (obstack, length)
struct obstack *obstack;
int length;
{
obstack_blank_fast (obstack, length);
}

POINTER (obstack_finish) (obstack)
struct obstack *obstack;
{
return obstack_finish (obstack);
}

POINTER (obstack_alloc) (obstack, length)
struct obstack *obstack;
int length;
{
return obstack_alloc (obstack, length);
}

POINTER (obstack_copy) (obstack, pointer, length)
struct obstack *obstack;
POINTER pointer;
int length;
{
return obstack_copy (obstack, pointer, length);
}

POINTER (obstack_copy0) (obstack, pointer, length)
struct obstack *obstack;
POINTER pointer;
int length;
{
return obstack_copy0 (obstack, pointer, length);
}

#endif /* __STDC__ */

#endif /* 0 */
oleo-1.3/lists.c 644 722 0 61066 5355226402 12020 0ustar lordwheel/* Copyright (C) 1990, 1992, 1993 Free Software Foundation, Inc.

This file is part of Oleo, the GNU Spreadsheet.

Oleo 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, or (at your option)
any later version.

Oleo 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 Oleo; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */

#include "funcdef.h"

#define obstack_chunk_alloc ck_malloc
#define obstack_chunk_free free
#include "obstack.h"
#include "sysdef.h"
#include "global.h"
#include "cell.h"
#include "ref.h"
#include "window.h"
#include "io-term.h"
#include "io-abstract.h"

#define ROW_BUF 3
#define COL_BUF 2
#define MAX MAX_ROW
#define MIN MIN_ROW
static struct obstack find_stack;

#if 1
#define malloc_chain_check(x)
#endif

#ifdef __GNUC__
#define inline __inline__
#else
#define inline
#endif

#ifdef TEST_ME
typedef unsigned char CELLREF;
typedef unsigned int size_t;
#define ck_malloc malloc
extern void *malloc ();
#define MIN 1
#define MAX 65535
#endif

struct list
{
CELLREF lo, hi;
struct list *next;
char mem[1];
};

struct find
{
struct find *next;
CELLREF lo, hi, cur;
struct list **start;
struct list *curptr;
CELLREF left;
void *ret;
char fini;
int ele;
};

struct find *finds = 0;

#ifdef __STDC__
static inline void
flush (struct list *ptr)
#else
static inline void
flush (ptr)
struct list *ptr;
#endif
{
struct list *nxt;

while (ptr)
{
nxt = ptr->next;
free (ptr);
ptr = nxt;
}
}

#ifdef __STDC__
static inline void
resync (struct list *tofree, struct list *new, int ele)
#else
static inline void
resync (tofree, new, ele)
struct list *tofree;
struct list *new;
int ele;
#endif
{
struct find *findp;

if (ele == sizeof (struct cell)
&& my_cell
&& (char *) my_cell >= tofree->mem
&& (char *) my_cell <= tofree->mem + ele * (1 + tofree->hi - tofree->lo))
my_cell = (struct cell *) (new->mem + ele * (cur_row - new->lo));

for (findp = finds; findp; findp = findp->next)
{
if (tofree == findp->curptr)
{
CELLREF hi;
findp->curptr = new;
findp->ret = new->mem + (findp->cur - new->lo) * ele;
hi = (findp->hi < new->hi ? findp->hi : new->hi);
if (findp->cur < hi)
findp->left = hi - findp->cur;
}
}

free (tofree);
}

#ifdef __STDC__
static inline void *
find (CELLREF pos, struct list *ptr, int ele)
#else
static inline void *
find (pos, ptr, ele)
CELLREF pos;
struct list *ptr;
int ele;
#endif
{
for (; ptr; ptr = ptr->next)
{
if (ptr->lo > pos)
break;
if (ptr->hi >= pos)
return ptr->mem + (pos - ptr->lo) * ele;
}
return 0;
}

#ifdef __STDC__
static inline void *
make (CELLREF pos, struct list **prevp, int ele, int buf)
#else
static inline void *
make (pos, prevp, ele, buf)
CELLREF pos;
struct list **prevp;
int ele;
int buf;
#endif
{
CELLREF lo, hi;
size_t size;
struct list *ptr;

while (*prevp && (*prevp)->next && (*prevp)->next->lo < pos)
prevp = &((*prevp)->next);

/* Was it easy? */
if (*prevp && (*prevp)->lo <= pos && (*prevp)->hi >= pos)
return (*prevp)->mem + (pos - (*prevp)->lo) * ele;

lo = (pos < MIN + buf) ? MIN : pos - buf;
hi = (pos > MAX - buf) ? MAX : pos + buf;

if (!*prevp
|| ((*prevp)->hi < lo - 1
&& (!(*prevp)->next
|| (*prevp)->next->lo - 1 > hi)))
{
/* Allocate a whole new structure */
size = (1 + hi - lo) * ele;
ptr = ck_malloc (sizeof (struct list) + size);
ptr->lo = lo;
ptr->hi = hi;
if (*prevp && (*prevp)->hi < lo)
{
ptr->next = (*prevp)->next;
(*prevp)->next = ptr;
}
else
{
ptr->next = *prevp;
*prevp = ptr;
}
bzero (ptr->mem, size);
malloc_chain_check (1);
}
else if ((*prevp)->lo > lo)
{
/* Stretch one down a bit to fit */
hi = (*prevp)->hi;
size = (1 + hi - lo) * ele;
ptr = ck_malloc (sizeof (struct list) + size);
ptr->lo = lo;
ptr->hi = hi;
ptr->next = (*prevp)->next;
bcopy ((*prevp)->mem, ptr->mem + ((*prevp)->lo - ptr->lo) * ele, (1 + (*prevp)->hi - (*prevp)->lo) * ele);
bzero (ptr->mem, ((*prevp)->lo - ptr->lo) * ele);
resync (*prevp, ptr, ele);
*prevp = ptr;
malloc_chain_check (1);
}
else if ((*prevp)->hi < hi && (*prevp)->next && (*prevp)->next->lo <= hi)
{
/* Merge this one and the one after it */
size = (1 + (*prevp)->next->hi - (*prevp)->lo) * ele;
ptr = ck_malloc (sizeof (struct list) + size);
ptr->lo = (*prevp)->lo;
ptr->hi = (*prevp)->next->hi;
ptr->next = (*prevp)->next->next;
bcopy ((*prevp)->mem, ptr->mem, (1 + (*prevp)->hi - (*prevp)->lo) * ele);
bzero (ptr->mem + (1 + (*prevp)->hi - ptr->lo) * ele, ((*prevp)->next->lo - (*prevp)->hi) * ele);
bcopy ((*prevp)->next->mem,
ptr->mem + ((*prevp)->next->lo - ptr->lo) * ele,
(1 + (*prevp)->next->hi - (*prevp)->next->lo) * ele);
resync ((*prevp)->next, ptr, ele);
resync (*prevp, ptr, ele);
*prevp = ptr;
malloc_chain_check (1);
}
else if ((*prevp)->hi < hi)
{
/* stretch this one up a bit */
size = (1 + hi - (*prevp)->lo) * ele;
ptr = ck_malloc (sizeof (struct list) + size);
ptr->lo = (*prevp)->lo;
ptr->hi = hi;
ptr->next = (*prevp)->next;
bcopy ((*prevp)->mem, ptr->mem, (1 + (*prevp)->hi - (*prevp)->lo) * ele);
bzero (ptr->mem + (1 + (*prevp)->hi - ptr->lo) * ele, (hi - (*prevp)->hi) * ele);
resync (*prevp, ptr, ele);
*prevp = ptr;
malloc_chain_check (1);
}
else
ptr = *prevp;
#ifdef TEST
if (ptr->lo > pos || ptr->hi < pos)
panic ("Make at %u not in %u %u", pos, ptr->lo, ptr->hi);
#endif

return ptr->mem + (pos - ptr->lo) * ele;
}

#ifdef __STDC__
static inline void *
find_rng (struct list **start, CELLREF lo, CELLREF hi, int ele)
#else
static inline void *
find_rng (start, lo, hi, ele)
struct list **start;
CELLREF lo;
CELLREF hi;
int ele;
#endif
{
struct list *ptr;
struct find *f;

f = (struct find *)obstack_alloc (&find_stack, sizeof (struct find));
f->lo = lo;
f->hi = hi;
f->ele = ele;
f->start = start;
for (ptr = *start; ptr; ptr = ptr->next)
if (ptr->hi >= lo)
break;
if (ptr && ptr->lo <= hi)
{
f->cur = (ptr->lo > lo ? ptr->lo : lo);
f->curptr = ptr;
f->ret = ptr->mem + (f->cur - ptr->lo) * ele;
f->left = 1 + (f->hi < ptr->hi ? f->hi : ptr->hi) - f->cur;
f->fini = 0;
}
else
f->fini = 1;
f->next = finds;
finds = f;
return f;
}

#ifdef __STDC__
static inline void *
make_rng (struct list **start, CELLREF lo, CELLREF hi, int ele, int buf)
#else
static inline void *
make_rng (start, lo, hi, ele, buf)
struct list **start;
CELLREF lo;
CELLREF hi;
int ele;
int buf;
#endif
{
struct list **prevp;
struct list *ptr;
size_t size;
struct find *f;

f = (struct find *)obstack_alloc (&find_stack, sizeof (struct find));
f->lo = f->cur = lo;
f->hi = hi;
f->left = 1 + hi - lo;
f->fini = 0;
f->ele = ele;
f->start = start;

lo = lo <= MIN + buf ? MIN : lo - buf;
hi = hi >= MAX - buf ? MAX : hi + buf;

for (prevp = start; *prevp && (*prevp)->hi < lo - 1; prevp = &((*prevp)->next))
;
ptr = *prevp;
if (!*prevp || (*prevp)->lo - 1 > hi)
{
/* Allocate the whole thing */
size = (1 + hi - lo) * ele;
ptr = ck_malloc (sizeof (struct list) + size);
ptr->lo = lo;
ptr->hi = hi;
ptr->next = *prevp;
bzero (ptr->mem, size);
if (*prevp && (*prevp)->hi < lo)
{
ptr->next = (*prevp)->next;
(*prevp)->next = ptr;
}
else
{
ptr->next = *prevp;
*prevp = ptr;
}
*prevp = ptr;
malloc_chain_check (1);
}
else
{
if ((*prevp)->lo > lo)
{
/* Stretch this one down a bit */
size = (1 + (*prevp)->hi - lo) * ele;
ptr = ck_malloc (sizeof (struct list) + size);
ptr->lo = lo;
ptr->hi = (*prevp)->hi;
ptr->next = (*prevp)->next;
bcopy ((*prevp)->mem,
ptr->mem + ((*prevp)->lo - ptr->lo) * ele,
(1 + (*prevp)->hi - (*prevp)->lo) * ele);
bzero (ptr->mem, ((*prevp)->lo - lo) * ele);
resync (*prevp, ptr, ele);
*prevp = ptr;
malloc_chain_check (1);
}
while ((*prevp)->hi < hi && (*prevp)->next && (*prevp)->next->lo <= hi)
{
/* Merge this one and the one after it */
/* Repeat as needed */
size = (1 + (*prevp)->next->hi - (*prevp)->lo) * ele;
ptr = ck_malloc (sizeof (struct list) + size);
ptr->lo = (*prevp)->lo;
ptr->hi = (*prevp)->next->hi;
ptr->next = (*prevp)->next->next;
bcopy ((*prevp)->mem, ptr->mem, (1 + (*prevp)->hi - (*prevp)->lo) * ele);
bzero (ptr->mem + (1 + (*prevp)->hi - ptr->lo) * ele, ((*prevp)->next->lo - (*prevp)->hi) * ele);
bcopy ((*prevp)->next->mem,
ptr->mem + ((*prevp)->next->lo - ptr->lo) * ele,
(1 + (*prevp)->next->hi - (*prevp)->next->lo) * ele);
resync ((*prevp)->next, ptr, ele);
resync (*prevp, ptr, ele);
*prevp = ptr;
malloc_chain_check (1);
}
if ((*prevp)->hi < hi)
{
/* stretch this one up a bit */
size = (1 + hi - (*prevp)->lo) * ele;
ptr = ck_malloc (sizeof (struct list) + size);
ptr->lo = (*prevp)->lo;
ptr->hi = hi;
ptr->next = (*prevp)->next;
bcopy ((*prevp)->mem, ptr->mem, (1 + (*prevp)->hi - (*prevp)->lo) * ele);
bzero (ptr->mem + (1 + (*prevp)->hi - ptr->lo) * ele, (hi - (*prevp)->hi) * ele);
resync (*prevp, ptr, ele);
*prevp = ptr;
malloc_chain_check (1);
}
}
#ifdef TEST
if (ptr->lo > f->lo || ptr->hi < f->hi)
panic ("Vector of %u-%u not big enough for %u-%u", (*prevp)->lo, (*prevp)->hi, f->lo, f->hi);
#endif
f->curptr = ptr;
f->ret = ptr->mem + (f->cur - ptr->lo) * ele;
f->next = finds;
finds = f;
return f;
}

#ifdef __STDC__
static inline void *
next_rng (struct find *f, CELLREF *posp)
#else
static inline void *
next_rng (f, posp)
struct find *f;
CELLREF *posp;
#endif
{
void *ret;
struct find *next;

if (!f)
return 0;
if (!f->fini)
{
if (f->left)
{
--(f->left);
fini:
if (posp)
*posp = f->cur;
f->cur++;
ret = f->ret;
f->ret = (char *) (f->ret) + f->ele;
return ret;
}
if (f->curptr->hi < f->hi)
{
f->curptr = f->curptr->next;
if (f->curptr && f->curptr->lo <= f->hi)
{
f->ret = f->curptr->mem;
f->left = (f->hi < f->curptr->hi ? f->hi : f->curptr->hi) - f->curptr->lo;
f->cur = f->curptr->lo;
goto fini;
}
}
}
next = f->next;
obstack_free (&find_stack, f);
finds = next;
return 0;
}


struct cf
{
struct cf *next;
struct find *rows, *cols;
int make;
};

static struct cf *fp;
static struct list *the_cols;

static struct find *w_find;
static struct find *h_find;
static struct list *wids, *hgts;

void
init_cells ()
{
obstack_begin (&find_stack, sizeof (struct find) * 15);
the_cols = 0;
wids = 0;
hgts = 0;
}

#ifdef __STDC__
void
flush_everything (void)
#else
void
flush_everything ()
#endif
{
struct list *ptr, *nxt;
int n;

flush_variables ();
for (ptr = the_cols; ptr; ptr = nxt)
{
nxt = ptr->next;
for (n = 0; n <= ptr->hi - ptr->lo; n++)
flush (*(struct list **) (ptr->mem + (n * sizeof (struct list *))));
free (ptr);
}
the_cols = 0;
flush (wids);
wids = 0;
flush (hgts);
hgts = 0;
flush_fonts ();
}

#if __STDC__
struct cell *
find_cell (CELLREF row, CELLREF col)
#else
struct cell *
find_cell (row, col)
CELLREF row;
CELLREF col;
#endif
{
void **v;

v = find (col, the_cols, sizeof (void *));
return v ? find (row, *v, sizeof (struct cell)) : 0;
}

#if __STDC__
struct cell *
find_or_make_cell (CELLREF row, CELLREF col)
#else
struct cell *
find_or_make_cell (row, col)
CELLREF row;
CELLREF col;
#endif
{
struct list **v;

v = make (col, &the_cols, sizeof (struct list *), COL_BUF);
return make (row, v, sizeof (struct cell), ROW_BUF);
}

#ifdef __STDC__
void
find_cells_in_range (struct rng *r)
#else
void
find_cells_in_range (r)
struct rng *r;
#endif
{
struct cf *new;
struct list **firstcol;

new = (struct cf *)obstack_alloc (&find_stack, sizeof (struct cf));
new->make = 0;
new->next = fp;
fp = new;
new->rows = find_rng (&the_cols, r->lc, r->hc, sizeof (void *));
firstcol = next_rng (new->rows, 0);
if (firstcol)
new->cols = find_rng (firstcol, r->lr, r->hr, sizeof (struct cell));
else
new->cols = 0;
}

#ifdef __STDC__
void
make_cells_in_range (struct rng *r)
#else
void
make_cells_in_range (r)
struct rng *r;
#endif
{
struct cf *new;
struct list **firstcol;

new = (struct cf *)obstack_alloc (&find_stack, sizeof (struct cf));
new->make = 1;
new->next = fp;
fp = new;
new->rows = make_rng (&the_cols, r->lc, r->hc, sizeof (void *), ROW_BUF);
firstcol = next_rng (new->rows, 0);
new->cols = make_rng (firstcol, r->lr, r->hr, sizeof (struct cell), COL_BUF);
}

#ifdef __STDC__
struct cell *
next_cell_in_range (void)
#else
struct cell *
next_cell_in_range ()
#endif
{
struct cell *ret;
void *new_row;

for (;;)
{
if (ret = next_rng (fp->cols, 0))
return ret;
new_row = next_rng (fp->rows, 0);
if (!new_row)
{
struct cf *old;

old = fp->next;
obstack_free (&find_stack, fp);
fp = old;
return 0;
}
fp->cols = fp->make ? make_rng (new_row, fp->cols->lo, fp->cols->hi, sizeof (struct cell), ROW_BUF)
: find_rng (new_row, fp->cols->lo, fp->cols->hi, sizeof (struct cell));
}
}

#ifdef __STDC__
struct cell *
next_row_col_in_range (CELLREF *rowp, CELLREF *colp)
#else
struct cell *
next_row_col_in_range (rowp, colp)
CELLREF *rowp;
CELLREF *colp;
#endif
{
struct cell *ret;
struct list **new_row;

for (;;)
{
if (ret = next_rng (fp->cols, rowp))
{
*colp = fp->rows->cur - 1;
return ret;
}
new_row = next_rng (fp->rows, colp);
if (!new_row)
{
struct cf *old;

old = fp->next;
obstack_free (&find_stack, fp);
fp = old;
return 0;
}
fp->cols = fp->make ? make_rng (new_row, fp->cols->lo, fp->cols->hi, sizeof (struct cell), ROW_BUF)
: find_rng (new_row, fp->cols->lo, fp->cols->hi, sizeof (struct cell));
}
}

#ifdef __STDC__
void
no_more_cells (void)
#else
void
no_more_cells ()
#endif
{
struct cf *old;

/* This relies on knowing that the obstack contains
* the current find (struct cf) underneath two associated
* `struct find's.
* Here, we pop all those frames, and then free them at once.
*/

old = fp->next;
finds = finds->next->next;
obstack_free (&find_stack, fp);
fp = old;
}

#ifdef __STDC__
CELLREF
max_row (CELLREF col)
#else
CELLREF
max_row (col)
CELLREF col;
#endif
{
struct list **ptr;

ptr = find (col, the_cols, sizeof (void *));
if (!ptr || !*ptr)
return MIN;
while ((*ptr)->next)
ptr = &((*ptr)->next);
return (*ptr)->hi;
}

#ifdef __STDC__
CELLREF
max_col (CELLREF row)
#else
CELLREF
max_col (row)
CELLREF row;
#endif
{
struct list *ptr;

if (!the_cols)
return MIN;
for (ptr = the_cols; ptr->next; ptr = ptr->next)
;
return ptr->hi;
}

#ifdef __STDC__
CELLREF
highest_row (void)
#else
CELLREF
highest_row ()
#endif
{
void *f;
struct list **ptr;
CELLREF hi = MIN;

f = find_rng (&the_cols, MIN, MAX, sizeof (void *));
while (ptr = next_rng (f, 0))
{
if (*ptr)
{
while ((*ptr)->next)
ptr = &((*ptr)->next);
if ((*ptr)->hi > hi)
hi = (*ptr)->hi;
}
}
return hi;
}


#ifdef __STDC__
CELLREF
highest_col (void)
#else
CELLREF
highest_col ()
#endif
{
struct list *ptr;

if (!the_cols)
return MIN;
for (ptr = the_cols; ptr->next; ptr = ptr->next)
;
return ptr->hi;
}


/* Routines for dealing with the widths of columns. . . */

#ifdef __STDC__
int
get_width (CELLREF col)
#else
int
get_width (col)
CELLREF col;
#endif
{
int *ptr;

ptr = find (col, wids, sizeof (int));
if (!ptr || !*ptr)
return default_width;
return (*ptr) - 1;
}


#ifdef __STDC__
int
get_nodef_width (CELLREF col)
#else
int
get_nodef_width (col)
CELLREF col;
#endif
{
int *ptr;

ptr = find (col, wids, sizeof (int));
return ptr ? *ptr : 0;
}

#ifdef __STDC__
void
set_width (CELLREF col, int wid)
#else
void
set_width (col, wid)
CELLREF col;
int wid;
#endif
{
int *ptr;

ptr = make (col, &wids, sizeof (int), COL_BUF);
*ptr = wid;
}

#ifdef __STDC__
void
find_widths (CELLREF lo, CELLREF hi)
#else
void
find_widths (lo, hi)
CELLREF lo;
CELLREF hi;
#endif
{
w_find = find_rng (&wids, lo, hi, sizeof (int));
}

#ifdef __STDC__
int
next_width (CELLREF *posp)
#else
int
next_width (posp)
CELLREF *posp;
#endif
{
int *ptr;

do
ptr = next_rng (w_find, posp);
while (ptr && !*ptr);
return ptr ? *ptr : 0;
}

#ifdef __STDC__
static void
do_shift (int over, CELLREF lo, CELLREF hi, struct list **start, int buf)
#else
static void
do_shift (over, lo, hi, start, buf)
int over;
CELLREF lo;
CELLREF hi;
struct list **start;
int buf;
#endif
{
CELLREF pos;
int w;
int *ptr;
int inc;
struct list *p;

if (!*start)
return;
for (p = *start; p->next; p = p->next)
;

if (hi > p->hi)
hi = p->hi;

if (over > 0)
{
pos = hi;
hi = lo;
lo = pos;
inc = -1;
}
else
inc = 1;

if (inc > 0)
{
if (lo > hi)
return;
}
else if (hi > lo)
return;

for (pos = lo;; pos += inc)
{
ptr = find (pos, *start, sizeof (int));
w = ptr ? *ptr : 0;
ptr = w ? make (pos + over, start, sizeof (int), buf) :
find (pos + over, *start, sizeof (int));
if (w || (ptr && *ptr))
*ptr = w;
if (pos == hi)
break;
}
for (pos = hi + over;;)
{
pos += inc;
ptr = find (pos, *start, sizeof (int));
if (ptr)
*ptr = 0;
if (pos == hi)
break;
}
}

#ifdef __STDC__
void
shift_widths (int over, CELLREF lo, CELLREF hi)
#else
void
shift_widths (over, lo, hi)
int over;
CELLREF lo;
CELLREF hi;
#endif
{
do_shift (over, lo, hi, &wids, COL_BUF);
}


/* This inserts lines in which formulas can be displayed.
* It probably ought to be 1 or 0.
*/
int display_formula_mode = 0;

/* Routines for dealing with the height of rows
*/
#ifdef __STDC__
int
get_height (CELLREF row)
#else
int
get_height (row)
CELLREF row;
#endif
{
int *ptr;

ptr = find (row, hgts, sizeof (int));
if (!ptr || !*ptr)
return default_height;
return *ptr - 1 + (display_formula_mode && using_curses);
}

#ifdef __STDC__
int
get_nodef_height (CELLREF row)
#else
int
get_nodef_height (row)
CELLREF row;
#endif
{
int *ptr;

ptr = find (row, hgts, sizeof (int));
return ptr ? *ptr : 0;
}

#ifdef __STDC__
void
set_height (CELLREF row, int hgt)
#else
void
set_height (row, hgt)
CELLREF row;
int hgt;
#endif
{
int *ptr;

ptr = make (row, &hgts, sizeof (int), ROW_BUF);
*ptr = hgt;
}

float height_scale = 1.;
float width_scale = 1.;

float user_height_scale = 1.;
float user_width_scale = 1.;

#ifdef __STDC__
void
set_user_scales (double hs, double ws)
#else
void
set_user_scales (hs, ws)
double hs;
double ws;
#endif
{
user_height_scale = hs;
user_width_scale = ws;
io_repaint ();
}

#ifdef __STDC__
int
get_scaled_height (CELLREF r)
#else
int
get_scaled_height (r)
CELLREF r;
#endif
{
return ((user_height_scale <= 0.)
? 1
: (int) (get_height (r) * height_scale * user_height_scale));
}

#ifdef __STDC__
int
get_scaled_width (CELLREF c)
#else
int
get_scaled_width (c)
CELLREF c;
#endif
{
return ((user_width_scale <= 0.)
? 1
: (int)(get_width (c) * width_scale * user_width_scale));
}


#ifdef __STDC__
void
find_heights (CELLREF lo, CELLREF hi)
#else
void
find_heights (lo, hi)
CELLREF lo;
CELLREF hi;
#endif
{
h_find = find_rng (&hgts, lo, hi, sizeof (int));
}

#ifdef __STDC__
int
next_height (CELLREF *posp)
#else
int
next_height (posp)
CELLREF *posp;
#endif
{
int *ptr;

do
ptr = next_rng (h_find, posp);
while (ptr && !*ptr);
return ptr ? *ptr : 0;
}

#ifdef __STDC__
void
shift_heights (int dn, CELLREF lo, CELLREF hi)
#else
void
shift_heights (dn, lo, hi)
int dn;
CELLREF lo;
CELLREF hi;
#endif
{
do_shift (dn, lo, hi, &hgts, ROW_BUF);
}

#ifdef TEST
extern char *bname[];

extern void dbg_print_ref_fm ();
extern void dbg_print_ref_to ();
extern void dbg_print_formula ();

void
dbg_print_cell (cp)
CELL *cp;
{
char *ptr1, *ptr2;
char tmpbuf[30];

switch (GET_TYP (cp))
{
case 0:
ptr1 = "(null)";
ptr2 = "";
break;
case TYP_FLT:
sprintf (tmpbuf, "Float: %.16g", cp->cell_flt);
ptr1 = tmpbuf;
ptr2 = "";
break;
case TYP_INT:
sprintf (tmpbuf, "Int: %ld", cp->cell_int);
ptr1 = tmpbuf;
ptr2 = "";
break;
case TYP_ERR:
sprintf (tmpbuf, "Error: %d: ", cp->cell_err);
ptr1 = tmpbuf;
ptr2 = ename[cp->cell_err];
break;
case TYP_BOL:
sprintf (tmpbuf, "Bool: %d: ", cp->cell_bol);
ptr1 = tmpbuf;
ptr2 = bname[cp->cell_bol];
break;
case TYP_STR:
sprintf (tmpbuf, "String: %p: ", cp->cell_str);
ptr1 = tmpbuf;
ptr2 = cp->cell_str;
break;
default:
sprintf (tmpbuf, "Unknown: %d", GET_TYP (cp));
ptr1 = tmpbuf;
ptr2 = "";
break;
}
io_text_line (" Cell %p: flg %#lx fm %p to %p fa %p cy %d val %s%s",
cp, cp->cell_flags, cp->cell_refs_from, cp->cell_refs_to,
cp->cell_formula, cp->cell_cycle, ptr1, ptr2);
dbg_print_ref_fm (cp->cell_refs_from);
dbg_print_ref_to (cp->cell_refs_to);
dbg_print_formula (cp->cell_formula);
}


void
dbg_print_list (ptr, ele, txt, prsub)
struct list *ptr;
int ele;
char *txt;
void (*prsub) ();
{
CELLREF pos;

while (ptr)
{
io_text_line ("%s %p: lo %u hi %u nxt %p mem %p", txt, ptr, ptr->lo, ptr->hi, ptr->next, &(ptr->mem[0]));
pos = ptr->lo;
for (;;)
{
(*prsub) (ptr->mem + ele * (pos - ptr->lo));
if (pos == ptr->hi)
break;
pos++;
}
ptr = ptr->next;
}
}

static void
dbg_pr_row (p)
VOIDSTAR p;
{
io_text_line (" %p", p);
}

void
dbg_print_rows (pos)
CELLREF pos;
{
dbg_print_list (the_cols, sizeof (struct list *), "row", dbg_pr_row);
}

static void
dbg_pr_all (p)
VOIDSTAR p;
{
struct list **ptr;

io_text_line (" %p", p);
ptr = p;
dbg_print_list (*ptr, sizeof (struct cell), " col",
(void (*)(void *)) dbg_print_cell);
}

void
dbg_print_array ()
{
dbg_print_list (the_cols, sizeof (struct list *), "row", dbg_pr_all);
}

void
dbg_print_cols (pos)
CELLREF pos;
{
/* struct list **ptr;

ptr=find(...);
if(...); */
}

#endif

#ifdef TEST_ME
main ()
{
char buf[100];
static void *vec[10];
static siz[10];
char *ret;
int n;
int t;
int hi, lo;
CELLREF pos;
int z;


while (printf ("-->"), gets (buf))
{
n = buf[1] - '0';
switch (buf[0])
{
case 'i':
if (sscanf (&buf[2], "%d %d", &siz[n], &t) < 1)
{
printf ("No size?\n");
break;
}
vec[n] = list_init (siz[n], t);
printf ("vec %d init'd to %lx with siz %u and buf %d\n", n, vec[n], siz[n], t);
break;

case 'f':
ret = find (vec[n], atoi (&buf[2]));
if (ret)
{
printf ("Found at %lx ", ret);
for (t = 0; t < siz[n]; t++)
printf ("%x ", ret[t]);
printf ("\n");
}
else
printf ("Not found\n");
break;

case 'F':
if (sscanf (&buf[2], "%d %d", &lo, &hi) != 2)
{
printf ("Faild to scan\n");
break;
}
find_rng (vec[n], lo, hi);
while (ret = next_rng (&pos))
{
printf ("Found %u at %lx ", pos, ret);
for (t = 0; t < siz[n]; t++)
printf ("%x ", ret[t]);
printf ("\n");
}
break;

case 'm':
ret = make (vec[n], atoi (&buf[2]));
if (ret)
{
z = atoi (&buf[4]);
printf ("Made at %lx ", ret);
for (t = 0; t < siz[n]; t++)
{
printf ("%x(%x) ", ret[t], z);
ret[t] = z;
}
printf ("\n");
}
else
printf ("Failed!!\n");
break;

case 'M':
z = 0;
if (sscanf (&buf[2], "%d %d %d", &lo, &hi, &z) < 2)
{
printf ("Scan failed\n");
break;
}
make_rng (vec[n], lo, hi);
while (ret = next_rng (&pos))
{
printf ("Found %u at %lx ", pos, ret);
for (t = 0; t < siz[n]; t++)
{
printf ("%x(%x) ", ret[t], z);
ret[t] = z;
}
if (z)
z++;
printf ("\n");
}
break;

case 'q':
exit (0);

default:
printf ("Unknown command!\n");
}
}
}

#endif
oleo-1.3/io-term.c 644 722 0 62033 5356002776 12240 0ustar lordwheel/* Copyright (C) 1990, 1992, 1993 Free Software Foundation, Inc.

This file is part of Oleo, the GNU Spreadsheet.

Oleo 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, or (at your option)
any later version.

Oleo 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 Oleo; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */

#include
#include

#include "global.h"

#include "basic.h"
#include "cell.h"
#include "cmd.h"
#include "format.h"
#include "font.h"
#include "getopt.h"
#include "init.h"
#define DEFINE_IO_VARS 1
#include "io-abstract.h"
#include "io-curses.h"
#include "io-edit.h"
#include "io-generic.h"
#include "io-term.h"
#include "io-utils.h"
#include "io-x11.h"
#include "key.h"
#include "line.h"
#include "lists.h"
#define obstack_chunk_alloc ck_malloc
#define obstack_chunk_free free
#include "obstack.h"
#include "oleofile.h"
#include "print.h"
#include "ref.h"
#include "regions.h"
#include "window.h"
#include "funcs.h"
#include "graph.h"

#ifdef USE_DLD
/* If we're using dynamic linking, we get the names of the
functions to call by prepending the basename of save_name onto
_read_file
_write_file
_set_options
_show_options
so, if the file is sylk.o , the functions are named
sylk_read_file
sylk_write_file
sylk_set_options
sylk_show_options
*/
char *io_name;
#else
#include "list.h"
#include "sc.h"
#include "sylk.h"
#endif




/* This should be updated for every release.
* The file ANNOUNCE must be udpated as well.
*/
const char oleo_version_string[] = "Oleo version 1.3";

/* This variable is non-zero if the spreadsheet has been changed in any way */
int modified = 0;

/* User settable options */
int bkgrnd_recalc = 1;
int auto_recalc = 1;
int a0 = 0;
int topclear = 0;

/* This is how frequently the alarm should go off. */
unsigned int alarm_seconds = 1;

/* This is whether the alarm should go off at all. */
unsigned int alarm_active = 1;

/* Jump here on error. This simply restarts the top
* level command loop. User state should have been
* reset appropriately before the longjmp.
*/
jmp_buf error_exception;

char * current_filename = 0;

/* These are the hooks used to do file-io. */
#ifdef __STDC__
void (*read_file) (FILE *, int) = oleo_read_file;
void (*write_file) (FILE *, struct rng *) = oleo_write_file;
int (*set_file_opts) (int, char *) = oleo_set_options;
void (*show_file_opts) () = oleo_show_options;
#else
void (*read_file) () = oleo_read_file;
void (*write_file) () = oleo_write_file;
int (*set_file_opts) () = oleo_set_options;
void (*show_file_opts) () = oleo_show_options;
#endif

static char * disclaimer[] =
{
" Copyright (C) 1990, 1991, 1992, 1993 Free Software Foundation,Inc.\n",
"There is ABSOLUTELY NO WARRANTY for Oleo; see the file COPYING\n",
"for details. Oleo is free software and you are welcome to distribute\n",
"copies of it under certain conditions; see the file COPYING to see the\n",
"conditions.\n\n",
0
};

static char short_options[] = "Vqfh";
static struct option long_options[] =
{
{"version", 0, NULL, 'V'},
{"quiet", 0, NULL, 'q'},
{"ignore-init-file", 0, NULL, 'f'},
{"nw", 0, NULL, 'x'},
{"help", 0, NULL, 'h'},
{NULL, 0, NULL, 0}
};


static char * usage[] =
{
" [--version] [--quiet] [--ignore-init-file] [--nw] [--help] \n",
" [-Vqfh] [file]\n",
0
};

/* Avoid needless messages to stdout. */
int spread_quietly = 0;

/* Avoid using X no matter what else. (-x --no-x) */
int no_x = 0;

/* What kind of display? */
int using_x = 0;
int using_curses = 0;


/* Cell size paramaters. */
unsigned int default_width = 8;
unsigned int default_height = 1;

/* These values are used by clear_spreadsheet ()
* to restore the defaults.
*/
unsigned int saved_default_width = 8;
unsigned int saved_default_height = 1;

/* Other cell defaults: */
int default_jst = JST_LFT;
int default_fmt = FMT_GEN;
int default_lock = LCK_UNL;

/* Pointers to interesting cmd_func structures. */
struct cmd_func *end_macro_cmd;
struct cmd_func *digit_0_cmd;
struct cmd_func *digit_9_cmd;
struct cmd_func * break_cmd;
struct cmd_func * universal_arg_cmd;

/* A bland signal handler. */
#ifdef __STDC__
static RETSIGTYPE
got_sig (int sig)
#else
static RETSIGTYPE
got_sig (sig)
int sig;
#endif
{
}



/* An parser for the language grokked by option setting commands. */

#ifdef __STDC__
static int
do_set_option (char *ptr)
#else
static int
do_set_option (ptr)
char *ptr;
#endif
{
int set_opt = 1;

while (*ptr == ' ')
ptr++;
if (!strincmp ("no", ptr, 2))
{
ptr += 2;
set_opt = 0;
while (*ptr == ' ')
ptr++;
}
if (!stricmp ("auto", ptr))
{
auto_recalc = set_opt;
return 0;
}
if (!stricmp ("bkgrnd", ptr) || !stricmp ("background", ptr))
{
bkgrnd_recalc = set_opt;
return 0;
}
if (!stricmp ("a0", ptr))
{
a0 = set_opt;
io_repaint ();
return 0;
}
if (!stricmp ("backup", ptr))
{
__make_backups = set_opt;
return 0;
}
if (!stricmp ("bkup_copy", ptr))
{
__backup_by_copying = set_opt;
return 0;
}
if (set_opt && !strincmp ("ticks ", ptr, 6))
{
ptr += 6;
cell_timer_seconds = astol (&ptr);
return 0;
}
if (set_opt && !strincmp ("print ", ptr, 6))
{
ptr += 6;
print_width = astol (&ptr);
return 0;
}
if (set_opt && !strincmp ("file ", ptr, 5))
{
#ifdef USE_DLD
char *tmpstr;

ptr += 5;
tmpstr = ck_malloc (strlen (ptr) + 20);
if (io_name)
{
sprintf (tmpstr, "%s.o", ptr);
if (dld_unlink_by_file (tmpstr, 0))
{
io_error_msg ("Couldn't unlink old file format %s: %s", io_name, (dld_errno < 0 || dld_errno > dld_nerr) ? "Unknown error" : dld_errlst[dld_errno]);
goto bad_file;
}
free (io_name);
}
if (!stricmp (ptr, "panic"))
{
io_name = 0;
read_file = panic_read_file;
write_file = panic_write_file;
set_file_opts = panic_set_options;
show_file_opts = panic_show_options;
free (tmpstr);
return 0;
}
io_name = strdup (ptr);
sprintf (tmpstr, "%s.o", ptr);
if (dld_link (tmpstr))
{
io_error_msg ("Couldn't link new file format %s: %s", io_name, (dld_errno < 0 || dld_errno > dld_nerr) ? "Unknown error" : dld_errlst[dld_errno]);
goto bad_file;
}
if (dld_link ("libc.a"))
io_error_msg ("Couldn't link libc.a");
if (dld_link ("libm.a"))
io_error_msg ("Couldn't link libm.a");

sprintf (tmpstr, "%s_read_file", ptr);
read_file = dld_function_executable_p (tmpstr) ? dld_get_func (tmpstr) : 0;
sprintf (tmpstr, "%s_write_file", ptr);
write_file = dld_function_executable_p (tmpstr) ? dld_get_func (tmpstr) : 0;

sprintf (tmpstr, "%s_set_options", ptr);
set_file_opts = (int (*)()) (dld_function_executable_p (tmpstr) ? dld_get_func (tmpstr) : 0);
sprintf (tmpstr, "%s_show_options", ptr);
show_file_opts = dld_function_executable_p (tmpstr) ? dld_get_func (tmpstr) : 0;

if (!read_file
|| !write_file
|| !set_file_opts
|| !show_file_opts)
{
char **missing;
int n;

missing = dld_list_undefined_sym ();
io_text_start ();
io_text_line ("Undefined symbols in file format %s:", ptr);
io_text_line ("");
for (n = 0; n < dld_undefined_sym_count; n++)
io_text_line ("%s", missing[n]);
io_text_line ("");
io_text_finish ();
free (missing);
io_error_msg ("File format %s has undefined symbols: not loaded", ptr);
bad_file:
sprintf (tmpstr, "%s.o", io_name);
dld_unlink_by_file (io_name, 0);
if (io_name)
free (io_name);
io_name = 0;
read_file = panic_read_file;
write_file = panic_write_file;
set_file_opts = panic_set_options;
show_file_opts = panic_show_options;
}
free (tmpstr);
#else
ptr += 5;
if (!stricmp ("oleo", ptr))
{
read_file = oleo_read_file;
write_file = oleo_write_file;
set_file_opts = oleo_set_options;
show_file_opts = oleo_show_options;
}
else if (!stricmp ("sylk", ptr))
{
sylk_a0 = 1;
read_file = sylk_read_file;
write_file = sylk_write_file;
set_file_opts = sylk_set_options;
show_file_opts = sylk_show_options;
}
else if (!stricmp ("sylk-noa0", ptr))
{
sylk_a0 = 0;
read_file = sylk_read_file;
write_file = sylk_write_file;
set_file_opts = sylk_set_options;
show_file_opts = sylk_show_options;
}
else if (!stricmp ("sc", ptr))
{
read_file = sc_read_file;
write_file = sc_write_file;
set_file_opts = sc_set_options;
show_file_opts = sc_show_options;
}
else if (!stricmp ("panic", ptr))
{
read_file = panic_read_file;
write_file = panic_write_file;
set_file_opts = panic_set_options;
show_file_opts = panic_show_options;
}
else if (!stricmp ("list", ptr))
{
read_file = list_read_file;
write_file = list_write_file;
set_file_opts = list_set_options;
show_file_opts = list_show_options;
/*if (ptr[4])
{
ptr+=4;
sl_sep=string_to_char(&ptr);
} */
}
else
io_error_msg ("Unknown file format %s", ptr);
#endif
return 0;
}
#ifdef USE_DLD
else if (!strincmp (ptr, "load ", 5))
{
char *tmpstr;
struct function *new_funs;
struct cmd_func *new_cmds;
struct keymap **new_maps;
void (*init_cmd) ();

ptr += 5;
tmpstr = ck_malloc (strlen (ptr) + 20);
sprintf (tmpstr, "%s.o", ptr);
if (dld_link (tmpstr))
{
io_error_msg ("Couldn't link %s: %s", tmpstr, (dld_errno < 0 || dld_errno > dld_nerr) ? "Unknown error" : dld_errlst[dld_errno]);
free (tmpstr);
return 0;
}
if (dld_link ("libc.a"))
io_error_msg ("Couldn't link libc.a");
if (dld_link ("libm.a"))
io_error_msg ("Couldn't link libm.a");

if (dld_undefined_sym_count)
{
char **missing;
int n;

missing = dld_list_undefined_sym ();
io_text_start ();
io_text_line ("Undefined symbols in file format %s:", ptr);
io_text_line ("");
for (n = 0; n < dld_undefined_sym_count; n++)
io_text_line ("%s", missing[n]);
io_text_line ("");
io_text_finish ();
free (missing);
io_error_msg ("%d undefined symbols in %s", dld_undefined_sym_count, ptr);
dld_unlink_by_file (tmpstr, 0);
free (tmpstr);
return 0;
}
sprintf (tmpstr, "%s_funs", ptr);
new_funs = (struct function *) dld_get_symbol (tmpstr);
if (new_funs)
add_usr_funs (new_funs);
sprintf (tmpstr, "%s_cmds", ptr);
new_cmds = (struct cmd_func *) dld_get_symbol (tmpstr);
if (new_cmds)
add_usr_cmds (new_cmds);
sprintf (tmpstr, "%s_maps", ptr);
new_maps = (struct keymap **) dld_get_symbol (tmpstr);
if (new_maps)
add_usr_maps (new_maps);
if (!new_funs && !new_cmds && !new_maps)
{
io_error_msg ("Couldn't find anything to load in %s", ptr);
sprintf (tmpstr, "%s.o", ptr);
dld_unlink_by_file (tmpstr, 0);
}
sprintf (tmpstr, "%s_init", ptr);
init_cmd = dld_function_executable_p (tmpstr) ? dld_get_func (tmpstr) : 0;
if (init_cmd)
(*init_cmd) ();
free (tmpstr);
return 0;
}
#endif
if (set_window_option (set_opt, ptr) == 0)
{
if ((*set_file_opts) (set_opt, ptr))
io_error_msg ("Unknown option '%s'", ptr);
return 0;
}
return 1;
}

#ifdef __STDC__
void
set_options (char * ptr)
#else
void
set_options (ptr)
char *ptr;
#endif
{
if (do_set_option (ptr))
io_recenter_cur_win ();
}

#ifdef __STDC__
void
show_options (void)
#else
void
show_options ()
#endif
{
int n;
int fmts;
char *data_buf[9];

n = auto_recalc;
io_text_start ();

io_text_line ("auto-recalculation: %s Recalculate in background: %s",
n ? " on" : "off", bkgrnd_recalc ? "on" : "off");
io_text_line ("make backup files: %s Copy files into backups: %s",
__make_backups ? " on" : "off", __backup_by_copying ? "on" : "off");

io_text_line ("Asynchronous updates every %u ???",
cell_timer_seconds);

io_text_line ("Print width: %5u", print_width);

io_text_line ("");

(*show_file_opts) ();

io_text_line ("");
show_window_options ();
io_text_line ("");

fmts = usr_set_fmts ();
if (fmts)
{
io_text_line ("User-defined formats:");
io_text_line ("Fmt +Hdr -Hdr +Trlr -Trlr Zero Comma Decimal Prec Scale");
for (n = 0; n < 16; n++)
{
if (fmts & (1 << n))
{
get_usr_stats (n, data_buf);
io_text_line ("%3d %7s %7s %7s %7s %7s %7s %7s %5s %13s",
n + 1,
data_buf[0],
data_buf[1],
data_buf[2],
data_buf[3],
data_buf[4],
data_buf[5],
data_buf[6],
data_buf[7],
data_buf[8]);
}
}
}
else
io_text_line ("No user-defined formats have been defined");

io_text_finish ();
}


#ifdef __STDC__
void
read_mp_usr_fmt (char *ptr)
#else
void
read_mp_usr_fmt (ptr)
char *ptr;
#endif
{
int usr_n = -1;
int n_chrs = 0;
char *p;
char *buf[9];
int i;

for (i = 0; i < 9; i++)
buf[i] = "";
p = ptr;
while (*p == ';')
{
*p++ = '\0';
switch (*p++)
{
case 'N':
usr_n = astol (&p) - 1;
break;
case 'H':
switch (*p++)
{
case 'P':
i = 0;
break;
case 'N':
i = 1;
break;
default:
goto badline;
}
goto count_chars;
case 'T':
switch (*p++)
{
case 'P':
i = 2;
break;
case 'N':
i = 3;
break;
default:
goto badline;
}
goto count_chars;

case 'Z':
i = 4;
goto count_chars;

case 'C':
i = 5;
goto count_chars;

case 'D':
i = 6;
goto count_chars;

case 'P':
i = 7;
goto count_chars;

case 'S':
i = 8;
goto count_chars;

count_chars:
buf[i] = p;
n_chrs++;
while (*p && *p != ';')
{
p++;
n_chrs++;
}
break;

default:
badline:
io_error_msg ("Unknown OLEO line %s", ptr);
return;
}
}
if (*p || usr_n < 0 || usr_n > 15)
goto badline;

set_usr_stats (usr_n, buf);
}

/* Modify this to write out *all* the options */
#ifdef __STDC__
void
write_mp_options (FILE *fp)
#else
void
write_mp_options (fp)
FILE *fp;
#endif
{
fprintf (fp, "O;%sauto;%sbackground;%sa0;ticks %d\n",
auto_recalc ? "" : "no",
bkgrnd_recalc ? "" : "no",
a0 ? "" : "no",
cell_timer_seconds);
}

#ifdef __STDC__
void
read_mp_options (char *str)
#else
void
read_mp_options (str)
char *str;
#endif
{
char *np;

while (np = (char *)index (str, ';'))
{
*np = '\0';
do_set_option (str);
*np++ = ';';
str = np;
}
if (np = (char *)rindex (str, '\n'))
*np = '\0';
(void) do_set_option (str);
}




/* Commands related to variables. */

#ifdef __STDC__
void
set_var (char * var, char * val)
#else
void
set_var (var, val)
char * var;
char * val;
#endif
{
char *ret;
if (val)
{
while (isspace (*val))
++val;
if (!*val)
val = 0;
}
modified = 1;
ret = new_var_value (var, strlen(var), val);
if (ret)
io_error_msg ("Can't set-variable %s: %s\n", var, ret);
}

#ifdef __STDC__
void
show_var (char *ptr)
#else
void
show_var (ptr)
char *ptr;
#endif
{
struct var *v;
int num;

while (*ptr == ' ')
ptr++;
for (num = 0; ptr[num] && ptr[num] != ' '; num++)
;

v = find_var (ptr, num);
if (!v || v->var_flags == VAR_UNDEF)
{
io_error_msg ("There is no '%s'", ptr);
return;
}
if (a0)
{
if (v->v_rng.lr != v->v_rng.hr || v->v_rng.lc != v->v_rng.hc)
/* FOO */ sprintf (print_buf, "%s $%s$%u:$%s$%u", v->var_name, col_to_str (v->v_rng.lc), v->v_rng.lr, col_to_str (v->v_rng.hc), v->v_rng.hr);
else
/* FOO */ sprintf (print_buf, "%s $%s$%u", v->var_name, col_to_str (v->v_rng.lc), v->v_rng.lr);
}
else
sprintf (print_buf, "%s %s", v->var_name, range_name (&(v->v_rng)));
io_info_msg (print_buf);
}

#ifdef __STDC__
static void
show_a_var (char *name, struct var *v)
#else
static void
show_a_var (name, v)
char *name;
struct var *v;
#endif
{
if (v->var_flags == VAR_UNDEF)
return;
if (a0)
{
if (v->v_rng.lr != v->v_rng.hr || v->v_rng.lc != v->v_rng.hc)
/* FOO */ io_text_line ("%-20s $%s$%u:$%s$%u", v->var_name, col_to_str (v->v_rng.lc), v->v_rng.lr, col_to_str (v->v_rng.hc), v->v_rng.hr);
else
/* FOO */ io_text_line ("%-20s $%s$%u", v->var_name, col_to_str (v->v_rng.lc), v->v_rng.lr);
}
else
io_text_line ("%-20s %s", v->var_name, range_name (&(v->v_rng)));
}

#ifdef __STDC__
void
show_all_var (void)
#else
void
show_all_var ()
#endif
{
io_text_start ();
io_text_line ("%-20s Current Value", "Variable Name");
for_all_vars (show_a_var);
io_text_finish ();
}

static FILE * write_variable_fp = 0;

#ifdef __STDC__
static void
write_a_var (char *name, struct var *v)
#else
static void
write_a_var (name, v)
char *name;
struct var *v;
#endif
{
CELLREF r, c;
if (v->var_flags == VAR_UNDEF)
return;
r = v->v_rng.lr;
c = v->v_rng.lc;
if (v->var_flags == VAR_CELL)
fprintf (write_variable_fp, "%s=%s\n",
v->var_name, cell_value_string (r, c));
}

#ifdef __STDC__
void
write_variables (FILE * fp)
#else
void
write_variables (fp)
FILE * fp;
#endif
{
if (write_variable_fp)
io_error_msg ("Can't re-enter write_variables.");
else
{
write_variable_fp = fp;
for_all_vars (write_a_var);
write_variable_fp = 0;
}
}

#ifdef __STDC__
void
read_variables (FILE * fp)
#else
void
read_variables (fp)
FILE * fp;
#endif
{
char buf[1024];
int lineno = 0;
while (fgets (buf, 1024, fp))
{
char * ptr;
for (ptr = buf; *ptr && *ptr != '\n'; ++ptr)
;
*ptr = '\0';
for (ptr = buf; isspace (*ptr); ptr++)
;
if (!*ptr || (*ptr == '#'))
continue;
{
char * var_name = ptr;
int var_name_len;
char * value_string;
while (*ptr && *ptr != '=')
++ptr;
if (!*ptr)
{
io_error_msg ("read-variables: format error near line %d.", lineno);
return;
}
var_name_len = ptr - var_name;
++ptr;
value_string = ptr;
{
struct var * var = find_var (var_name, var_name_len);
if (var)
{
switch (var->var_flags)
{
case VAR_UNDEF:
break;
case VAR_CELL:
{
char * error = new_value (var->v_rng.lr, var->v_rng.lc,
value_string);
if (error)
{
io_error_msg (error);
return; /* actually, io_error_msg never returns. */
}
else
modified = 1;
break;
}
case VAR_RANGE:
io_error_msg ("read-variables (line %d): ranges not supported.",
lineno);
return;
}
}
}
}
++lineno;
}
if (!feof (fp))
{
io_error_msg ("read-variables: read error near line %d.", lineno);
return;
}
}



#ifdef __STDC__
void
init_maps (void)
#else
void
init_maps ()
#endif
{
num_maps = 0;
the_maps = 0;
map_names = 0;
map_prompts = 0;

the_funcs = ck_malloc (sizeof (struct cmd_func *) * 2);
num_funcs = 1;
the_funcs[0] = &cmd_funcs[0];

find_func (0, &end_macro_cmd, "end-macro");
find_func (0, &digit_0_cmd, "digit-0");
find_func (0, &digit_9_cmd, "digit-9");
find_func (0, &break_cmd, "break");
find_func (0, &universal_arg_cmd, "universal-argument");

create_keymap ("universal", 0);
push_command_frame (0, 0, 0);
}

#ifdef __STDC__
int
add_usr_cmds (struct cmd_func *new_cmds)
#else
int
add_usr_cmds (new_cmds)
struct cmd_func *new_cmds;
#endif
{
num_funcs++;
the_funcs = ck_realloc (the_funcs, num_funcs * sizeof (struct cmd_func *));
the_funcs[num_funcs - 1] = new_cmds;
return num_funcs - 1;
}

#ifdef USE_DLD
#ifdef __STDC__
static int
add_usr_maps (struct keymap **new_maps)
#else
static int
add_usr_maps (new_maps)
struct keymap **new_maps;
#endif
{
int n;

for (n = 1; new_maps[n]; n++)
;
the_maps = ck_realloc (the_maps, (n + num_maps) * sizeof (struct keymap *));
bcopy (new_maps, &the_maps[num_maps], n * sizeof (struct keymap *));
num_maps += n;
return num_maps - n;
}
#endif /* USE_DLD */

#ifdef __STDC__
static void
show_usage (void)
#else
static void
show_usage ()
#endif
{
char ** use = usage;
fprintf (stderr, "Usage: %s ", argv_name);
while (*use)
{
fprintf (stderr, "%s\n", *use);
++use;
}
}

#ifdef __STDC__
static RETSIGTYPE
continue_oleo (int sig)
#else
static RETSIGTYPE
continue_oleo (sig)
int sig;
#endif
{
io_repaint ();
if (using_curses)
cont_curses ();
}

int display_opened = 0;

extern int sneaky_linec;

#ifdef __STDC__
int
main (int argc, char **argv)
#else
int
main (argc, argv)
int argc;
char **argv;
#endif
{
volatile int ignore_init_file = 0;
FILE * init_fp[2];
char * init_file_names[2];
volatile int init_fpc = 0;

argv_name = argv[0];
__make_backups = 1;

/* Set up the minimal io handler. */
#if 0
cmd_graphics ();
#endif

{
int opt;
for (opt = getopt_long (argc, argv, short_options, long_options, (int *)0);
opt != EOF;
opt = getopt_long (argc, argv, short_options, long_options, (int *)0))
{
switch (opt)
{
case 'V':
fprintf (stdout, "%s\n", oleo_version_string);
break;
case 'q':
spread_quietly = 1;
break;
case 'f':
ignore_init_file = 1;
break;
case 'x':
no_x = 1;
break;
case 'h':
show_usage ();
break;
}
}
}
init_infinity ();
init_mem ();
init_eval ();
init_refs ();
init_cells ();
init_fonts ();
init_info ();

#ifdef USE_DLD
if (!index (argv_name, '/'))
{
char *name;

name = dld_find_executable (argv_name);
num = dld_init (name);
free (name);
}
else
num = dld_init (argv_name);
if (num)
io_error_msg ("dld_init() failed: %s", (dld_errno < 0 || dld_errno > dld_nerr) ? "Unknown error" : dld_errlst[dld_errno]);
dld_search_path = ":/usr/local/lib/oleo:/lib:/usr/lib:/usr/local/lib";
#endif



/* Find the init files.
* This is done even if ignore_init_file is true because
* it effects whether the disclaimer will be shown.
*/
{
char *ptr, *home;

home = getenv ("HOME");
if (home)
{
ptr = mk_sprintf ("%s/%s", home, RCFILE);
init_fp[init_fpc] = fopen (ptr, "r");
init_file_names[init_fpc] = ptr;
if (init_fp[init_fpc])
++init_fpc;
}

init_fp[init_fpc] = fopen (RCFILE, "r");
if (init_fp[init_fpc])
++init_fpc;
}

if (!init_fpc && !spread_quietly)
{
char ** msg;
fputs (oleo_version_string, stdout);
for (msg = disclaimer; *msg; ++msg)
fputs (*msg, stdout);
fflush (stdout);
}

FD_ZERO (&read_fd_set);
FD_ZERO (&read_pending_fd_set);
FD_ZERO (&exception_fd_set);
FD_ZERO (&exception_pending_fd_set);

#ifdef HAVE_X11_X_H
if (!no_x)
get_x11_args (&argc, argv);
if (!no_x && io_x11_display_name)
{
x11_graphics ();
using_x = 1;
}
else
#endif
{
tty_graphics ();
using_curses = 1;
/* Allow the disclaimer to be read. */
if (!init_fpc && !spread_quietly)
sleep (5);
}

io_open_display ();

init_graphing ();

if (setjmp (error_exception))
{
fprintf (stderr, "Error in the builtin init scripts (a bug!).");
exit (69);
}
else
{
init_maps ();
init_named_macro_strings ();
run_init_cmds ();
}

if (argc - optind > 1)
{
show_usage ();
exit (1);
}

/* These probably don't all need to be ifdef, but
* it is harmless.
*/
#ifdef SIGCONT
signal (SIGCONT, continue_oleo);
#endif
#ifdef SIGINT
signal (SIGINT, got_sig);
#endif
#ifdef SIGQUIT
signal (SIGQUIT, got_sig);
#endif
#ifdef SIGILL
signal (SIGILL, got_sig);
#endif
#ifdef SIGEMT
signal (SIGEMT, got_sig);
#endif
#ifdef SIGBUS
signal (SIGBUS, got_sig);
#endif
#ifdef SIGSEGV
signal (SIGSEGV, got_sig);
#endif
#ifdef SIGPIPE
signal (SIGPIPE, got_sig);
#endif

/* Read the init file. */
{
volatile int x;
for (x = 0; x < init_fpc; ++x)
{
if (setjmp (error_exception))
{
fprintf (stderr, " error occured in init file %s near line %d.",
init_file_names [x], sneaky_linec);
}
else
if (!ignore_init_file)
read_cmds_cmd (init_fp[x]);
fclose (init_fp[x]);
}
}


if (argc - optind == 1)
{
FILE * fp;
/* fixme: record file name */
++optind;
if (fp = fopen (argv[1], "r"))
{
if (setjmp (error_exception))
fprintf (stderr, " error occured reading %s", argv[1]);
else
read_file_and_run_hooks (fp, 0, argv[1]);
fclose (fp);
}
else
fprintf (stderr, "Can't open %s: %s", argv[1], err_msg ());
}
/* Force the command frame to be rebuilt now that the keymaps exist. */
{
struct command_frame * last_of_the_old = the_cmd_frame->next;
while (the_cmd_frame != last_of_the_old)
free_cmd_frame (the_cmd_frame);
free_cmd_frame (last_of_the_old);
}
io_recenter_cur_win ();

display_opened = 1;

run_string_as_macro
("{with-keymap press-any}{builtin-help _NON_WARRANTY_", 1);
while (1)
{
setjmp (error_exception);
command_loop (0);
}
}


oleo-1.3/getopt.c 644 722 0 45651 5355700422 12165 0ustar lordwheel/* Getopt for GNU.
NOTE: getopt is now part of the C library, so if you don't know what
"Keep this file name-space clean" means, talk to [email protected]
before changing it!

Copyright (C) 1987, 88, 89, 90, 91, 1992 Free Software Foundation, Inc.

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, 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, 675 Mass Ave, Cambridge, MA 02139, USA. */

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

/* AIX requires this to be the first thing in the file. */
#ifdef __GNUC__
#define alloca __builtin_alloca
#else /* not __GNUC__ */
#if defined (HAVE_ALLOCA_H) || (defined(sparc) && (defined(sun) || (!defined(USG) && !defined(SVR4) && !defined(__svr4__))))
#include
#else
#ifdef _AIX
#pragma alloca
#else
char *alloca ();
#endif
#endif /* alloca.h */
#endif /* not __GNUC__ */

#if !__STDC__ && !defined(const)
#define const
#endif

#include

/* This needs to come after some library #include
to get __GNU_LIBRARY__ defined. */
#ifdef __GNU_LIBRARY__
#undef alloca
/* Don't include stdlib.h for non-GNU C libraries because some of them
contain conflicting prototypes for getopt. */
#include
#else /* Not GNU C library. */
#define __alloca alloca
#endif /* GNU C library. */

/* If GETOPT_COMPAT is defined, `+' as well as `--' can introduce a
long-named option. Because this is not POSIX.2 compliant, it is
being phased out. */
/* #define GETOPT_COMPAT */

/* This version of `getopt' appears to the caller like standard Unix `getopt'
but it behaves differently for the user, since it allows the user
to intersperse the options with the other arguments.

As `getopt' works, it permutes the elements of ARGV so that,
when it is done, all the options precede everything else. Thus
all application programs are extended to handle flexible argument order.

Setting the environment variable POSIXLY_CORRECT disables permutation.
Then the behavior is completely standard.

GNU application programs can use a third alternative mode in which
they can distinguish the relative order of options and other arguments. */

#include "getopt.h"

/* For communication from `getopt' to the caller.
When `getopt' finds an option that takes an argument,
the argument value is returned here.
Also, when `ordering' is RETURN_IN_ORDER,
each non-option ARGV-element is returned here. */

char *optarg = 0;

/* Index in ARGV of the next element to be scanned.
This is used for communication to and from the caller
and for communication between successive calls to `getopt'.

On entry to `getopt', zero means this is the first call; initialize.

When `getopt' returns EOF, this is the index of the first of the
non-option elements that the caller should itself scan.

Otherwise, `optind' communicates from one call to the next
how much of ARGV has been scanned so far. */

int optind = 0;

/* The next char to be scanned in the option-element
in which the last option character we returned was found.
This allows us to pick up the scan where we left off.

If this is zero, or a null string, it means resume the scan
by advancing to the next ARGV-element. */

static char *nextchar;

/* Callers store zero here to inhibit the error message
for unrecognized options. */

int opterr = 1;

/* Describe how to deal with options that follow non-option ARGV-elements.

If the caller did not specify anything,
the default is REQUIRE_ORDER if the environment variable
POSIXLY_CORRECT is defined, PERMUTE otherwise.

REQUIRE_ORDER means don't recognize them as options;
stop option processing when the first non-option is seen.
This is what Unix does.
This mode of operation is selected by either setting the environment
variable POSIXLY_CORRECT, or using `+' as the first character
of the list of option characters.

PERMUTE is the default. We permute the contents of ARGV as we scan,
so that eventually all the non-options are at the end. This allows options
to be given in any order, even with programs that were not written to
expect this.

RETURN_IN_ORDER is an option available to programs that were written
to expect options and other ARGV-elements in any order and that care about
the ordering of the two. We describe each non-option ARGV-element
as if it were the argument of an option with character code 1.
Using `-' as the first character of the list of option characters
selects this mode of operation.

The special argument `--' forces an end of option-scanning regardless
of the value of `ordering'. In the case of RETURN_IN_ORDER, only
`--' can cause `getopt' to return EOF with `optind' != ARGC. */

static enum
{
REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER
} ordering;

#ifdef __GNU_LIBRARY__
/* We want to avoid inclusion of string.h with non-GNU libraries
because there are many ways it can cause trouble.
On some systems, it contains special magic macros that don't work
in GCC. */
#include
#define my_index strchr
#define my_bcopy(src, dst, n) memcpy ((dst), (src), (n))
#else

/* Avoid depending on library functions or files
whose names are inconsistent. */

char *getenv ();

static char *
my_index (string, chr)
char *string;
int chr;
{
while (*string)
{
if (*string == chr)
return string;
string++;
}
return 0;
}

static void
my_bcopy (from, to, size)
char *from, *to;
int size;
{
int i;
for (i = 0; i < size; i++)
to[i] = from[i];
}
#endif /* GNU C library. */

/* Handle permutation of arguments. */

/* Describe the part of ARGV that contains non-options that have
been skipped. `first_nonopt' is the index in ARGV of the first of them;
`last_nonopt' is the index after the last of them. */

static int first_nonopt;
static int last_nonopt;

/* Exchange two adjacent subsequences of ARGV.
One subsequence is elements [first_nonopt,last_nonopt)
which contains all the non-options that have been skipped so far.
The other is elements [last_nonopt,optind), which contains all
the options processed since those non-options were skipped.

`first_nonopt' and `last_nonopt' are relocated so that they describe
the new indices of the non-options in ARGV after they are moved. */

static void
exchange (argv)
char **argv;
{
int nonopts_size = (last_nonopt - first_nonopt) * sizeof (char *);
char **temp = (char **) __alloca (nonopts_size);

/* Interchange the two blocks of data in ARGV. */

my_bcopy ((char *) &argv[first_nonopt], (char *) temp, nonopts_size);
my_bcopy ((char *) &argv[last_nonopt], (char *) &argv[first_nonopt],
(optind - last_nonopt) * sizeof (char *));
my_bcopy ((char *) temp,
(char *) &argv[first_nonopt + optind - last_nonopt],
nonopts_size);

/* Update records for the slots the non-options now occupy. */

first_nonopt += (optind - last_nonopt);
last_nonopt = optind;
}

/* Scan elements of ARGV (whose length is ARGC) for option characters
given in OPTSTRING.

If an element of ARGV starts with '-', and is not exactly "-" or "--",
then it is an option element. The characters of this element
(aside from the initial '-') are option characters. If `getopt'
is called repeatedly, it returns successively each of the option characters
from each of the option elements.

If `getopt' finds another option character, it returns that character,
updating `optind' and `nextchar' so that the next call to `getopt' can
resume the scan with the following option character or ARGV-element.

If there are no more option characters, `getopt' returns `EOF'.
Then `optind' is the index in ARGV of the first ARGV-element
that is not an option. (The ARGV-elements have been permuted
so that those that are not options now come last.)

OPTSTRING is a string containing the legitimate option characters.
If an option character is seen that is not listed in OPTSTRING,
return '?' after printing an error message. If you set `opterr' to
zero, the error message is suppressed but we still return '?'.

If a char in OPTSTRING is followed by a colon, that means it wants an arg,
so the following text in the same ARGV-element, or the text of the following
ARGV-element, is returned in `optarg'. Two colons mean an option that
wants an optional arg; if there is text in the current ARGV-element,
it is returned in `optarg', otherwise `optarg' is set to zero.

If OPTSTRING starts with `-' or `+', it requests different methods of
handling the non-option ARGV-elements.
See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above.

Long-named options begin with `--' instead of `-'.
Their names may be abbreviated as long as the abbreviation is unique
or is an exact match for some defined option. If they have an
argument, it follows the option name in the same ARGV-element, separated
from the option name by a `=', or else the in next ARGV-element.
When `getopt' finds a long-named option, it returns 0 if that option's
`flag' field is nonzero, the value of the option's `val' field
if the `flag' field is zero.

The elements of ARGV aren't really const, because we permute them.
But we pretend they're const in the prototype to be compatible
with other systems.

LONGOPTS is a vector of `struct option' terminated by an
element containing a name which is zero.

LONGIND returns the index in LONGOPT of the long-named option found.
It is only valid when a long-named option has been found by the most
recent call.

If LONG_ONLY is nonzero, '-' as well as '--' can introduce
long-named options. */

int
_getopt_internal (argc, argv, optstring, longopts, longind, long_only)
int argc;
char *const *argv;
const char *optstring;
const struct option *longopts;
int *longind;
int long_only;
{
int option_index;

optarg = 0;

/* Initialize the internal data when the first call is made.
Start processing options with ARGV-element 1 (since ARGV-element 0
is the program name); the sequence of previously skipped
non-option ARGV-elements is empty. */

if (optind == 0)
{
first_nonopt = last_nonopt = optind = 1;

nextchar = NULL;

/* Determine how to handle the ordering of options and nonoptions. */

if (optstring[0] == '-')
{
ordering = RETURN_IN_ORDER;
++optstring;
}
else if (optstring[0] == '+')
{
ordering = REQUIRE_ORDER;
++optstring;
}
else if (getenv ("POSIXLY_CORRECT") != NULL)
ordering = REQUIRE_ORDER;
else
ordering = PERMUTE;
}

if (nextchar == NULL || *nextchar == '\0')
{
if (ordering == PERMUTE)
{
/* If we have just processed some options following some non-options,
exchange them so that the options come first. */

if (first_nonopt != last_nonopt && last_nonopt != optind)
exchange ((char **) argv);
else if (last_nonopt != optind)
first_nonopt = optind;

/* Now skip any additional non-options
and extend the range of non-options previously skipped. */

while (optind < argc
&& (argv[optind][0] != '-' || argv[optind][1] == '\0')
#ifdef GETOPT_COMPAT
&& (longopts == NULL
|| argv[optind][0] != '+' || argv[optind][1] == '\0')
#endif /* GETOPT_COMPAT */
)
optind++;
last_nonopt = optind;
}

/* Special ARGV-element `--' means premature end of options.
Skip it like a null option,
then exchange with previous non-options as if it were an option,
then skip everything else like a non-option. */

if (optind != argc && !strcmp (argv[optind], "--"))
{
optind++;

if (first_nonopt != last_nonopt && last_nonopt != optind)
exchange ((char **) argv);
else if (first_nonopt == last_nonopt)
first_nonopt = optind;
last_nonopt = argc;

optind = argc;
}

/* If we have done all the ARGV-elements, stop the scan
and back over any non-options that we skipped and permuted. */

if (optind == argc)
{
/* Set the next-arg-index to point at the non-options
that we previously skipped, so the caller will digest them. */
if (first_nonopt != last_nonopt)
optind = first_nonopt;
return EOF;
}

/* If we have come to a non-option and did not permute it,
either stop the scan or describe it to the caller and pass it by. */

if ((argv[optind][0] != '-' || argv[optind][1] == '\0')
#ifdef GETOPT_COMPAT
&& (longopts == NULL
|| argv[optind][0] != '+' || argv[optind][1] == '\0')
#endif /* GETOPT_COMPAT */
)
{
if (ordering == REQUIRE_ORDER)
return EOF;
optarg = argv[optind++];
return 1;
}

/* We have found another option-ARGV-element.
Start decoding its characters. */

nextchar = (argv[optind] + 1
+ (longopts != NULL && argv[optind][1] == '-'));
}

if (longopts != NULL
&& ((argv[optind][0] == '-'
&& (argv[optind][1] == '-' || long_only))
#ifdef GETOPT_COMPAT
|| argv[optind][0] == '+'
#endif /* GETOPT_COMPAT */
))
{
const struct option *p;
char *s = nextchar;
int exact = 0;
int ambig = 0;
const struct option *pfound = NULL;
int indfound = 0;

while (*s && *s != '=')
s++;

/* Test all options for either exact match or abbreviated matches. */
for (p = longopts, option_index = 0; p->name;
p++, option_index++)
if (!strncmp (p->name, nextchar, s - nextchar))
{
if (s - nextchar == strlen (p->name))
{
/* Exact match found. */
pfound = p;
indfound = option_index;
exact = 1;
break;
}
else if (pfound == NULL)
{
/* First nonexact match found. */
pfound = p;
indfound = option_index;
}
else
/* Second nonexact match found. */
ambig = 1;
}

if (ambig && !exact)
{
if (opterr)
fprintf (stderr, "%s: option `%s' is ambiguous\n",
argv[0], argv[optind]);
nextchar += strlen (nextchar);
optind++;
return '?';
}

if (pfound != NULL)
{
option_index = indfound;
optind++;
if (*s)
{
/* Don't test has_arg with >, because some C compilers don't
allow it to be used on enums. */
if (pfound->has_arg)
optarg = s + 1;
else
{
if (opterr)
{
if (argv[optind - 1][1] == '-')
/* --option */
fprintf (stderr,
"%s: option `--%s' doesn't allow an argument\n",
argv[0], pfound->name);
else
/* +option or -option */
fprintf (stderr,
"%s: option `%c%s' doesn't allow an argument\n",
argv[0], argv[optind - 1][0], pfound->name);
}
nextchar += strlen (nextchar);
return '?';
}
}
else if (pfound->has_arg == 1)
{
if (optind < argc)
optarg = argv[optind++];
else
{
if (opterr)
fprintf (stderr, "%s: option `%s' requires an argument\n",
argv[0], argv[optind - 1]);
nextchar += strlen (nextchar);
return '?';
}
}
nextchar += strlen (nextchar);
if (longind != NULL)
*longind = option_index;
if (pfound->flag)
{
*(pfound->flag) = pfound->val;
return 0;
}
return pfound->val;
}
/* Can't find it as a long option. If this is not getopt_long_only,
or the option starts with '--' or is not a valid short
option, then it's an error.
Otherwise interpret it as a short option. */
if (!long_only || argv[optind][1] == '-'
#ifdef GETOPT_COMPAT
|| argv[optind][0] == '+'
#endif /* GETOPT_COMPAT */
|| my_index (optstring, *nextchar) == NULL)
{
if (opterr)
{
if (argv[optind][1] == '-')
/* --option */
fprintf (stderr, "%s: unrecognized option `--%s'\n",
argv[0], nextchar);
else
/* +option or -option */
fprintf (stderr, "%s: unrecognized option `%c%s'\n",
argv[0], argv[optind][0], nextchar);
}
nextchar = (char *) "";
optind++;
return '?';
}
}

/* Look at and handle the next option-character. */

{
char c = *nextchar++;
char *temp = my_index (optstring, c);

/* Increment `optind' when we start to process its last character. */
if (*nextchar == '\0')
++optind;

if (temp == NULL || c == ':')
{
if (opterr)
{
if (c < 040 || c >= 0177)
fprintf (stderr, "%s: unrecognized option, character code 0%o\n",
argv[0], c);
else
fprintf (stderr, "%s: unrecognized option `-%c'\n", argv[0], c);
}
return '?';
}
if (temp[1] == ':')
{
if (temp[2] == ':')
{
/* This is an option that accepts an argument optionally. */
if (*nextchar != '\0')
{
optarg = nextchar;
optind++;
}
else
optarg = 0;
nextchar = NULL;
}
else
{
/* This is an option that requires an argument. */
if (*nextchar != '\0')
{
optarg = nextchar;
/* If we end this ARGV-element by taking the rest as an arg,
we must advance to the next element now. */
optind++;
}
else if (optind == argc)
{
if (opterr)
fprintf (stderr, "%s: option `-%c' requires an argument\n",
argv[0], c);
c = '?';
}
else
/* We already incremented `optind' once;
increment it again when taking next ARGV-elt as argument. */
optarg = argv[optind++];
nextchar = NULL;
}
}
return c;
}
}

int
getopt (argc, argv, optstring)
int argc;
char *const *argv;
const char *optstring;
{
return _getopt_internal (argc, argv, optstring,
(const struct option *) 0,
(int *) 0,
0);
}

#ifdef TEST

/* Compile with -DTEST to make an executable for use in testing
the above definition of `getopt'. */

int
main (argc, argv)
int argc;
char **argv;
{
int c;
int digit_optind = 0;

while (1)
{
int this_option_optind = optind ? optind : 1;

c = getopt (argc, argv, "abc:d:0123456789");
if (c == EOF)
break;

switch (c)
{
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
if (digit_optind != 0 && digit_optind != this_option_optind)
printf ("digits occur in two different argv-elements.\n");
digit_optind = this_option_optind;
printf ("option %c\n", c);
break;

case 'a':
printf ("option a\n");
break;

case 'b':
printf ("option b\n");
break;

case 'c':
printf ("option c with value `%s'\n", optarg);
break;

case '?':
break;

default:
printf ("?? getopt returned character code 0%o ??\n", c);
}
}

if (optind < argc)
{
printf ("non-option ARGV-elements: ");
while (optind < argc)
printf ("%s ", argv[optind++]);
printf ("\n");
}

exit (0);
}

#endif /* TEST */
oleo-1.3/getopt1.c 644 722 0 6624 5322361710 12220 0ustar lordwheel/* Getopt for GNU.
Copyright (C) 1987, 88, 89, 90, 91, 1992 Free Software Foundation, Inc.

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, 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, 675 Mass Ave, Cambridge, MA 02139, USA. */

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include "getopt.h"

#if !__STDC__ && !defined(const)
#define const
#endif

#include

/* This needs to come after some library #include
to get __GNU_LIBRARY__ defined. */
#ifdef __GNU_LIBRARY__
#include
#else
char *getenv ();
#endif

#ifndef NULL
#define NULL 0
#endif

int
getopt_long (argc, argv, options, long_options, opt_index)
int argc;
char *const *argv;
const char *options;
const struct option *long_options;
int *opt_index;
{
return _getopt_internal (argc, argv, options, long_options, opt_index, 0);
}

/* Like getopt_long, but '-' as well as '--' can indicate a long option.
If an option that starts with '-' (not '--') doesn't match a long option,
but does match a short option, it is parsed as a short option
instead. */

int
getopt_long_only (argc, argv, options, long_options, opt_index)
int argc;
char *const *argv;
const char *options;
const struct option *long_options;
int *opt_index;
{
return _getopt_internal (argc, argv, options, long_options, opt_index, 1);
}

#ifdef TEST

#include

int
main (argc, argv)
int argc;
char **argv;
{
int c;
int digit_optind = 0;

while (1)
{
int this_option_optind = optind ? optind : 1;
int option_index = 0;
static struct option long_options[] =
{
{"add", 1, 0, 0},
{"append", 0, 0, 0},
{"delete", 1, 0, 0},
{"verbose", 0, 0, 0},
{"create", 0, 0, 0},
{"file", 1, 0, 0},
{0, 0, 0, 0}
};

c = getopt_long (argc, argv, "abc:d:0123456789",
long_options, &option_index);
if (c == EOF)
break;

switch (c)
{
case 0:
printf ("option %s", long_options[option_index].name);
if (optarg)
printf (" with arg %s", optarg);
printf ("\n");
break;

case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
if (digit_optind != 0 && digit_optind != this_option_optind)
printf ("digits occur in two different argv-elements.\n");
digit_optind = this_option_optind;
printf ("option %c\n", c);
break;

case 'a':
printf ("option a\n");
break;

case 'b':
printf ("option b\n");
break;

case 'c':
printf ("option c with value `%s'\n", optarg);
break;

case 'd':
printf ("option d with value `%s'\n", optarg);
break;

case '?':
break;

default:
printf ("?? getopt returned character code 0%o ??\n", c);
}
}

if (optind < argc)
{
printf ("non-option ARGV-elements: ");
while (optind < argc)
printf ("%s ", argv[optind++]);
printf ("\n");
}

exit (0);
}

#endif /* TEST */
oleo-1.3/io-utils.c 644 722 0 56401 5356003007 12417 0ustar lordwheel/* Copyright (C) 1990, 1992, 1993 Free Software Foundation, Inc.

This file is part of Oleo, the GNU Spreadsheet.

Oleo 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, or (at your option)
any later version.

Oleo 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 Oleo; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */

#include
#include
#include
#include "sysdef.h"
#include "io-utils.h"
#include "cell.h"
#include "ref.h"
#include "decompile.h"
#include "io-generic.h"
#include "io-abstract.h"
#include "lists.h"
#include "io-term.h"
#include "cmd.h"


/* Routines for formatting cell values */
#ifdef __STDC__
struct user_fmt;
static char *pr_flt (double, struct user_fmt *, int);
static char *pr_int (long, struct user_fmt *, int);
#else
static char *pr_flt ();
static char *pr_int ();
#endif


/* Constants */
char *bname[] =
{
"#FALSE", "#TRUE"
};

char numb_oflo[] = "########################################";

double __plinf;
double __neinf;
double __nan;

char nname[] = "#NOT_A_NUMBER";
char iname[] = "#INFINITY";
char mname[] = "#MINUS_INFINITY";

static double
divide (a, b)
double a;
double b;
{
return a / b;
}

static RETSIGTYPE
ignore_sig (sig)
int sig;
{
(void)signal (SIGFPE, ignore_sig);
}

/* It's ok of this fails and generates signals. In that case,
* the same signal will occur when evaluating formulas and a
* (less informative) error value substituted. Note that this
* should be called before init_eval.
*/
#ifdef __STDC__
void
init_infinity (void)
#else
void
init_infinity ()
#endif
{
(void)signal (SIGFPE, ignore_sig);
__plinf = divide (1., 0.);
(void)signal (SIGFPE, ignore_sig);
__neinf = divide (-1., 0.);
(void)signal (SIGFPE, ignore_sig);
__nan = __plinf + __neinf;
}



/* Slightly larger than the maximum exponent we ever expect to see */
#define BIGFLT 309
#ifdef TEST
char print_buf[1024 * 8];
#else
char print_buf[BIGFLT + 20];
#endif



/* Structures/vars/functions for dealing with formatting floating-point
numbers, etc */

struct user_fmt
{
char *p_hdr, *n_hdr;
char *p_trl, *n_trl;
char *zero, *comma, *decpt;
unsigned char prec;
double scale;
};


struct user_fmt dol =
{
"$", "($", 0, ")", "$0", ",", ".", PRC_FLT, 1};

struct user_fmt cma =
{
0, "(", 0, ")", "0", ",", ".", PRC_FLT, 1};

struct user_fmt pct =
{
0, "-", "%", "%", "0%", 0, ".", PRC_FLT, 100};

struct user_fmt fxt =
{
0, "-", 0, 0, "0", 0, ".", PRC_FLT, 1};

/* Variables */

struct user_fmt u[16] =
{
{0, "-", 0, 0, "0", 0, ".", PRC_FLT, 1},
{0, "-", 0, 0, "0", 0, ".", PRC_FLT, 1},
{0, "-", 0, 0, "0", 0, ".", PRC_FLT, 1},
{0, "-", 0, 0, "0", 0, ".", PRC_FLT, 1},
{0, "-", 0, 0, "0", 0, ".", PRC_FLT, 1},
{0, "-", 0, 0, "0", 0, ".", PRC_FLT, 1},
{0, "-", 0, 0, "0", 0, ".", PRC_FLT, 1},
{0, "-", 0, 0, "0", 0, ".", PRC_FLT, 1},
{0, "-", 0, 0, "0", 0, ".", PRC_FLT, 1},
{0, "-", 0, 0, "0", 0, ".", PRC_FLT, 1},
{0, "-", 0, 0, "0", 0, ".", PRC_FLT, 1},
{0, "-", 0, 0, "0", 0, ".", PRC_FLT, 1},
{0, "-", 0, 0, "0", 0, ".", PRC_FLT, 1},
{0, "-", 0, 0, "0", 0, ".", PRC_FLT, 1},
{0, "-", 0, 0, "0", 0, ".", PRC_FLT, 1},
{0, "-", 0, 0, "0", 0, ".", PRC_FLT, 1},
};


/* Turn a floating-point number into the canonical text form. This scribbles
on print_buf */

#ifdef __STDC__
char *
flt_to_str (double val)
#else
char *
flt_to_str (val)
double val;
#endif
{
double f;

if (val == __plinf)
return iname;
if (val == __neinf)
return mname;
f = fabs (val);
if (f >= 1e6 || (f > 0 && f <= 9.9999e-6))
{
sprintf (print_buf, "%e", val);
return print_buf;
}
return pr_flt (val, &fxt, PRC_FLT);
}


#ifdef __STDC__
char *
long_to_str (long val)
#else
char *
long_to_str (val)
long val;
#endif
{
sprintf (print_buf, "%ld", val);
return print_buf;
}

/* create the human-readable version of the contents of a cell
This scribbles on print-buf bigtime */

#ifdef __STDC__
char *
print_cell (CELL *cp)
#else
char *
print_cell (cp)
CELL *cp;
#endif
{
int j;
int p;
long num;
static char zeroes[] = "000000000000000";

if (!cp)
return "";

j = GET_FMT (cp);

if (j == FMT_DEF)
j = default_fmt;
if (j == FMT_HID || GET_TYP (cp) == 0)
return "";

if (GET_TYP (cp) == TYP_STR)
return cp->cell_str;
if (GET_TYP (cp) == TYP_BOL)
{
#ifdef TEST
if (cp->cell_bol < 0 || cp->cell_bol > 1)
panic ("Bool %d out of range", cp->cell_bol);
#endif
return bname[cp->cell_bol];
}
if (GET_TYP (cp) == TYP_ERR)
{
#ifdef TEST
if (cp->cell_err > ERR_MAX || cp->cell_err < 0)
panic ("Error %d out of range", cp->cell_err);
#endif
return ename[cp->cell_err];
}
if (GET_TYP (cp) == TYP_FLT)
{
p = GET_PRC (j);
switch (j | PRC_FLT)
{
case FMT_GPH:
if (cp->cell_flt < 0)
{
j = '-';
num = -(cp->cell_flt);
}
else if (cp->cell_flt >= 1)
{
j = '+';
num = (cp->cell_flt);
}
else
{
j = '0';
num = 1;
}
graph:
if (num >= sizeof (print_buf))
{
io_error_msg ("Cannot graph %d '%c'", p, j);
num = sizeof (print_buf) - 1;
}
print_buf[num] = '\0';
while (--num >= 0)
print_buf[num] = j;
return print_buf;

case FMT_USR:
return pr_flt (cp->cell_flt, &u[p], u[p].prec);

case FMT_GEN:
{
double f;

f = fabs (cp->cell_flt);
if (f >= 1e6 || (f > 0 && f <= 9.9999e-6))
goto handle_exp;
return pr_flt (cp->cell_flt, &fxt, p);
}

case FMT_DOL:
return pr_flt (cp->cell_flt, &dol, p);

case FMT_CMA:
return pr_flt (cp->cell_flt, &cma, p);

case FMT_PCT:
return pr_flt (cp->cell_flt, &pct, p);

case FMT_FXT:
return pr_flt (cp->cell_flt, &fxt, p);

case FMT_EXP:
handle_exp:
if (cp->cell_flt == __plinf)
return iname;
if (cp->cell_flt == __neinf)
return mname;
if (p == PRC_FLT)
sprintf (print_buf, "%e", cp->cell_flt);
else
sprintf (print_buf, "%.*e", p, cp->cell_flt);
return print_buf;
#ifdef TEST
default:
panic ("Unknown format %d", j);
return 0;
#endif
}
}

if (GET_TYP (cp) == TYP_INT)
{
p = GET_PRC (j);
switch (j | PRC_FLT)
{
case FMT_GPH:
if (cp->cell_int < 0)
{
j = '-';
num = -(cp->cell_int);
}
else if (cp->cell_int >= 1)
{
j = '+';
num = (cp->cell_int);
}
else
{
j = '0';
num = 1;
}
goto graph;

case FMT_USR:
return pr_int (cp->cell_int, &u[p], u[p].prec);

case FMT_GEN:
sprintf (print_buf, "%ld", cp->cell_int);
return print_buf;

case FMT_DOL:
return pr_int (cp->cell_int, &dol, p);

case FMT_CMA:
return pr_int (cp->cell_int, &cma, p);

case FMT_PCT:
return pr_int (cp->cell_int, &pct, p);

case FMT_FXT:
if (p != PRC_FLT && p != 0)
sprintf (print_buf, "%ld.%.*s", cp->cell_int, p, zeroes);
else
sprintf (print_buf, "%ld", cp->cell_int);
return print_buf;

case FMT_EXP:
if (p != PRC_FLT)
sprintf (print_buf, "%.*e", p, (double) (cp->cell_int));
else
sprintf (print_buf, "%e", (double) (cp->cell_int));
return print_buf;
#ifdef TEST
default:
panic ("Unknown format %d", j);
return 0;
#endif
}
}
#ifdef TEST
panic ("Unknown cell type %d", GET_TYP (cp));
#endif
return 0;
}

/* Return the value of ROW,COL in a human-readable fashion
In paticular, strings have "" around them, and are \\ed
*/
#ifdef __STDC__
char *
cell_value_string (CELLREF row, CELLREF col)
#else
char *
cell_value_string (row, col)
CELLREF row;
CELLREF col;
#endif
{
CELL *cp;

cp = find_cell (row, col);
if (!cp || !GET_TYP (cp))
return "";
switch (GET_TYP (cp))
{
case TYP_FLT:
return flt_to_str (cp->cell_flt);

case TYP_INT:
sprintf (print_buf, "%ld", cp->cell_int);
return print_buf;

case TYP_STR:
return backslash_a_string (cp->cell_str, 1);

case TYP_BOL:
return bname[cp->cell_bol];

case TYP_ERR:
return ename[cp->cell_err];
#ifdef TEST
default:
panic ("unknown type %d in cell_value_string", GET_TYP (cp));
#endif
}
return 0;
}

static char *
pr_int (val, fmt, prec)
long val;
struct user_fmt *fmt;
int prec;
{
char *pf, *pff, *pt;
long int n;
int nn = 0;

pt = &print_buf[sizeof (print_buf) - 1];
*pt = '\0';

n = fmt->scale * ((val < 0) ? -val : val);
if (n == 0)
return fmt->zero ? fmt->zero : "";

pf = pff = (val < 0) ? fmt->n_trl : fmt->p_trl;
if (pf && *pf)
{
while (*pf)
pf++;
do
*--pt = *--pf;
while (pf != pff);
}

if (prec != PRC_FLT && prec != 0)
{
while (prec-- > 0)
*--pt = '0';
pf = pff = fmt->decpt;
if (pf)
{
while (*pf)
pf++;
do
*--pt = *--pf;
while (pf != pff);
}
/* *--pt='.'; */
}
do
{
*--pt = (n % 10) + '0';
n /= 10;
if (nn++ == 2 && n > 0)
{
if (fmt->comma && *(fmt->comma))
{
for (pf = pff = fmt->comma; *pf; pf++)
;
do
*--pt = *--pf;
while (pf != pff);
}
nn = 0;
}
}
while (n > 0);

pf = pff = (val < 0) ? fmt->n_hdr : fmt->p_hdr;
if (pf && *pf)
{
while (*pf)
pf++;
do
*--pt = *--pf;
while (pf != pff);
}
return pt;
}

static char *
pr_flt (val, fmt, prec)
double val;
struct user_fmt *fmt;
int prec;
{
char *iptr;
char *fptr;
char *pptr;
char *pf, *pff;
double fract, integer, tmpval;
int n;
int isneg;
int comlen;

val *= fmt->scale;

if (val == __plinf)
return iname;
if (val == __neinf)
return mname;
if (val != val)
return nname;

iptr = &print_buf[BIGFLT];
fptr = &print_buf[BIGFLT];


if (val == 0)
return fmt->zero ? fmt->zero : "";

if (val < 0)
{
isneg = 1;
val = -val;
}
else
isneg = 0;

comlen = 0;
if (fmt->comma && *(fmt->comma))
for (pf = fmt->comma; *pf; comlen++, pf++)
;

fract = modf (val, &integer);
n = 0;
do
{
if (iptr < &print_buf[comlen])
return numb_oflo;
tmpval = modf (integer / 10, &integer);
*--iptr = '0' + (int) ((tmpval + .01) * 10);
if (comlen && n++ == 2 && integer)
{
n = 0;
pff = fmt->comma;
pf = pff + comlen;
do
*--iptr = *--pf;
while (pf != pff);
}
}
while (integer);

if (prec)
{
int p1;

p1 = (prec == PRC_FLT) ? 15 : (prec > 0) ? prec : -prec;
pf = fmt->decpt;
while (pf && *pf)
*fptr++ = *pf++;
/* *fptr++='.'; */
if (fract)
{
do
{
fract = modf (fract * 10, &tmpval);
*fptr++ = '0' + (int) tmpval;
}
while (--p1 && fract);
}
if (prec > 0 && prec != PRC_FLT)
while (p1--)
*fptr++ = '0';
else
{
fract = 0;
while (fptr[-1] == '0')
--fptr;
while (!isdigit (fptr[-1]))
--fptr;
*fptr = '\0';
}
}
if (fract)
{
(void) modf (fract * 10, &tmpval);
if (tmpval > 4)
{
iptr[-1] = '0';
for (pptr = fptr - 1;; --pptr)
{
if (!isdigit (*pptr))
continue;
else if (*pptr == '9')
{
if (pptr == fptr - 1 && pptr > &print_buf[BIGFLT] && (prec < 0 || prec == PRC_FLT))
{
--fptr;
while (!isdigit (pptr[-1]))
{
--fptr;
--pptr;
}
*pptr = '\0';
}
else
*pptr = '0';
}
else
{
(*pptr)++;
break;
}
}
if (pptr < iptr)
{
--iptr;
if (n == 3)
{
char tmpch;

tmpch = *iptr++;
for (pf = pff = fmt->comma; *pf; pf++)
;
do
*--iptr = *--pf;
while (pf != pff);
*--iptr = tmpch;
}
}
}
}
pf = pff = (isneg) ? fmt->n_hdr : fmt->p_hdr;
if (pf && *pf)
{
while (*pf)
pf++;
do
*--iptr = *--pf;
while (pf != pff);
}

pf = (isneg) ? fmt->n_trl : fmt->p_trl;
while (pf && *pf)
*fptr++ = *pf++;
*fptr = 0;
return iptr;
}

#ifdef __STDC__
char *
adjust_prc (char *oldp, CELL *cp, int width, int smallwid, int just)
#else
char *
adjust_prc (oldp, cp, width, smallwid, just)
char *oldp;
CELL *cp;
int width;
int smallwid;
int just;
#endif
{
int fmt;
int prc;
struct user_fmt *ufmt;
char *bptr;
char *eptr;
int len;

fmt = GET_FMT (cp);
if (fmt == FMT_DEF)
fmt = default_fmt;
prc = GET_PRC (fmt);
switch (fmt | PRC_FLT)
{
case FMT_GPH:
case FMT_HID:
return numb_oflo;
case FMT_DOL:
ufmt = &dol;
goto deal_fmt;

case FMT_CMA:
ufmt = &cma;
goto deal_fmt;

case FMT_PCT:
ufmt = &cma;
goto deal_fmt;

case FMT_FXT:
ufmt = &fxt;
goto deal_fmt;

case FMT_USR:
ufmt = &u[prc];
prc = ufmt->prec;
goto deal_fmt;

case FMT_GEN:
if (prc != PRC_FLT)
return numb_oflo;
if (index (oldp, 'e') || !index (oldp, '.'))
goto handle_exp;

ufmt = &fxt;
prc = PRC_FLT;
goto deal_fmt;

deal_fmt:
if (prc != PRC_FLT)
return numb_oflo;
len = strlen (oldp);
bptr = (char *)strstr (oldp, ufmt->decpt);
if (!bptr)
return numb_oflo;
while (eptr = (char *)strstr (bptr + 1, ufmt->decpt))
bptr = eptr;

if (width < bptr - oldp)
return numb_oflo;
if (bptr - oldp + strlen (ufmt->decpt) >= width)
prc = 0;
else
{
prc = width - (strlen (ufmt->decpt) + bptr - oldp);
}
bptr = pr_flt (cp->cell_flt, ufmt, -prc);
len = strlen (bptr);
if (len > width && prc > 0)
{
bptr = pr_flt (cp->cell_flt, ufmt, -(prc - 1));
len = strlen (bptr);
}
if (len > width)
return numb_oflo;
break;

case FMT_EXP:
handle_exp:
{
double f;

f = fabs (cp->cell_flt);
if (f > 9.99999e99 || f < 1e-99)
len = width - 7;
else /* if(f>9.9999999e9 || f<1e-9) */
len = width - 6;
/* else
len=width-5; */
if (cp->cell_flt < 0)
--len;
if (len > 0)
{
sprintf (oldp, "%.*e", len, cp->cell_flt);
len = strlen (oldp);
if (len <= width)
{
bptr = oldp;
break;
}
}
}
return numb_oflo;
default:
bptr = 0;
len = 0;
#ifdef TEST
panic ("Unknown format %d in adjust_prc()", fmt);
#endif
break;
}

/* If we get here, bptr points to a a string of len characters
(len<=width) that we want to output */
if (len < smallwid)
{
if (just == JST_RGT || just == JST_CNT)
{
int n;

n = (just == JST_RGT) ? smallwid - len : (1 + smallwid - len) / 2;
for (;;)
{
bptr[len + n] = bptr[len];
if (len-- == 0)
break;
}
while (n-- >= 0)
bptr[n] = ' ';
}
}
return bptr;
}


#ifdef __STDC__
void
set_usr_stats (int usr_n, char **usr_buf)
#else
void
set_usr_stats (usr_n, usr_buf)
int usr_n;
char **usr_buf;
#endif
{
int len;
int i;
char *p_in, *p_out;

len = 0;
for (i = 0; i < 7; i++)
len += strlen (usr_buf[i]);
u[usr_n].p_hdr = ck_malloc (len + 7);
p_out = u[usr_n].p_hdr;
if (usr_buf[0][0])
{
p_in = usr_buf[0];
while (*p_out++ = *p_in++)
;
}
else
*p_out++ = '\0';

if (usr_buf[1][0])
{
p_in = usr_buf[1];
u[usr_n].n_hdr = p_out;
while (*p_out++ = *p_in++)
;
}
else
u[usr_n].n_hdr = 0;

if (usr_buf[2][0])
{
p_in = usr_buf[2];
u[usr_n].p_trl = p_out;
while (*p_out++ = *p_in++)
;
}
else
u[usr_n].p_trl = 0;

if (usr_buf[3][0])
{
p_in = usr_buf[3];
u[usr_n].n_trl = p_out;
while (*p_out++ = *p_in++)
;
}
else
u[usr_n].n_trl = 0;

if (usr_buf[4][0])
{
p_in = usr_buf[4];
u[usr_n].zero = p_out;
while (*p_out++ = *p_in++)
;
}
else
u[usr_n].zero = 0;

if (usr_buf[5][0])
{
p_in = usr_buf[5];
u[usr_n].comma = p_out;
while (*p_out++ = *p_in++)
;
}
else
u[usr_n].comma = 0;

if (usr_buf[6][0])
{
p_in = usr_buf[6];
u[usr_n].decpt = p_out;
while (*p_out++ = *p_in++)
;
}
else
u[usr_n].decpt = 0;

if (!stricmp (usr_buf[7], "float") || !stricmp (usr_buf[7], "f"))
u[usr_n].prec = 15;
else
u[usr_n].prec = astol (&usr_buf[7]);

u[usr_n].scale = astof (&usr_buf[8]);
}

#ifdef __STDC__
int
usr_set_fmts (void)
#else
int
usr_set_fmts ()
#endif
{
int n;
int ret = 0;

for (n = 0; n < 16; n++)
if (u[n].p_hdr)
ret |= 1 << n;
return ret;
}

#ifdef __STDC__
void
get_usr_stats (int usr_num, char **usr_buf)
#else
void
get_usr_stats (usr_num, usr_buf)
int usr_num;
char **usr_buf;
#endif
{
static char buf1[30];
static char buf2[30];
static char NullStr[] = "";

usr_buf[0] = u[usr_num].p_hdr ? u[usr_num].p_hdr : NullStr;
usr_buf[1] = u[usr_num].n_hdr ? u[usr_num].n_hdr : NullStr;
usr_buf[2] = u[usr_num].p_trl ? u[usr_num].p_trl : NullStr;
usr_buf[3] = u[usr_num].n_trl ? u[usr_num].n_trl : NullStr;
usr_buf[4] = u[usr_num].zero ? u[usr_num].zero : NullStr;
usr_buf[5] = u[usr_num].comma ? u[usr_num].comma : NullStr;
usr_buf[6] = u[usr_num].decpt ? u[usr_num].decpt : NullStr;
if (u[usr_num].prec == 15)
usr_buf[7] = "float";
else
{
sprintf (buf1, "%u", u[usr_num].prec);
usr_buf[7] = buf1;
}
sprintf (buf2, "%.12g", u[usr_num].scale);
usr_buf[8] = buf2;
}

/* Functions for printing out the names of cells and ranges */

#ifdef __STDC__
char *
cell_name (CELLREF rr, CELLREF cc)
#else
char *
cell_name (rr, cc)
CELLREF rr;
CELLREF cc;
#endif
{
static char strs[2][20];
static num = 0;
char *ptr;

num = num ? 0 : 1;

if (a0)
{
ptr = &strs[num][9];
sprintf (ptr, "%u", rr);
if (cc < MIN_COL + 26)
*--ptr = 'A' - MIN_COL + cc;
#if MAX_COL>702
else if (cc < MIN_COL + 702)
{
cc -= MIN_COL + 26;
*--ptr = 'A' + cc % 26;
*--ptr = 'A' + cc / 26;
}
else if (cc < MIN_COL + 18278)
{
cc -= MIN_COL + 702;
*--ptr = 'A' + cc % 26;
cc /= 26;
*--ptr = 'A' + cc % 26;
*--ptr = 'A' + cc / 26;
}
else
{
cc -= MIN_COL + 18278;
*--ptr = 'A' + cc % 26;
cc /= 26;
*--ptr = 'A' + cc % 26;
cc /= 26;
*--ptr = 'A' + cc % 26;
*--ptr = 'A' + cc / 26;
}
#else
else
{
cc -= MIN_COL + 26;
*--ptr = 'A' + cc % 26;
*--ptr = 'A' + cc / 26;
}
#endif
}
else
{
ptr = &strs[num][0];
sprintf (ptr, "r%uc%u", rr, cc);
}
return ptr;
}

#ifdef __STDC__
char *
range_name (struct rng *rng)
#else
char *
range_name (rng)
struct rng *rng;
#endif
{
CELLREF lr, lc, hr, hc;
static char buf[2][40];
static num;
char *ptr;

ptr = &buf[num][0];
num = num ? 0 : 1;

lr = rng->lr;
lc = rng->lc;
hr = rng->hr;
hc = rng->hc;

if (a0)
sprintf (ptr, "%s:%s", cell_name (lr, lc), cell_name (hr, hc));
else
{
if (lr == hr && lc == hc)
sprintf (ptr, "r%uc%u", lr, lc);
else if (lr == hr && lc != hc)
sprintf (ptr, "r%uc%u:%u", lr, lc, hc);
else if (lr != hr && lc == hc)
sprintf (ptr, "r%u:%uc%u", lr, hr, lc);
else
sprintf (ptr, "r%u:%uc%u:%u", lr, hr, lc, hc);
}
return ptr;
}


/* Parse a range, allowing variable names.
* Return 1 on failure, 0 on succes.
*/
#ifdef __STDC__
int
get_abs_rng (char **pptr, struct rng *retp)
#else
int
get_abs_rng (pptr, retp)
char **pptr;
struct rng *retp;
#endif
{
unsigned char n;
struct rng ignored;

if (!retp)
retp = &ignored;

while (**pptr == ' ')
(*pptr)++;
if (!**pptr)
return 1;
cur_row = curow;
cur_col = cucol;
n = parse_cell_or_range (pptr, retp);
if (!n)
{
struct var *v;
char *ptr;

ptr = *pptr;
while (ptr[n] && ptr[n] != ' ')
n++;
v = find_var (ptr, n);
if (!v)
return 1;
(*pptr) += n;
*retp = v->v_rng;
}
return 0;
}


#ifdef __STDC__
char *
col_to_str (CELLREF col)
#else
char *
col_to_str (col)
CELLREF col;
#endif
{
static char strs[2][10];
static num;
char *ptr;

ptr = &strs[num][9];
num = num ? 0 : 1;

if (col < MIN_COL + 26)
*--ptr = 'A' - MIN_COL + col;
#if MAX_COL>702
else if (col < MIN_COL + 702)
{
col -= MIN_COL + 26;
*--ptr = 'A' + col % 26;
*--ptr = 'A' + col / 26;
}
else if (col < MIN_COL + 18278)
{
col -= MIN_COL + 702;
*--ptr = 'A' + col % 26;
col /= 26;
*--ptr = 'A' + col % 26;
*--ptr = 'A' + col / 26;
}
else
{
col -= MIN_COL + 18278;
*--ptr = 'A' + col % 26;
col /= 26;
*--ptr = 'A' + col % 26;
col /= 26;
*--ptr = 'A' + col % 26;
*--ptr = 'A' + col / 26;
}
#else
else
{
col -= MIN_COL + 26;
*--ptr = 'A' + col % 26;
*--ptr = 'A' + col / 26;
}
#endif
return ptr;
}

#ifdef __STDC__
void
clear_spreadsheet (void)
#else
void
clear_spreadsheet ()
#endif
{
int n;

flush_everything ();
/* flush_widths(); */
flush_all_timers ();
for (n = 0; n < 16; n++)
{
if (u[n].p_hdr)
{
free (u[n].p_hdr);
u[n].p_hdr = 0;
u[n].prec = PRC_FLT;
u[n].scale = 1;
}
}
default_width = saved_default_width;
default_height = saved_default_height;
default_jst = JST_LFT;
default_fmt = FMT_GEN;
default_lock = LCK_UNL;
}

char *ename[] =
{
"#WHAT?",
"#ERROR", "#BAD_INPUT", "#NON_NUMBER", "#NON_STRING",
"#NON_BOOL", "#NON_RANGE", "#OUT_OF_RANGE", "#NO_VALUES",
"#DIV_BY_ZERO", "#BAD_NAME", "#NOT_AVAIL", "#PARSE_ERROR",
"#NEED_OPEN", "#NEED_CLOSE", "#NEED_QUOTE", "#UNK_CHAR",
"#UNK_FUNC",
0
};

char tname[] = "#TRUE";
char fname[] = "#FALSE";


#ifdef __STDC__
int
words_imatch (char ** ptr, char * key)
#else
int
words_imatch (ptr, key)
char ** ptr;
char * key;
#endif
{
char * str = * ptr;

while (isspace (*str))
++str;
while (isspace (*key))
++key;

while (1)
{
while (*str && *key && (toupper (*str) == toupper (*key)))
{
++str;
++key;
}
/* If we're not at word breaks in both strings... */
if (!((!*str || isspace (*str)) && (!*key || isspace (*key))))
return 0;
else
{
while (isspace (*key))
++key;
while (isspace (*str))
++str;
if (!*key)
{
*ptr = str;
return 1;
}
}
}
}

#ifdef __STDC__
int
parray_len (char ** array)
#else
int
parray_len (array)
char ** array;
#endif
{
int x;
for (x = 0; array[x]; ++x) ;
return x;
}


/* Return the index of CHECK in KEYS or -1. Case and whitespeace insenstive.
*/

#ifdef __STDC__
int
words_member (char ** keys, int len, char * check)
#else
int
words_member (keys, len, check)
char ** keys;
int len;
char * check;
#endif
{
int x;
for (x = 0; x < len; ++x)
{
char * ch = check;
if (words_imatch (&ch, keys[x]))
if (!*ch)
return x;
}
return -1;
}

#ifdef __STDC__
int
prompt_len (char * prompt)
#else
int
prompt_len (prompt)
char * prompt;
#endif
{
char * pos;
if (!prompt)
return 0;
for (pos = prompt; *pos && (*pos != '\n'); ++pos)
;
return pos - prompt;
}


#ifdef __STDC__
int
says_default (char * str)
#else
int
says_default (str)
char * str;
#endif
{
char * key = "ault";
if (strincmp(str, "def", 3))
return 0;
str += 3;
while (*str && *key)
{
if (tolower(*str) != *key)
return 0;
++key;
++str;
}
while (isspace(*str))
++str;
return !*str;
}
oleo-1.3/io-x11.c 644 722 0 163431 5356002774 11724 0ustar lordwheel#ifdef HAVE_X11_X_H
/* Copyright (C) 1992, 1993 Free Software Foundation, Inc.

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, 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 software; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */


#include
#include
#include
#define NeedFunctionPrototypes 0
#include
#include
#include
#include
#include
#include "global.h"
#include "utils.h"
#include "io-generic.h"
#include "io-edit.h"
#include "io-utils.h"
#include "io-term.h"
#include "cmd.h"
#include "window.h"
#include "line.h"
#include "font.h"
#include "lists.h"
#include "ir.h"
#include "display.h"
#include "io-abstract.h"
#include "regions.h"
#include "math.h"
#include "input.h"
#include "info.h"


#if defined(HAVE_RINT)
#ifdef __STDC__
extern double rint (double);
#else
extern double rint ();
#endif
#else
#define rint(x) (((x)<0) ? ceil((x)-.5) : floor((x)+.5))
#endif
static void record_damage ();

#ifdef __STDC__
extern char * x_get_string_resource (XrmDatabase, char *, char *);
extern XrmDatabase x_load_resources (Display *, char *, char *);
extern char * getenv (const char *);
#else
extern char * x_get_string_resource ();
extern XrmDatabase x_load_resources ();
extern char * getenv ();
#endif


static char *emergency_font_name = "8x13";
static char *cell_font_name = "times_roman12";
static char *default_font_name = "8x13";
static char *input_font_name = "8x13";
static char *status_font_name = "6x10";
static char *text_line_font_name = "8x13";
static char *label_font_name = "5x8";
int cell_font_point_size = 12;
static char *default_bg_color_name = "black";
static char *default_fg_color_name = "white";

/* If non-0 and !no_x, these display functions will be used. */
char *io_x11_display_name = 0;

/* The geometry of the first window. */
static int geom_x = 0;
static int geom_y = 0;
static int geom_w = 675;
static int geom_h = 350;
static char geom_string[] = "675x350+0+0";

/* This global is used only during command line and .Xdefaults handling. */
static Display * theDisplay;

static char * rdb_class_name = "Oleo";
static char * rdb_name = "oleo";

#if 0
static XrmOptionDescRec x11_options[] =
{
{0, 0, 0, 0}
};

/* This dynamicly computes the size of x11_options to make
* upkeep of this file less error prone.
*/
static int
count_options ()
{
int x;
for (x = 0; x11_options[x].option; ++x)
;
return x;
}
#endif
/* This synthesizes class and generic names for resources (fancy strcat).
* Memory is reused after a reasonable number of calls.
*/
#define RDB_NAME_BUF 8
#define RDB_NAME_SIZE 256

#ifdef __STDC__
static char *
resource_name (char * left, char * right)
#else
static char *
resource_name (left, right)
char * left;
char * right;
#endif
{
static char bufs[RDB_NAME_BUF][RDB_NAME_SIZE];
static int buf_pos = 0;
int len = strlen(left);

bcopy (left, bufs[buf_pos], len);
bufs[buf_pos][len] = '.';
strcpy (bufs[buf_pos] + len + 1, right);
return bufs [buf_pos++];
}

#ifdef __STDC__
static char *
class_of (char * foo)
#else
static char *
class_of (foo)
char * foo;
#endif
{
return resource_name (rdb_class_name, foo);
}

#ifdef __STDC__
static char *
name_of (char * foo)
#else
static char *
name_of (foo)
char * foo;
#endif
{
return resource_name (rdb_name, foo);
}

static XrmDatabase rdb;

#ifdef __STDC__
void
get_x11_args (int * argc_p, char ** argv)
#else
void
get_x11_args (argc_p, argv)
int * argc_p;
char ** argv;
#endif
{
XrmInitialize ();

#if 0
XrmDatabase argv_resources;
/* Get the command line arguments. */
XrmParseCommand (&argv_resources, x11_options,
count_options (x11_options),
rdb_name, argc_p, argv);

/* Compute the display from either resources or getenv. */

io_x11_display_name =
x_get_string_resource (argv_resources, class_of ("Display"),
name_of ("display"));
#endif
if (!io_x11_display_name)
io_x11_display_name = ck_savestr (getenv ("DISPLAY"));

if (!io_x11_display_name)
return;

theDisplay = XOpenDisplay (io_x11_display_name);
if (!theDisplay)
panic ("Can not connect to X. Check your DISPLAY evironment variable.");

FD_SET (ConnectionNumber (theDisplay), &read_fd_set);
FD_SET (ConnectionNumber (theDisplay), &exception_fd_set);

/* Load the resource databases in a manner not unlike emacs :). */
rdb = x_load_resources (theDisplay, 0, rdb_class_name);

#if 0
/* Merge in the command line database. */
XrmMergeDatabases (argv_resources, rdb);
#endif

/* Set up the various defaults (staticly declared above). */
{
char * val;

val = x_get_string_resource (rdb, class_of ("Foreground"),
name_of("foreground"));
if (val)
default_fg_color_name = val;

val = x_get_string_resource (rdb, class_of ("Background"),
name_of("background"));
if (val)
default_bg_color_name = val;

val = x_get_string_resource (rdb, class_of ("Geometry"),
name_of("geometry"));
if (val)
XGeometry (theDisplay, DefaultScreen(theDisplay), val, geom_string,
0, 1, 1, 0, 0, &geom_x, &geom_y, &geom_w, &geom_h);
}
}


static int x11_opened = 0;
static struct sXport *thePort;
typedef struct sXport *Xport;

struct sXport
{
Display *dpy;
int screen;
Colormap color_map;
XColor fg_color;
XColor bg_color;
unsigned long fg_color_pixel;
unsigned long bg_color_pixel;
Window window;
Cursor mouse_cursor;

XFontStruct *input_font;
XFontStruct *text_line_font;
XFontStruct *label_font;
XFontStruct *status_font;

GC neutral_gc;
GC normal_gc;
GC standout_gc;
GC input_gc;
GC standout_input_gc;
GC text_line_gc;
GC text_line_standout_gc;
GC label_gc;
GC label_standout_gc;
GC status_gc;

struct x_window *xwins;
int cursor_visible; /* init to 1 */
int redisp_needed;
Atom wm_delete_window;

/* The state of the input area. */
struct input_view input_view;

/* If there is a message, that gets put in the input area. */
char * message;
int message_timeout;
};

#ifdef __STDC__
static void
beep (Xport xport)
#else
static void
beep (xport)
Xport xport;
#endif
{
#if 0
XBell (xport->dpy, 30);
XFlush (xport->dpy);
#endif
}

#ifdef __STDC__
static void
xio_bell (void)
#else
static void
xio_bell ()
#endif
{
beep (thePort);
}


#ifdef __STDC__
static void
draw_text_item (Xport xport, int c, int r, int wid, int hgt,
XFontStruct *font, GC gc, XTextItem *text, int do_clip)
#else
static void
draw_text_item (xport, c, r, wid, hgt, font, gc, text, do_clip)
Xport xport;
int c;
int r;
int wid;
int hgt;
XFontStruct *font;
GC gc;
XTextItem *text;
int do_clip;
#endif
{
XRectangle clip;
int widused;
int tab_char;
XTextItem to_draw;

clip.x = c;
clip.y = r;
clip.width = wid;
clip.height = hgt;
if (!x11_opened)
return;
if (do_clip)
XSetClipRectangles (xport->dpy, gc, 0, 0, &clip, 1, YXBanded);


tab_char = 0;
to_draw = *text;
widused = 0;
while (to_draw.nchars)
{
XTextItem draw_now;
XTextItem after_tab;

/* Draw tab characters carefully. */
{
int x;
for (x = 0; x < to_draw.nchars; ++x)
if (to_draw.chars[x] == '\t')
{
draw_now = to_draw;
draw_now.nchars = x;
after_tab = to_draw;
after_tab.chars += x + 1;
after_tab.nchars -= x + 1;
goto draw_burst;
}
/* No tabs found. */
draw_now = to_draw;
bzero (&after_tab, sizeof (after_tab));
}

draw_burst:
XDrawImageString (xport->dpy, xport->window, gc,
c + widused, r + font->ascent,
draw_now.chars, draw_now.nchars);
widused += XTextWidth (font, draw_now.chars, draw_now.nchars);
tab_char += draw_now.nchars;
if (after_tab.chars)
{
int tab_stop_col = ((tab_char + 8 - tab_char % 8)
* font->max_bounds.width);
XFillRectangle (xport->dpy, xport->window, xport->neutral_gc,
c + widused, r, tab_stop_col - widused, hgt);
widused = tab_stop_col;
tab_char += 8 - tab_char % 8;
}
to_draw = after_tab;
}

if (widused < wid)
XFillRectangle (xport->dpy, xport->window, xport->neutral_gc,
c + widused, r, wid - widused, hgt);
if (do_clip)
XSetClipMask (xport->dpy, gc, None);
}

#ifdef __STDC__
static void
xio_redraw_input_cursor (int on)
#else
static void
xio_redraw_input_cursor (on)
int on;
#endif
{
struct input_view * iv = &thePort->input_view;
int offset = iv->input_cursor - iv->visibility_begin;
int start;
XTextItem cursor_text;
int cwid;
int ypos = (iv->current_info ? 0 : input);
char * inp;

inp = (iv->input_area
? iv->input_area->buf + iv->visibility_begin
: "");
start = (XTextWidth (thePort->input_font, inp, offset) + iv->prompt_wid);

cursor_text.font = thePort->input_font->fid;
cursor_text.nchars = 1;
if (iv->input_cursor <= iv->visibility_end)
{
cwid = XTextWidth (thePort->input_font, inp + offset, 1);
cursor_text.chars = inp + offset;
}
else
{
cwid = XTextWidth (thePort->input_font, " ", 1);
cursor_text.chars = " ";
}
draw_text_item (thePort, start, ypos, cwid, input_rows,
thePort->input_font,
(on ? thePort->standout_input_gc : thePort->input_gc),
&cursor_text, 1);
}

#ifdef __STDC__
static void
xio_cellize_cursor (void)
#else
static void
xio_cellize_cursor ()
#endif
{
xio_redraw_input_cursor (0);
}

#ifdef __STDC__
static void
xio_inputize_cursor (void)
#else
static void
xio_inputize_cursor ()
#endif
{
xio_redraw_input_cursor (1);
}

static int
x_input_metric (str, len)
char * str;
int len;
{
return XTextWidth (thePort->input_font, str, len);
}

/* This redraws the input area without recomputing anything. */
#ifdef __STDC__
static void
xio_redraw_input (void)
#else
static void
xio_redraw_input ()
#endif
{
if (thePort->message)
{ /* This isn't in use. */
XTextItem text;
text.chars = thePort->message;
text.nchars = strlen (thePort->message);
text.font = thePort->input_font->fid;
draw_text_item (thePort, 0, input, scr_cols, input_rows,
thePort->input_font, thePort->input_gc,
&text, 1);
return;
}

{
struct input_view * iv = &thePort->input_view;
int ypos = (iv->current_info ? 0 : input);

if (iv->redraw_needed == NO_REDRAW)
return;
if (iv->redraw_needed == FULL_REDRAW)
{
XTextItem text;
if (iv->expanded_keymap_prompt)
{
text.font = thePort->input_font->fid;
text.chars = iv->expanded_keymap_prompt;
text.nchars = strlen (iv->expanded_keymap_prompt);
draw_text_item (thePort,
0, ypos, scr_cols, input_rows,
thePort->input_font, thePort->input_gc,
&text, 0);
iv->redraw_needed = NO_REDRAW;
if (input_active || iv->current_info)
xio_redraw_input_cursor (1);
return;
}
else if (iv->prompt_wid)
{
text.font = thePort->input_font->fid;
text.chars = iv->prompt;
text.nchars = prompt_len (text.chars);
draw_text_item (thePort, 0, ypos, iv->prompt_wid, input_rows,
thePort->input_font, thePort->input_gc,
&text, 0);
}
}

if (!iv->input_area
|| (iv->visibility_begin > iv->visibility_end))
{
XFillRectangle (thePort->dpy, thePort->window, thePort->neutral_gc,
iv->prompt_wid, ypos,
scr_cols - iv->prompt_wid, input_rows);
iv->redraw_needed = NO_REDRAW;
return;
}


if (iv->visibility_end >= iv->visibility_begin)
{
int pos = ((iv->redraw_needed == FULL_REDRAW)
? iv->visibility_begin
: iv->redraw_needed);

int xpos = (iv->prompt_wid
+ XTextWidth (thePort->input_font,
iv->input_area->buf + iv->visibility_begin,
pos - iv->visibility_begin));
int wid = scr_cols - xpos;
int hgt = input_rows;

XTextItem text;

text.font = thePort->input_font->fid;
text.chars = iv->input_area->buf + pos;
text.nchars = iv->visibility_end - pos + 1;

draw_text_item (thePort, xpos, ypos, wid, hgt,
thePort->input_font, thePort->input_gc,
&text, 0);

if (input_active || iv->current_info)
xio_redraw_input_cursor (1);
iv->redraw_needed = NO_REDRAW;
}
}
}


#ifdef __STDC__
static void
xio_fix_input (void)
#else
static void
xio_fix_input ()
#endif
{
iv_fix_input (&thePort->input_view);
}

#ifdef __STDC__
static void
xio_move_cursor (void)
#else
static void
xio_move_cursor ()
#endif
{
if (input_active)
xio_redraw_input_cursor (0);
iv_move_cursor (&thePort->input_view);
if (input_active)
xio_redraw_input_cursor (1);
}

#ifdef __STDC__
static void
xio_erase (int len)
#else
static void
xio_erase (len)
int len;
#endif
{
iv_erase (&thePort->input_view, len);
}

#ifdef __STDC__
static void
xio_insert (int len)
#else
static void
xio_insert (len)
int len;
#endif
{
iv_insert (&thePort->input_view, len);
}

#ifdef __STDC__
static void
xio_over (char * str, int len)
#else
static void
xio_over (str, len)
char * str;
int len;
#endif
{
iv_over (&thePort->input_view, len);
}

#ifdef __STDC__
int
io_col_to_input_pos (int c)
#else
int
io_col_to_input_pos (c)
int c;
#endif
{
struct input_view * iv = &thePort->input_view;
char * prompt = (iv->expanded_keymap_prompt
? iv->expanded_keymap_prompt
: (iv->prompt ? iv->prompt : ""));
int prompt_wid = iv->prompt_metric (prompt, strlen(prompt));

c -= prompt_wid;
{
int cpos;
int max = iv->visibility_end - iv->visibility_begin + 1;
for (cpos = 1; cpos < max; ++cpos)
if (iv->input_metric (iv->input_area->buf + iv->visibility_begin, cpos)
>= c)
break;
return iv->visibility_begin + cpos - 1;
}
}


/****************************************************************
* Low level Input
****************************************************************/

/* To be like curses, we offer this option: */
static int block_on_getch = 1;

/* This is the buffer of decoded keyboard events. */
static char *input_buf = 0;
static int input_buf_allocated = 0;
static int chars_buffered = 0;
#define MAX_KEY_TRANSLATION (1024)

static XComposeStatus compose;

#ifdef __STDC__
static void
xio_scan_for_input (int blockp)
#else
static void
xio_scan_for_input (blockp)
int blockp;
#endif
{
XEvent event_return;
static int pendingw;
static int pendingh;
static int resize_pending = 0;
int events_pending;
int len;

events_pending = XPending (thePort->dpy);
do
{
if (resize_pending && !events_pending)
{
if ( ((pendingh / height_scale) > 9.)
&& ((pendingw / width_scale) > 9.))
{
io_set_scr_size (pendingh, pendingw);
resize_pending = 0;
}
}

if (!events_pending)
io_redisp ();

if (events_pending || blockp)
XNextEvent (thePort->dpy, &event_return);
else
return;

switch (event_return.type)
{
case ClientMessage:
if (event_return.xclient.data.l[0] == thePort->wm_delete_window)
{
XCloseDisplay(thePort->dpy);
exit(0);
}
break;
case KeyPress:
case ButtonPress:
case ButtonRelease:
if (chars_buffered + MAX_KEY_TRANSLATION >= input_buf_allocated)
{
input_buf_allocated =
2 * (input_buf_allocated
? input_buf_allocated
: MAX_KEY_TRANSLATION);
input_buf =
(char *) ck_remalloc (input_buf, input_buf_allocated);
}
}


switch (event_return.type)
{
case KeyPress:
len = XLookupString (&event_return,
input_buf + chars_buffered,
MAX_KEY_TRANSLATION, 0, &compose);
if ((len == 1) && (event_return.xkey.state & Mod1Mask))
input_buf[chars_buffered] |= 0x80;
chars_buffered += len;
break;

case ButtonPress:
case ButtonRelease:
{
int seq =
enqueue_mouse_event (event_return.xbutton.y,
event_return.xbutton.x,
event_return.xbutton.button,
event_return.type == ButtonPress);
input_buf[chars_buffered++] = MOUSE_CHAR;
input_buf[chars_buffered++] =
event_return.xbutton.button - 1 + '0';
input_buf[chars_buffered++] = (char) seq;
break;
}

case Expose:
record_damage (thePort,
event_return.xexpose.x, event_return.xexpose.y,
event_return.xexpose.width,
event_return.xexpose.height);
break;

case MapNotify:
break;

case ReparentNotify:
break;

case ConfigureNotify:
pendingw = event_return.xconfigure.width;
pendingh = event_return.xconfigure.height;
resize_pending = 1;
break;

default:
break;
}
events_pending = XPending (thePort->dpy);
}
while (events_pending || !chars_buffered);
}


#ifdef __STDC__
static int
xio_input_avail (void)
#else
static int
xio_input_avail ()
#endif
{
return chars_buffered;
}

#ifdef __STDC__
static void
xio_wait_for_input (void)
#else
static void
xio_wait_for_input ()
#endif
{
io_scan_for_input (1);
}

#ifdef __STDC__
static int
xio_read_kbd (VOLATILE char *buffer, int size)
#else
static int
xio_read_kbd (buffer, size)
VOLATILE char *buffer;
int size;
#endif
{
int amt_read = size < chars_buffered ? size : chars_buffered;
bcopy (input_buf, (char *) buffer, amt_read);
chars_buffered -= amt_read;
if (chars_buffered)
bcopy ((char *) input_buf + amt_read, (char *) input_buf, chars_buffered);
return amt_read;
}

#ifdef __STDC__
static void
xio_nodelay (int delayp)
#else
static void
xio_nodelay (delayp)
int delayp;
#endif
{
block_on_getch = delayp;
}

#ifdef __STDC__
static int
xio_getch (void)
#else
static int
xio_getch ()
#endif
{
char buf;

if (!chars_buffered)
io_scan_for_input (block_on_getch);

if (chars_buffered)
{
io_read_kbd (&buf, 1);
return buf;
}
else
return 0;
}


/****************************************************************
* Low level support for input and status areas.
****************************************************************/

/*
* CRAM tells how many characters of a string will fit within
* a given number of cols, presuming that if they don't all fit,
* the string CONTINUE must be added to the end of those that do.
*/
#ifdef __STDC__
static int
cram (int cols, XFontStruct *font, char *text, int len, char *continuation)
#else
static int
cram (cols, font, text, len, continuation)
int cols;
XFontStruct *font;
char *text;
int len;
char *continuation;
#endif
{
int cont_cols = XTextWidth (font, continuation, strlen (continuation));
int cols_used = 0;
int x = 0;

if (XTextWidth (font, text, len) < cols)
return len;

cols_used = 0;
while (x < len && cols_used < (cols - cont_cols))
cols_used += XTextWidth (font, text + x, 1);

return x;
}




#ifdef __STDC__
static void
set_text (XTextItem *xtext, char *text, int len)
#else
static void
set_text (xtext, text, len)
XTextItem *xtext;
char *text;
int len;
#endif
{
if (xtext->nchars < len)
{
xtext->chars = ck_remalloc (xtext->chars, len);
xtext->nchars = len;
}
bcopy (text, xtext->chars, len);
while (len < xtext->nchars)
xtext->chars[len++] = ' ';
}



/* The input area. */






/*
* Low level interface to the input area specificly.
*/

static XTextItem input_text;
static int term_cursor_visible = 0;
static int input_cursor = 0; /* Position of cursor, if visible */
static int textout;
static int input_more_mode = 0;

#ifdef __STDC__
static void
draw_input (void)
#else
static void
draw_input ()
#endif
{
if (!input_text.chars)
{
XFillRectangle (thePort->dpy, thePort->window, thePort->neutral_gc,
input, 0, scr_cols, input_rows);
return;
}
input_text.font = thePort->input_font->fid;
draw_text_item (thePort, 0, input, scr_cols, input_rows, thePort->input_font,
thePort->input_gc, &input_text, 1);
if (input_more_mode)
{
XTextItem more_text;
int mwid = XTextWidth (thePort->input_font, "[more]", 6);
more_text.chars = "[MORE]";
more_text.nchars = 6;
more_text.delta = 0;
more_text.font = thePort->input_font->fid;
draw_text_item (thePort, scr_cols - mwid, input, mwid, input_rows,
thePort->input_font, thePort->standout_input_gc,
&more_text, 1);
}
else if (term_cursor_visible)
{
int start = XTextWidth (thePort->input_font, input_text.chars, input_cursor);
int cwid = XTextWidth (thePort->input_font,
input_text.chars + input_cursor, 1);
XTextItem cursor_text;
cursor_text.chars = input_text.chars + input_cursor;
cursor_text.nchars = 1;
cursor_text.font = thePort->input_font->fid;
draw_text_item (thePort, start, input, cwid, input_rows,
thePort->input_font, thePort->standout_input_gc,
&cursor_text, 1);
}
}


#ifdef __STDC__
static void
xio_clear_input_before (void)
#else
static void
xio_clear_input_before ()
#endif
{
textout = 0;
if (topclear == 2)
{
int x;
for (x = 0; x < input_text.nchars; ++x)
input_text.chars[x] = ' ';
input_cursor = 0;
draw_input ();
topclear = 0;
}
}

#ifdef __STDC__
static void
xio_clear_input_after (void)
#else
static void
xio_clear_input_after ()
#endif
{
if (topclear)
{
int x;
for (x = 0; x < input_text.nchars; ++x)
input_text.chars[x] = ' ';
input_cursor = 0;
draw_input ();
topclear = 0;
}
}

#ifdef __STDC__
static void
set_input (char *text, int len, int cursor)
#else
static void
set_input (text, len, cursor)
char *text;
int len;
int cursor;
#endif
{
set_text (&input_text, text, len);
if (cursor + 1 > input_text.nchars)
{
input_text.chars = (char *) ck_remalloc (input_text.chars, cursor + 1);
while (input_text.nchars < cursor + 1)
input_text.chars[input_text.nchars++] = ' ';
}
input_cursor = cursor;
draw_input ();
}


/*
* Low level interface to the status area specificly.
*/
static XTextItem status_text;

#ifdef __STDC__
static void
draw_status (void)
#else
static void
draw_status ()
#endif
{
if (!x11_opened || thePort->input_view.current_info)
return;
if (user_status)
draw_text_item (thePort, 0, status, scr_cols,
status_rows, thePort->status_font,
thePort->status_gc, &status_text, 1);
}

#ifdef __STDC__
static void
set_status (char *text)
#else
static void
set_status (text)
char *text;
#endif
{
set_text (&status_text, text, strlen (text));
status_text.font = thePort->status_font->fid;
draw_status ();
}


/****************************************************************
* High level interfaces for the input and status areas.
****************************************************************/

#ifdef __STDC__
static void
xio_update_status (void)
#else
static void
xio_update_status ()
#endif
{
CELL *cp;
char *dec;
char *ptr;
int plen;
int dlen;
int mplen;
char buf[1024];
char *assembled;
char *pos = buf;

if (!user_status)
return;

if (mkrow != NON_ROW)
{
struct rng r;
*pos++ = '*';
set_rng (&r, curow, cucol, mkrow, mkcol);
ptr = range_name (&r);
}
else
ptr = cell_name (curow, cucol);
bcopy (ptr, pos, strlen (ptr));
pos += strlen (ptr);
if (how_many != 1)
{
sprintf (pos, " {%d}", how_many);
pos += strlen (pos);
}
*pos++ = ' ';
mplen = XTextWidth (thePort->status_font, buf, pos - buf);

if ((cp = find_cell (curow, cucol)) && cp->cell_formula)
{
dec = decomp (curow, cucol, cp);
dlen = XTextWidth (thePort->status_font, dec, strlen (dec));
}
else
{
dec = 0;
dlen = 0;
}

ptr = cell_value_string (curow, cucol);
plen = XTextWidth (thePort->status_font, ptr, strlen (ptr));

assembled = (char *) ck_malloc (plen + dlen + mplen);
bcopy (buf, assembled, pos - buf);
pos = assembled + (pos - buf);

{
int c;
int l;
int wid;

l = strlen (ptr);
c = cram (scr_cols - mplen - thePort->status_font->max_bounds.width,
thePort->status_font, ptr, l, (dec ? " [...]" : "..."));
bcopy (ptr, pos, c);
pos += c;
if (c == l)
*pos++ = ' ';
else if (dec)
{
bcopy (" [...]", pos, 6);
pos += 6;
dec = 0;
dlen = 0;
decomp_free ();
}
else
{
bcopy ("...", pos, 3);
pos += 3;
}
*pos++ = ' ';
wid = XTextWidth (thePort->status_font, assembled, pos - assembled);

if (dec)
{
l = strlen (dec);
c = cram (scr_cols - wid, thePort->status_font, dec, l, "[...]");
*pos++ = '[';
if (c < l)
{
bcopy (dec, pos, c);
bcopy ("...]", pos, 4);
pos += c + 4;
}
else
{
bcopy (dec, pos, c);
pos += c;
*pos++ = ']';
}
}

*pos++ = '\0';
set_status (assembled);
draw_status ();
free (assembled);
}
}


#ifdef __STDC__
static int
xio_get_chr (char *prompt)
#else
static int
xio_get_chr (prompt)
char *prompt;
#endif
{
int len = strlen (prompt);
set_input (prompt, len, len);
topclear = 2;
draw_input ();
return io_getch ();
}


/*
* Multi-line informational messages to the user:
*/

/* old: */
struct text_line
{
struct text_line *next;
int nchars;
int standout;
char line[TAIL_ARRAY];
};
static int text_damaged = 0;
static struct text_line *text_lines = 0;
extern int auto_recalc;


/****************************************************************
* Low level support for the cell windows.
****************************************************************/

/* Every cell has an associated font name. This is a cache mapping
* font names and scales to graphics contexts.
*/

struct cell_gc
{
struct cell_gc *next;
struct cell_gc *prev;
Xport port;
GC gc;
char *font_name;
double scale;
XFontStruct *font;
int clipped_to;
int cursor:1;
};

/* The cell_gc cache is only valid for a specific size default font. If the
* defualt font size changes, then the cache must be flushed.
*/
static int cell_gc_basis = 12;


/* Individual cache entries are also validated by the clipping set for their
* gc. To the rest of the system, it appears that there is one clipping region
* for all cell_gc's.
*/
static int clipcnt = 0;
static int cliprectc = 0;
static int cliprect_alloc = 0;
static XRectangle *cliprectv = 0;

#define GC_CACHE_SIZE 10
static struct cell_gc *cell_gc_cache = 0;


/* This takes the full name of an X11 font, and returns its point size (in
* tenths of a point. If the string is not a valid font name, 0 is returned.
*/

#ifdef __STDC__
static int
name_to_ps (char *xfont)
#else
static int
name_to_ps (xfont)
char *xfont;
#endif
{
while (*xfont)
if (*xfont == '-')
{
++xfont;
if (*xfont == '-') /* look for -- */
{
++xfont;
break;
}
}
else
++xfont;
if (!*xfont)
return 0;
while (isdigit (*xfont++));
--xfont;
if (!*xfont++ == '-')
return 0;
return atoi (xfont);
}


#define ABS(A) ((A) < 0 ? -(A) : (A))

#ifdef __STDC__
static struct cell_gc *
cell_gc (Xport port, struct font_memo *font_passed, int cursor)
#else
static struct cell_gc *
cell_gc (port, font_passed, cursor)
Xport port;
struct font_memo *font_passed;
int cursor;
#endif
{
struct font_memo *font =
(font_passed ? font_passed : default_font());
char *font_name = font->names->x_name;
double scale = font->scale;
struct cell_gc *c = cell_gc_cache;
if (cell_gc_basis != cell_font_point_size)
{
do
{
if (c->font_name)
{
XFreeFont (c->port->dpy, c->font);
free (c->font_name);
}
c->font_name = 0;
c->port = 0;
c->font = 0;
c = c->next;
}
while (c != cell_gc_cache);
cell_gc_basis = cell_font_point_size;
}
else
{
do
{
if ((c->scale == scale)
&& port == c->port
&& c->font_name && !strcmp (font_name, c->font_name))
{
if (cell_gc_cache == c)
cell_gc_cache = cell_gc_cache->next;
c->next->prev = c->prev;
c->prev->next = c->next;
c->next = cell_gc_cache;
c->prev = cell_gc_cache->prev;
c->prev->next = c;
c->next->prev = c;
cell_gc_cache = c;
goto check_clipping;
}
c = c->next;
}
while (c != cell_gc_cache);
}

c = c->prev;
cell_gc_cache = c;
if (c->font_name)
{
XFreeFont (c->port->dpy, c->font);
free (c->font_name);
}
c->port = port;
c->scale = scale;
{
char **fontv;
int fontc;
fontv = XListFonts (port->dpy, font_name, 1024, &fontc);
if (fontv)
{
int x, best;
int ideal_size = rint (scale * (double) cell_font_point_size * 10.);
int best_dist;
best = 0;
best_dist = ideal_size - name_to_ps (fontv[0]);
for (x = 1; x < fontc; ++x)
{
int ps = name_to_ps (fontv[x]);
int tdist = ideal_size - ps;
if (ABS (tdist) < ABS (best_dist)
|| ((ABS (tdist) == ABS (best_dist)) && (tdist > best_dist)))
{
best_dist = tdist;
best = x;
}
}
c->font = XLoadQueryFont (port->dpy, fontv[best]);
XFreeFontNames (fontv);
}
else
c->font = 0;
}
if (c->font)
c->font_name = (char *) ck_savestr (font_name);
else
{
c->font = XLoadQueryFont (port->dpy, cell_font_name);
if (c->font)
c->font_name = ck_savestr (cell_font_name);
else
{
c->font = XLoadQueryFont (port->dpy, emergency_font_name);
if (c->font)
c->font_name = ck_savestr (emergency_font_name);
else
panic ("Unable to load even the emergency font.");
}
}

{
XGCValues v;
v.font = c->font->fid;
XChangeGC (port->dpy, c->gc, GCFont, &v);
}

check_clipping:

if (clipcnt != c->clipped_to)
{
XSetClipRectangles (port->dpy, c->gc, 0, 0, cliprectv, cliprectc, Unsorted);
c->clipped_to = clipcnt;
}

{
XGCValues v;
v.foreground = cursor ? port->bg_color_pixel : port->fg_color_pixel;
v.background = cursor ? port->fg_color_pixel : port->bg_color_pixel;
XChangeGC (port->dpy, c->gc, GCForeground | GCBackground, &v);
c->cursor = cursor;
}
return c;
}



/* This is the data for an oleo window, displayed under X. */

enum kinds_of_layout_needed
{
damaged_display = 1,
new_display = 2
};

struct x_window
{
struct x_window *next;
struct window *win;
struct display display;
int layout_needed;
int label_damage;
Xport port;
};



#ifdef __STDC__
static void
collect_clipping (xx_IntRectangle rect)
#else
static void
collect_clipping (rect)
xx_IntRectangle rect;
#endif
{
if (cliprectc == cliprect_alloc)
{
cliprect_alloc = cliprect_alloc ? cliprect_alloc * 2 : 16;
cliprectv =
((XRectangle *)
ck_remalloc (cliprectv,
cliprect_alloc * sizeof (XRectangle)));
}
cliprectv[cliprectc].x = rect->x;
cliprectv[cliprectc].y = rect->y;
cliprectv[cliprectc].width = rect->w;
cliprectv[cliprectc].height = rect->h;
++cliprectc;
}

#ifdef __STDC__
static void
clip_to_intrectangle (struct x_window * xwin, xx_IntRectangle rect)
#else
static void
clip_to_intrectangle (xwin, rect)
struct x_window * xwin;
xx_IntRectangle rect;
#endif
{
struct window * win = xwin->win;
int x_ceil = win->win_over + win->numc;
int y_ceil = win->win_down + win->numr;

if (rect->w + rect->x >= x_ceil)
{
rect->w = x_ceil - rect->x;
}
if (rect->h + rect->y >= y_ceil)
{
rect->h = y_ceil - rect->y;
}
cliprectc = 0;
collect_clipping (rect);
++clipcnt;
}


#ifdef __STDC__
static void
place_text (xx_IntRectangle out, struct display *disp, struct cell_display *cd, XFontStruct *font, char *string)
#else
static void
place_text (out, disp, cd, font, string)
xx_IntRectangle out;
struct display *disp;
struct cell_display *cd;
XFontStruct *font;
char *string;
#endif
{
int *widths = disp->widths;
int *heights = disp->heights;
int *colx = disp->colx;
int *rowy = disp->rowy;
struct rng *range = &disp->range;
int hout = font->ascent + font->descent;
int wout = XTextWidth (font, string, strlen (string));
int ci = cd->c - range->lc;
int ri = cd->r - range->lr;
int yout = rowy[ri] + heights[ri] - (font->ascent + font->descent);
int xout;
switch (cd->justification)
{
default:
case JST_LFT:
xout = colx[ci];
break;
case JST_RGT:
xout = colx[ci] + widths[ci] - 1 - wout;
break;
case JST_CNT:
xout = colx[ci] + (widths[ci] - wout) / 2;
break;
}
xx_IRinit (out, xout, yout, wout, hout);
}



#ifdef __STDC__
static void
x_metric (struct cell_display *cd, struct display *disp)
#else
static void
x_metric (cd, disp)
struct cell_display *cd;
struct display *disp;
#endif
{
struct x_window *xw = (struct x_window *) disp->vdata;
Xport port = xw->port;
if (!cd->unclipped)
xx_IRinit (&cd->goal, 0, 0, 0, 0);
else
{
struct cell_gc *cgc = cell_gc (port, cd->font, 0);
place_text (&cd->goal, disp, cd, cgc->font, cd->unclipped);
}
}



#ifdef __STDC__
static struct x_window *
x_win (Xport port, struct window *win, int rebuild)
#else
static struct x_window *
x_win (port, win, rebuild)
Xport port;
struct window *win;
int rebuild;
#endif
{
struct x_window *xw;

for (xw = port->xwins; xw && xw->win != win; xw = xw->next);

if (xw && !rebuild)
return xw;

if (xw)
{
free_display (&xw->display);
}
else
{
xw = (struct x_window *) ck_malloc (sizeof (*xw));
xw->next = port->xwins;
port->xwins = xw;
xw->port = port;
}
xw->win = win;
build_display (&xw->display, &win->screen, x_metric, xw);
xw->label_damage = 1;
xw->layout_needed = new_display;
port->redisp_needed = 1;
return xw;
}

#ifdef __STDC__
static void
flush_x_windows (Xport port)
#else
static void
flush_x_windows (port)
Xport port;
#endif
{
while (port->xwins)
{
struct x_window * xw = port->xwins;
free_display (&xw->display);
port->xwins = xw->next;
free (xw);
port->redisp_needed = 1;
}
}




#ifdef __STDC__
static void
record_damage (Xport port, int x, int y, int w, int h)
#else
static void
record_damage (port, x, y, w, h)
Xport port;
int x;
int y;
int w;
int h;
#endif
{
struct x_window *xwin = port->xwins;

if (port->input_view.current_info)
{
port->input_view.info_redraw_needed = 1;
return;
}

if (text_lines)
{
text_damaged = 1;
return;
}

while (xwin)
{
struct window *win = xwin->win;
record_display_damage (&xwin->display,
x - win->win_over,
y - win->win_down,
w, h);
port->redisp_needed = 1;
if ( ( (x + w >= win->win_over - win_label_cols(win, win->screen.hr))
&& (x <= win->win_over)
&& (y + h >= win->win_down - win_label_rows(win))
&& (y <= win->win_down + display_height(&xwin->display)))
|| ( (y + h >= win->win_down - win_label_rows(win))
&& (y <= win->win_down)
&& (x + w >= win->win_over - win_label_cols(win, win->screen.hr))
&& (x <= win->win_over + display_width(&xwin->display))))
xwin->label_damage = 1;
xwin = xwin->next;
}

if (((input + input_rows) >= y) && (input <= y + h))
port->input_view.redraw_needed = FULL_REDRAW;
}



#ifdef __STDC__
static void
xio_pr_cell_win (struct window *win, CELLREF r, CELLREF c, CELL *cp)
#else
static void
xio_pr_cell_win (win, r, c, cp)
struct window *win;
CELLREF r;
CELLREF c;
CELL *cp;
#endif
{
struct x_window *xwin = x_win (thePort, win, 0);
struct display *disp = &xwin->display;

if (pr_display_cell (disp, r, c, cp))
{
thePort->redisp_needed = 1;
if (!xwin->layout_needed)
xwin->layout_needed = damaged_display;
}
}


#ifdef __STDC__
static void
xio_repaint_win (struct window *win)
#else
static void
xio_repaint_win (win)
struct window *win;
#endif
{
x_win (thePort, win, 1);
XFillRectangle (thePort->dpy, thePort->window, thePort->neutral_gc,
win->win_over, win->win_down, win->numc, win->numr);
record_damage (thePort, win->win_over, win->win_down, win->numc, win->numr);
}



#ifdef __STDC__
static void
xio_repaint (void)
#else
static void
xio_repaint ()
#endif
{
struct window *win;
if (thePort->input_view.current_info)
{
thePort->input_view.info_redraw_needed = 1;
return;
}
flush_x_windows (thePort);
for (win = wins; win < &wins[nwin]; win++)
xio_repaint_win (win);
}


#ifdef __STDC__
static void
draw_cell (struct x_window *xwin, struct cell_display *cd_passed, int cursor)
#else
static void
draw_cell (xwin, cd_passed, cursor)
struct x_window *xwin;
struct cell_display *cd_passed;
int cursor;

#endif
{
struct cell_display *cd = cd_passed->used_by;
Xport port = xwin->port;
struct window *win = xwin->win;
int ov = win->win_over;
int dn = win->win_down;
CELLREF r = cd->r;
CELLREF c = cd->c;
struct display *disp = &xwin->display;
int *rowy = disp->rowy;
int *colx = disp->colx;
int *widths = disp->widths;
int *heights = disp->heights;
struct cell_gc *cgc;
int ri = r - disp->range.lr;
int ci = c - disp->range.lc;

if (!(widths[ci] && heights[ri]))
return;

if (!cd->unclipped)
{
cgc = cell_gc (port, default_font(), !cursor);
XFillRectangle (port->dpy, port->window, cgc->gc,
colx[ci] + ov, rowy[ri] + dn,
widths[ci], heights[ri]);
return;
}

cgc = cell_gc (port, cd->font, cursor);
{
int isclipped;
char *str;
struct xx_sIntRectangle *strbox;

isclipped = !xx_IRencloses_width (&cd->layout, &cd->goal);
if (!isclipped)
{
str = cd->unclipped;
strbox = &cd->goal;
}
else
{
if (!cd->clipped)
{
int chr_scale = XTextWidth (cgc->font, "8", 1);
int w_avail = xx_IRw (&cd->layout) / chr_scale;
int cell_wid = widths[ci] / chr_scale;
CELL *cp = find_cell (r, c);
cd->clipped =
ck_savestr (adjust_prc (cd->unclipped, cp, w_avail, cell_wid,
cd->justification));
place_text (&cd->clip, disp, cd, cgc->font, cd->clipped);
}
str = cd->clipped;
strbox = &cd->clip;
}
XDrawImageString (port->dpy, port->window, cgc->gc,
strbox->x + ov, strbox->y + cgc->font->ascent + dn,
str, strlen (str));
{
struct xx_sIntRectangle tofill[4];
int fillc;

fillc = xx_IRsubtract (tofill, &cd->layout, strbox);
{
XGCValues v;
v.foreground = cursor ? port->fg_color_pixel : port->bg_color_pixel;
v.background = cursor ? port->bg_color_pixel : port->fg_color_pixel;
XChangeGC (port->dpy, cgc->gc, GCForeground | GCBackground, &v);
cgc->cursor = !cursor;
}
while (fillc--)
XFillRectangle (port->dpy, port->window, cgc->gc,
tofill[fillc].x + ov, tofill[fillc].y + dn,
tofill[fillc].w, tofill[fillc].h);
}
}
}


/* Cell values */

#ifdef __STDC__
static void
set_cursor (int on)
#else
static void
set_cursor (on)
int on;
#endif
{
struct x_window *xwin = x_win (thePort, cwin, 0);
struct display *disp = &xwin->display;
int *rowy = disp->rowy;
int *colx = disp->colx;
int *widths = disp->widths;
int *heights = disp->heights;
int ri = curow - disp->range.lr;
int ci = cucol - disp->range.lc;
int ov = xwin->win->win_over;
int dn = xwin->win->win_down;
struct cell_display *cd = cell_display_of (disp, curow, cucol);
struct xx_sIntRectangle clip;

/* The cursor might not even be visible. Though commands should never leave
* the user in such a state, it can happen in several ways transiently.
*/
if (!cd)
return;

thePort->cursor_visible = on;

if (xwin->layout_needed == new_display)
return;

if (cd->used_by == cd)
{
clip = cd->layout;
clip.x += ov;
clip.y += dn;
}
else
xx_IRinit (&clip,
colx[ci] + ov, rowy[ri] + dn,
widths[ci], heights[ri]);
clip_to_intrectangle (xwin, &clip);
draw_cell (xwin, cd, on);
}


#ifdef __STDC__
static void
xio_hide_cell_cursor (void)
#else
static void
xio_hide_cell_cursor ()
#endif
{
if (thePort->cursor_visible)
set_cursor (0);
}

#ifdef __STDC__
static void
xio_display_cell_cursor (void)
#else
static void
xio_display_cell_cursor ()
#endif
{
if (!thePort->cursor_visible)
{
if ( (curow < cwin->screen.lr)
|| (cucol < cwin->screen.lc)
|| (curow > cwin->screen.hr)
|| (cucol > cwin->screen.hc))
io_recenter_cur_win ();
set_cursor (1);
}
}


static int xx[10] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1};


#ifdef __STDC__
static void
draw_labels (void)
#else
static void
draw_labels ()
#endif
{
struct x_window *xwin;
XRectangle rect;
for (xwin = thePort->xwins; xwin; xwin = xwin->next)
if (xwin->win->lh_wid && xwin->label_damage)
{
XGCValues gcv;
struct window *win = xwin->win;
int wid2 = win->lh_wid / 2;
if (xx[0]) {
XFillRectangle (thePort->dpy, thePort->window,
thePort->label_standout_gc,
win->win_over - win->lh_wid,
win->win_down - label_rows,
wid2, label_rows);
};
gcv.line_width = win->lh_wid;
gcv.cap_style = CapRound;
XChangeGC (thePort->dpy, thePort->label_gc,
GCLineWidth | GCCapStyle, &gcv);
if (xx[1]) {
XDrawLine (thePort->dpy, thePort->window, thePort->label_gc,
win->win_over - wid2,
win->win_down - label_rows + wid2,
win->win_over - wid2,
win->win_down + win->numr - wid2);

};
gcv.cap_style = CapButt;
XChangeGC (thePort->dpy, thePort->label_gc, GCCapStyle, &gcv);
if (xx[2]) {
XDrawLine (thePort->dpy, thePort->window, thePort->label_gc,
win->win_over - wid2,
win->win_down + wid2,
win->win_over - wid2,
win->win_down + win->numr);
};

if (xx[3]) {
XFillRectangle (thePort->dpy, thePort->window, thePort->label_gc,
win->win_over - wid2,
win->win_down - label_rows,
win->numc + wid2,
label_rows);
};

rect.x = 0;
rect.y = 0;
rect.width = scr_cols;
rect.height = scr_lines;
XSetClipRectangles (thePort->dpy, thePort->label_standout_gc,
0, 0, &rect, 1, YXBanded);
{
char buf[100];
CELLREF cr;
int x;
int len;

sprintf (buf, "#%d", 1 + win - wins);
for (x = len = 0; buf[x]; ++x)
{
int cwid = XTextWidth (thePort->label_font, buf, 1);
if (cwid + len > wid2)
break;
len += cwid;
}
XDrawImageString (thePort->dpy, thePort->window,
thePort->label_standout_gc,
win->win_over - wid2,
win->win_down - thePort->label_font->descent,
buf, x);

rect.x = win->win_over - win->lh_wid;
rect.y = win->win_down;
rect.width = win->lh_wid;
rect.height = win->numr;
XSetClipRectangles (thePort->dpy, thePort->label_standout_gc,
0, 0, &rect, 1, YXBanded);

x = win->win_down + thePort->label_font->ascent;
for (cr = win->screen.lr; cr <= win->screen.hr; ++cr)
{
int hgt = get_scaled_height (cr);
if (hgt)
{
if (a0)
sprintf (buf, "%d", cr);
else
sprintf (buf, "R%d", cr);
XDrawImageString (thePort->dpy, thePort->window,
thePort->label_standout_gc,
win->win_over - win->lh_wid, x,
buf, strlen (buf));
x += hgt;
}
if (cr == MAX_ROW)
break;
}
rect.x = 0;
rect.y = 0;
rect.width = scr_cols;
rect.height = scr_lines;
XSetClipRectangles (thePort->dpy, thePort->label_standout_gc,
0, 0, &rect, 1, YXBanded);

x = win->win_over;
for (cr = win->screen.lc; cr <= win->screen.hc; ++cr)
{
int wid = get_scaled_width (cr);
if (wid > win->numc)
wid = win->numc;
if (wid)
{
int txtwid;
char *ptr;
if (a0)
ptr = col_to_str (cr);
else
{
ptr = buf;
sprintf (ptr, "C%u", cr);
}
txtwid = XTextWidth (thePort->label_font, ptr, strlen (ptr));
if (txtwid > wid - thePort->label_font->max_bounds.width)
{
int txtlen =
((wid - thePort->label_font->max_bounds.width)
/ XTextWidth (thePort->label_font, "#", 1));
txtwid = txtlen * XTextWidth (thePort->label_font,
"#", 1);
buf[txtlen] = 0;
while (txtlen)
buf[txtlen--] = '#';
ptr = buf;
}
XDrawImageString (thePort->dpy, thePort->window,
thePort->label_standout_gc,
x + (wid - txtwid) / 2,
(win->win_down
- thePort->label_font->descent),
ptr, strlen (ptr));
x += wid;
}
if (cr == MAX_COL)
break;
}
}
xwin->label_damage = 0;
}
}


/* Refresh the existing image. */


#ifdef __STDC__
static void
xio_redisp (void)
#else
static void
xio_redisp ()
#endif
{
static int was_text = 0;
if (thePort->input_view.current_info)
{
if (!was_text)
thePort->input_view.redraw_needed = FULL_REDRAW;

if (thePort->input_view.redraw_needed != NO_REDRAW)
xio_redraw_input ();

if (thePort->input_view.info_redraw_needed)
{
int ipos = thePort->input_view.info_pos;
int top = ipos + (scr_lines - input_rows) / info_rows - 1;
int ypos;
XTextItem text;

if (top >= thePort->input_view.current_info->len)
top = thePort->input_view.current_info->len - 1;

ypos = input_rows;

text.font = thePort->text_line_font->fid;
while (ipos <= top)
{
text.chars = thePort->input_view.current_info->text[ipos];
text.nchars = strlen (text.chars);
draw_text_item (thePort, 0, ypos, scr_cols, input_rows,
thePort->text_line_font, thePort->text_line_gc,
&text, 0);
ypos += info_rows;
++ipos;
}
XFillRectangle (thePort->dpy, thePort->window,
thePort->neutral_gc, 0, ypos,
scr_cols, scr_lines - ypos - 1);
thePort->input_view.redraw_needed = FULL_REDRAW;
xio_redraw_input ();
thePort->input_view.info_redraw_needed = 0;
was_text = 1;
}
}
else
{
struct x_window *xwin;
if (was_text)
{
thePort->input_view.info_redraw_needed = 0;
was_text = 0;
io_repaint ();
}
else
{
struct rng * rng = &cwin->screen;
if ( (curow > rng->hr)
|| (curow < rng->lr)
|| (cucol > rng->hc)
|| (cucol < rng->lc))
io_recenter_cur_win ();
}
thePort->redisp_needed = 0;
if (thePort->redisp_needed != NO_REDRAW)
xio_redraw_input ();
draw_status ();
draw_labels ();
for (xwin = thePort->xwins; xwin; xwin = xwin->next)
{
struct display *disp = &xwin->display;
int ov = xwin->win->win_over;
int dn = xwin->win->win_down;
struct cell_display * cd;
struct cell_display * cursor_cd = 0;
int must_draw_cursor;

if (xwin->layout_needed)
{
layout (disp);
xwin->layout_needed = 0;
}

/* If the cursor cell has been damaged,
* it will be redrawn. However, if the
* cursor cell is empty, then redrawing
* some other cell might damage the cursor.
* This watches for that condition and
* redraws the cursor if it occurs.
*/
must_draw_cursor = 0;
if (thePort->cursor_visible
&& (xwin->win == cwin)
&& (curow >= disp->range.lr)
&& (curow <= disp->range.hr)
&& (cucol >= disp->range.lc)
&& (cucol <= disp->range.hc))
{
cursor_cd = cell_display_of (disp, curow, cucol);
/* If the cursor cell is not empty, we never have
* to explicitly redraw the cursor.
*/
if (cursor_cd->used_by == cursor_cd)
cursor_cd = 0;
}

cd = disp->damaged;
while (cd != (struct cell_display *) disp)
{
struct xx_sIntRectangle clip;
struct cell_display *owner = cd->used_by;
clip = owner->layout;
clip.x += ov;
clip.y += dn;
clip_to_intrectangle (xwin, &clip);
if (cursor_cd && (cd->used_by == cursor_cd->used_by))
must_draw_cursor = 1;
draw_cell (xwin, owner,
(thePort->cursor_visible
&& (xwin->win == cwin)
&& (owner->r == curow)
&& (owner->c == cucol)));
{
struct cell_display *cdt = cd;
cd = cd->next_damaged;
cdt->next_damaged = 0;
}
}
disp->damaged = (struct cell_display *) disp;
if (must_draw_cursor)
set_cursor (1);
}
}
}




#ifdef __STDC__
static XFontStruct *
reasonable_font (Xport port, char *name)
#else
static XFontStruct *
reasonable_font (port, name)
Xport port;
char *name;
#endif
{
XFontStruct *f = XLoadQueryFont (port->dpy, name);

if (!f)
{
printf("(warning) Font %s could not be loaded.\n", name);
f = XLoadQueryFont (port->dpy, default_font_name);
if (!f)
{
panic ("Default font %s could not be loaded.\n",
default_font_name);
exit(0);
}
}
return f;
}

#ifdef __STDC__
extern void
xio_open_display (void)
#else
extern void
xio_open_display ()
#endif
{
XGCValues gcv;
XWMHints wmhints;

thePort = (Xport) ck_malloc (sizeof (*thePort));
thePort->cursor_visible = 1;
thePort->redisp_needed = 1;
thePort->xwins = 0;

thePort->dpy = theDisplay;

bzero (&thePort->input_view, sizeof (struct input_view));
thePort->input_view.prompt_metric = x_input_metric;
thePort->input_view.input_metric = x_input_metric;

thePort->screen = DefaultScreen (thePort->dpy);
thePort->color_map = DefaultColormap (thePort->dpy, thePort->screen);

if (default_fg_color_name &&
XParseColor (thePort->dpy, thePort->color_map, default_fg_color_name, &thePort->fg_color) &&
XAllocColor(thePort->dpy, thePort->color_map, &thePort->fg_color))
thePort->fg_color_pixel = thePort->fg_color.pixel;
else
if (default_fg_color_name && !stricmp (default_fg_color_name, "black"))
thePort->fg_color_pixel = BlackPixel (thePort->dpy, thePort->screen);
else
if (default_fg_color_name && !stricmp (default_fg_color_name, "white"))
thePort->fg_color_pixel = WhitePixel (thePort->dpy, thePort->screen);

if (default_bg_color_name &&
XParseColor (thePort->dpy, thePort->color_map, default_bg_color_name, &thePort->bg_color) &&
XAllocColor(thePort->dpy, thePort->color_map, &thePort->bg_color))
thePort->bg_color_pixel = thePort->bg_color.pixel;
else
if (default_bg_color_name && !stricmp (default_bg_color_name, "black"))
thePort->bg_color_pixel = BlackPixel (thePort->dpy, thePort->screen);
else
if (default_bg_color_name && !stricmp (default_bg_color_name, "white"))
thePort->fg_color_pixel = WhitePixel (thePort->dpy, thePort->screen);

thePort->window =
XCreateSimpleWindow (thePort->dpy, DefaultRootWindow (thePort->dpy),
geom_x, geom_y, geom_w, geom_h,
1, thePort->fg_color_pixel, thePort->bg_color_pixel);
XStoreName (thePort->dpy, thePort->window, oleo_version_string);
wmhints.flags = InputHint;
wmhints.input = True;
XSetWMHints(thePort->dpy, thePort->window, &wmhints);

thePort->wm_delete_window = XInternAtom(thePort->dpy, "WM_DELETE_WINDOW", False);
(void) XSetWMProtocols( thePort->dpy, thePort->window, &thePort->wm_delete_window, 1);

gcv.foreground = thePort->bg_color_pixel;
gcv.background = thePort->bg_color_pixel;
thePort->neutral_gc =
XCreateGC (thePort->dpy, DefaultRootWindow (thePort->dpy),
(GCForeground | GCBackground), &gcv);

gcv.foreground = thePort->fg_color_pixel;
gcv.background = thePort->bg_color_pixel;
thePort->normal_gc =
XCreateGC (thePort->dpy, DefaultRootWindow (thePort->dpy),
(GCForeground | GCBackground), &gcv);

gcv.foreground = thePort->bg_color_pixel;
gcv.background = thePort->fg_color_pixel;
thePort->standout_gc =
XCreateGC (thePort->dpy, DefaultRootWindow (thePort->dpy),
(GCForeground | GCBackground), &gcv);

thePort->input_font = reasonable_font (thePort, input_font_name);
gcv.font = thePort->input_font->fid;
gcv.foreground = thePort->fg_color_pixel;
gcv.background = thePort->bg_color_pixel;
thePort->input_gc =
XCreateGC (thePort->dpy, DefaultRootWindow (thePort->dpy),
(GCForeground | GCBackground | GCFont), &gcv);

gcv.foreground = thePort->bg_color_pixel;
gcv.background = thePort->fg_color_pixel;
thePort->standout_input_gc =
XCreateGC (thePort->dpy, DefaultRootWindow (thePort->dpy),
(GCForeground | GCBackground | GCFont), &gcv);

gcv.foreground = thePort->fg_color_pixel;
gcv.background = thePort->bg_color_pixel;
thePort->status_font = reasonable_font (thePort, status_font_name);
gcv.font = thePort->status_font->fid;
thePort->status_gc =
XCreateGC (thePort->dpy, DefaultRootWindow (thePort->dpy),
(GCForeground | GCBackground | GCFont), &gcv);

thePort->label_font = reasonable_font (thePort, label_font_name);
gcv.font = thePort->label_font->fid;
gcv.cap_style = CapRound;
thePort->label_gc =
XCreateGC (thePort->dpy, DefaultRootWindow (thePort->dpy),
(GCForeground | GCBackground | GCFont | GCCapStyle), &gcv);

gcv.background = thePort->fg_color_pixel;
gcv.foreground = thePort->bg_color_pixel;
thePort->label_standout_gc =
XCreateGC (thePort->dpy, DefaultRootWindow (thePort->dpy),
(GCForeground | GCBackground | GCFont | GCCapStyle), &gcv);

gcv.background = thePort->bg_color_pixel;
gcv.foreground = thePort->fg_color_pixel;
thePort->text_line_font = reasonable_font (thePort, text_line_font_name);
gcv.font = thePort->text_line_font->fid;
thePort->text_line_gc =
XCreateGC (thePort->dpy, DefaultRootWindow (thePort->dpy),
(GCForeground | GCBackground | GCFont), &gcv);

info_rows = (thePort->text_line_font->max_bounds.ascent
+ thePort->text_line_font->max_bounds.descent);

gcv.background = thePort->fg_color_pixel;
gcv.foreground = thePort->bg_color_pixel;
thePort->text_line_standout_gc =
XCreateGC (thePort->dpy, DefaultRootWindow (thePort->dpy),
(GCForeground | GCBackground | GCFont), &gcv);

gcv.background = thePort->fg_color_pixel;
gcv.foreground = thePort->bg_color_pixel;
thePort->text_line_standout_gc =
XCreateGC (thePort->dpy, DefaultRootWindow (thePort->dpy),
(GCForeground | GCBackground | GCFont), &gcv);

gcv.background = thePort->bg_color_pixel;
gcv.foreground = thePort->fg_color_pixel;

{
int x;
for (x = 0; x < GC_CACHE_SIZE; ++x)
{
struct cell_gc *cg =
(struct cell_gc *) ck_malloc (sizeof (struct cell_gc));
cg->font_name = 0;
cg->font = 0;
cg->clipped_to = 0;
cg->cursor = 0;
cg->gc = XCreateGC (thePort->dpy, DefaultRootWindow (thePort->dpy),
(GCForeground | GCBackground), &gcv);
if (!cell_gc_cache)
{
cg->next = cg;
cg->prev = cg;
}
else
{
cg->next = cell_gc_cache;
cg->prev = cg->next->prev;
cg->next->prev = cg;
cg->prev->next = cg;
}
cell_gc_cache = cg;
}
}

XSelectInput (thePort->dpy, thePort->window,
(ExposureMask | StructureNotifyMask | KeyPressMask
| ButtonPressMask));

io_init_windows (geom_h, geom_w, 1, 2,
thePort->input_font->ascent + thePort->input_font->descent,
(thePort->status_font->ascent
+ thePort->status_font->descent),
thePort->label_font->ascent + thePort->label_font->descent,
thePort->label_font->max_bounds.width);
x11_opened = 1;

{
struct cell_gc *cgc = cell_gc (thePort, default_font(), 0);
height_scale = cgc->font->ascent + cgc->font->descent;
width_scale = XTextWidth (cgc->font, "M", 1);
}

/* Setup the arrow keys. Modifiers effect the last character
* of the translation.
*/
{
static KeySym meta_shift_ctrl[]
= {Mod1MapIndex, ShiftMapIndex, ControlMapIndex };
#define shift_ctrl &meta_shift_ctrl[1]
#define ctrl &meta_shift_ctrl[2]
static KeySym meta_shift[] = {Mod1MapIndex, ShiftMapIndex};
#define shift &meta_shift[1]
static KeySym ctrl_meta[] = {ControlMapIndex, Mod1MapIndex};
#define meta &ctrl_meta[1]

static KeySym * mod_combos [] =
{
0,
ctrl, shift, meta,
shift_ctrl, ctrl_meta, meta_shift,
meta_shift_ctrl
};
static char meta_modp [] = { 0, 0, 0, 1, 0, 1, 1, 1 };
static char base_char [] =
{
'A', '\001', 'a', 'A',
'\001', '\001', 'a', '\001'
};
/* In ansi order: */
static KeySym arrows[] = {XK_Up, XK_Down, XK_Left, XK_Right};
int arrow;

for (arrow = 0; arrow < 4; ++arrow)
{
int mod;
for (mod = 0; mod < 8; ++mod)
{
char string[10];
sprintf (string, "\033[%s%c",
meta_modp[mod] ? "\033" : "",
base_char[mod] + arrow);
XRebindKeysym (thePort->dpy, arrows[arrow],
mod_combos[mod], (mod + 2) / 3,
string, strlen(string));
}
}
}

XMapWindow (thePort->dpy, thePort->window);
}


#ifdef __STDC__
extern void
xio_close_display (void)
#else
extern void
xio_close_display ()
#endif
{
XCloseDisplay (thePort->dpy);
x11_opened = 0;
}

#ifdef __STDC__
static void
xio_flush (void)
#else
static void
xio_flush ()
#endif
{
XFlush (theDisplay);
}




#define _io_open_display xio_open_display
#define _io_redisp xio_redisp
#define _io_repaint xio_repaint
#define _io_repaint_win xio_repaint_win
#define _io_close_display xio_close_display
#define _io_input_avail xio_input_avail
#define _io_scan_for_input xio_scan_for_input
#define _io_wait_for_input xio_wait_for_input
#define _io_read_kbd xio_read_kbd
#define _io_nodelay xio_nodelay
#define _io_getch xio_getch
#define _io_bell xio_bell
#define _io_get_chr xio_get_chr
#define _io_update_status xio_update_status
#define _io_info_msg xio_info_msg
#define _io_error_msg xio_error_msg
#define _io_fix_input xio_fix_input
#define _io_move_cursor xio_move_cursor
#define _io_erase xio_erase
#define _io_insert xio_insert
#define _io_over xio_over
#define _io_flush xio_flush
#define _io_clear_input_before xio_clear_input_before
#define _io_clear_input_after xio_clear_input_after
#define _io_pr_cell_win xio_pr_cell_win
#define _io_hide_cell_cursor xio_hide_cell_cursor
#define _io_display_cell_cursor xio_display_cell_cursor
#define _io_cellize_cursor xio_cellize_cursor
#define _io_inputize_cursor xio_inputize_cursor


#ifdef __STDC__
void
x11_graphics (void)
#else
void
x11_graphics ()
#endif
{
IO_SETUP;
}

#ifdef __STDC__
void
set_x_default_point_size (int l)
#else
void
set_x_default_point_size (l)
int l;
#endif
{
if (l > 4)
{
cell_font_point_size = l;
{
struct cell_gc *cgc = cell_gc (thePort, default_font(), 0);
height_scale = cgc->font->ascent + cgc->font->descent;
width_scale = cgc->font->max_bounds.width;
}
io_set_scr_size (scr_lines, scr_cols);
}
}


#endif /* HAVE_X11_X_H */

oleo-1.3/window.c 644 722 0 101377 5356352130 12210 0ustar lordwheel/* Copyright (C) 1992, 1993 Free Software Foundation, Inc.

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, 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 software; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */

#include
#include "global.h"
#include "window.h"
#include "io-generic.h"
#include "io-abstract.h"
#include "io-utils.h"
#include "io-term.h"
#include "cmd.h"
#include "lists.h"
#include "regions.h"

int scr_lines = 24;
int scr_cols = 80;
#define LINES scr_lines
#define COLS scr_cols


/* These control the layout of input and status lines. */
int user_input = 1; /* As specified (+/- [0-2]). */
int user_status = 2;
int input = 0; /* As row address. */
int status = 1;
int input_rows = 1; /* Size of input and status areas. */
int status_rows = 1;

/* These control the layout of edge labels. */
int label_rows;
int label_emcols;

/* Temporary hacks for displaying multi-line messages. */
/* If this is non-0, it should be displayed instead of
* the windows of cells. This is a temporary hack.
* Use set_info to change this.
*/
struct info_buffer * current_info;

int info_rows; /* The height of one row of info in a */
/* multi-line message. */
int info_line; /* In the current info buffer, the first vis. line */
int info_over; /* Info scrolls left/right as well as up/down */


/* Window borders: */
int default_right_border = 0;
int default_bottom_border = 0;

/* The window list. */
int nwin = 0;
struct window *cwin = 0;
struct window *wins = 0;
static int win_id = 1;


/* Low level window operators. */

#define MIN_WIN_HEIGHT(W) (W->bottom_edge_r \
+ label_rows * (W->flags & WIN_EDGES ? 2 : 1))

#define MIN_WIN_WIDTH(W) (W->right_edge_c \
+ label_emcols * (W->flags & WIN_EDGES ? 6 : 1))
#define MIN_CWIN_HEIGHT MIN_WIN_HEIGHT(cwin)
#define MIN_CWIN_WIDTH MIN_WIN_WIDTH(cwin)


#ifdef __STDC__
static void
do_close_window (int num)
#else
static void
do_close_window (num)
int num;
#endif
{
int n;
struct window *win, *kwin;
int nlf, nrt, nup, nbl;
int klo, kho, kld, khd;
int lo, ho, ld, hd;
struct tmp
{
int l, r, u, b;
}
*tmpptr;

if (nwin == 1)
{
io_error_msg ("Attempt to delete sole ordinary window.");
return;
}
tmpptr = ck_malloc (sizeof (struct tmp) * nwin);

kwin = &wins[num];
nlf = nrt = nup = nbl = 0;
klo = kwin->win_over - kwin->lh_wid;
kho = kwin->win_over + kwin->numc + kwin->right_edge_c - 1;
kld = kwin->win_down - (kwin->lh_wid ? label_rows : 0);
khd = kwin->win_down + kwin->numr + kwin->bottom_edge_r - 1;

for (win = wins; win < &wins[nwin]; win++)
{
lo = win->win_over - win->lh_wid;
ho = win->win_over + win->numc + win->right_edge_c - 1;
ld = win->win_down - (win->lh_wid ? label_rows : 0);
hd = win->win_down + win->numr + win->bottom_edge_r - 1;

/* Match to the left ? */
if (lo == kho + 1)
{
if (ld >= kld && hd <= khd)
tmpptr[nrt++].r = win - wins;
else if (hd >= kld && ld <= khd)
nrt = nwin;
}
else if (ho == klo - 1)
{
if (ld >= kld && hd <= khd)
tmpptr[nlf++].l = win - wins;
else if (hd >= kld && ld <= khd)
nlf = nwin;
}
else if (ld == khd + 1)
{
if (lo >= klo && ho <= kho)
tmpptr[nbl++].b = win - wins;
else if (ho >= kho && lo <= kho)
nbl = nwin;
}
else if (hd == kld - 1)
{
if (lo >= klo && ho <= kho)
tmpptr[nup++].u = win - wins;
else if (ho >= kho && lo <= kho)
nup = nwin;
}

}
if (nrt == 0)
nrt = nwin;
if (nlf == 0)
nlf = nwin;
if (nbl == 0)
nbl = nwin;
if (nup == 0)
nup = nwin;
if (nrt <= nlf && nrt <= nbl && nrt <= nup)
for (n = 0; n < nrt; n++)
{
wins[tmpptr[n].r].numc
+= kwin->lh_wid + kwin->numc + kwin->right_edge_c;
wins[tmpptr[n].r].win_over
-= kwin->lh_wid + kwin->numc + kwin->right_edge_c;
}
else if (nlf <= nbl && nlf <= nup)
for (n = 0; n < nlf; n++)
wins[tmpptr[n].l].numc
+= kwin->lh_wid + kwin->numc + kwin->right_edge_c;
else if (nbl <= nup)
for (n = 0; n < nbl; n++)
{
wins[tmpptr[n].b].numr
+= kwin->numr + (kwin->lh_wid ? 1 : 0) * label_rows
+ kwin->bottom_edge_r;

wins[tmpptr[n].b].win_down
-= kwin->numr + (kwin->lh_wid ? 1 : 0) * label_rows
+ kwin->bottom_edge_r;
}
else
for (n = 0; n < nup; n++)
wins[tmpptr[n].u].numr
+= kwin->numr + (kwin->lh_wid ? 1 : 0) * label_rows;

if (kwin == cwin && kwin != wins)
--cwin;
if (cwin == &wins[nwin - 1])
--cwin;
while (kwin < &wins[nwin])
{
*kwin = kwin[1];
kwin++;
}
--nwin;
io_recenter_all_win ();
return;
}

#ifdef __STDC__
int
win_label_cols (struct window * win, CELLREF hr)
#else
int
win_label_cols (win, hr)
struct window * win;
CELLREF hr;
#endif
{
int lh;

if ((win->flags & WIN_EDGES) == 0)
lh = 0;
#if BITS_PER_CELLREF>8
else if ((win->flags & WIN_PAG_HZ) || hr >= 10000)
lh = 7;
else if (hr >= 1000)
lh = 6;
else if (hr >= 100)
lh = 5;
#else
else if ((win->flags & WIN_PAG_HZ) || hr >= 100)
lh = 5;
#endif
else if (hr > 10)
lh = 4;
else
lh = 3;
lh *= label_emcols;
return lh;
}

#ifdef __STDC__
int
win_label_rows (struct window * win)
#else
int
win_label_rows (win)
struct window * win;
#endif
{
return (win->flags & WIN_EDGES) ? label_rows : 0;
}

#ifdef __STDC__
static void
set_numcols (struct window *win, CELLREF hr)
#else
static void
set_numcols (win, hr)
struct window *win;
CELLREF hr;
#endif
{
int lh = win_label_cols (win, hr);
win->win_over -= win->lh_wid - lh;
win->numc += win->lh_wid - lh;
win->lh_wid = lh;
}


#ifdef __STDC__
static void
page_axis (CELLREF cur, int (*get) (CELLREF), int total,
CELLREF *loP, CELLREF *hiP)
#else
static void
page_axis (cur, get, total, loP, hiP)
CELLREF cur;
int (*get) ();
int total;
CELLREF *loP;
CELLREF *hiP;
#endif
{
CELLREF lo, hi;
int w, ww;

lo = hi = MIN_ROW;
w = (*get) (hi);
for (;;)
{
ww = (*get) (hi + 1);
while (w + ww <= total && hi < MAX_ROW)
{
hi++;
w += ww;
ww = (*get) (hi + 1);
}
if (hi >= cur)
break;
hi++;
lo = hi;
w = ww;
}
if (lo > cur || hi > MAX_ROW)
io_error_msg ("Can't find a non-zero-sized cell page_axis");
*loP = lo;
*hiP = hi;
}


#ifdef __STDC__
static void
recenter_axis (CELLREF cur, int (*get) (CELLREF), int total,
CELLREF *loP, CELLREF *hiP)
#else
static void
recenter_axis (cur, get, total, loP, hiP)
CELLREF cur;
int (*get) ();
int total;
CELLREF *loP;
CELLREF *hiP;
#endif
{
CELLREF lo, hi;
int tot;
int n;
int more;

lo = hi = cur;
n = tot = (*get) (cur);
do
{
if (lo > MIN_ROW && tot + (n = (*get) (lo - 1)) <= total)
{
--lo;
tot += n;
more = 1;
}
else
more = 0;
if (hi < MAX_ROW && tot + (n = (*get) (hi + 1)) <= total)
{
hi++;
tot += n;
more++;
}
}
while (more);
*loP = lo;
*hiP = hi;
}

#ifdef __STDC__
static void
recenter_window (struct window *win)
#else
static void
recenter_window (win)
struct window *win;
#endif
{
if (win->flags & WIN_PAG_VT)
page_axis (win->win_curow, get_scaled_height, win->numr,
&(win->screen.lr), &(win->screen.hr));
else
recenter_axis (win->win_curow, get_scaled_height, win->numr,
&(win->screen.lr), &(win->screen.hr));
set_numcols (win, win->screen.hr);
if (win->flags & WIN_PAG_HZ)
page_axis (win->win_cucol, get_scaled_width, win->numc,
&(win->screen.lc), &(win->screen.hc));
else
recenter_axis (win->win_cucol, get_scaled_width, win->numc,
&(win->screen.lc), &(win->screen.hc));
}


/*
* RESIZE_SCREEN adjusts the windows list after a screen size change.
* It presumes that LINES and COLS are the new values. DR and DC
* are the changes that just occured to those values.
*/
#ifdef __STDC__
static void
resize_screen (int dr, int dc)
#else
static void
resize_screen (dr, dc)
int dr;
int dc;
#endif
{
int x, n;
int lines;
int firstln;
int ncols;
int firstcol;
int old_lines;

if (!nwin)
return;

lines = scr_lines - (!!user_status * status_rows) - input_rows;
old_lines = lines - dr;
firstln = (user_input > 0) * input_rows + (user_status > 0) * status_rows;

/* First, delete windows that will shrink too much. */
cwin->win_curow = curow;
cwin->win_cucol = cucol;
if (dr < 0)
for (x = 0; x < nwin; x++)
{
int rlow =
(wins[x].win_down - (wins[x].lh_wid ? label_rows : 0) - firstln);
int rhi = ((wins[x].win_down + wins[x].numr + wins[x].bottom_edge_r)
- firstln);
int sqbelow = dr * rlow;
int sqtohere = dr * rhi;
sqbelow /= old_lines;
sqtohere /= old_lines;
if (wins[x].numr <= sqbelow - sqtohere)
{
do_close_window (x);
x--;
}
}
for (x = 0; x < nwin; ++x)
{
int rlow =
(wins[x].win_down - (wins[x].lh_wid ? label_rows : 0) - firstln);
int rhi = ((wins[x].win_down + wins[x].numr + wins[x].bottom_edge_r)
- firstln);
int sqbelow = dr * rlow;
int sqtohere = dr * rhi;
sqbelow /= old_lines;
sqtohere /= old_lines;
wins[x].win_down += sqbelow;
wins[x].numr += sqtohere - sqbelow;
}

/* then columns */
firstcol = 0;
ncols = COLS;
ncols -= dc;

/* First, delete windows that will shrink too much. */
if (dc < 0)
for (x = 0; x < nwin; x++)
{
int clow = (wins[x].win_over - wins[x].lh_wid) - firstcol;
int chi = (wins[x].win_over + wins[x].numc + wins[x].right_edge_c
- firstcol);
int sqbelow = dc * clow;
int sqtohere = dc * chi;
sqbelow /= ncols;
sqtohere /= ncols;
if (wins[x].numc <= sqbelow - sqtohere)
{
do_close_window (x);
x--;
}
}
for (x = 0; x < nwin; ++x)
{
int clow = (wins[x].win_over - wins[x].lh_wid) - firstcol;
int chi = (wins[x].win_over + wins[x].numc + wins[x].right_edge_c
- firstcol);
int sqbelow = dc * clow;
int sqtohere = dc * chi;
sqbelow /= ncols;
sqtohere /= ncols;
wins[x].win_over += sqbelow;
wins[x].numc += sqtohere - sqbelow;
}
for (n = 0; n < nwin; n++)
recenter_window (&wins[n]);
io_repaint ();
}

#ifdef __STDC__
static void
shift_linked_window (long dn, long ov)
#else
static void
shift_linked_window (dn, ov)
long dn;
long ov;
#endif
{
struct window *win;

win = cwin;
while (win->link != -1)
{
win = &wins[win->link];
if (win == cwin) /* Loop check! */
return;
if ((win->flags & WIN_LCK_VT) == 0)
win->win_curow += dn;
if ((win->flags & WIN_LCK_HZ) == 0)
win->win_cucol += ov;
if (win->win_curow < win->screen.lr || win->win_curow > win->screen.hr
|| win->win_cucol < win->screen.lc || win->win_cucol > win->screen.hc)
recenter_window (win);
}
}


#ifdef __STDC__
static void
find_nonzero (CELLREF *curp, CELLREF lo, CELLREF hi,
int (*get) (CELLREF))
#else
static void
find_nonzero (curp, lo, hi, get)
CELLREF *curp;
CELLREF lo;
CELLREF hi;
int (*get) ();
#endif
{
CELLREF cc;
int n;

cc = *curp;

if (cc < hi)
{
cc++;
while ((n = (*get) (cc)) == 0)
{
if (cc == hi)
break;
cc++;
}
if (n)
{
*curp = cc;
return;
}
}
if (cc > lo)
{
--cc;
while ((n = (*get) (cc)) == 0)
{
if (cc == lo)
break;
--cc;
}
if (n)
{
*curp = cc;
return;
}
}
}

#ifdef __STDC__
static int
scroll_axis (CELLREF cur, int over, int total, int (*get) (CELLREF),
CELLREF *ret1, CELLREF *ret2, int *offp)
#else
static int
scroll_axis (cur, over, total, get, ret1, ret2, offp)
CELLREF cur;
int over;
int total;
int (*get) ();
CELLREF *ret1;
CELLREF *ret2;
int *offp;
#endif
{
int tot;

int inc;
CELLREF fini;
int num;
CELLREF p1, p2;
int n;

inc = (over > 0 ? 1 : -1);
fini = over > 0 ? MAX_ROW : MIN_ROW;
num = over > 0 ? over : -over;

if (inc > 0 ? *ret2 == MAX_ROW : *ret1 == MIN_ROW)
return 1;
p1 = inc > 0 ? *ret2 + 1 : *ret1 - 1;
p2 = p1;
for (;;)
{
--num;
tot = (*get) (p1);
while (p2 != fini && tot + (n = (*get) (p2 + inc)) <= total)
{
p2 += inc;
tot += n;
}
if (!num || p2 == fini)
break;
}
if (num)
return 1;
while (tot + (n = (*get) (p1 - inc)) <= total)
{
p1 -= inc;
tot += n;
if (inc > 0)
(*offp)++;
}
if (p1 > p2)
{
*ret1 = p2;
*ret2 = p1;
}
else
{
*ret1 = p1;
*ret2 = p2;
}
return 0;
}

#ifdef __STDC__
static int
page_scroll_axis (CELLREF cur, int over, int total, int (*get) (CELLREF),
CELLREF *ret1, CELLREF *ret2, int *offp)
#else
static int
page_scroll_axis (cur, over, total, get, ret1, ret2, offp)
CELLREF cur;
int over;
int total;
int (*get) ();
CELLREF *ret1;
CELLREF *ret2;
int *offp;
#endif
{
int n_over;
CELLREF lo, hi;
int tot;
int ww;

n_over = 0;
lo = hi = MIN_ROW;
tot = (*get) (hi);
for (;;)
{
while (hi < MAX_ROW && tot + (ww = (*get) (hi + 1)) <= total)
{
hi++;
tot += ww;
}
if (hi >= cur)
break;
hi++;
n_over++;
lo = hi;
tot = ww;
}
n_over += over;
if (n_over < 0)
return 1;

lo = hi = MIN_ROW;
tot = (*get) (hi);
for (;;)
{
while (hi < MAX_ROW && tot + (ww = (*get) (hi + 1)) <= total)
{
hi++;
tot += ww;
}
if (!n_over || hi == MAX_ROW)
break;
--n_over;
hi++;
lo = hi;
tot = ww;
}
if (hi == MAX_ROW && n_over)
return 1;
*ret1 = lo;
*ret2 = hi;
return 0;
}



/* External window interface */

#ifdef __STDC__
void
io_set_label_size (int r, int c)
#else
void
io_set_label_size (r, c)
int r;
int c;
#endif
{
/* fixme */
}

#ifdef __STDC__
void
io_set_scr_size (int lines, int cols)
#else
void
io_set_scr_size (lines, cols)
int lines;
int cols;
#endif
{
int dl = lines - scr_lines;
int dc = cols - scr_cols;

scr_lines = lines;
scr_cols = cols;

resize_screen (dl, dc);
}

#ifdef __STDC__
void
io_set_input_rows (int n)
#else
void
io_set_input_rows (n)
int n;
#endif
{
input_rows = n;
io_set_input_status (user_input, user_status, 1);
}

#ifdef __STDC__
void
io_set_status_rows (int n)
#else
void
io_set_status_rows (n)
int n;
#endif
{
status_rows = n;
io_set_input_status (user_input, user_status, 1);
}

#ifdef __STDC__
void
io_set_input_status (int inp, int stat, int redraw)
#else
void
io_set_input_status (inp, stat, redraw)
int inp;
int stat;
int redraw;
#endif
{
int inpv = inp < 0 ? -inp : inp;
int inpsgn = inp == inpv ? 1 : -1;
int statv = stat < 0 ? -stat : stat;
int statsgn = stat == statv ? 1 : -1;
int new_ui;
int new_us;
int new_inp;
int new_stat;

if (inpv == 0 || inpv > 2)
io_error_msg ("Bad input location %d; it should be +/- 1, or 2", inp);
else if (statv > 2)
io_error_msg ("Bad status location %d; it should be +/- 0, 1, or 2",
inp);
else
{
new_ui = inp;
new_us = stat;
if (inpsgn != statsgn)
if (inpsgn > 0)
{
new_inp = 0;
new_stat = LINES - status_rows;
}
else
{
new_inp = LINES - input_rows;
new_stat = 0;
}
else
{
if (inpv > statv)
{
new_inp = user_status ? status_rows : 0;
new_stat = 0;
}
else
{
new_inp = 0;
new_stat = input_rows;
}
if (inpsgn < 0)
{
new_stat = LINES - status - status_rows;
new_inp = LINES - input - input_rows;
}
}
if (redraw)
{
int vchange =
(((new_ui > 0 ? input_rows : 0)
+ (new_us > 0 ? status_rows : 0))
- ((user_input > 0 ? input_rows : 0)
+ (user_status > 0 ? status_rows : 0)));
int grow = (user_status
? (new_us ? 0 : status_rows)
: (new_us ? -status_rows : 0));
int cell_top =
((user_status > 0 ? status_rows : 0)
+ (user_input > 0 ? input_rows : 0));

if (grow < 0)
{
int x;
re:
for (x = 0; x < nwin; ++x)
{
int top = wins[x].win_down - win_label_rows(&wins[x]);
if (cell_top == top && (wins[x].numr <= -grow))
{
do_close_window (x);
goto re;
}
}
}

if (grow)
{
int x;
for (x = 0; x < nwin; ++x)
{
int top =
wins[x].win_down - win_label_rows (&wins[x]);
if (cell_top == top)
wins[x].numr += vchange;
}
}
if (vchange)
{
int x;
for (x = 0; x < nwin; ++x)
wins[x].win_down += vchange;
}
io_repaint ();
}
user_input = new_ui;
user_status = new_us;
input = new_inp;
status = new_stat;
}
}

#ifdef __STDC__
void
io_set_cwin (struct window *win)
#else
void
io_set_cwin (win)
struct window *win;
#endif
{
io_hide_cell_cursor ();
cwin->win_curow = curow;
cwin->win_cucol = cucol;
cwin = win;
curow = cwin->win_curow;
cucol = cwin->win_cucol;
io_display_cell_cursor ();
}


#ifdef __STDC__
void
io_pr_cell (CELLREF r, CELLREF c, CELL *cp)
#else
void
io_pr_cell (r, c, cp)
CELLREF r;
CELLREF c;
CELL *cp;
#endif
{
struct window *win;

for (win = wins; win < &wins[nwin]; win++)
{
if (r < win->screen.lr || r > win->screen.hr
|| c < win->screen.lc || c > win->screen.hc)
continue;
io_pr_cell_win (win, r, c, cp);
}
}

#ifdef __STDC__
void
io_redo_region (struct rng * rng)
#else
void
io_redo_region (rng)
struct rng * rng;
#endif
{
CELL * cp;
CELLREF r, c;
find_cells_in_range (rng);
cp = next_row_col_in_range (&r, &c);
while (cp)
{
io_pr_cell (r, c, cp);
cp = next_row_col_in_range (&r, &c);
}
}

/* Create a new window by splitting the current one. */
#ifdef __STDC__
void
io_win_open (int hv, int where)
#else
void
io_win_open (hv, where)
int hv;
int where;
#endif
{
int tmp;
struct window *win;

if ( (!hv
&& (where < MIN_CWIN_WIDTH
|| (cwin->numc + cwin->lh_wid + cwin->right_edge_c - where
< MIN_CWIN_WIDTH)))
|| (hv
&& (where < MIN_CWIN_HEIGHT
|| (cwin->numr + cwin->bottom_edge_r
+ (cwin->lh_wid ? label_rows : 0) - where
< MIN_CWIN_HEIGHT))))
{
io_error_msg ("Window won't fit!");
return;
}

nwin++;
tmp = cwin - wins;
wins = ck_realloc (wins, nwin * sizeof (struct window));
win = &wins[nwin - 1];
cwin = &wins[tmp];
win->id = win_id++;
win->bottom_edge_r = cwin->bottom_edge_r;
win->right_edge_c = cwin->right_edge_c;
/* set_numcols will take care of fixing win_over if edges are on. */
win->win_over = cwin->win_over + (hv ? 0 : where) - cwin->lh_wid;
win->win_down = cwin->win_down + (hv ? where : 0);
win->flags = cwin->flags;
win->link = -1;
win->lh_wid = 0;
win->win_slops = 0;
win->numc = cwin->numc + cwin->lh_wid + (hv ? 0 : -where);
win->numr = cwin->numr + (hv ? -where : 0);
win->win_curow = curow;
win->win_cucol = cucol;
set_numcols (win, curow);
cwin->numc -= (hv ? 0 : win->numc + win->lh_wid + win->right_edge_c);
cwin->numr -=
(hv ? win->numr + (win->lh_wid ? label_rows : 0) + win->bottom_edge_r
: 0);
cwin->win_curow = curow;
cwin->win_cucol = cucol;
io_hide_cell_cursor ();
win = cwin;
cwin = &wins[nwin - 1];
recenter_window (cwin);
recenter_window (win);
io_display_cell_cursor ();
io_repaint ();
}

#ifdef __STDC__
void
io_win_close (struct window *win)
#else
void
io_win_close (win)
struct window *win;
#endif
{
do_close_window (win - wins);
}

#ifdef __STDC__
void
io_move_cell_cursor (CELLREF rr, CELLREF cc)
#else
void
io_move_cell_cursor (rr, cc)
CELLREF rr;
CELLREF cc;
#endif
{
if (cwin->link != -1)
shift_linked_window ((long) rr - curow, (long) cc - cucol);
if (rr < cwin->screen.lr || rr > cwin->screen.hr
|| cc < cwin->screen.lc || cc > cwin->screen.hc)
{
cwin->win_curow = curow = rr;
cwin->win_cucol = cucol = cc;
recenter_window (cwin);
io_repaint_win (cwin);
if (cwin->link > 0)
io_repaint_win (&wins[cwin->link]);
}
else
{
io_hide_cell_cursor ();
curow = rr;
cucol = cc;
io_display_cell_cursor ();
io_update_status ();
}
if (get_scaled_width (cucol) == 0)
find_nonzero (&cucol, cwin->screen.lc, cwin->screen.hc, get_scaled_width);
if (get_scaled_height (curow) == 0)
find_nonzero (&curow, cwin->screen.lr, cwin->screen.hr, get_scaled_height);
}

#ifdef __STDC__
void
io_shift_cell_cursor (int dirn, int repeat)
#else
void
io_shift_cell_cursor (dirn, repeat)
int dirn;
int repeat;
#endif
{
CELLREF c;
CELLREF r;
int w = 0;
int over, down;

over = colmagic[dirn] * repeat;
down = rowmagic[dirn] * repeat;
if (over > 0)
{
c = cucol;
while (c < MAX_COL && over-- > 0)
{
c++;
while ((w = get_scaled_width (c)) == 0 && c < MAX_COL)
c++;
}
if (over > 0 || c == cucol || w == 0)
{
io_error_msg ("Can't go right");
return;
}
}
else if (over < 0)
{
c = cucol;
while (c > MIN_COL && over++ < 0)
{
--c;
while ((w = get_scaled_width (c)) == 0 && c > MIN_COL)
--c;
}
if (over < 0 || c == cucol || w == 0)
{
io_error_msg ("Can't go left");
return;
}
}
else
c = cucol;

if (down > 0)
{
r = curow;
while (r < MAX_ROW && down-- > 0)
{
r++;
while ((w = get_scaled_height (r)) == 0 && r < MAX_ROW)
r++;
}
if (down > 0 || r == curow || w == 0)
{
io_error_msg ("Can't go down");
return;
}
}
else if (down < 0)
{
r = curow;
while (r > MIN_ROW && down++ < 0)
{
--r;
while ((w = get_scaled_height (r)) == 0 && r > MIN_ROW)
--r;
}
if (down < 0 || r == curow || w == 0)
{
io_error_msg ("Can't go up");
return;
}
}
else
r = curow;

io_move_cell_cursor (r, c);
}

#ifdef __STDC__
void
io_scroll_cell_cursor (int magic, int repeat)
#else
void
io_scroll_cell_cursor (magic, repeat)
int magic;
int repeat;
#endif
{
int off_dn, off_rt;

struct rng s;
CELLREF cr, cc;
int over, down;
int ret;

over = colmagic[magic];
down = rowmagic[magic];

s.lr = cwin->screen.lr;
s.hr = cwin->screen.hr;
if (down)
{
off_dn = curow - cwin->screen.lr;
if (cwin->flags & WIN_PAG_VT)
ret = page_scroll_axis
(curow, down, cwin->numr, get_scaled_height, &(s.lr), &(s.hr), &off_dn);
else
ret = scroll_axis
(curow, down, cwin->numr, get_scaled_height, &(s.lr), &(s.hr), &off_dn);
cr = (off_dn > s.hr - s.lr) ? s.hr : s.lr + off_dn;
if (ret)
io_error_msg ("Can't scroll that far");
set_numcols (cwin, s.hr);
}
else
cr = curow;

off_rt = cucol - cwin->screen.lc;

s.lc = cwin->screen.lc;
s.hc = cwin->screen.hc;
if (over)
{
if (cwin->flags & WIN_PAG_HZ)
ret = page_scroll_axis
(cucol, over, cwin->numc, get_scaled_width, &(s.lc), &(s.hc), &off_rt);
else
ret = scroll_axis (cucol, over, cwin->numc, get_scaled_width, &(s.lc), &(s.hc), &off_rt);
if (ret)
io_error_msg ("Can't scroll that far");
cc = (s.hc - s.lc < off_rt) ? s.hc : s.lc + off_rt;
}
else if ((cwin->flags & WIN_PAG_HZ) == 0)
/* ... */
cc = cucol;
else
cc = cucol;

/*fixme The original has a big #if 0 here. */
if (cwin->link != -1)
shift_linked_window ((long) cr - curow, (long) cc - cucol);

cwin->screen = s;
curow = cr;
cucol = cc;

if (get_scaled_width (cucol) == 0)
find_nonzero (&cucol, cwin->screen.lc, cwin->screen.hc, get_scaled_width);
if (get_scaled_height (curow) == 0)
find_nonzero (&curow, cwin->screen.lr, cwin->screen.hr, get_scaled_height);

io_repaint_win (cwin);
if (cwin->link > 0)
io_repaint_win (&wins[cwin->link]);
}

#ifdef __STDC__
void
io_recenter_cur_win (void)
#else
void
io_recenter_cur_win ()
#endif
{
cwin->win_curow = curow;
cwin->win_cucol = cucol;
recenter_window (cwin);
io_repaint_win (cwin);
if (cwin->link > 0)
io_repaint_win (&wins[cwin->link]);
}

#ifdef __STDC__
void
io_recenter_all_win (void)
#else
void
io_recenter_all_win ()
#endif
{
int n;
if (!nwin)
return;
cwin->win_curow = curow;
cwin->win_cucol = cucol;
for (n = 0; n < nwin; n++)
recenter_window (&wins[n]);
io_repaint ();
}

#ifdef __STDC__
void
io_set_win_flags (struct window *w, int f)
#else
void
io_set_win_flags (w, f)
struct window *w;
int f;
#endif
{
if ((f & WIN_EDGES) && !(w->flags & WIN_EDGES))
{
if (w->numr < 2 || w->numc < 6)
io_error_msg ("Edges wouldn't fit!");
w->win_down++;
w->numr--;
set_numcols (w, w->screen.hr);
}
else if (!(f & WIN_EDGES) && (w->flags & WIN_EDGES))
{
w->win_over -= w->lh_wid;
w->numc += w->lh_wid;
w->lh_wid = 0;
w->win_down--;
w->numr++;
}
w->flags = f;
}

#ifdef __STDC__
void
io_write_window_config (struct line * out)
#else
void
io_write_window_config (out)
struct line *out;
#endif
{
int n;
char buf[90];
struct line scratch;
scratch.alloc = 0;
scratch.buf = 0;

cwin->win_curow = curow;
cwin->win_cucol = cucol;
sprint_line (out, "O;status %d\n", user_status);
if (nwin > 1)
{
/* ... *//* fixme ? */
}
for (n = 0; n < nwin; n++)
{
buf[0] = '\0';
if (wins[n].flags & WIN_LCK_HZ)
strcat (buf, ",lockh");
if (wins[n].flags & WIN_LCK_VT)
strcat (buf, ",lockv");
if (wins[n].flags & WIN_PAG_HZ)
strcat (buf, ",pageh");
if (wins[n].flags & WIN_PAG_VT)
strcat (buf, ",pagev");
if (wins[n].flags & WIN_EDGE_REV)
strcat (buf, ",standout");
if ((wins[n].flags & WIN_EDGES) == 0)
strcat (buf, ",noedges");
scratch = *out;
out->alloc = 0;
out->buf = 0;
sprint_line (out, "%sW;N%d;A%u %u;C%d %d %d;O%s\n",
scratch.buf, n + 1, wins[n].win_curow, wins[n].win_cucol,
7, 0, 7, buf + 1);
free (scratch.buf);
}
}

#ifdef __STDC__
void
io_read_window_config (char * line)
#else
void
io_read_window_config (line)
char *line;
#endif
{
int wnum = 0;
char *text;
CELLREF nrow = NON_ROW, ncol = NON_COL;
char *split = 0;
char *opts = 0;
struct window *win;

text = line;
for (;;)
{
switch (*text++)
{
/* Window Number */
case 'N':
wnum = astol (&text);
break;
/* Cursor At */
case 'A':
nrow = astol (&text);
ncol = astol (&text);
break;
/* JF: Window options */
case 'O':
opts = text;
while (*text && *text != ';')
text++;
break;
/* Split into two windows */
case 'S':
split = text;
while (*text && *text != ';')
text++;
break;
/* Set Colors NOT supported */
case 'C':
while (*text && *text != ';')
text++;
break;
/* Alternate border NOT supported. . . */
case 'B':
break;
default:
--text;
break;
}
if (*text == '\0' || *text == '\n')
break;
if (*text != ';')
{
char *bad;

bad = text;
while (*text && *text != ';')
text++;
if (*text)
*text++ = '\0';
io_error_msg ("Unknown SYLK window cmd: %s", bad);
if (!*text)
break;
}
else
*text++ = '\0';
}
if (wnum < 1 || wnum > nwin)
{
io_error_msg ("Window %d out of range in SYLK line %s", wnum, line);
return;
}
--wnum;
win = &wins[wnum];
if (nrow != NON_ROW)
{
win->win_curow = nrow;
win->win_cucol = ncol;
if (win == cwin)
{
curow = nrow;
cucol = ncol;
}
recenter_window (win);
}
if (split)
{
int hv = 0;
int where;
int link;
struct window *new;

switch (*split++)
{
case 'H':
case 'h':
hv = 1;
break;
case 'v':
case 'V':
hv = 0;
break;
case 't':
case 'T':
io_error_msg ("Window split titles not supported");
return;
default:
break;
}
if (*split == 'L')
{
link = wnum;
split++;
}
else
link = -1;

where = astol (&split);

if (hv ? where >= win->numr : where >= win->numc)
io_error_msg ("Can't split window: screen too small");

nwin++;
wins = ck_realloc (wins, nwin * sizeof (struct window));
cwin = wins;
win = &wins[wnum];
new = &wins[nwin - 1];

win->numc -= (hv ? 0 : where);
win->numr -= (hv ? where : 0);
win->win_curow = curow;
win->win_cucol = cucol;

new->flags = WIN_EDGES | WIN_EDGE_REV; /* Mplan defaults */
new->lh_wid = 0; /* For now */
new->link = link;

new->win_over = win->win_over + (hv ? -win->lh_wid : win->numc);
new->win_down = win->win_down + (hv ? win->numr + 1 : 0);
new->numc = (hv ? win->numc + win->lh_wid : where);
new->numr = (hv ? where - 1 : win->numr);
new->win_curow = curow;
new->win_cucol = cucol;
set_numcols (new, curow);
recenter_window (win);
recenter_window (new);
}
if (opts)
{
char *np;
while (np =(char *) index (opts, ','))
{
*np = '\0';
set_options (opts);
*np++ = ';';
opts = np;
}
if (np = (char *)rindex (opts, '\n'))
*np = '\0';
set_options (opts);
}
}



static struct mouse_event *current_mouse;
static struct mouse_event *free_mouse;
static int mouse_id = 0;

#ifdef __STDC__
static void
init_mouse (void)
#else
static void
init_mouse ()
#endif
{
current_mouse = free_mouse =
(struct mouse_event *) ck_malloc (sizeof (struct mouse_event));
free_mouse->next = free_mouse;
free_mouse->prev = free_mouse;
}

static int mouse_location ();

#ifdef __STDC__
int
enqueue_mouse_event (int r, int c, int button, int downp)
#else
int
enqueue_mouse_event (r, c, button, downp)
int r;
int c;
int button;
int downp;
#endif
{
struct mouse_event *m = free_mouse;
if (m->next == current_mouse)
{
m->next =
(struct mouse_event *) ck_malloc (sizeof (struct mouse_event));
m->next->prev = m;
m->next->next = current_mouse;
current_mouse->prev = m->next;
m->seq = mouse_id++;
if (m->seq > 255)
panic ("Too many mouse events enqueued.");
}
free_mouse = m->next;
m->row = r;
m->col = c;
m->button = button;
m->downp = downp;
m->location = mouse_location (&m->r, &m->c, m);
return m->seq;
}

#ifdef __STDC__
void
dequeue_mouse_event (struct mouse_event *out, int seq)
#else
void
dequeue_mouse_event (out, seq)
struct mouse_event *out;
int seq;
#endif
{
free_mouse->seq = seq;
while (current_mouse->seq != seq)
current_mouse = current_mouse->next;
if (current_mouse == free_mouse)
{
out->seq = seq;
out->button = MOUSE_QERROR;
return;
}
*out = *current_mouse;
out->next = out->prev = 0;
current_mouse = current_mouse->next;
}



#ifdef __STDC__
void
io_init_windows (int sl, int sc, int ui, int us, int ir, int sr,
int lr, int lc)
#else
void
io_init_windows (sl, sc, ui, us, ir, sr, lr, lc)
int sl, sc;
int ui, us;
int ir, sr;
int lr, lc;
#endif
{
print_width = 80; /* default ascii print width */
scr_lines = sl;
scr_cols = sc;
input_rows = ir;
status_rows = sr;
label_rows = lr;
label_emcols = lc;
io_set_input_status (ui, us, 0);
nwin = 1;
wins = cwin = ck_malloc (sizeof (struct window));
wins->id = win_id++;
wins->win_over = 0; /* This will be fixed by a future set_numcols */
wins->win_down = (label_rows
+ (user_status > 0) * status_rows
+ (user_input > 0) * input_rows);
wins->flags = WIN_EDGES | WIN_EDGE_REV;
wins->numr = (scr_lines - label_rows - !!user_status * status_rows
- input_rows - default_bottom_border);
wins->numc = scr_cols - default_right_border;
wins->bottom_edge_r = default_bottom_border;
wins->right_edge_c = default_right_border;
wins->link = -1;
wins->lh_wid = 0;
wins->win_curow = MIN_ROW;
wins->win_cucol = MIN_COL;
wins->win_slops = 0;
init_mouse ();
}

#ifdef __STDC__
static int
mouse_location (CELLREF *cr, CELLREF *cc, struct mouse_event *ev)
#else
static int
mouse_location (cr, cc, ev)
CELLREF *cr;
CELLREF *cc;
struct mouse_event *ev;
#endif
{
int n;
if (ev->row >= input && ev->row <= input + input_rows)
return MOUSE_ON_INPUT;
if (user_status && ev->row >= status
&& ev->row <= status + status_rows)
return MOUSE_ON_STATUS;
for (n = 0; n < nwin; ++n)
{
struct window *w = &wins[n];
if (ev->row >= w->win_down
&& ev->row < w->win_down + w->numr
&& ev->col < w->win_over + w->numc
&& ev->col >= w->win_over)
{
int row_off = ev->row - w->win_down;
int col_off = ev->col - w->win_over;
int rh = 0;
int cw = 0;
CELLREF c, r;
for (c = w->screen.lc; c <= w->screen.hc; ++c)
if ((cw += get_scaled_width (c)) > col_off)
break;
*cc = c;
for (r = w->screen.lr; r <= w->screen.hr; ++r)
if ((rh += get_scaled_height (r)) > row_off)
break;
*cr = r;
return n;
}
}
return MOUSE_ON_EDGE;
}

oleo-1.3/io-edit.c 644 722 0 37203 5356122527 12214 0ustar lordwheel/* Copyright (C) 1992, 1993 Free Software Foundation, Inc.

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, 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 software; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */




#include "funcdef.h"
#include
#include
#include
#include

#undef NULL

#include "sysdef.h"
#include "global.h"
#include "cell.h"
#include "io-utils.h"
#include "io-edit.h"
#include "io-abstract.h"
#include "io-generic.h"
#include "cmd.h"
#include "format.h"
#include "lists.h"
#include "regions.h"


/* Shorthand */

#define cursor the_cmd_arg.cursor
#define text the_cmd_arg.text
#define do_prompt the_cmd_arg.do_prompt
#define is_set the_cmd_arg.is_set
#define overwrite the_cmd_arg.overwrite



/* Editting primitives
*
* Commands that edit arguments to other commands should work by changing
* the string stored in the_cmd_arg.text. These functions edit that string
* and correctly update the display.
*/

#ifdef __STDC__
int
check_editting_mode (void)
#else
int
check_editting_mode ()
#endif
{
if (!the_cmd_frame->cmd || cur_arg >= cmd_argc || !do_prompt || is_set)
{
io_error_msg ("Command '%s' is not appropriate now.",
cur_cmd->func_name);
/* not reached */
}
return 0;
}

/* Set the currently-being-editted line.
*
* When this function is called, it indicates that some argument
* is being read interactively from the user. That fact is recorded
* in the command frame because it relevant to error handling.
* (See cmd_error in cmd.c)
*
*/
#ifdef __STDC__
void
begin_edit (void)
#else
void
begin_edit ()
#endif
{
topclear = 0;
the_cmd_frame->complex_to_user = 1;
io_fix_input ();
}

#ifdef __STDC__
void
setn_edit_line (char * str, int len)
#else
void
setn_edit_line (str, len)
char * str;
int len;
#endif
{
setn_line (&text, str, len);
cursor = len;
}

#ifdef __STDC__
void
toggle_overwrite (int set, int setting)
#else
void
toggle_overwrite (set, setting)
int set;
int setting;
#endif
{
if (!set)
overwrite = !overwrite;
else
overwrite = (setting > 0);
}

#ifdef __STDC__
void
beginning_of_line (void)
#else
void
beginning_of_line ()
#endif
{
if (check_editting_mode ())
return;
cursor = 0;
io_move_cursor ();
}


#ifdef __STDC__
void
end_of_line (void)
#else
void
end_of_line ()
#endif
{
if (check_editting_mode ())
return;
cursor = strlen (text.buf);
io_move_cursor ();
}

#ifdef __STDC__
void
backward_char (int n)
#else
void
backward_char (n)
int n;
#endif
{
if (check_editting_mode ())
return;
if (n < 0)
forward_char (-n);
else
{
char * error = 0;
if (cursor < n)
{
error = "Beginning of buffer.";
cursor = 0;
}
else
cursor -= n;
io_move_cursor ();
if (error)
io_error_msg (error); /* Doesn't return. */
}
}

#ifdef __STDC__
void
backward_word (int n)
#else
void
backward_word (n)
#endif
{
if (check_editting_mode ())
return;
if (n < 0)
forward_word (-n);
else
{
if (cursor == strlen (text.buf))
--cursor;
while (n)
{
while (cursor
&& !isalnum (text.buf[cursor]))
--cursor;
while (cursor
&& isalnum (text.buf[cursor]))
--cursor;
--n;
}
io_move_cursor ();
}
}


#ifdef __STDC__
void
forward_char (int n)
#else
void
forward_char (n)
int n;
#endif
{
if (check_editting_mode ())
return;
if (n < 0)
backward_char (-n);
else
{
char * error = 0;
int len = strlen(text.buf);
if ((cursor + n) >= len)
{
error = "End of buffer.";
cursor = len;
}
else
cursor += n;
io_move_cursor ();
if (error)
io_error_msg (error); /* Doesn't return. */
}
}


#ifdef __STDC__
void
goto_char (int n)
#else
void
goto_char (n)
int n;
#endif
{
if ((n < 0) || (n > (strlen (text.buf) + 1)))
io_error_msg ("Char out of range (%d)", n);
cursor = n;
io_move_cursor ();
}

#ifdef __STDC__
void
forward_word (int n)
#else
void
forward_word (n)
int n;
#endif
{
if (check_editting_mode ())
return;
if (n < 0)
backward_word (-n);
else
{
int len = strlen (text.buf);
while (n)
{
while ((cursor < len)
&& !isalnum (text.buf[cursor]))
++cursor;
while ((cursor < len)
&& isalnum (text.buf[cursor]))
++cursor;
--n;
}
io_move_cursor ();
}
}


#ifdef __STDC__
static void
erase (int len)
#else
static void
erase (len)
int len;
#endif
{
if (check_editting_mode ())
return;
else
{
strcpy (&text.buf[cursor],
&text.buf[cursor + len]);
io_erase (len);
}
}


#ifdef __STDC__
void
backward_delete_char (int n)
#else
void
backward_delete_char (n)
#endif
{
if (check_editting_mode ())
return;
if (n < 0)
delete_char (-n);
else
{
char * error = 0;
if (cursor < n)
{
error = "Beginning of buffer.";
n = cursor;
}
cursor -= n;
erase (n);
if (error)
io_error_msg (error); /* Doesn't return. */
}
}


#ifdef __STDC__
void
backward_delete_word (int n)
#else
void
backward_delete_word (n)
#endif
{
if (check_editting_mode ())
return;
else
{
int at = cursor;
while (n)
{
while (cursor
&& !isalnum (text.buf[cursor]))
--cursor;

while (cursor
&& isalnum (text.buf[cursor - 1]))
--cursor;
--n;
}
erase (at - cursor);
}
}


#ifdef __STDC__
void
delete_to_start(void)
#else
void
delete_to_start()
#endif
{
if (check_editting_mode ())
return;
else
{
int at = cursor;
cursor = 0;
erase (at);
}
}


#ifdef __STDC__
void
delete_char (int n)
#else
void
delete_char (n)
int n;
#endif
{
if (check_editting_mode ())
return;
if (n < 0)
backward_delete_char (-n);
else
{
char * error = 0;
int len = strlen (text.buf);
if (cursor + n > len)
{
error = "End of buffer.";
n = len - cursor;
}
erase (n);
if (error)
io_error_msg (error); /* Doesn't return. */
}
}

#ifdef __STDC__
void
delete_word (int n)
#else
void
delete_word (n)
int n;
#endif
{
if (check_editting_mode ())
return;
if (n < 0)
backward_delete_word (-n);
else
{
int len = strlen (text.buf);
int erase_len = 0;
while (n)
{
while (((cursor + erase_len) < len)
&& !isalnum (text.buf[(cursor + erase_len)]))
++erase_len;
while (((cursor + erase_len) < len)
&& isalnum (text.buf[(cursor + erase_len)]))
++erase_len;
--n;
}
erase (erase_len);
}
}


#ifdef __STDC__
void
kill_line(void)
#else
void
kill_line()
#endif
{
if (check_editting_mode ())
return;
else
{
int len = strlen (text.buf);
erase (len - cursor);
}
}

#ifdef __STDC__
void
insert_string (char * str, int len)
#else
void
insert_string (str, len)
char * str;
int len;
#endif
{
if (check_editting_mode ())
return;
splicen_line (&text, str, len, cursor);
io_insert (len);
cursor += len;
}

#ifdef __STDC__
void
over_string (char * str, int len)
#else
void
over_string (str, len)
char * str;
int len;
#endif
{
if (check_editting_mode ())
return;
if (cursor + len > strlen (text.buf))
{
catn_line (&text, str + text.alloc - cursor,
len - (text.alloc - cursor));
len = text.alloc - cursor;
}
bcopy (str, text.buf + cursor, len);
io_over (str, len);
cursor += len;
}

#ifdef __STDC__
void
put_string (char * str, int len)
#else
void
put_string (str, len)
char * str;
int len;
#endif
{
if (check_editting_mode ())
return;
(overwrite ? over_string : insert_string) (str, len);
}



/* Higher Level editting commands. */

#ifdef __STDC__
void
insert_cell_expression (void)
#else
void
insert_cell_expression ()
#endif
{
if (check_editting_mode ())
return;
else
{
CELL *cp;
char * in_str;
if (!(cp = find_cell (curow, cucol)))
return;
in_str = decomp (curow, cucol, cp);
put_string (in_str, strlen(in_str));
decomp_free ();
}
}


#ifdef __STDC__
void
insert_cell_value(void)
#else
void
insert_cell_value()
#endif
{
if (check_editting_mode ())
return;
else
{
char * in_str;
in_str = cell_value_string (curow, cucol);
put_string (in_str, strlen(in_str));
}
}

#ifdef __STDC__
void
insert_rel_ref(void)
#else
void
insert_rel_ref()
#endif
{
if (check_editting_mode ())
return;
else
{
char vbuf[50];
char * in_str;
if (a0)
{
if (mkrow != NON_ROW)
{
struct rng r;
set_rng (&r, curow, cucol, mkrow, mkcol);
in_str = range_name (&r);
}
else
in_str = cell_name (curow, cucol);
}
else
{
if (mkrow != NON_ROW)
{
switch (((curow == setrow) << 3)
+ ((mkrow == setrow) << 2)
+ ((cucol == setcol) << 1)
+ (mkcol == setcol))
{
case 0:
case 1:
case 2:
case 4:
case 5:
case 6:
case 8:
case 9:
case 10:
sprintf (vbuf, "r[%+d:%+d]c[%+d:%+d]",
(curow < mkrow ? curow : mkrow) - setrow,
(curow < mkrow ? mkrow : curow) - setrow,
(cucol < mkcol ? cucol : mkcol) - setcol,
(cucol < mkcol ? mkcol : cucol) - setcol);
break;

case 3:
case 7:
case 11:
sprintf (vbuf, "r[%+d:%+d]c",
(curow < mkrow ? curow : mkrow) - setrow,
(curow < mkrow ? mkrow : curow) - setrow);
break;

case 12:
case 14:
case 13:
sprintf (vbuf, "rc[%+d:%+d]",
(cucol < mkcol ? cucol : mkcol) - setcol,
(cucol < mkcol ? mkcol : cucol) - setcol);
break;

case 15:
strcpy (vbuf, "rc");
break;
}
}

else
{
switch (((curow == setrow) << 1) + (cucol == setcol))
{
case 0:
sprintf (vbuf, "r[%+d]c[%+d]", curow - setrow, cucol - setcol);
break;
case 1:
sprintf (vbuf, "r[%+d]c", curow - setrow);
break;
case 2:
sprintf (vbuf, "rc[%+d]", cucol - setcol);
break;
case 3:
strcpy (vbuf, "rc");
break;
#ifdef TEST
default:
panic ("huh what");
#endif
}
}
in_str = vbuf;
}
put_string (in_str, strlen (in_str));
}
}


#ifdef __STDC__
void
insert_abs_ref(void)
#else
void
insert_abs_ref()
#endif
{
if (check_editting_mode ())
return;
else
{
char vbuf[50];
char * in_str;
/* Insert current cell/range name as an absolute reference */
if (a0)
{
if (mkrow != NON_ROW)
sprintf (vbuf, "$%s$%u:$%s:$%u",
col_to_str (cucol), curow, col_to_str (mkcol), mkrow) ;
else
sprintf (vbuf, "$%s$%u", col_to_str (cucol), curow);
in_str = vbuf;
}
else
{
if (mkrow != NON_ROW)
{
struct rng r;

set_rng (&r, curow, cucol, mkrow, mkcol);
in_str = range_name (&r);
}
else
in_str = cell_name (curow, cucol);
}
put_string (in_str, strlen (in_str));
}
}

#ifdef __STDC__
void
insert_cell_attr (struct rng * rng, char * attr)
#else
void
insert_cell_attr (rng, attr)
struct rng * rng;
char * attr;
#endif
{
struct line line;
init_line (&line);
if (!stricmp (attr, "width"))
{
int wid = get_nodef_width (rng->lc);
if (wid == 0)
set_line (&line, "def");
else
sprint_line (&line, "%d", wid - 1);
}
else if (!stricmp (attr, "height"))
{
int hgt = get_nodef_height (rng->lr);
if (hgt == 0)
set_line (&line, "def");
else
sprint_line (&line, "%d", hgt - 1);
}
else if (!stricmp (attr, "format"))
{
CELL * cp = find_cell (rng->lr, rng->lc);
if (!cp)
set_line (&line, "def");
else
{
int fmt = GET_FMT (cp);
set_line (&line, fmt_to_str (fmt));
}
}
else if (!stricmp (attr, "font"))
{
CELL * cp = find_cell (rng->lr, rng->lc);
if (!(cp && cp->cell_font))
set_line (&line, "def");
else
set_line (&line, cp->cell_font->names->oleo_name);
}
else if (!stricmp (attr, "font-scale"))
{
CELL * cp = find_cell (rng->lr, rng->lc);
if (!(cp && cp->cell_font))
set_line (&line, "1.0");
else
sprint_line (&line, "%lf", cp->cell_font->scale);
}
put_string (line.buf, strlen (line.buf));
}

#ifdef __STDC__
void
insert_usr_fmt_part (int fmt, int stat)
#else
void
insert_usr_fmt_part (fmt, stat)
int fmt;
int stat;
#endif
{
char * usr_stats[9];
if ((fmt < 1) || (fmt > 16))
io_error_msg
("insert-user-format-part arg 1 out of range (%d); should be in [1-16].",
fmt);
--fmt;
if ((stat < 1) || (stat > 16))
io_error_msg
("insert-user-format-part arg 2 out of range (%d); should be in [1-9].",
stat);
--stat;
get_usr_stats (fmt, usr_stats);
put_string (usr_stats[stat], strlen (usr_stats[stat]));
}

#ifdef __STDC__
void
self_insert_command (int ch, int count)
#else
void
self_insert_command (ch, count)
int ch;
int count;
#endif
{
if (check_editting_mode ())
return;
else if (count == 1)
{
char chr = ch;
put_string (&chr, 1);
}
else if (count > 0)
{
char * buf = (char *)ck_malloc (count); /* sleazy, huh? */
int x;
for (x = 0; x < count; ++x)
buf[x] = ch;
put_string (buf, count);
}
}


/* Keysequences are read using the `keyseq' keymap.
* Every key in that map should be bound to this function.
*/
#ifdef __STDC__
void
self_map_command (int c)
#else
void
self_map_command (c)
int c;
#endif
{
struct keymap * map = the_maps[the_cmd_arg.val.key.cmd.code];
char space = ' ';
char * str = char_to_string (c);

insert_string (str, strlen (str));
insert_string (&space, 1);

while (map)
{
the_cmd_arg.val.key.cmd = map->keys[c];
if (the_cmd_arg.val.key.cmd.vector < 0)
{
if (the_cmd_arg.val.key.cmd.code < 0)
map = map->map_next;
else
return;
}
else
break;
}
exit_minibuffer ();
return;
}

#ifdef __STDC__
void
insert_current_filename (void)
#else
void
insert_current_filename ()
#endif
{
if (current_filename)
put_string (current_filename, strlen (current_filename));
}


/* Reading a single character is done with the read-char
* map. Every key in that map should be bound to this function.
*/
#ifdef __STDC__
void
exit_self_inserting (int c)
#else
void
exit_self_inserting (c)
int c;
#endif
{
char * str = char_to_string (c);

insert_string (str, strlen (str));
exit_minibuffer ();
}


#ifdef __STDC__
static int
issymb (int c)
#else
static int
issymb (c)
int c;
#endif
{
return isalpha (c) || isdigit (c) || (c == '_');
}

#undef text
#undef cursor
#undef do_prompt
#ifdef __STDC__
void
insert_context_word (void)
#else
void
insert_context_word ()
#endif
{
struct command_frame * cf = the_cmd_frame->prev;
if ( (cf == the_cmd_frame)
|| !cf->cmd
|| !cf->argv [cf->_cur_arg].do_prompt)
return;
{
struct command_arg * ca = &cf->argv [cf->_cur_arg];
char * beg_text = ca->text.buf;
char * last = beg_text + ca->cursor;
char * start;

while ((last > beg_text) && !issymb(*last))
--last;
while (*last && issymb (*last))
++last;
--last;
start = last;
while ((start > beg_text) && issymb(*start))
--start;
if (!issymb (*start) && (start < last))
++start;

if ((start <= last) && issymb (*start))
{
insert_string (start, last - start + 1);
the_cmd_arg.cursor = 0;
}
}
}
#define text the_cmd_arg.text
#define do_prompt the_cmd_arg.do_prompt
#define cursor the_cmd_arg.cursor
oleo-1.3/hash.c 644 722 0 67312 5351437106 11606 0ustar lordwheel/*
* hash.c - hash table lookup strings - Copyright (C) 1987, 1992, 1993 Free Software
* Foundation, Inc.
*
* This file is part of GAS, the GNU Assembler.
*
* GAS 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, or (at your option) any later version.
*
* GAS 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
* GAS; see the file COPYING. If not, write to the Free Software Foundation,
* 675 Mass Ave, Cambridge, MA 02139, USA.
*/

/*
* BUGS, GRIPES, APOLOGIA etc.
*
* A typical user doesn't need ALL this: I intend to make a library out of it
* one day - Dean Elsner. Also, I want to change the definition of a symbol
* to (address,length) so I can put arbitrary binary in the names stored.
* [see hsh.c for that]
*
* This slime is common coupled inside the module. Com-coupling (and other
* vandalism) was done to speed running time. The interfaces at the module's
* edges are adequately clean.
*
* There is no way to (a) run a test script through this heap and (b) compare
* results with previous scripts, to see if we have broken any code. Use GNU
* (f)utilities to do this. A few commands assist test. The testing is
* awkward: it tries to be both batch & interactive. For now, interactive
* rules!
*/


/* The idea is to implement a symbol table. A test jig is here. Symbols are
arbitrary strings; they can't contain '\0'. Each symbol is associated with a
VOIDSTAR, which can point to anything you want, allowing an arbitrary
property list for each symbol.

The basic operations are:
new creates symbol table, returns handle
find (symbol) returns VOIDSTAR
insert(symbol,VOIDSTAR) error if symbol already in table
delete (symbol) returns VOIDSTAR if symbol was in table
apply so you can delete all symbols before
die() destroy symbol table (free up memory)
Supplementary functions include:
say how big?
what % full?
replace (symbol,newval) report previous value
jam (symbol,value) assert symbol:=value

You, the caller, have control over errors: this just reports them.

This package requires malloc(), free(). Malloc(size) returns NULL or address
of char[size]. Free(address) frees same. */


/*
* The code and its structures are re-enterent. Before you do anything else,
* you must call hash_new() which will return the address of a
* hash-table-control-block (or NULL if there is not enough memory). You then
* use this address as a handle of the symbol table by passing it to all the
* other hash_...() functions. The only approved way to recover the memory
* used by the symbol table is to call hash_die() with the handle of the
* symbol table.
*
* Before you call hash_die() you normally delete anything pointed to by
* individual symbols. After hash_die() you can't use that symbol table
* again.
*
* The char* you associate with a symbol may not be NULL (0) because NULL is
* returned whenever a symbol is not in the table. Any other value is OK,
* except DELETED, #defined below.
*
* When you supply a symbol string for insertion, YOU MUST PRESERVE THE STRING
* until that symbol is deleted from the table. The reason is that only the
* address you supply, NOT the symbol string itself, is stored in the symbol
* table.
*
* You may delete and add symbols arbitrarily. Any or all symbols may have the
* same 'value' (char *). In fact, these routines don't do anything with your
* symbol values.
*
* You have no right to know where the symbol:char* mapping is stored, because
* it moves around in memory; also because we may change how it works and we
* don't want to break your code do we? However the handle (address of struct
* hash_control) is never changed in the life of the symbol table.
*
* What you CAN find out about a symbol table is: how many slots are in the hash
* table? how many slots are filled with symbols? (total hashes,collisions)
* for (reads,writes) (*) All of the above values vary in time. (*) some of
* these numbers will not be meaningful if we change the internals.
*/


/*
* I N T E R N A L
*
* Hash table is an array of hash_entries; each entry is a pointer to a a string
* and a user-supplied value 1 char* wide.
*
* The array always has 2 ** n elements, n>0, n integer. There is also a 'wall'
* entry after the array, which is always empty and acts as a sentinel to
* stop running off the end of the array. When the array gets too full, we
* create a new array twice as large and re-hash the symbols into the new
* array, then forget the old array. (Of course, we copy the values into the
* new array before we junk the old array!)
*
*/

#include
#ifndef VOIDSTAR
#define VOIDSTAR void *
#endif
VOIDSTAR malloc ();
void free ();

#undef TRUE
#define TRUE (1)
#undef FALSE
#define FALSE (0)
#include
#define min(a, b) ((a) < (b) ? (a) : (b))

#include "sysdef.h" /* For Oleo, specificly. define bzero etc. */
#include "hash.h"

#define DELETED ((char *)1) /* guarenteed invalid address */
#define START_POWER (11) /* power of two: size of new hash table */ /* JF was 6 */
/* JF These next two aren't used any more. */
/* #define START_SIZE (64) / * 2 ** START_POWER */
/* #define START_FULL (32) / * number of entries before table expands */
#define islive(ptr) (ptr->hash_string && ptr->hash_string!=DELETED)
/* above TRUE if a symbol is in entry @ ptr */

#define STAT_SIZE (0) /* number of slots in hash table */
/* the wall does not count here */
/* we expect this is always a power of 2 */
#define STAT_ACCESS (1) /* number of hash_ask()s */
#define STAT__READ (0) /* reading */
#define STAT__WRITE (1) /* writing */
#define STAT_COLLIDE (3) /* number of collisions (total) */
/* this may exceed STAT_ACCESS if we have */
/* lots of collisions/access */
#define STAT_USED (5) /* slots used right now */
#define STATLENGTH (6) /* size of statistics block */
#if STATLENGTH != HASH_STATLENGTH
Panic ! Please make
#include "stat.h" agree with previous definitions!
#endif

/* #define SUSPECT to do runtime checks */
/* #define TEST_ME to be a test jig for hash...() */

#ifdef TEST_ME /* TEST_ME: use smaller hash table */
#undef START_POWER
#define START_POWER (3)
#undef START_SIZE
#define START_SIZE (8)
#undef START_FULL
#define START_FULL (4)
#endif


/*------------------ plan ---------------------------------- i = internal

struct hash_control * c;
struct hash_entry * e; i
int b[z]; buffer for statistics
z size of b
char * s; symbol string (address) [ key ]
char * v; value string (address) [datum]
boolean f; TRUE if we found s in hash table i
char * t; error string; NULL means OK
int a; access type [0...n) i

c=hash_new () create new hash_control

hash_die (c) destroy hash_control (and hash table)
table should be empty.
doesn't check if table is empty.
c has no meaning after this.

hash_say (c,b,z) report statistics of hash_control.
also report number of available statistics.

v=hash_delete (c,s) delete symbol, return old value if any.
ask() NULL means no old value.
f

v=hash_replace (c,s,v) replace old value of s with v.
ask() NULL means no old value: no table change.
f

t=hash_insert (c,s,v) insert (s,v) in c.
ask() return error string.
f it is an error to insert if s is already
in table.
if any error, c is unchanged.

t=hash_jam (c,s,v) assert that new value of s will be v. i
ask() it may decide to GROW the table. i
f i
grow() i
t=hash_grow (c) grow the hash table. i
jam() will invoke JAM. i

?=hash_apply (c,y) apply y() to every symbol in c.
y evtries visited in 'unspecified' order.

v=hash_find (c,s) return value of s, or NULL if s not in c.
ask()
f

f,e=hash_ask() (c,s,a) return slot where s SHOULD live. i
code() maintain collision stats in c. i

.=hash_code (c,s) compute hash-code for s, i
from parameters of c. i

*/


static char hash_found; /* returned by hash_ask() to stop
* extra */
/* testing. hash_ask() wants to return both */
/* a slot and a status. This is the status. */
/* TRUE: found symbol */
/* FALSE: absent: empty or deleted slot */
/* Also returned by hash_jam(). */
/* TRUE: we replaced a value */
/* FALSE: we inserted a value */

static struct hash_entry *hash_ask ();
static int hash_code ();
static char *hash_grow ();


/*
* h a s h _ n e w ( )
*
*/
struct hash_control *
hash_new () /* create a new hash table */
/* return handle (address of struct hash) */
{
register struct hash_control *retval;
register struct hash_entry *room; /* points to hash table */
register struct hash_entry *wall;
register struct hash_entry *entry;

/* +1 for the wall entry */
if ((room = (struct hash_entry *) malloc (sizeof (struct hash_entry) * ((1 << START_POWER) + 1))) == 0)
return NULL;
if ((retval = (struct hash_control *) malloc (sizeof (struct hash_control))) == 0)
{
free (room);
return NULL;
}
bzero (retval->hash_stat, STATLENGTH * sizeof (int));

retval->hash_stat[STAT_SIZE] = 1 << START_POWER;
retval->hash_mask = (1 << START_POWER) - 1;
retval->hash_sizelog = START_POWER;
/* works for 1's compl ok */
retval->hash_where = room;
retval->hash_wall =
wall = room + (1 << START_POWER);
retval->hash_full = (1 << START_POWER) / 2;
for (entry = room; entry <= wall; entry++)
entry->hash_string = NULL;
return retval;
}

/*
* h a s h _ d i e ( )
*
* Table should be empty, but this is not checked. To empty the table, try
* hash_apply()ing a symbol deleter. Return to free memory both the hash
* table and it's control block. 'handle' has no meaning after this function.
* No errors are recoverable.
*/
void
hash_die (handle)
struct hash_control *handle;
{
free ((char *) handle->hash_where);
free ((char *) handle);
}


/*
* h a s h _ s a y ( )
*
* Return the size of the statistics table, and as many statistics as we can
* until either (a) we have run out of statistics or (b) caller has run out
* of buffer. NOTE: hash_say treats all statistics alike. These numbers may
* change with time, due to insertions, deletions and expansions of the
* table. The first "statistic" returned is the length of hash_stat[]. Then
* contents of hash_stat[] are read out (in ascending order) until your
* buffer or hash_stat[] is exausted.
*/
void
hash_say (handle, buffer, bufsiz)
register struct hash_control *handle;
register int buffer[ /* bufsiz */ ];
register int bufsiz;
{
register int *nd; /* limit of statistics block */
register int *ip; /* scan statistics */

ip = handle->hash_stat;
nd = ip + min (bufsiz - 1, STATLENGTH);
if (bufsiz > 0)
{ /* trust nothing! bufsiz<=0 is dangerous */
*buffer++ = STATLENGTH;
for (; ip < nd; ip++, buffer++)
{
*buffer = *ip;
}
}
}


/*
* h a s h _ d e l e t e ( )
*
* Try to delete a symbol from the table. If it was there, return its value (and
* adjust STAT_USED). Otherwise, return NULL. Anyway, the symbol is not
* present after this function.
*
*/
char * /* NULL if string not in table, else */
/* returns value of deleted symbol */
hash_delete (handle, string)
register struct hash_control *handle;
register char *string;
{
register char *retval; /* NULL if string not in table */
register struct hash_entry *entry; /* NULL or entry of this
* symbol */

entry = hash_ask (handle, string, STAT__WRITE);
if (hash_found)
{
retval = entry->hash_value;
entry->hash_string = DELETED; /* mark as deleted */
handle->hash_stat[STAT_USED] -= 1; /* slots-in-use count */
#ifdef SUSPECT
if (handle->hash_stat[STAT_USED] < 0)
{
error ("hash_delete");
}
#endif /* def SUSPECT */
}
else
{
retval = NULL;
}
return (retval);
}


/*
* h a s h _ r e p l a c e ( )
*
* Try to replace the old value of a symbol with a new value. Normally return
* the old value. Return NULL and don't change the table if the symbol is not
* already in the table.
*/
char *
hash_replace (handle, string, value)
register struct hash_control *handle;
register char *string;
register char *value;
{
register struct hash_entry *entry;
register char *retval;

entry = hash_ask (handle, string, STAT__WRITE);
if (hash_found)
{
retval = entry->hash_value;
entry->hash_value = value;
}
else
{
retval = NULL;
}
;
return (retval);
}


/*
* h a s h _ i n s e r t ( )
*
* Insert a (symbol-string, value) into the hash table. Return an error string,
* NULL means OK. It is an 'error' to insert an existing symbol.
*/

char * /* return error string */
hash_insert (handle, string, value)
register struct hash_control *handle;
register char *string;
register VOIDSTAR value;
{
register struct hash_entry *entry;
register char *retval;

retval = NULL;
if (handle->hash_stat[STAT_USED] > handle->hash_full)
retval = hash_grow (handle);
if (!retval)
{
entry = hash_ask (handle, string, STAT__WRITE);
if (hash_found)
retval = "exists";
else
{
entry->hash_value = value;
entry->hash_string = string;
handle->hash_stat[STAT_USED] += 1;
}
}
return (retval);
}


/*
* h a s h _ j a m ( )
*
* Regardless of what was in the symbol table before, after hash_jam() the named
* symbol has the given value. The symbol is either inserted or (its value
* is) relpaced. An error message string is returned, NULL means OK.
*
* WARNING: this may decide to grow the hashed symbol table. To do this, we call
* hash_grow(), WHICH WILL recursively CALL US.
*
* We report status internally: hash_found is TRUE if we replaced, but false if
* we inserted.
*/
char *
hash_jam (handle, string, value)
register struct hash_control *handle;
register char *string;
register char *value;
{
register char *retval;
register struct hash_entry *entry;

if (handle->hash_stat[STAT_USED] > handle->hash_full)
retval = hash_grow (handle);
else
retval = NULL;
if (!retval)
{
entry = hash_ask (handle, string, STAT__WRITE);
if (!hash_found)
{
entry->hash_string = string;
handle->hash_stat[STAT_USED] += 1;
}
entry->hash_value = value;
}
return (retval);
}

/*
* h a s h _ g r o w ( )
*
* Grow a new (bigger) hash table from the old one. We choose to double the hash
* table's size. Return a human-scrutible error string: NULL if OK. Warning!
* This uses hash_jam(), which had better not recurse back here! Hash_jam()
* conditionally calls us, but we ALWAYS call hash_jam()! Internal.
*/
static char *
hash_grow (handle) /* make a hash table grow */
struct hash_control *handle;
{
register struct hash_entry *newwall;
register struct hash_entry *newwhere;
struct hash_entry *newtrack;
register struct hash_entry *oldtrack;
register struct hash_entry *oldwhere;
register struct hash_entry *oldwall;
register int temp;
int newsize;
char *string;
char *retval;
#ifdef SUSPECT
int oldused;
#endif

/*
* capture info about old hash table
*/
oldwhere = handle->hash_where;
oldwall = handle->hash_wall;
#ifdef SUSPECT
oldused = handle->hash_stat[STAT_USED];
#endif
/*
* attempt to get enough room for a hash table twice as big
*/
temp = handle->hash_stat[STAT_SIZE];
/* +1 for wall slot */
if ((newwhere = (struct hash_entry *) malloc ((long) ((temp + temp + 1) * sizeof (struct hash_entry)))) == 0)
return "no room";
retval = 0; /* assume success until proven otherwise */
/*
* have enough room: now we do all the work. double the size
* of everything in handle, note: hash_mask frob works for
* 1's & for 2's complement machines
*/
handle->hash_mask = handle->hash_mask + handle->hash_mask + 1;
handle->hash_stat[STAT_SIZE] <<= 1;
newsize = handle->hash_stat[STAT_SIZE];
handle->hash_where = newwhere;
handle->hash_full <<= 1;
handle->hash_sizelog += 1;
handle->hash_stat[STAT_USED] = 0;
handle->hash_wall =
newwall = newwhere + newsize;
/*
* set all those pesky new slots to vacant.
*/
for (newtrack = newwhere; newtrack <= newwall; newtrack++)
newtrack->hash_string = NULL;
/*
* we will do a scan of the old table, the hard way, using
* the new control block to re-insert the data into new hash
* table.
*/
handle->hash_stat[STAT_USED] = 0; /* inserts will bump it
* up to correct */
for (oldtrack = oldwhere; oldtrack < oldwall; oldtrack++)
{
if ((string = oldtrack->hash_string) && string != DELETED)
{
if ((retval = hash_jam (handle, string, oldtrack->hash_value)))
break;
}
}
#ifdef SUSPECT
if (!retval && handle->hash_stat[STAT_USED] != oldused)
return "hash_used";
#endif
if (!retval)
{
/*
* we have a completely faked up control block.
* return the old hash table.
*/
free ((char *) oldwhere);
/*
* Here with success. retval is already NULL.
*/
}
return (retval);
}


/*
* h a s h _ a p p l y ( )
*
* Use this to scan each entry in symbol table. For each symbol, this calls
* (applys) a nominated function supplying the symbol's value (and the
* symbol's name). The idea is you use this to destroy whatever is associted
* with any values in the table BEFORE you destroy the table with hash_die.
* Of course, you can use it for other jobs; whenever you need to visit all
* extant symbols in the table.
*
* We choose to have a call-you-back idea for two reasons: asthetic: it is a
* neater idea to use apply than an explicit loop sensible: if we ever had to
* grow the symbol table (due to insertions) then we would lose our place in
* the table when we re-hashed symbols into the new table in a different
* order.
*
* The order symbols are visited depends entirely on the hashing function.
* Whenever you insert a (symbol, value) you risk expanding the table. If you
* do expand the table, then the hashing function WILL change, so you MIGHT
* get a different order of symbols visited. In other words, if you want the
* same order of visiting symbols as the last time you used hash_apply() then
* you better not have done any hash_insert()s or hash_jam()s since the last
* time you used hash_apply().
*
* In future we may use the value returned by your nominated function. One idea
* is to abort the scan if, after applying the function to a certain node,
* the function returns a certain code. To be safe, please make your
* functions of type char *. If you always return NULL, then the scan will
* complete, visiting every symbol in the table exactly once. ALL OTHER
* RETURNED VALUES have no meaning yet! Caveat Actor!
*
* The function you supply should be of the form: char * myfunct(string,value)
* char * string; |* the symbol's name *| char * value; |* the
* symbol's value *| { |* ... *| return(NULL); }
*
* The returned value of hash_apply() is (char*)NULL. In future it may return
* other values. NULL means "completed scan OK". Other values have no meaning
* yet. (The function has no graceful failures.)
*/
char *
hash_apply (handle, function)
struct hash_control *handle;
char *(*function) ();
{
register struct hash_entry *entry;
register struct hash_entry *wall;

wall = handle->hash_wall;
for (entry = handle->hash_where; entry < wall; entry++)
{
if (islive (entry)) /* silly code: tests entry->string
* twice! */
(*function) (entry->hash_string, entry->hash_value);
}
return (NULL);
}


/*
* h a s h _ f i n d ( )
*
* Given symbol string, find value (if any). Return found value or NULL.
*/
VOIDSTAR
hash_find (handle, string) /* return char* or NULL */
struct hash_control *handle;
char *string;
{
register struct hash_entry *entry;

entry = hash_ask (handle, string, STAT__READ);
return hash_found ? entry->hash_value : NULL;
}


/*
* h a s h _ a s k ( )
*
* Searches for given symbol string. Return the slot where it OUGHT to live. It
* may be there. Return hash_found: TRUE only if symbol is in that slot.
* Access argument is to help keep statistics in control block. Internal.
*/
static struct hash_entry * /* string slot, may be empty or deleted */
hash_ask (handle, string, access)
struct hash_control *handle;
char *string;
int access; /* access type */
{
register char *string1; /* JF avoid strcmp calls */
register char *s;
register int c;
register struct hash_entry *slot;
register int collision; /* count collisions */

slot = handle->hash_where + hash_code (handle, string); /* start looking here */
handle->hash_stat[STAT_ACCESS + access] += 1;
collision = 0;
hash_found = FALSE;
while ((s = slot->hash_string) && s != DELETED)
{
for (string1 = string;;)
{
if (!(c = *s++))
{
if (!*string1)
hash_found = TRUE;
break;
}
if (*string1++ != c)
break;
}
if (hash_found)
break;
collision++;
slot++;
}
/*
* slot: return:
* in use: we found string slot at
* empty: at wall: we fell off: wrap round ???? in table:
* dig here slot at DELETED: dig here
* slot
*/
if (slot == handle->hash_wall)
{
slot = handle->hash_where;/* now look again */
while ((s = slot->hash_string) && s != DELETED)
{
for (string1 = string; *s; string1++, s++)
{
if (*string1 != *s)
break;
}
if (*s == *string1)
{
hash_found = TRUE;
break;
}
collision++;
slot++;
}
/*
* slot:
* return: in use: we found it
* slot empty: wall: ERROR IMPOSSIBLE
* !!!! in table: dig here slot
* DELETED:dig here slot
*/
}
/*
* fprintf(stderr,"hash_ask(%s)->%d(%d)\n",string,hash_code(handle,str
* ing),collision);
*/
handle->hash_stat[STAT_COLLIDE + access] += collision;
return (slot); /* also return hash_found */
}


/*
* h a s h _ c o d e
*
* Does hashing of symbol string to hash number. Internal.
*/
static int
hash_code (handle, string)
struct hash_control *handle;
register char *string;
{
register long int h; /* hash code built here */
register long int c; /* each character lands here */
register int n; /* Amount to shift h by */

n = (handle->hash_sizelog - 3);
h = 0;
while (c = *string++)
{
h += c;
h = (h << 3) + (h >> n) + c;
}
return (h & handle->hash_mask);
}


/*
* Here is a test program to exercise above.
*/
#ifdef TEST_ME

#define TABLES (6) /* number of hash tables to maintain */
/* (at once) in any testing */
#define STATBUFSIZE (12) /* we can have 12 statistics */

int statbuf[STATBUFSIZE]; /* display statistics here */
char answer[100]; /* human farts here */
char *hashtable[TABLES]; /* we test many hash tables at once */
char *h; /* points to curent hash_control */
char **pp;
char *p;
char *name;
char *value;
int size;
int used;
char command;
int number; /* number 0:TABLES-1 of current hashed */
/* symbol table */

int
main ()
{
char (*applicatee ());
VOIDSTAR hash_find ();
char *destroy ();
char *what ();
struct hash_control *hash_new ();
char *hash_replace ();
int *ip;

number = 0;
h = 0;
printf ("type h for help\n");
for (;;)
{
printf ("hash_test command: ");
gets (answer);
command = answer[0];
if (isupper (command))
command = tolower (command); /* ecch! */
switch (command)
{
case '#':
printf ("old hash table #=%d.\n", number);
whattable ();
break;
case '?':
for (pp = hashtable; pp < hashtable + TABLES; pp++)
{
printf ("address of hash table #%d control block is %xx\n"
,pp - hashtable, *pp);
}
break;
case 'a':
hash_apply (h, applicatee);
break;
case 'd':
hash_apply (h, destroy);
hash_die (h);
break;
case 'f':
p = hash_find (h, name = what ("symbol"));
printf ("value of \"%s\" is \"%s\"\n", name, p ? p : "NOT-PRESENT");
break;
case 'h':
printf ("# show old, select new default hash table number\n");
printf ("? display all hashtable control block addresses\n");
printf ("a apply a simple display-er to each symbol in table\n");
printf ("d die: destroy hashtable\n");
printf ("f find value of nominated symbol\n");
printf ("h this help\n");
printf ("i insert value into symbol\n");
printf ("j jam value into symbol\n");
printf ("n new hashtable\n");
printf ("r replace a value with another\n");
printf ("s say what %% of table is used\n");
printf ("q exit this program\n");
printf ("x delete a symbol from table, report its value\n");
break;
case 'i':
p = hash_insert (h, name = what ("symbol"), value = what ("value"));
if (*p)
{
printf ("symbol=\"%s\" value=\"%s\" error=%s\n", name, value, p);
}
break;
case 'j':
p = hash_jam (h, name = what ("symbol"), value = what ("value"));
if (*p)
{
printf ("symbol=\"%s\" value=\"%s\" error=%s\n", name, value, p);
}
break;
case 'n':
h = hashtable[number] = (char *) hash_new ();
break;
case 'q':
exit (0);
case 'r':
p = hash_replace (h, name = what ("symbol"), value = what ("value"));
printf ("old value was \"%s\"\n", p ? p : "{}");
break;
case 's':
hash_say (h, statbuf, STATBUFSIZE);
for (ip = statbuf; ip < statbuf + STATBUFSIZE; ip++)
{
printf ("%d ", *ip);
}
printf ("\n");
break;
case 'x':
p = hash_delete (h, name = what ("symbol"));
printf ("old value was \"%s\"\n", p ? p : "{}");
break;
default:
printf ("I can't understand command \"%c\"\n", command);
break;
}
}
}

char *
what (description)
char *description;
{
char *retval;

printf (" %s : ", description);
gets (answer);
/* will one day clean up answer here */
retval = malloc (strlen (answer) + 1);
if (!retval)
{
error ("room");
}
(void) strcpy (retval, answer);
return (retval);
}

char *
destroy (string, value)
char *string;
char *value;
{
free (string);
free (value);
return (NULL);
}


char *
applicatee (string, value)
char *string;
char *value;
{
printf ("%.20s-%.20s\n", string, value);
return (NULL);
}

void
whattable () /* determine number: what hash table to use */
{

for (;;)
{
printf (" what hash table (%d:%d) ? ", 0, TABLES - 1);
gets (answer);
sscanf (answer, "%d", &number);
if (number >= 0 && number < TABLES)
{
h = hashtable[number];
if (!h)
{
printf ("warning: current hash-table-#%d. has no hash-control\n", number);
}
return;
}
else
{
printf ("invalid hash table number: %d\n", number);
}
}
}



#endif /* #ifdef TEST_ME */

/* end: hash.c */
oleo-1.3/panic.c 644 722 0 6667 5356003006 11734 0ustar lordwheel/* Copyright (C) 1990, 1992, 1993 Free Software Foundation, Inc.

This file is part of Oleo, the GNU Spreadsheet.

Oleo 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, or (at your option)
any later version.

Oleo 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 Oleo; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */

#include
#include "funcdef.h"
#include "sysdef.h"

#include "global.h"
#include "io-generic.h"
#include "io-abstract.h"
#include "info.h"
#include "cmd.h"


extern char **environ;
/* I hope i don't need these since they aren't write for all systems. */
#if 0
#ifdef __STDC__
extern int dup (int);
extern int close (int);
extern VOIDSTAR sbrk (size_t);
extern VOIDSTAR brk (VOIDSTAR);
#else
extern int dup ();
extern int close ();
extern VOIDSTAR sbrk ();
extern VOIDSTAR brk ();
#endif
#endif



void
panic_write_file (fp, rng)
FILE *fp;
struct rng *rng;
{
int fd;
VOIDSTAR datend;
VOIDSTAR datstart;
unsigned long cnt;

if (rng)
{
io_error_msg ("Can't write partial panic-save files");
return;
}
fd = dup (fileno (fp));
if (fd < 0)
{
io_error_msg ("Couldn't dup save file");
return;
}
datstart = (VOIDSTAR) (&environ + sizeof (char **));
datend = (VOIDSTAR) sbrk (0);
if (datend == (char *) -1)
{
io_error_msg ("Couldn't sbrk(0)!");
close (fd);
return;
}

cnt = (char *) datend - (char *) datstart;
if (write (fd, &cnt, sizeof (cnt)) != sizeof (cnt))
{
io_error_msg ("Couldn't write %lu (%d bytes) to save file", cnt, sizeof (cnt));
close (fd);
return;
}
if (write (fd, datstart, cnt) != cnt)
{
io_error_msg ("Couldn't write %lu bytes to save file", cnt);
close (fd);
return;
}
if (close (fd) < 0)
{
io_error_msg ("Couldn't close save file");
return;
}
}

void
panic_read_file (fp, ismerge)
FILE *fp;
int ismerge;
{
int fd;
unsigned long cnt;
VOIDSTAR datstart;

if (ismerge)
{
io_error_msg ("Can't merge panic-save files");
return;
}
if ((fd = dup (fileno (fp))) < 0)
{
io_error_msg ("Couldn't dup save file");
return;
}
if (read (fd, (VOIDSTAR) & cnt, sizeof (cnt)) != sizeof (cnt))
{
io_error_msg ("Couldn't read data_size (%d bytes) from save file", sizeof (cnt));
close (fd);
return;
}
datstart = (VOIDSTAR) (&environ + sizeof (char **));
if ((VOIDSTAR)brk ((char *) datstart + cnt) == (VOIDSTAR) - 1)
{
io_error_msg ("Couldn't allocate %lu bytes of memory", cnt);
close (fd);
return;
}
if (read (fd, datstart, cnt) != cnt)
{
io_error_msg ("Couldn't read in %lu bytes of data", cnt);
close (fd);
return;
}
if (close (fd) < 0)
io_error_msg ("Couldn't close save file");
io_recenter_all_win ();
}

int
panic_set_options (set_opt, option)
int set_opt;
char *option;
{
return -1;
}


void
panic_show_options ()
{
io_text_line ("File format: panic save (quick-n-dirty data-segment dump)");
}
oleo-1.3/line.c 644 722 0 7741 5354421020 11561 0ustar lordwheel#include
#include "global.h"
#include "line.h"

#ifdef __STDC__
void
set_line (struct line *line, char *string)
#else
void
set_line (line, string)
struct line *line;
char *string;
#endif
{
int len;

len = strlen (string);
if (line->alloc <= len)
{
if (len < LINE_MIN)
len = LINE_MIN;
else
len++;
line->alloc = len + 1;
if (line->buf)
line->buf = ck_realloc (line->buf, line->alloc);
else
line->buf = ck_malloc (line->alloc);
}
strcpy (line->buf, string);
}

#ifdef __STDC__
void
setn_line (struct line *line, char *string, int n)
#else
void
setn_line (line, string, n)
struct line *line;
char *string;
int n;
#endif
{
int len = n;
if (line->alloc <= len)
{
if (len < LINE_MIN)
len = LINE_MIN;
else
len++;
line->alloc = len;
line->buf = ck_remalloc (line->buf, line->alloc);
}
strcpy (line->buf, string);
}

#define Max(A,B) ((A) > (B) ? (A) : (B))

#ifdef __STDC__
void
catn_line (struct line *line, char *string, int n)
#else
void
catn_line (line, string, n)
struct line *line;
char *string;
int n;
#endif
{
int len = (line->buf ? strlen (line->buf) : 0);
if (line->alloc <= len + n + 1)
{
line->alloc = Max (len + n + 1, LINE_MIN);
line->buf = ck_remalloc (line->buf, line->alloc);
}
bcopy (string, line->buf + len, n);
line->buf[len + n] = '\0';
}


#ifdef __STDC__
void
sprint_line (struct line *line, char * fmt, ...)
#else
void
sprint_line (line, fmt, va_alist)
struct line *line;
char *fmt;
va_dcl
#endif
{
va_list iggy;
int len;

len = strlen (fmt) + 200;
if (!line->alloc)
{
line->buf = ck_malloc (len);
line->alloc = len;
}
else if (line->alloc < len)
{
line->buf = ck_realloc (line->buf, len);
line->alloc = len;
}
var_start (iggy, fmt);
vsprintf (line->buf, fmt, iggy);
va_end (iggy);
}

#ifdef __STDC__
void
splicen_line (struct line * line, char * str, int n, int pos)
#else
void
splicen_line (line, str, n, pos)
struct line * line;
char * str;
int n;
int pos;
#endif
{
int old_len = strlen (line->buf);
int len = old_len + n;
if (line->alloc <= len)
{
line->alloc = len;
line->buf = ck_remalloc (line->buf, len + 1);
}
line->buf[len--] = '\0';
--old_len;
while (old_len >= pos)
{
line->buf[len] = line->buf[old_len];
--len;
--old_len;
}
while (n--)
line->buf[pos + n] = str[n];
}

#ifdef __STDC__
void
edit_line (struct line * line, int begin, int len)
#else
void
edit_line (line, begin, len)
struct line * line;
int begin;
int len;
#endif
{
int old_len = strlen (line->buf);
int new_len = old_len - len;
while (begin < new_len)
{
line->buf[begin] = line->buf[begin + len];
++begin;
}
line->buf[begin] = '\0';
}


#ifdef __STDC__
void
free_line (struct line * line)
#else
void
free_line (line)
struct line * line;
#endif
{
if (line->buf && line->alloc)
free (line->buf);
line->buf = 0;
line->alloc = 0;
}




#ifdef __STDC__
int
read_line (struct line * line, FILE * fp, int * linec)
#else
int
read_line (line, fp, linec)
struct line * line;
FILE * fp;
int * linec;
#endif
{
int pos = 0;
int c = getc (fp);

while ((c != EOF) && (c != '\n'))
{
if (pos + 2 >= line->alloc)
{
line->alloc = (line->alloc ? line->alloc * 2 : 1);
line->buf = ck_remalloc (line->buf, line->alloc);
}
if (c != '\\')
line->buf[pos++] = c;
else
{
int next_c = getc (fp);
if (next_c != '\n')
{
line->buf[pos++] = '\\';
line->buf[pos++] = next_c;
}
/* Else the backslash and newline are discarded from the input. */
else
++*linec;
}
c = getc (fp);
}
if (pos + 1 > line->alloc)
{
++line->alloc;
line->buf = ck_remalloc (line->buf, line->alloc);
}
line->buf[pos] = 0;
if (line->buf[0] || (c != EOF))
{
++*linec;
return 1;
}
else
return 0;
}
oleo-1.3/key.c 644 722 0 24126 5356013647 11454 0ustar lordwheel/* Copyright (C) 1993 Free Software Foundation, Inc.

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, 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 software; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */

#include

#include "key.h"
#include "cmd.h"
#include "io-abstract.h"
#include "io-generic.h"
#include "io-utils.h"
#include "io-term.h"

struct keymap **the_maps;
char **map_names;
char **map_prompts;
int num_maps;
struct cmd_func **the_funcs;
int num_funcs;


#ifdef __STDC__
int
search_map_for_cmd (struct line * line, int map, int vec, int code)
#else
int
search_map_for_cmd (line, map, vec, code)
struct line * line;
int map;
int vec;
int code;
#endif
{
int len = strlen (line->buf);
struct keymap * this_map;
int x;
char used[256];
int try_prefix;

for (try_prefix = 0; try_prefix < 2; ++try_prefix)
{
bzero (used, sizeof (used));

for (this_map = the_maps[map]; this_map; this_map = this_map->map_next)
{
for (x = 128; x >= 0; --x)
if (!used[x])
{
int found_it = ((this_map->keys[x].vector == vec)
&& this_map->keys[x].code == code);
int prefix_key = ((this_map->keys[x].vector == -1)
&& (this_map->keys[x].code != -1));
if (!( (this_map->keys[x].vector == -1)
&& (this_map->keys[x].code == -1)))
used[x] = 1;
if (found_it || (try_prefix && prefix_key))
{
char * c = char_to_string (x);
catn_line (line, " ", 1);
catn_line (line, c, strlen (c));
if (found_it
|| (try_prefix
&& search_map_for_cmd (line,
this_map->keys[x].code,
vec, code)))
return 1;
line->buf[len] = 0;
}
}
}
}
return 0;
}

#ifdef __STDC__
static void
do_bind_key (struct keymap *m, int key, int vector, int code)
#else
static void
do_bind_key (m, key, vector, code)
struct keymap *m;
int key;
int vector;
int code;
#endif
{
m->keys[key].vector = (short)vector;
m->keys[key].code = (short)code;
}


#ifdef __STDC__
void
bind_key (char * keymap, char * function, int ch)
#else
void
bind_key (keymap, function, ch)
char * keymap;
char * function;
int ch;
#endif
{
struct cmd_func * tmpfunc;
int map = map_id (keymap);
int vec;
int code;
struct rng rng;
struct cmd_func * cmd;

if (map < 0)
{
io_error_msg ("bind_key: bad keymap.");
return;
}

if (!find_func (&vec, &cmd, function))
{
code = (cmd - the_funcs[vec]);
goto fini;
}

for (code = 0; code < num_maps; code++)
{
if (!strcmp (function, map_names[code]))
{
vec = -1;
goto fini;
}
}
if (get_abs_rng (&function, &rng))
{
io_error_msg ("Unknown command '%s'", function);
return;
}

for (code = 0; code < n_bound_macros; code++)
{
if (!bcmp (&bound_macros[code], &rng, sizeof (struct rng)))
goto fini;
}

function = range_name (&rng);
if (!bound_macro_vec)
{
bound_macros = ck_malloc (sizeof (struct rng));
n_bound_macros = 1;
tmpfunc = (struct cmd_func *)ck_malloc (2 * sizeof (struct cmd_func));
bzero (tmpfunc + 1, sizeof (*tmpfunc));
bound_macro_vec = add_usr_cmds (tmpfunc);
}
else
{
n_bound_macros++;
bound_macros = ck_realloc (bound_macros,
n_bound_macros * sizeof (struct rng));
the_funcs[bound_macro_vec]
= ck_realloc (the_funcs[bound_macro_vec],
(1 + n_bound_macros) * sizeof (struct cmd_func));
tmpfunc = &the_funcs[bound_macro_vec][n_bound_macros - 1];
bzero (tmpfunc + 1, sizeof (*tmpfunc));
}
vec = bound_macro_vec;
bound_macros[n_bound_macros - 1] = rng;
tmpfunc->func_args = (char **)ck_malloc (2 * sizeof (char *));
tmpfunc->func_args[0] = mk_sprintf ("#%d", n_bound_macros - 1);
tmpfunc->func_args[1] = 0;
tmpfunc->init_code = 0;
tmpfunc->func_doc = 0;
tmpfunc->func_name = ck_savestr (function);
tmpfunc->func_func = bound_macro;
fini:
do_bind_key (the_maps[map], ch, vec, code);
}

#ifdef __STDC__
void
bind_set (char * keymap, char * command, char * keyset)
#else
void
bind_set (keymap, command, keyset)
char * keymap;
char * command;
char * keyset;
#endif
{
int first;
int last;
first = string_to_char (&keyset);
if (first < 0)
{
io_error_msg ("Invalid character set.");
return;
}
while (isspace (*keyset))
++keyset;
if (*keyset == '-')
{
++keyset;
last = string_to_char (&keyset);
if (last < 0)
{
io_error_msg ("Unterminated character set.");
return;
}
}
else if (*keyset)
{
io_error_msg ("Extra characters in keyset: `%s'.",
keyset);
return;
}
else
last = first;

while (first <= last)
{
bind_key (keymap, command, first);
++first;
}
}


#ifdef __STDC__
void
bind_all_keys (char * keymap, char * function)
#else
void
bind_all_keys (keymap, function)
char * keymap;
char * function;
#endif
{
struct cmd_func * tmpfunc;
int map = map_id (keymap);
int vec;
int code;
struct rng rng;
struct cmd_func * cmd;

if (map < 0)
{
io_error_msg ("bind_key: bad keymap.");
return;
}

if (!find_func (&vec, &cmd, function))
{
code = (cmd - the_funcs[vec]);
goto fini;
}

for (code = 0; code < num_maps; code++)
{
if (!strcmp (function, map_names[code]))
{
vec = -1;
goto fini;
}
}
if (get_abs_rng (&function, &rng))
{
io_error_msg ("Unknown command '%s'", function);
return;
}

vec = bound_macro_vec;
for (code = 0; code < n_bound_macros; code++)
{
if (!bcmp (&bound_macros[code], &rng, sizeof (struct rng)))
goto fini;
}

function = range_name (&rng);
if (!bound_macro_vec)
{
bound_macros = ck_malloc (sizeof (struct rng));
n_bound_macros = 1;
tmpfunc = (struct cmd_func *)ck_malloc (2 * sizeof (struct cmd_func));
bzero (tmpfunc + 1, sizeof (*tmpfunc));
bound_macro_vec = add_usr_cmds (tmpfunc);
}
else
{
n_bound_macros++;
bound_macros = ck_realloc (bound_macros,
n_bound_macros * sizeof (struct rng));
the_funcs[bound_macro_vec]
= ck_realloc (the_funcs[bound_macro_vec],
(1 + n_bound_macros) * sizeof (struct cmd_func));
tmpfunc = &the_funcs[bound_macro_vec][n_bound_macros - 1];
bzero (tmpfunc + 1, sizeof (*tmpfunc));
}
bound_macros[n_bound_macros - 1] = rng;
tmpfunc->func_args = (char **)ck_malloc (2 * sizeof (char *));
tmpfunc->func_args[0] = mk_sprintf ("#%d", n_bound_macros - 1);
tmpfunc->func_args[1] = 0;
tmpfunc->func_doc = 0;
tmpfunc->func_name = ck_savestr (function);
tmpfunc->func_func = bound_macro;
fini:
{
int ch;
for (ch = 0; ch < 256; ++ch)
do_bind_key (the_maps[map], ch, vec, code);
}
}


#ifdef __STDC__
void
write_keys_cmd (FILE *fp)
#else
void
write_keys_cmd (fp)
FILE *fp;
#endif
{
struct keymap *map;
int n;
int key;
int vec;
int code;

for (n = 0; n < num_maps; n++)
{
char *def;
map = the_maps[n];
def = 0;
if (map && map->map_next)
{
for (key = 0; key < num_maps; key++)
if (the_maps[key] == map->map_next)
{
def = map_names[key];
break;
}
}
if (def)
fprintf (fp, "create-keymap %s %s\n", map_names[n], def);
else
fprintf (fp, "create-keymap %s\n", map_names[n]);
}
for (n = 0; n < num_maps; n++)
{
map = the_maps[n];
for (key = 0; key < 256; key++)
{
vec = map->keys[key].vector;
code = map->keys[key].code;
if (vec < 0 && code >= 0)
fprintf (fp, "bind-key %s %s %s\n",
map_names[n],
map_names[code],
char_to_string (key));
else if (vec >= 0)
fprintf (fp, "bind-key %s %s %s\n",
map_names[n],
the_funcs[vec][code].func_name,
char_to_string (key));
}
}
}



#ifdef __STDC__
void
clear_keymap (struct keymap *m)
#else
void
clear_keymap (m)
struct keymap *m;
#endif
{
int n;
for (n = 0; n < 256; n++)
{
m->keys[n].vector = -1;
m->keys[n].code = -1;
}
}

#ifdef __STDC__
int
map_idn (char *name, int n)
#else
int
map_idn (name, n)
char *name;
int n;
#endif
{
int x;
for (x = 0; x < num_maps; ++x)
if (!strincmp (name, map_names[x], n))
return x;
return -1;
}

#ifdef __STDC__
void
create_keymap (char * mapname, char * parentname)
#else
void
create_keymap (mapname, parentname)
char * mapname;
char * parentname;
#endif
{
int map = map_id (mapname);
int parent = parentname ? map_id (parentname) : -1;

if (map > 0)
{
io_info_msg ("Map %s already exists.", mapname);
return;
}
if (parentname && (parent < 0))
{
io_error_msg ("Map %s does not exist.", parentname);
return;
}
the_maps = ck_realloc (the_maps, (num_maps + 1) * sizeof (struct keymap *));
the_maps[num_maps] = ck_malloc (sizeof (struct keymap));
the_maps[num_maps]->id = num_maps;
the_maps[num_maps]->map_next = ((parent >= 0)
? the_maps[parent]
: 0);
{
int c;
for (c = 0; c < 256; ++c)
{
the_maps[num_maps]->keys[c].vector = -1;
the_maps[num_maps]->keys[c].code = -1;
}
}
map_names = ck_realloc (map_names, (num_maps + 1) * sizeof (char *));
map_prompts = ck_realloc (map_prompts, (num_maps + 1) * sizeof (char *));
map_names[num_maps] = ck_savestr (mapname);
map_prompts[num_maps] = 0;
num_maps++;
}


#ifdef __STDC__
void
set_map_prompt (char * map, char * str)
#else
void
set_map_prompt (map, str)
char * map;
char * str;
#endif
{
int id = map_id (map);
if (id < 0)
io_error_msg ("No such keymap as %s.", map); /* No return. */
if (map_prompts[id])
free (map_prompts [id]);
map_prompts[id] = ck_savestr (str);
}
oleo-1.3/format.c 644 722 0 11226 5356003010 12130 0ustar lordwheel/* Copyright (C) 1993 Free Software Foundation, Inc.

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, 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 software; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */

#include "global.h"
#include "format.h"
#include "line.h"
#include "cell.h"
#include "cmd.h"
#include "io-term.h"
#include "io-abstract.h"
#include "io-generic.h"




#ifdef __STDC__
char *
fmt_to_str (int fmt)
#else
char *
fmt_to_str (fmt)
int fmt;
#endif
{
char *ptr;
static char buf[30];
char nbuf[10];

if (fmt == FMT_DEF)
return "default";
if (fmt == FMT_HID)
return "hidden";
if (fmt == FMT_GPH)
return "graph";
if ((fmt & PRC_FLT) == PRC_FLT)
strcpy (nbuf, "float");
else
sprintf (nbuf, "%d", (fmt & PRC_FLT));
switch (fmt | PRC_FLT)
{
case FMT_USR:
ptr = "user-";
sprintf (nbuf, "%d", (fmt & PRC_FLT) + 1);
break;
case FMT_GEN:
ptr = "general.";
break;
case FMT_DOL:
ptr = "dollar.";
break;
case FMT_CMA:
ptr = "comma.";
break;
case FMT_PCT:
ptr = "percent.";
break;
case FMT_FXT:
if ((fmt & PRC_FLT) == 0)
return "integer";
if (fmt == FMT_FXT)
return "decimal";
ptr = "fixed.";
break;
case FMT_EXP:
ptr = "exponent.";
break;
default:
io_error_msg ("Unknown format %d (%x)", fmt, fmt);
ptr = "UNKNOWN";
break;
}
sprintf (buf, "%s%s", ptr, nbuf);
return buf;
}

struct fmt
{
int fmt;
char **strs;
};

static char *def_names[] =
{"default", "def", "D", 0};
static char *hid_names[] =
{"hidden", "hid", "H", 0};
static char *gph_names[] =
{"graph", "gph", "*", 0};
static char *int_names[] =
{"integer", "int", "I", 0};
static char *dec_names[] =
{"decimal", "dec", 0};

static struct fmt simple[] =
{
{FMT_DEF, def_names},
{FMT_HID, hid_names},
{FMT_GPH, gph_names},
{FMT_FXT - PRC_FLT, int_names},
{FMT_FXT, dec_names},
{0, 0}
};

char *gen_names[] =
{"general.", "gen.", "G", 0};
char *dol_names[] =
{"dollar.", "dol.", "$", 0};
char *cma_names[] =
{"comma.", "com.", ",", 0};
char *pct_names[] =
{"percent.", "pct.", "%", 0};
char *fxt_names[] =
{"fixed.", "fxt.", "F", 0};
char *exp_names[] =
{"exponent.", "exp.", "E", 0};

static struct fmt withprec[] =
{
{FMT_GEN - PRC_FLT, gen_names},
{FMT_DOL - PRC_FLT, dol_names},
{FMT_CMA - PRC_FLT, cma_names},
{FMT_PCT - PRC_FLT, pct_names},
{FMT_FXT - PRC_FLT, fxt_names},
{FMT_EXP - PRC_FLT, exp_names},
{0, 0}
};

#ifdef __STDC__
int
str_to_fmt (char *ptr)
#else
int
str_to_fmt (ptr)
char *ptr;
#endif
{
struct fmt *f;
char **strs;
int n;
int ret;
char *p1, *p2;

for (f = simple; f->strs; f++)
{
for (strs = f->strs; *strs; strs++)
{
if (*ptr != **strs)
continue;
for (p1 = ptr, p2 = *strs; *p1 == *p2 && *p1; p1++, p2++)
;
if (*p1 == '\0' && *p2 == '\0')
return f->fmt;
}
}
if (!strncmp (ptr, "user-", 5))
{
ptr += 5;
n = astol (&ptr);
if (*ptr || n < 1 || n > 16)
return -1;
return n - 1 - PRC_FLT + FMT_USR;
}
for (f = withprec, ret = 0; !ret && f->strs; f++)
{
for (strs = f->strs; *strs; strs++)
{
if (*ptr != **strs)
continue;
for (p1 = ptr, p2 = *strs; *p2 && *p1 == *p2; p1++, p2++)
;
if (!*p2)
{
ret = f->fmt;
ptr = p1;
break;
}
}
}

if (!ret || !*ptr)
return -1;
if (!strcmp (ptr, "float") || !strcmp (ptr, "f"))
{
n = PRC_FLT;
}
else
{
n = astol (&ptr);
if (*ptr || n < 0 || n > 14)
return -1;
}
return ret + n;
}

#ifdef __STDC__
char *
jst_to_str (int jst)
#else
char *
jst_to_str (jst)
int jst;
#endif
{
if (jst == JST_DEF)
return "default";
if (jst == JST_LFT)
return "left";
if (jst == JST_RGT)
return "right";
if (jst == JST_CNT)
return "center";
return "unknown";
}

#ifdef __STDC__
int
chr_to_jst (int chr)
#else
int
chr_to_jst (chr)
int chr;
#endif
{
if (chr == 'd' || chr == 'D')
return JST_DEF;
if (chr == 'l' || chr == 'L')
return JST_LFT;
if (chr == 'r' || chr == 'R')
return JST_RGT;
if (chr == 'c' || chr == 'C')
return JST_CNT;
return -1;
}

oleo-1.3/funcs.c 644 722 0 6571 5355225131 11756 0ustar lordwheel/* Copyright (C) 1993 Free Software Foundation, Inc.

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, 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 software; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */



/*
* This file contains descriptions of all the interactive functions
* built into oleo.
*/

#include "global.h"
#include "cmd.h"
#include "key.h"
#include "io-term.h"
#include "basic.h"
#include "format.h"
#include "print.h"
#include "font.h"
#include "io-x11.h"
#include "io-edit.h"
#include "regions.h"
#include "help.h"
#include "window.h"
#include "font.h"
#include "graph.h"
#include "lists.h"


/* This include builds the function table, doc strings, and FUNC_ARGS strings.
*/
#include "defuns.h"


/* Returns 0 if the function is found.
* Also returns (through parameters) the vector and cmd_func.
* The output parameters can be NULL.
*/

#ifdef __STDC__
int
find_function (int * vec_out, struct cmd_func ** cmd_out, char * name, int len)
#else
int
find_function (vec_out, cmd_out, name, len)
int * vec_out;
struct cmd_func ** cmd_out;
char * name;
int len;
#endif
{
int vector;
struct cmd_func * cmd;
for (vector = 0; vector < num_funcs; vector++)
for (cmd = &the_funcs[vector][0]; cmd->func_name; cmd++)
if (!(strincmp (name, cmd->func_name, len) || cmd->func_name[len]))
{
if (vec_out)
*vec_out = vector;
if (cmd_out)
*cmd_out = cmd;
return 0;
}
return 1;
}




static struct cmd_func * named_macro_strings = 0;
static int num_named_macro_strings = 0;
static int named_macro_vec;

#ifdef __STDC__
void
init_named_macro_strings (void)
#else
void
init_named_macro_strings ()
#endif
{
named_macro_strings =
(struct cmd_func *) ck_malloc (sizeof (struct cmd_func));
bzero (named_macro_strings, sizeof (struct cmd_func));
named_macro_vec = add_usr_cmds (named_macro_strings);
}


#ifdef __STDC__
void
name_macro_string (char * name, char * str)
#else
void
name_macro_string (name, str)
char * name;
char * str;
#endif
{
int i = num_named_macro_strings;
++num_named_macro_strings;
named_macro_strings =
((struct cmd_func *)
ck_realloc (named_macro_strings,
((1 + num_named_macro_strings) * sizeof (struct cmd_func))));
the_funcs [named_macro_vec] = named_macro_strings;
bzero (named_macro_strings + num_named_macro_strings,
sizeof (struct cmd_func));
{
struct cmd_func * cf = &named_macro_strings [i];
cf->func_name = ck_savestr (name);
cf->func_func = run_string_as_macro;
cf->init_code = 0;
{
struct info_buffer * ib = find_or_make_info (name);
clear_info (ib);
print_info (ib, "Equivelent to %s.", str);
cf->func_doc = ib->text;
}
{
int i = 0;
cf->func_args = (char **)ck_malloc (3 * sizeof (char *));
cf->func_args [i++] = mk_sprintf ("=%s", str);
cf->func_args [i++] = "p";
cf->func_args [i++] = 0;
}
}
}

oleo-1.3/io-curses.c 644 722 0 53415 5356007306 12573 0ustar lordwheel/* Copyright (C) 1992, 1993 Free Software Foundation, Inc.

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, 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 software; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */


#include "proto.h"
#include "funcdef.h"
#include
#include
#include
#include
#include
#include
#undef NULL
#include "sysdef.h"
#include "global.h"
#include "cell.h"
#include "cmd.h"
#include "line.h"
#include "io-generic.h"
#include "io-edit.h"
#include "io-term.h"
#include "io-abstract.h"
#include "io-utils.h"
#include "lists.h"
#include "regions.h"
#include "window.h"
#include "key.h"
#include "input.h"
#include "info.h"

#define MIN_WIN_HEIGHT (cwin->flags&WIN_EDGES ? 2 : 1)
#define MIN_WIN_WIDTH (cwin->flags&WIN_EDGES ? 6 : 1)

static int redrew = 0;
static int textout = 0;
static int term_cursor_claimed = 0;

#ifdef __STDC__
static void move_cursor_to (struct window *, CELLREF, CELLREF, int);
#else
static void move_cursor_to ();
#endif


#ifdef __STDC__
static int
curses_metric (char * str, int len)
#else
static int
curses_metric (str, len)
char * str;
int len;
#endif
{
return len;
}

static struct input_view input_view
= {0, curses_metric, curses_metric, 0, 0, 0, 0, 0, 0, 0, 0, 0};

#ifdef __STDC__
static void
_io_redraw_input (void)
#else
static void
_io_redraw_input ()
#endif
{
int pos;
int row = (input_view.current_info ? 1 : input);

if (input_view.info_redraw_needed)
{
input_view.info_redraw_needed = 0;
io_repaint ();
return;
}

if (input_view.redraw_needed == NO_REDRAW)
return;

if (input_view.redraw_needed == FULL_REDRAW)
{
/* Redraw the prompt. */
move (row, 0);
if (input_view.expanded_keymap_prompt)
{
addstr (input_view.expanded_keymap_prompt);
clrtoeol ();
input_view.redraw_needed = NO_REDRAW;
return;
}
if (input_view.prompt_wid)
addstr (input_view.prompt);
pos = input_view.visibility_begin;
}
else
{
pos = input_view.redraw_needed;
move (row,
input_view.prompt_wid + pos - input_view.visibility_begin);
}

if ( input_view.input_area
&& (input_view.visibility_end >= input_view.visibility_begin)
&& (input_view.visibility_begin < strlen (input_view.input_area->buf)))
{
int x;
for (x = pos; x <= input_view.visibility_end; ++x)
addch (input_view.input_area->buf[x]);
}
clrtoeol ();
input_view.redraw_needed = NO_REDRAW;
}


#undef MIN
#define MIN(A,B) (((A) < (B)) ? (A) : (B))

#ifdef __STDC__
void
redraw_info (void)
#else
void
redraw_info ()
#endif
{
if (!input_view.current_info)
return;
{
int ipos = input_view.info_pos;
int stop = MIN (input_view.current_info->len, scr_lines - 1 + ipos);
while (ipos < stop)
{
move (2 + ipos - input_view.info_pos, 0);
addstr (input_view.current_info->text[ipos]);
clrtoeol ();
++ipos;
}
}
_io_redraw_input ();
}


#ifdef __STDC__
static void
_io_fix_input (void)
#else
static void
_io_fix_input ()
#endif
{
iv_fix_input (&input_view);
}

#ifdef __STDC__
static void
_io_move_cursor (void)
#else
static void
_io_move_cursor ()
#endif
{
iv_move_cursor (&input_view);
}

#ifdef __STDC__
static void
_io_erase (int len)
#else
static void
_io_erase (len)
int len;
#endif
{
iv_erase (&input_view, len);
}

#ifdef __STDC__
static void
_io_insert (int len)
#else
static void
_io_insert (len)
int len;
#endif
{
iv_insert (&input_view, len);
}

#ifdef __STDC__
static void
_io_over (char * str, int len)
#else
static void
_io_over (str, len)
char * str;
int len;
#endif
{
iv_over (&input_view, len);
}





#ifdef __STDC__
static void
_io_display_cell_cursor (void)
#else
static void
_io_display_cell_cursor ()
#endif
{
int cell_cursor_row;
int cell_cursor_col;
int cc;
int rr;
int cwid;
int n;
int x, y;

if (input_view.current_info)
return;

if ( (curow < cwin->screen.lr)
|| (cucol < cwin->screen.lc)
|| (curow > cwin->screen.hr)
|| (cucol > cwin->screen.hc))
return;

getyx (stdscr, y, x);
cell_cursor_col = cwin->win_over;
for (cc = cwin->screen.lc; cc < cucol; cc++)
cell_cursor_col += get_width (cc);
cell_cursor_row = cwin->win_down;
for (rr = cwin->screen.lr; rr < curow; rr++)
cell_cursor_row += get_height (rr);
cwid = get_width (cucol);
if (cwid > cwin->numc)
cwid = cwin->numc;
move (cell_cursor_row, cell_cursor_col);
standout ();
for (n = cwid; n; n--)
#ifdef A_STANDOUT
addch (inch () | A_STANDOUT);
#else
addch (inch ());
#endif
standend ();
move (y, x);
}

#ifdef __STDC__
static void
_io_hide_cell_cursor (void)
#else
static void
_io_hide_cell_cursor ()
#endif
{
int cc;
int rr;
int cell_cursor_row;
int cell_cursor_col;
int cwid;
int n;
int x, y;

if (input_view.current_info)
return;
if ( (curow < cwin->screen.lr)
|| (cucol < cwin->screen.lc)
|| (curow > cwin->screen.hr)
|| (cucol > cwin->screen.hc))
return;
getyx (stdscr, y, x);
cell_cursor_col = cwin->win_over;
for (cc = cwin->screen.lc; cc < cucol; cc++)
cell_cursor_col += get_width (cc);
cell_cursor_row = cwin->win_down;
for (rr = cwin->screen.lr; rr < curow; rr++)
cell_cursor_row += get_height (rr);
cwid = get_width (cucol);
if (cwid > cwin->numc)
cwid = cwin->numc;
move (cell_cursor_row, cell_cursor_col);
for (n = cwid; n; n--)
#ifdef A_STANDOUT
addch (inch () & ~A_STANDOUT);
#else
addch (inch ());
#endif
move (y, x);
}



/* Functions, etc for dealing with cell contents being displayed
on top of other cells. */

struct slops
{
int s_alloc, s_used;
struct s
{
CELLREF row, clo, chi;
} s_b[1];
};

#ifdef __STDC__
static void
flush_slops (VOIDSTAR where)
#else
static void
flush_slops (where)
VOIDSTAR where;
#endif
{
struct slops *s;

s = where;
if (s)
s->s_used = 0;
}

#ifdef __STDC__
static int
find_slop (VOIDSTAR where, CELLREF r, CELLREF c, CELLREF *cclp, CELLREF *cchp)
#else
static int
find_slop (where, r, c, cclp, cchp)
VOIDSTAR where;
CELLREF r;
CELLREF c;
CELLREF *cclp;
CELLREF *cchp;
#endif
{
int n;
struct slops *s;

s = where;
if (!s)
return 0;
for (n = 0; n < s->s_used; n++)
{
if (s->s_b[n].row == r && s->s_b[n].clo <= c && s->s_b[n].chi >= c)
{
*cclp = s->s_b[n].clo;
*cchp = s->s_b[n].chi;
return 1;
}
}
return 0;
}

#ifdef __STDC__
static void
kill_slop (VOIDSTAR where, CELLREF r, CELLREF clo, CELLREF chi)
#else
static void
kill_slop (where, r, clo, chi)
VOIDSTAR where;
CELLREF r;
CELLREF clo;
CELLREF chi;
#endif
{
int n;
struct slops *s;

s = where;
for (n = 0; n < s->s_used; n++)
{
if (s->s_b[n].row == r && s->s_b[n].clo == clo && s->s_b[n].chi == chi)
{
--(s->s_used);
s->s_b[n] = s->s_b[s->s_used];
return;
}
}
}

#ifdef __STDC__
static void
set_slop (VOIDSTAR *wherep, CELLREF r, CELLREF clo, CELLREF chi)
#else
static void
set_slop (wherep, r, clo, chi)
VOIDSTAR *wherep;
CELLREF r;
CELLREF clo;
CELLREF chi;
#endif
{
int n;
struct slops **sp;

sp = (struct slops **) wherep;
if (!*sp)
{
(*sp) = ck_malloc (sizeof (struct slops) + 2 * sizeof (struct s));
(*sp)->s_alloc = 2;
(*sp)->s_used = 1;
n = 0;
}
else
{
n = (*sp)->s_used++;
if ((*sp)->s_alloc == n)
{
(*sp)->s_alloc = n * 2;
(*sp) = ck_realloc ((*sp), sizeof (struct slops) + n * 2 * sizeof (struct s));
}
}
(*sp)->s_b[n].row = r;
(*sp)->s_b[n].clo = clo;
(*sp)->s_b[n].chi = chi;
}

#ifdef __STDC__
static void
change_slop (VOIDSTAR where,
CELLREF r, CELLREF olo, CELLREF ohi, CELLREF lo, CELLREF hi)
#else
static void
change_slop (where, r, olo, ohi, lo, hi)
VOIDSTAR where;
CELLREF r;
CELLREF olo;
CELLREF ohi;
CELLREF lo;
CELLREF hi;
#endif
{
int n;
struct slops *s;

s = where;
for (n = 0; n < s->s_used; n++)
{
if (s->s_b[n].row == r && s->s_b[n].clo == olo && s->s_b[n].chi == ohi)
{
s->s_b[n].clo = lo;
s->s_b[n].chi = hi;
return;
}
}
}


#ifdef __STDC__
static void
_io_open_display (void)
#else
static void
_io_open_display ()
#endif
{
initscr ();
scrollok (stdscr, 0);
#ifdef HAVE_CBREAK
cbreak ();
#else
crmode ();
#endif
raw ();
noecho ();
nonl ();
/* Must be after initscr() */
io_init_windows (LINES, COLS - 1, 1, 2, 1, 1, 1, 1);
info_rows = 1;
print_width = COLS; /* Make ascii print width == terminal width. */
}

#ifdef __STDC__
void
cont_curses(void)
#else
void
cont_curses()
#endif
{
#ifdef HAVE_CBREAK
cbreak ();
#else
crmode ();
#endif
raw ();
noecho ();
nonl ();
}


#ifdef __STDC__
void
stop_curses(void)
#else
void
stop_curses()
#endif
{
#ifdef HAVE_CBREAK
nocbreak ();
#else
nocrmode ();
#endif
noraw ();
echo ();
nl ();
io_redisp ();
}

#ifdef __STDC__
static void
_io_cellize_cursor (void)
#else
static void
_io_cellize_cursor ()
#endif
{
}

#ifdef __STDC__
static void
_io_inputize_cursor (void)
#else
static void
_io_inputize_cursor ()
#endif
{
}

#ifdef __STDC__
static void
_io_redisp (void)
#else
static void
_io_redisp ()
#endif
{
if (!term_cursor_claimed)
{
_io_redraw_input ();
if (!(input_view.current_info || input_active ||
input_view.expanded_keymap_prompt))
move_cursor_to (cwin, curow, cucol, 0);
else
move ((input_view.current_info ? 1 : input),
input_view.prompt_wid + input_view.input_cursor -
input_view.visibility_begin);
}
{
struct rng * rng = &cwin->screen;
if ( (curow > rng->hr)
|| (curow < rng->lr)
|| (cucol > rng->hc)
|| (cucol < rng->lc))
io_recenter_cur_win ();
}
refresh ();
}

#ifdef __STDC__
static void
_io_repaint_win (struct window *win)
#else
static void
_io_repaint_win (win)
struct window *win;
#endif
{
io_repaint ();
}

#ifdef __STDC__
static void
_io_repaint (void)
#else
static void
_io_repaint ()
#endif
{
CELLREF cc, rr;
int n, n1;
CELL *cp;
struct window *win;

clear ();
io_fix_input ();
redrew++;
if (input_view.current_info)
{
redraw_info ();
return;
}

for (win = wins; win < &wins[nwin]; win++)
{
if (win->lh_wid)
{
move (win->win_down - 1, win->win_over - win->lh_wid);
printw ("#%*d ", win->lh_wid - 2, 1 + win - wins);
if (win->flags & WIN_EDGE_REV)
standout ();
cc = win->screen.lc;
do
{
n = get_width (cc);
if (n > win->numc)
n = win->numc;
if (n > 1)
{
char *ptr;
char buf[30];

if (a0)
ptr = col_to_str (cc);
else
{
sprintf (buf, "C%u", cc);
ptr = buf;
}
--n;
n1 = strlen (ptr);
if (n < n1)
printw ("%.*s ", n, "###############");
else
{
n1 = (n - n1) / 2;
printw ("%*s%-*s ", n1, "", n - n1, ptr);
}
}
else if (n == 1)
addstr ("#");
}
while (cc++ < win->screen.hc);

rr = win->screen.lr;
n = win->win_down;
do
{
n1 = get_height (rr);
if (n1)
{
move (n, win->win_over - win->lh_wid);
if (a0)
printw ("%-*d ", win->lh_wid - 1, rr);
else
printw ("R%-*d", win->lh_wid - 1, rr);
n += n1;
}
}
while (rr++ < win->screen.hr);

if (win->flags & WIN_EDGE_REV)
standend ();
}
flush_slops (win->win_slops);
find_cells_in_range (&(win->screen));
while (cp = next_row_col_in_range (&rr, &cc))
if (GET_TYP (cp))
io_pr_cell_win (win, rr, cc, cp);
}
if (!(cp = find_cell (curow, cucol)) || !GET_TYP (cp))
io_display_cell_cursor ();
input_view.redraw_needed = FULL_REDRAW;
_io_redraw_input ();
io_update_status ();
}

#ifdef __STDC__
static void
_io_close_display (void)
#else
static void
_io_close_display ()
#endif
{
clear ();
refresh ();
(void) endwin ();
}

/* This is extern because it was convenient to leave the signal */
/* handler that increments it in io_term.c */
int input_avail_val;

#ifdef __STDC__
static int
_io_input_avail (void)
#else
static int
_io_input_avail ()
#endif
{
return (FD_ISSET (0, &read_pending_fd_set)
|| FD_ISSET (0, &exception_pending_fd_set));
}

#ifdef __STDC__
static void
_io_scan_for_input (int block)
#else
static void
_io_scan_for_input (block)
int block;
#endif
{
/* This function only exists because X kbd events don't generate */
/* SIGIO. Under curses, the SIGIO hander does the work of this */
/* function. */
}

#ifdef __STDC__
static void
_io_wait_for_input (void)
#else
static void
_io_wait_for_input ()
#endif
{
pause ();
}

#ifdef __STDC__
static int
_io_read_kbd (VOLATILE char *buf, int size)
#else
static int
_io_read_kbd (buf, size)
VOLATILE char *buf;
int size;
#endif
{
int r = read (0, buf, size);
FD_CLR (0, &read_pending_fd_set);
FD_CLR (0, &exception_pending_fd_set);
return r;
}


#if defined(SIGIO)


#ifdef __STDC__
static void
_io_nodelay (int delayp)
#else
static void
_io_nodelay (delayp)
int delayp;
#endif
{
panic ("Trying to curses nodelay on a system with SIGIO.");
}

#else

#ifdef __STDC__
static void
_io_nodelay (int delayp)
#else
static void
_io_nodelay (delayp)
int delayp;
#endif
{
nodelay (stdscr, delayp);
}

#endif

#ifdef __STDC__
static int
_io_getch (void)
#else
static int
_io_getch ()
#endif
{
char ch;
return ((io_read_kbd (&ch, 1) != 1)
? EOF
: ch);
}


#ifdef __STDC__
static int
_io_get_chr (char *prompt)
#else
static int
_io_get_chr (prompt)
char *prompt;
#endif
{
int x;
mvaddstr (input, 0, prompt);
clrtoeol ();
topclear = 2;
refresh ();
++term_cursor_claimed;
x = get_chr ();
--term_cursor_claimed;
return x;
}

#define BUFFER 10

#ifdef __STDC__
static void
local_putchar (int ch)
#else
static void
local_putchar (ch)
int ch;
#endif
{
(void) putc (ch, stdout);
/* (void)putchar(ch); */
}

#ifdef __STDC__
static void
local_puts (char *s)
#else
static void
local_puts (s)
char *s;
#endif
{
(void) tputs (s, 1, (int (*)()) local_putchar);
}

#ifdef __STDC__
static void
_io_bell (void)
#else
static void
_io_bell ()
#endif
{
#ifndef HAVE_GETCAP
putchar ('\007');
#else
static char *vb;
static int called = 0;

if (!called)
{
called++;
vb = getcap ("vb");
}
if (vb)
{
local_puts (vb);
}
else
{
local_putchar ('\007');
}
#endif
}


#if __STDC__
static void
move_cursor_to (struct window *win, CELLREF r, CELLREF c, int dn)
#else
static void
move_cursor_to (win, r, c, dn)
struct window *win;
CELLREF r;
CELLREF c;
int dn;
#endif
{
int cc;
int cell_cursor_col;
int rr;
int cell_cursor_row;

cell_cursor_col = win->win_over;
for (cc = win->screen.lc; cc < c; cc++)
cell_cursor_col += get_width (cc);
cell_cursor_row = win->win_down + dn;
for (rr = win->screen.lr; rr < r; rr++)
cell_cursor_row += get_height (rr);
move (cell_cursor_row, cell_cursor_col);
}

#ifdef __STDC__
static void
_io_update_status (void)
#else
static void
_io_update_status ()
#endif
{
CELL *cp;
char *dec;
char *ptr;
static char hmbuf[40];
int wid;
int plen;
int dlen;
int yy, xx;

if (!user_status || input_view.current_info)
return;
getyx (stdscr, yy, xx);
move (status, 0);
wid = COLS - 2;

if (mkrow != NON_ROW)
{
struct rng r;

addch ('*');
--wid;
set_rng (&r, curow, cucol, mkrow, mkcol);
ptr = range_name (&r);
}
else
ptr = cell_name (curow, cucol);

addstr (ptr);
wid -= strlen (ptr);

if (how_many != 1)
{
sprintf (hmbuf, " {%d}", how_many);
addstr (hmbuf);
wid -= strlen (hmbuf);
}

if ((cp = find_cell (curow, cucol)) && cp->cell_formula)
{
dec = decomp (curow, cucol, cp);
dlen = strlen (dec);
}
else
{
dec = 0;
dlen = 0;
}

ptr = cell_value_string (curow, cucol);
plen = strlen (ptr);

if (dec)
{
wid -= 4;
if (dlen + plen > wid)
{
if (plen + 3 > wid)
printw (" %.*s... [...]", wid - 6, ptr);
else
printw (" %s [%.*s...]", ptr, wid - plen - 3, dec);
}
else
printw (" %s [%s]", ptr, dec);
decomp_free ();
}
else if (plen)
{
--wid;
if (plen > wid)
printw (" %.*s...", wid - 3, ptr);
else
printw (" %s", ptr);
}

clrtoeol ();
move (yy, xx);
}

extern int auto_recalc;

#ifdef __STDC__
static void
_io_clear_input_before (void)
#else
static void
_io_clear_input_before ()
#endif
{
textout = 0;
if (topclear == 2)
{
move (input, 0);
clrtoeol ();
topclear = 0;
}
move (0, 0);
}

#ifdef __STDC__
static void
_io_clear_input_after (void)
#else
static void
_io_clear_input_after ()
#endif
{
if (topclear)
{
move (input, 0);
clrtoeol ();
topclear = 0;
}
}


#if __STDC__
static void
_io_pr_cell_win (struct window *win, CELLREF r, CELLREF c, CELL *cp)
#else
static void
_io_pr_cell_win (win, r, c, cp)
struct window *win;
CELLREF r;
CELLREF c;
CELL *cp;
#endif
{
int glowing;
int lenstr;
int j;
int wid, wwid;
int hgt;
char *ptr;
int yy, xx;

if (input_view.current_info)
return;

wid = get_width (c);
if (!wid)
return;
if (wid > win->numc)
wid = win->numc;
hgt = get_height (r);
if (!hgt)
return;
if (hgt > win->numr)
hgt = win->numr;

getyx (stdscr, yy, xx);
glowing = (r == curow && c == cucol && win == cwin);
ptr = print_cell (cp);
move_cursor_to (win, r, c, 0);
if (glowing)
standout ();
j = GET_JST (cp);
if (j == JST_DEF)
j = default_jst;
lenstr = strlen (ptr);

if (lenstr <= wid - 1)
{
CELLREF ccl, cch;

if (j == JST_LFT)
printw ("%-*.*s", wid, wid - 1, ptr);
else if (j == JST_RGT)
printw ("%*.*s ", wid - 1, wid - 1, ptr);
else if (j == JST_CNT)
{
wwid = (wid - 1) - lenstr;
printw ("%*s%*s ", (wwid + 1) / 2 + lenstr, ptr, wwid / 2, "");
}
#ifdef TEST
else
panic ("Unknown justification");
#endif
if (glowing)
standend ();

if (lenstr == 0 && c > win->screen.lc
&& find_slop (win->win_slops, r, c - 1, &ccl, &cch))
{
CELLREF ccdl, ccdh;

if (find_slop (win->win_slops, r, c, &ccdl, &ccdh) && ccdl == c)
{
kill_slop (win->win_slops, r, ccdl, ccdh);
for (; ccdh != ccdl; --ccdh)
if (ccdh != c && (wwid = get_width (ccdh)))
{
move_cursor_to (win, r, ccdh, 0);
printw ("%*s", wwid, "");
}
}
kill_slop (win->win_slops, r, ccl, cch);
io_pr_cell (r, ccl, find_cell (r, ccl));
}
else if (find_slop (win->win_slops, r, c, &ccl, &cch))
{
kill_slop (win->win_slops, r, ccl, cch);
for (; cch != ccl; --cch)
if (cch != c && (wwid = get_width (cch)))
{
move_cursor_to (win, r, cch, 0);
printw ("%*s", wwid, "");
}
io_pr_cell (r, ccl, find_cell (r, ccl));
}
}
else
{
CELLREF cc = c;
CELL *ccp;
CELLREF ccl, cch;

for (wwid = wid; lenstr > wwid - 1; wwid += get_width (cc))
{
if (++cc > win->screen.hc
|| ((ccp = find_cell (r, cc))
&& GET_TYP (ccp)
&& (GET_FMT (ccp) != FMT_HID
|| (GET_FMT (ccp) == FMT_DEF
&& default_fmt != FMT_HID))))
{
--cc;
break;
}
}

if (lenstr > wwid - 1)
if (GET_TYP (cp) == TYP_FLT)
ptr = adjust_prc (ptr, cp, wwid - 1, wid - 1, j);
else if (GET_TYP (cp) == TYP_INT)
ptr = (char *) numb_oflo;

if (wwid == 1)
{
addch (' ');
if (glowing)
standend ();
}
else if (wwid == wid)
{
printw ("%-*.*s ", wwid - 1, wwid - 1, ptr);
if (glowing)
standend ();
}
else if (glowing)
{
printw ("%.*s", wid, ptr);
standend ();
printw ("%-*.*s ", wwid - wid - 1, wwid - wid - 1, ptr + wid);
}
else if (r == curow && (cucol > c && cucol <= cc))
{
CELLREF ctmp;
int w_left;
int w_here;

w_left = wid;
for (ctmp = c + 1; ctmp < cucol; ctmp++)
w_left += get_width (ctmp);
printw ("%.*s", w_left, ptr);
standout ();
w_here = get_width (cucol);
if (wwid > w_left + w_here)
{
printw ("%-*.*s", w_here, w_here, ptr + w_left);
standend ();
printw ("%-*.*s ",
wwid - (w_left + w_here) - 1, wwid - (w_left + w_here) - 1,
ptr + w_left + w_here);
}
else
{
printw ("%-*.*s", w_here, w_here - 1, ptr + w_left);
standend ();
}
}
else
printw ("%-*.*s ", wwid - 1, wwid - 1, ptr);

if (find_slop (win->win_slops, r, c, &ccl, &cch))
{
change_slop (win->win_slops, r, ccl, cch, c, cc);
for (; cch > cc; --cch)
if (wwid = get_width (cch))
{
move_cursor_to (win, r, cch, 0);
printw ("%*s", wwid, "");
}
for (cch = c - 1; cch > ccl; --cch)
if (wwid = get_width (cch))
{
move_cursor_to (win, r, cch, 0);
printw ("%*s", wwid, "");
}
if (ccl != c)
io_pr_cell (r, ccl, find_cell (r, ccl));
}
else
set_slop ((VOIDSTAR *) (&(win->win_slops)), r, c, cc);
}
if ((hgt > 1) && display_formula_mode)
{
move_cursor_to (win, r, c, 1);
ptr = decomp (r, c, cp);
printw ("%.*s ", wid - 1, ptr);
decomp_free ();
}
if (glowing)
io_update_status ();
move (yy, xx);
}



#ifdef __STDC__
static void
_io_flush (void)
#else
static void
_io_flush ()
#endif
{
refresh ();
}




#ifdef __STDC__
void
tty_graphics (void)
#else
void
tty_graphics ()
#endif
{

FD_SET (0, &read_fd_set);
FD_SET (0, &exception_fd_set);
IO_SETUP;
}
oleo-1.3/font.c 644 722 0 16365 5355700403 11630 0ustar lordwheel/* Copyright (C) 1992, 1993 Free Software Foundation, Inc.

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, 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 software; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */


#include
#include
#include "font.h"
#include "math.h"
#include "window.h"
#include "io-abstract.h"
#include "cmd.h"
#include "io-x11.h"
#include "io-term.h"
#include "io-utils.h"




static char * default_oleo_name = "default";
static char * default_x_name = "*times-medium-r-*";
static char * default_ps_name = "Times-Roman";

static struct font_names * font_names = 0;
struct font_memo * font_list = 0;
struct font_memo * the_default_font = 0;


#ifdef __STDC__
void
define_font (char * oleo_name, char * x_name, char * ps_name)
#else
void
define_font (oleo_name, x_name, ps_name)
char * oleo_name;
char * x_name;
char * ps_name;
#endif
{
struct font_names * fn;

for (fn = font_names; fn; fn = fn->next)
if (!stricmp(fn->oleo_name, oleo_name))
{
if (fn->x_name)
free (fn->x_name);
if (fn->ps_name)
free (fn->ps_name);
break;
}
if (!fn)
{
fn = (struct font_names *)ck_malloc (sizeof (*fn));
fn->oleo_name = strdup (oleo_name);
fn->next = font_names;
font_names = fn;
}
fn->x_name = strdup (x_name);
fn->ps_name = strdup (ps_name);
}


#ifdef __STDC__
static struct font_names *
find_font_name (char * name)
#else
static struct font_names *
find_font_name (name)
char * name;
#endif
{
struct font_names * fn = font_names;
if (!name || says_default (name))
name = "default";

while (fn)
{
if (!stricmp (name, fn->oleo_name))
return fn;
fn = fn->next;
}
io_error_msg ("Unknown font family %s\n", name);
return 0; /* never reached, actually */
}


/* For backwards compatability, there are created-on-demand fonts
* who's oleo name is a concatenation of their x and postscript names.
*/

#ifdef __STDC__
static struct font_names *
matching_font_names (char * x_name, char * ps_name)
#else
static struct font_names *
matching_font_names (x_name, ps_name)
char * x_name;
char * ps_name;
#endif
{
struct font_names * fn;
for (fn = font_names; fn; fn = fn->next)
{
if ( stricmp (fn->oleo_name, "default")
&& !stricmp (ps_name, fn->ps_name)
&& !stricmp (x_name, fn->x_name))
return fn;
}
{
char * oleo_name = mk_sprintf ("%s,%s", x_name, ps_name);
define_font (oleo_name, x_name, ps_name);
fn = find_font_name (oleo_name);
free (oleo_name);
return fn;
}
}



#ifdef __STDC__
struct font_memo *
intern_font (char * oleo_name, double scale)
#else
struct font_memo *
intern_font (oleo_name, scale)
char * oleo_name;
double scale;
#endif
{
struct font_names *names = find_font_name (oleo_name);
struct font_memo *it = font_list;
while (it)
{
if ((scale == font_list->scale) && (names == font_list->names))
return it;
it = it->next;
}
it = (struct font_memo *)ck_malloc (sizeof (*it));
it->scale = scale;
it->names = names;
it->next = font_list;
font_list = it;
return it;
}

#ifdef __STDC__
struct font_memo *
default_font (void)
#else
struct font_memo *
default_font ()
#endif
{
return the_default_font;
}

#ifdef __STDC__
struct font_memo *
matching_font (char * x_name, char * ps_name, double scale)
#else
struct font_memo *
matching_font (x_name, ps_name, scale)
char * x_name;
char * ps_name;
double scale;
#endif
{
struct font_names * fn = matching_font_names (x_name, ps_name);
return intern_font (fn->oleo_name, scale);
}

/* This is for the benefit of oleofile.c only */

#ifdef __STDC__
struct font_memo *
parsed_matching_font (char * fullname)
#else
struct font_memo *
parsed_matching_font (fullname)
char * fullname;
#endif
{
char x_name[1000];
char ps_name[1000];
char *p;
char *p2;
double scale;

for (p = fullname; isspace (*p); ++p);
for (p2 = x_name; *p && (*p != ',') && !isspace (*p); *p2++ = *p++);
*p2 = '\0';
if (x_name[0] == '\0' || says_default(x_name))
strcpy (x_name, default_x_name);
/* Got rid of the weird defined font-name expansion here.
* These auto-magical fonts are only for the sake of reading old files
* which don't use that (cough) feature.
*/
while (isspace (*p)) ++p;
if (*p == ',') ++p;
while (isspace (*p)) ++p;
for (p2 = ps_name; *p && (*p != ',') && !isspace (*p); *p2++ = *p++) ;
*p2 = '\0';

if (ps_name[0] == '\0' || says_default(x_name))
strcpy (ps_name, default_ps_name);
while (isspace (*p)) ++p;
if (*p == ',') ++p;
while (isspace (*p)) ++p;

if (isdigit (*p))
{
errno = 0;
scale = atof (p);
if (errno)
scale = 1.;
}
else
scale = 1.;

return matching_font (x_name, ps_name, scale);
}



#ifdef __STDC__
void
set_region_font (struct rng *rng, char * oleo_name, double scale)
#else
void
set_region_font (rng, oleo_name, scale)
struct rng *rng;
char * oleo_name;
double scale;
#endif
{
struct font_memo *font = ((oleo_name || scale != 1.0)
? intern_font (oleo_name, scale)
: 0);
CELL * cp;

make_cells_in_range (rng);
cp = next_cell_in_range ();
while (cp)
{
cp->cell_font = font;
cp = next_cell_in_range ();
}
io_redo_region (rng);
}

#ifdef __STDC__
void
flush_fonts (void)
#else
void
flush_fonts ()
#endif
{
CELL * cp;
struct rng rng;
rng.lr = MIN_ROW;
rng.hr = MAX_ROW;
rng.lc = MIN_COL;
rng.hc = MAX_COL;
find_cells_in_range (&rng);
cp = next_cell_in_range ();
while (cp)
{
cp->cell_font = 0;
cp = next_cell_in_range ();
}
}

#ifdef __STDC__
void
set_x_default_font (char * str)
#else
void
set_x_default_font (str)
char * str;
#endif
{
define_font (default_oleo_name, str, the_default_font->names->ps_name);
io_repaint ();
}

#ifdef __STDC__
void
set_ps_font_cmd (char * ps_name)
#else
void
set_ps_font_cmd (ps_name)
char * ps_name;
#endif
{
define_font (default_oleo_name, the_default_font->names->x_name, ps_name);
}

#ifdef __STDC__
void
set_default_font (char * name, double scale)
#else
void
set_default_font (name, scale)
char * name;
double scale;
#endif
{
struct font_names * fn = find_font_name (name);
if (fn != find_font_name (default_oleo_name))
define_font (default_oleo_name, fn->x_name, fn->ps_name);
the_default_font = intern_font (default_oleo_name, scale);
#ifdef HAVE_X11_X_H
if (using_x)
set_x_default_point_size (cell_font_point_size);
else
#endif
io_repaint ();
}


#ifdef __STDC__
void
init_fonts (void)
#else
void
init_fonts ()
#endif
{
define_font (default_oleo_name, default_x_name, default_ps_name);
define_font ("times", default_x_name, default_ps_name);
define_font ("f9x15", "9x15", "sdlkfj");
the_default_font = intern_font (default_oleo_name, 1.0);
}
oleo-1.3/display.c 644 722 0 24415 5354762333 12333 0ustar lordwheel/* Copyright (C) 1992, 1993 Free Software Foundation, Inc.

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, 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 software; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */


#include
#include "display.h"
#include "lists.h"
#include "cell.h"
#include "io-utils.h"

#if __STDC__
struct cell_display *
cell_display_of (struct display *disp, CELLREF r, CELLREF c)
#else
struct cell_display *
cell_display_of (disp, r, c)
struct display *disp;
CELLREF r;
CELLREF c;
#endif
{
int cols = disp->range.hc - disp->range.lc + 1;
if ( (r < disp->range.lr)
|| (c < disp->range.lc)
|| (r > disp->range.hr)
|| (c > disp->range.hc))
return 0;
r -= disp->range.lr;
c -= disp->range.lc;
return disp->cells + r * cols + c;
}


void
free_display (disp)
struct display *disp;
{
int rows = disp->range.hr - disp->range.lr + 1;
int cols = disp->range.hc - disp->range.lc + 1;
struct cell_display *cd = disp->cells;
int x, y;
for (y = 0; y < rows; ++y)
for (x = 0; x < cols; ++x)
{
if (cd->unclipped)
free (cd->unclipped);
if (cd->clipped)
free (cd->clipped);
++cd;
}
free (disp->widths);
free (disp->heights);
free (disp->cells);
free (disp->rowy);
free (disp->colx);
}

void
damage (disp, cd)
struct display *disp;
struct cell_display *cd;
{
if (cd && !cd->next_damaged)
{
cd->next_damaged = disp->damaged;
disp->damaged = cd;
}
}

#if __STDC__
int
pr_display_cell (struct display *disp, CELLREF r, CELLREF c, CELL *cp)
#else
int
pr_display_cell (disp, r, c, cp)
struct display *disp;
CELLREF r;
CELLREF c;
CELL *cp;
#endif
{
int cols = disp->range.hc - disp->range.lc + 1;
struct cell_display *cd =
&disp->cells[cols * (r - disp->range.lr) + (c - disp->range.lc)];
xx_IntRectangle ir = &cd->layout;
struct font_memo * new_font = 0;
char * new_unclipped = 0;
int new_type = 0;
int new_jst = 0;

if (cp && disp->widths[c - disp->range.lc]
&& disp->heights[r - disp->range.lr])
{
new_unclipped = print_cell (cp);
if (!new_unclipped || *new_unclipped == '\0')
new_unclipped = 0;
else
{
new_type = GET_TYP (cp);
new_jst = GET_JST (cp);
new_font = cp->cell_font;
if (new_jst == JST_DEF)
new_jst = default_jst;
}
}


if (((!new_unclipped && !cd->unclipped)
|| ((new_unclipped && cd->unclipped)
&& !strcmp(cd->unclipped, new_unclipped)))
&& (cd->font == new_font)
&& (cd->cell_type == new_type)
&& (cd->justification == new_jst))
return 0;

record_display_damage (disp, xx_IRx (ir), xx_IRy (ir),
xx_IRw (ir), xx_IRh (ir));
if (cd->unclipped)
{
free (cd->unclipped);
cd->unclipped = 0;
}
if (cd->clipped)
{
free (cd->clipped);
cd->clipped = 0;
}
cd->font = new_font;
cd->cell_type = new_type;
cd->justification = new_jst;
if (!cp || !GET_TYP (cp))
{
xx_IRinit (&cd->goal, 0, 0, 0, 0);
xx_IRinit (&cd->clip, 0, 0, 0, 0);
cd->unclipped = 0;
return 1;
}
cd->unclipped = ck_savestr (new_unclipped);
cd->clipped = 0;
disp->metric (cd, disp);
if (new_type == TYP_INT)
cd->numeric.integer = cp->c_z.c_l;
else if (new_type == TYP_FLT)
cd->numeric.dbl = cp->c_z.c_d;
else
{
cd->clipped = ck_savestr (cd->unclipped);
cd->clip = cd->goal;
}
return 1;
}

static void null_metric (cd, disp)
struct cell_display * cd;
struct display * disp;
{}

static void
_build_display (disp, range, metric, vdata, scalep)
struct display *disp;
struct rng *range;
cell_display_metric metric;
void *vdata;
int scalep;
{
/* This would be more useful if it handled scrolling. */
int r, c;
int rows = range->hr - range->lr + 1;
int cols = range->hc - range->lc + 1;
int x, y;
disp->range = *range;
disp->widths = (int *) ck_malloc (sizeof (int) * cols);
disp->heights = (int *) ck_malloc (sizeof (int) * rows);
disp->rowy = (int *) ck_malloc (sizeof (int) * rows);
disp->colx = (int *) ck_malloc (sizeof (int) * cols);
disp->metric = metric ? metric : null_metric;
disp->vdata = vdata;
disp->cells = ((struct cell_display *)
ck_calloc (sizeof (struct cell_display) * rows * cols));
disp->damaged = (struct cell_display *) disp;
for (x = 0, r = range->lr; r <= range->hr; ++r)
{
disp->rowy[r - range->lr] = x;
x += disp->heights[r - range->lr] = (scalep ? get_scaled_height : get_height) (r);
}
for (y = 0, c = range->lc; c <= range->hc; ++c)
{
disp->colx[c - range->lc] = y;
y += disp->widths[c - range->lc] = (scalep ? get_scaled_width : get_width) (c);
for (r = range->lr; r <= range->hr; ++r)
{
struct cell_display *cd = cell_display_of (disp, r, c);
cd->r = r;
cd->c = c;
pr_display_cell (disp, r, c, find_cell (r, c));
}
}
}

void
build_display (disp, range, metric, vdata)
struct display *disp;
struct rng *range;
cell_display_metric metric;
void *vdata;
{
_build_display (disp, range, metric, vdata, 1);
}

void
build_unscaled_display (disp, range, metric, vdata)
struct display *disp;
struct rng *range;
cell_display_metric metric;
void *vdata;
{
_build_display (disp, range, metric, vdata, 0);
}

void
display_range (rng, disp, x, y, w, h)
struct rng *rng;
struct display *disp;
int x, y, w, h;
{
int t;
struct rng *winrng = &disp->range;
int *rowy = disp->rowy;
int *heights = disp->heights;
int *colx = disp->colx;
int *widths = disp->widths;
int rows = winrng->hr - winrng->lr + 1;
int cols = winrng->hc - winrng->lc + 1;

for (t = 0; t < rows - 1; ++t)
if (rowy[t] + heights[t] - 1 >= y)
break;
rng->lr = t + winrng->lr;

while (t < rows - 1)
{
if (rowy[t] + heights[t] >= y + h)
break;
t++;
}
rng->hr = t + winrng->lr;

for (t = 0; t < cols - 1; ++t)
if (colx[t] + widths[t] - 1 >= x)
break;
rng->lc = t + winrng->lc;

while (t < cols - 1)
{
if (colx[t] + widths[t] >= x + w)
break;
t++;
}
rng->hc = t + winrng->lc;
}

extern void
record_display_damage (disp, x, y, w, h)
struct display *disp;
int x, y, w, h;
{
CELLREF r, c;
struct rng rng;
display_range (&rng, disp, x, y, w, h);
for (r = rng.lr; r <= rng.hr && r > 0; ++r)
for (c = rng.lc; c <= rng.hc && c > 0; ++c)
damage (disp, cell_display_of (disp, r, c));
}


void
layout (disp)
struct display *disp;
{
int *widths = disp->widths;
int *heights = disp->heights;
int *rowy = disp->rowy;
int *colx = disp->colx;
int rows = disp->range.hr - disp->range.lr + 1;
int cols = disp->range.hc - disp->range.lc + 1;
int ri, ci;
struct cell_display *cd;

/* This assigns each non-empty cell's space to itself. The rest of the */
/* function allocates the space held by empty cells. */
for (cd = disp->cells, ri = 0; ri < rows; ++ri)
for (ci = 0; ci < cols; ++ci, ++cd)
{
cd->was_used_by = cd->used_by;
cd->used_by = cd->unclipped ? cd : 0;
}

for (ri = 0; ri < rows; ++ri)
for (ci = 0; ci < cols; ++ci)
{
struct cell_display *cd =
cell_display_of (disp, ri + disp->range.lr, ci + disp->range.lc);
if (cd->unclipped)
{
xx_IntRectangle gr = &cd->goal;
int xl = xx_IRxl (gr);
int xh = xx_IRxh (gr);
int yl = xx_IRyl (gr);
int rl_answer, rh_answer, cl_answer, ch_answer;
int rl, rh, cl, ch;
int rit, cit;
int xt, yt;

for (cl = ci, xt = colx[cl];
cl && (xt > xl);
--cl, xt = colx[cl]);
for (rl = ri, yt = rowy[rl];
rl && (yt > yl);
--rl, yt = rowy[rl]);
for (ch = ci, xt = colx[ch] + widths[ch];
(ch < (cols - 1)) && (xt < xh);
++ch, xt = colx[ch] + widths[ch]);
rh = ri;
/* rl/h & cl/h bound the cells covered by the goal rectangle.
* Of these, at least ri, ci is unused. The goal here is to
* allocate additional cells for use by ri,ci.
*/
for (rit = ri - 1; rit >= rl; --rit)
for (cit = cl; ci <= ch; ++cit)
{
struct cell_display *cdt = disp->cells + (rit * cols) + cit;
if (cdt->used_by)
goto got_rl;
}
got_rl:
++rit;
rl_answer = rit;

for (rit = ri + 1; rit <= rh; ++rit)
for (cit = cl; ci <= ch; ++cit)
{
struct cell_display *cdt = disp->cells + (rit * cols) + cit;
if (cdt->used_by)
goto got_rh;
}
got_rh:
--rit;
rh_answer = rit;

for (cit = ci - 1; cit >= cl; --cit)
for (rit = rl_answer; rit <= rh_answer; ++rit)
{
struct cell_display *cdt = disp->cells + (rit * cols) + cit;
if (cdt->used_by)
goto got_cl;
}
got_cl:
++cit;
cl_answer = cit;

for (cit = ci + 1; cit <= ch; ++cit)
for (rit = rl_answer; rit <= rh_answer; ++rit)
{
struct cell_display *cdt = disp->cells + (rit * cols) + cit;
if (cdt->used_by)
goto got_ch;
}
got_ch:
--cit;
ch_answer = cit;

for (rit = rl_answer; rit <= rh_answer; ++rit)
for (cit = cl_answer; cit <= ch_answer; ++cit)
{
struct cell_display *cdt = disp->cells + (rit * cols) + cit;
cdt->used_by = cd;
if (cdt->was_used_by != cdt->used_by)
{
damage (disp, cdt);
damage (disp, cdt->was_used_by);
}
}

xx_IRinit (&cd->layout,
colx[cl_answer], rowy[rl_answer],
colx[ch_answer] + widths[ch_answer] - colx[cl_answer],
rowy[rh_answer] + heights[rh_answer] - rowy[rl_answer]);
}
}

/* Unused cells are given to themselves. */
for (cd = disp->cells, ri = 0; ri < rows; ++ri)
for (ci = 0; ci < cols; ++ci, ++cd)
if (!cd->used_by)
{
cd->used_by = cd;
if (cd->was_used_by != cd)
{
damage (disp, cd);
damage (disp, cd->was_used_by);
}
xx_IRinit (&cd->layout, colx[ci], rowy[ri],
widths[ci], heights[ri]);
}
}
oleo-1.3/print.c 644 722 0 43161 5355700402 12007 0ustar lordwheel/* Copyright (C) 1992, 1993 Free Software Foundation, Inc.

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, 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 software; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */

#include
#include
#include "display.h"
#include "font.h"
#include "global.h"
#include "cmd.h"
#include "io-generic.h"
#include "io-abstract.h"



#ifdef __STDC__
static void
put_eps_header (struct display *dpy, float scale, float wid, float hgt, FILE *fp)
#else
static void
put_eps_header (dpy, scale, wid, hgt, fp)
struct display *dpy;
float scale;
float wid;
float hgt;
FILE *fp;
#endif
{
int dpy_wid = display_width (dpy);
int dpy_hgt = display_height (dpy);
struct font_memo *fm;
fputs ("%!PS-Adobe-2.0 EPSF-2.0\n", fp);
fprintf (fp, "%%%%BoundingBox: %d %d %d %d\n",
0, 0,
(int) ((float) dpy_wid * scale),
(int) ((float) (dpy_hgt + 1) * scale));
fputs ("%%Creator: oleo\n", fp);
fputs ("%%DocumentFonts: Times-Roman", fp);
for (fm = font_list; fm; fm = fm->next)
fprintf (fp, " %s", fm->names->ps_name);
fputc ('\n', fp);
{
time_t the_record_of_the_time = time (0);
fprintf (fp, "%%%%CreationDate: %s\n", ctime (&the_record_of_the_time));
}
fputs ("%%EndComments\n", fp);
}

#ifdef __STDC__
void
put_ps_string (char *str, FILE *fp)
#else
void
put_ps_string (str, fp)
char *str;
FILE *fp;
#endif
{
fputc ('(', fp);
while (*str)
{
if (*str == ')')
fputs ("\\)", fp);
else if (*str == '(')
fputs ("\\(", fp);
else
fputc (*str, fp);
++str;
}
fputc (')', fp);
}

#ifdef __STDC__
void
psprint_region (FILE * fp, struct rng * rng, float wid, float hgt, char * font)
#else
void
psprint_region (fp, rng, wid, hgt, font)
FILE *fp;
struct rng *rng;
float wid, hgt;
char * font;
#endif
{
struct display dpy;
int rows = rng->hr - rng->lr + 1;
int cols = rng->hc - rng->lc + 1;
int dpy_wid;
int dpy_hgt;
float scale;

build_unscaled_display (&dpy, rng, 0, 0);
dpy_wid = display_width (&dpy);
dpy_hgt = display_height (&dpy);
scale = wid / (float) dpy_wid;
if (scale * dpy_hgt > hgt)
scale = hgt / (float) dpy_hgt;

put_eps_header (&dpy, scale, wid, hgt, fp);
fprintf (fp, "/min { 2 copy lt { pop } if } def\n");
fprintf (fp, "/max { 2 copy lt { exch pop } if } def\n");
fprintf (fp, "/fed { exch def } def\n");
fprintf (fp, "/gget { cvi get } def\n");
fprintf (fp, "%% Some basic facts about the region being printed. \n");
fprintf (fp, "/CharsWide %d def\n", dpy_wid);
fprintf (fp, "/CharsTall %d def\n", dpy_hgt);
fprintf (fp, "/Cols %d def\n", cols);
fprintf (fp, "/Rows %d def\n", rows);
fprintf (fp, "%% The scale is just the point size of the default font. \n");
fprintf (fp, "%% The value here is just an initial approximation. The real value\n");
fprintf (fp, "%% is computed below.\n");
fprintf (fp, "/Scale %f def\n", scale);
fprintf (fp, "/PointsWide CharsWide Scale mul def\n");
fprintf (fp, "/PointsTall CharsTall Scale mul def\n");
fprintf (fp, "\n");
fprintf (fp, "%% font setup\n");
fprintf (fp, "/pair-sub \n");
fprintf (fp, "{\n");
fprintf (fp, " 3 -1 roll exch sub 3 1 roll sub exch\n");
fprintf (fp, "} def\n");
fprintf (fp, "/font-box\n");
fprintf (fp, "{\n");
fprintf (fp, " dup /FontBBox get /font-box-box fed\n");
fprintf (fp, " /FontMatrix get /font-box-matrix fed\n");
fprintf (fp, " font-box-box font-box-matrix transform\n");
fprintf (fp, " 4 2 roll font-box-matrix transform\n");
fprintf (fp, " pair-sub \n");
fprintf (fp, "} def\n");
fprintf (fp, "/DefaultFontName /%s def\n", default_font()->names->ps_name);
fprintf (fp, "/BasicDefaultFont DefaultFontName findfont def\n");
fprintf (fp, "/DefaultFontSize Scale round def\n");
fprintf (fp, "/SizeDir 1 def\n");
fprintf (fp, "{ \n");
fprintf (fp, " DefaultFontSize 4 le { exit } if\n");
fprintf (fp, " /DefaultFont BasicDefaultFont DefaultFontSize scalefont def\n");
fprintf (fp, " DefaultFont setfont \n");
fprintf (fp, " DefaultFont font-box\n");
fprintf (fp, " Scale le exch Scale le and not\n");
fprintf (fp, " { /SizeDir -1 def } { SizeDir 0 le { exit } if } ifelse\n");
fprintf (fp, " /DefaultFontSize DefaultFontSize SizeDir add def\n");
fprintf (fp, "} loop\n");
fprintf (fp, "/DefaultFontSize DefaultFontSize def\n");
fprintf (fp, "/DefaultFont BasicDefaultFont DefaultFontSize scalefont def\n");
fprintf (fp, "/Scale DefaultFontSize def\n");
fprintf (fp, "\n");
fprintf (fp, "DefaultFont font-box\n");
fprintf (fp, "/Scaleh fed\n");
fprintf (fp, "/Scalew fed\n");
fprintf (fp, "\n");
fprintf (fp, "/CellsUsed Rows Cols mul array def\n");
fprintf (fp, "0 1 Rows Cols mul 1 sub { CellsUsed exch false put } for\n");
fprintf (fp, "\n");
fprintf (fp, "/checkused %% r c -- bool\n");
fprintf (fp, "{\n");
fprintf (fp, " exch Cols mul add CellsUsed exch gget\n");
fprintf (fp, "} def\n");
fprintf (fp, "\n");
fprintf (fp, "/setused %% r c -- \n");
fprintf (fp, "{\n");
fprintf (fp, " exch Cols mul add CellsUsed exch true put\n");
fprintf (fp, "} def\n");
fprintf (fp, "\n");
{
int ri, ci;
for (ri = 0; ri < rows; ++ri)
for (ci = 0; ci < cols; ++ci)
{
struct cell_display * cd = dpy.cells + ri * cols + ci;
if (cd->unclipped)
fprintf (fp, "%d %d setused\n", ri, ci);
}
fprintf (fp, "/Rowy [ ");
for (ri = 0; ri < rows; ++ri)
fprintf (fp, "%d ", dpy.rowy[ri]);
fprintf (fp, "] def\n/Colx [ ");
for (ci = 0; ci < cols; ++ci)
fprintf (fp, "%d ", dpy.colx[ci]);
fprintf (fp, "] def\n");
fprintf (fp, "/Heights [ ");
for (ri = 0; ri < rows; ++ri)
fprintf (fp, "%d ", dpy.heights[ri]);
fprintf (fp, "] def\n/Widths [ ");
for (ci = 0; ci < cols; ++ci)
fprintf (fp, "%d ", dpy.widths[ci]);
fprintf (fp, "] def\n");
}
fprintf (fp, "\n");
fprintf (fp, "/to-oleo-matrix\n");
fprintf (fp, " 0 PointsTall neg matrix translate \n");
fprintf (fp, " 1 Scalew div 1 Scaleh div neg matrix scale\n");
fprintf (fp, " matrix concatmatrix def\n");
fprintf (fp, "\n");
fprintf (fp, "/from-oleo-matrix to-oleo-matrix matrix invertmatrix def\n");
fprintf (fp, "\n");
fprintf (fp, "/rc-to-oleo-xy { Colx exch gget exch Rowy exch gget } def\n");
fprintf (fp, "/rc-to-oleo-wh { Widths exch gget exch Heights exch gget } def\n");
fprintf (fp, "/oleo-xy-to-ps { from-oleo-matrix transform } def\n");
fprintf (fp, "/rc-to-xy { rc-to-oleo-xy oleo-xy-to-ps } def\n");
fprintf (fp, "/rc-to-wh { rc-to-oleo-wh Scaleh mul exch Scalew mul exch } def\n");
fprintf (fp, "/oleo-box-to-ps\n");
fprintf (fp, "{ \n");
fprintf (fp, " dup dup 0 gget exch 1 gget oleo-xy-to-ps\n");
fprintf (fp, " 3 -1 roll dup dup 2 gget exch 3 gget oleo-xy-to-ps\n");
fprintf (fp, " 3 -1 roll astore\n");
fprintf (fp, "} def\n");
fprintf (fp, "\n");
fprintf (fp, "\n");
fprintf (fp, "/cell-goal %% string just r c -- [x y x' y']\n");
fprintf (fp, "{\n");
fprintf (fp, " 3 index stringwidth pop /cell-goal-w exch def\n");
fprintf (fp, " /cell-goal-h DefaultFontSize 2 add def\n");
fprintf (fp, " 2 copy rc-to-xy %% str j r c xcel ycel\n");
fprintf (fp, " 5 -1 roll dup 0 lt \n");
fprintf (fp, " { pop } %% str r c xstr ycel\n");
fprintf (fp, " { 0 eq %% str r c xcel ycel bool\n");
fprintf (fp, " Widths 4 index gget Scalew mul exch %% str r c xcel ycel wcell bool\n");
fprintf (fp, " { cell-goal-w sub 2 div 3 -1 roll add exch }\n");
fprintf (fp, " { 2 index add cell-goal-w sub 3 -1 roll pop exch } ifelse \n");
fprintf (fp, " %% str r c xstr ycel \n");
fprintf (fp, " } ifelse \n");
fprintf (fp, " %% str r c xstr ycel \n");
fprintf (fp, " 5 -3 roll pop pop pop\n");
fprintf (fp, " 2 copy cell-goal-h add exch cell-goal-w add exch\n");
fprintf (fp, " 4 array astore \n");
fprintf (fp, "} def\n");
fprintf (fp, "\n");
fprintf (fp, "/layout %% [x y x' y'] r c -- [rlo clo rhi chi]\n");
fprintf (fp, "{\n");
fprintf (fp, " 2 copy \n");
fprintf (fp, " /layout_c fed\n");
fprintf (fp, " /layout_r fed\n");
fprintf (fp, " exch 2 copy 4 array astore %% [x y x' y'] [c r c r]\n");
fprintf (fp, " /layout_answer fed\n");
fprintf (fp, " /layout_goal fed\n");
fprintf (fp, "\n");
fprintf (fp, " layout_answer 0 gget \n");
fprintf (fp, " {\n");
fprintf (fp, " dup 0 eq { exit } if\n");
fprintf (fp, " dup Colx exch gget Scalew mul layout_goal 0 gget le { exit } if\n");
fprintf (fp, " 1 sub\n");
fprintf (fp, " } loop\n");
fprintf (fp, " layout_answer exch 0 exch put\n");
fprintf (fp, "\n");
fprintf (fp, " layout_answer 1 gget \n");
fprintf (fp, " {\n");
fprintf (fp, " dup 0 eq { exit } if\n");
fprintf (fp, " dup Rowy exch gget Scaleh mul layout_goal 1 gget le { exit } if\n");
fprintf (fp, " 1 sub\n");
fprintf (fp, " } loop\n");
fprintf (fp, " layout_answer exch 3 exch put\n");
fprintf (fp, "\n");
fprintf (fp, " layout_answer 2 gget \n");
fprintf (fp, " {\n");
fprintf (fp, " dup Cols 1 sub eq { exit } if\n");
fprintf (fp, " dup dup Colx exch gget exch Widths exch gget add Scalew mul\n");
fprintf (fp, " layout_goal 2 gget gt { exit } if\n");
fprintf (fp, " 1 add \n");
fprintf (fp, " } loop\n");
fprintf (fp, " layout_answer exch 2 exch put\n");
fprintf (fp, "\n");
fprintf (fp, " layout_answer dup 0 gget exch 1 gget \n");
fprintf (fp, " layout_answer exch 0 exch put layout_answer exch 1 exch put\n");
fprintf (fp, " layout_answer dup 2 gget exch 3 gget \n");
fprintf (fp, " layout_answer exch 2 exch put layout_answer exch 3 exch put\n");
fprintf (fp, " layout_answer 1 gget 1 layout_answer 3 gget\n");
fprintf (fp, " {\n");
fprintf (fp, " /layout_ct fed\n");
fprintf (fp, " layout_r 1 layout_answer 2 gget \n");
fprintf (fp, " {\n");
fprintf (fp, " /layout_rt fed\n");
fprintf (fp, " layout_rt layout_ct checkused \n");
fprintf (fp, " {\n");
fprintf (fp, " layout_ct layout_c lt\n");
fprintf (fp, " { layout_ct 1 add layout_answer 1 gget max layout_answer exch 1 exch put }\n");
fprintf (fp, " if\n");
fprintf (fp, " layout_ct layout_c gt\n");
fprintf (fp, " { layout_ct 1 sub layout_answer 3 gget min layout_answer exch 3 exch put }\n");
fprintf (fp, " if\n");
fprintf (fp, " layout_rt layout_r lt\n");
fprintf (fp, " { layout_rt 1 add layout_answer 0 gget max layout_answer exch 0 exch put }\n");
fprintf (fp, " if\n");
fprintf (fp, " } if\n");
fprintf (fp, " } for\n");
fprintf (fp, " } for\n");
fprintf (fp, "\n");
fprintf (fp, " layout_answer 0 gget 1 layout_answer 2 gget \n");
fprintf (fp, " {\n");
fprintf (fp, " /layout_rt fed\n");
fprintf (fp, " layout_answer 1 gget 1 layout_answer 3 gget\n");
fprintf (fp, " {\n");
fprintf (fp, " layout_rt exch setused\n");
fprintf (fp, " } for \n");
fprintf (fp, " } for\n");
fprintf (fp, "\n");
fprintf (fp, " layout_answer\n");
fprintf (fp, "} def\n");
fprintf (fp, "\n");
fprintf (fp, "\n");
fprintf (fp, "/add-pair\n");
fprintf (fp, "{\n");
fprintf (fp, " 3 -1 roll add 3 1 roll add exch\n");
fprintf (fp, "} def\n");
fprintf (fp, "\n");
fprintf (fp, "/layout-to-oleo-box\n");
fprintf (fp, "{\n");
fprintf (fp, " dup dup 0 gget exch 1 gget rc-to-oleo-xy 3 -1 roll\n");
fprintf (fp, " dup 0 gget exch 1 gget \n");
fprintf (fp, " 2 copy rc-to-oleo-xy 4 2 roll\n");
fprintf (fp, " rc-to-oleo-wh add-pair\n");
fprintf (fp, " 4 array astore\n");
fprintf (fp, "} def\n");
fprintf (fp, "\n");
fprintf (fp, "/layout-to-bbox\n");
fprintf (fp, "{\n");
fprintf (fp, " layout-to-oleo-box oleo-box-to-ps\n");
fprintf (fp, "} def\n");
fprintf (fp, "\n");
fprintf (fp, "/boxpath\n");
fprintf (fp, "{\n");
fprintf (fp, " newpath\n");
fprintf (fp, " dup dup 0 gget exch 1 gget moveto\n");
fprintf (fp, " dup dup 0 gget exch 3 gget lineto\n");
fprintf (fp, " dup dup 2 gget exch 3 gget lineto\n");
fprintf (fp, " dup 2 gget exch 1 gget lineto\n");
fprintf (fp, " closepath\n");
fprintf (fp, "} def\n");
fprintf (fp, "\n");
fprintf (fp, "/use-font\n");
fprintf (fp, "{\n");
fprintf (fp, " /CellFont fed\n");
fprintf (fp, " CellFont setfont\n");
fprintf (fp, " CellFont /FontBBox get\n");
fprintf (fp, " dup dup 0 gget exch 1 gget CellFont /FontMatrix get transform\n");
fprintf (fp, " neg /CellFontDescent fed\n");
fprintf (fp, " neg /CellFontLbearing fed\n");
fprintf (fp, " 3 gget 0 exch CellFont /FontMatrix get transform exch pop\n");
fprintf (fp, " /CellFontAscent fed\n");
fprintf (fp, "} def\n");
fprintf (fp, "DefaultFont use-font\n");
fprintf (fp, "\n");
fprintf (fp, "/cell %% str just r c\n");
fprintf (fp, "{\n");
fprintf (fp, " /cell-c fed\n");
fprintf (fp, " /cell-r fed\n");
fprintf (fp, " /cell-j fed\n");
fprintf (fp, " /cell-s fed\n");
fprintf (fp, " \n");
fprintf (fp, " /cell-g cell-s cell-j cell-r cell-c cell-goal def\n");
fprintf (fp, " /cell-l cell-g cell-r cell-c layout layout-to-bbox def\n");
fprintf (fp, "\n");
fprintf (fp, " cell-g 0 get cell-g 1 get moveto\n");
fprintf (fp, " CellFontLbearing\n");
fprintf (fp, " CellFontAscent neg rmoveto\n");
fprintf (fp, " cell-s show\n");
fprintf (fp, "} def\n");
fprintf (fp, "\n");
{
int ri, ci;
struct font_memo * last_font = default_font ();
for (ri = 0; ri < rows; ++ri)
for (ci = 0; ci < cols; ++ci)
{
struct cell_display * cd = dpy.cells + ri * cols + ci;
if (cd->unclipped)
{
fprintf (fp, "/S ");
put_ps_string (cd->unclipped, fp);
fprintf (fp, " def \nS ");
switch (cd->justification)
{
default:
case JST_LFT:
fprintf (fp, " -1 ");
break;
case JST_CNT:
fprintf (fp, " 0 ");
break;
case JST_RGT:
fprintf (fp, " 1 ");
break;
};

{
struct font_memo * font = cd->font;
if (!font)
font = default_font ();
if (font != last_font)
{
fprintf (fp, "/%s findfont %f DefaultFontSize mul",
font->names->ps_name, font->scale);
fprintf (fp, " scalefont use-font\n");
last_font = font;
}
fprintf (fp, "%d %d cell\n", ri, ci);
}
}
}
}
free_display (&dpy);
}



/* Front end to PostScript printing. */

struct page_size
{
char *name;
float wid;
float hgt;
};

static struct page_size size_table[] =
{
{ "letter", 612, 792 }, /* (8.5 x 11 in.) */
{ "landscape", 792, 612 }, /* (11 x 8.5 in.) */
{ "tabloid", 792, 1224 }, /* (11 x 17 in.) */
{ "ledger", 1224, 792 }, /* (17 x 11 in.) */
{ "legal", 612, 1008 }, /* (8.5 x 14 in.) */
{ "statement", 396, 612 }, /* (5.5 x 8.5 in.) */
{ "executive", 540, 720 }, /* (7.5 x 10 in.) */
{ "a3", 842, 1190 },
{ "a4", 595, 842 },
{ "latex-a4", 523, 770 }, /* A4 - 1in margins all round */
{ "a5", 420, 595 },
{ "b4", 729, 1032 },
{ "b5", 516, 729 },
{ "folio", 612, 936 }, /* (8.5 x 13 in.) */
{ "quarto", 610, 780 }
};

#ifdef __STDC__
static struct page_size *
find_size( char * size, int len )
#else
static struct page_size *
find_size( size, len )
char *size;
int len;
#endif
{
int i;
struct page_size *p = size_table;

for (i = 0;
i < sizeof(size_table)/sizeof(struct page_size);
i++, p++)
if (strincmp (size, p->name, len) == 0 )
return p;
return 0;
}

static float default_pswid = 8.5 * 72.;
static float default_pshgt = 11. * 72.;

#ifdef __STDC__
void
set_page_size_cmd (char * whole_str)
#else
void
set_page_size_cmd (whole_str)
char * whole_str;
#endif
{
char * str = whole_str;
float neww;
float newh;
while (*str && isspace(*str))
++str;
if (!isdigit (*str) && *str != '.')
{
char * end = str;
struct page_size * ps;
while (*end && !isspace(*end))
++end;
ps = find_size (str, end - str);
if (ps)
{
default_pswid = ps->wid;
default_pshgt = ps->hgt;
return;
}
io_error_msg
("Bad page size (should look like `8.5 x 11' or `21.6 x 28c'): %s.",
whole_str);
return;
}
neww = atof (str);
while (*str && isdigit(*str))
++str;
if (*str == '.')
{
++str;
while (isdigit (*str))
++str;
}
while (*str && isspace(*str))
++str;
if (*str == 'x')
{
++str;
while (*str && isspace(*str))
++str;
}
if (!isdigit (*str) && *str != '.')
{
io_error_msg
("Bad page size (should look like `8.5 x 11' or `21.6 x 28c'): %s.",
whole_str);
return;
}
newh = atof (str);
while (*str && isdigit(*str))
++str;
if (*str == '.')
{
++str;
while (*str && isdigit (*str))
++str;
}
while (*str && isspace(*str))
++str;
if (*str == 'c')
{
neww *= .3937;
newh *= .3937;
}
if (*str != 'p')
{
default_pswid = neww * 72;
default_pshgt = newh * 72;
}
}

#ifdef __STDC__
void
psprint_region_cmd (FILE *fp, struct rng *rng)
#else
void
psprint_region_cmd (fp, rng)
FILE *fp;
struct rng *rng;
#endif
{
psprint_region (fp, rng, default_pswid, default_pshgt, 0);
}


oleo-1.3/init.c 644 722 0 54051 5355700401 11615 0ustar lordwheel/* Copyright (C) 1993 Free Software Foundation, Inc.

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, 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 software; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */

#include "proto.h"
#include "init.h"
#include "global.h"
#include "io-term.h"
#include "utils.h"
#include "cmd.h"
/*
* These commands are run before we are ready to do output. They
* should not do any kind of io or cause errors. If they do, you
* will experience core dumps.
*/
char *init_cmds[] =
{
"",
"# The keymap tree.",
"",
"# The map `universal' already exists, and is always the keymap of last",
"# resort. It is almost always a bad idea to add new bindings there.",
"",
"# This is the generic top-level keymap. It should contain bindings that",
"# apply at the top level keymap regardless of what mode the editor is in.",
"# All keymaps that are used at the top level should inerit from this.",
"create-keymap generic-main universal",
"",
"# This is the keymap in force at the top level when no command arguments are",
"# being editted.",
"create-keymap main generic-main",
"",
"# The keymap after a M- or ESC prefix in main:",
"create-keymap generic-meta universal",
"create-keymap meta generic-meta",
"",
"# The keymap for ESC [, Arrow keys are bound in this map.",
"create-keymap generic-ansi universal",
"create-keymap ansi generic-ansi",
"",
"create-keymap generic-trolx universal",
"create-keymap trolx generic-trolx",
"",
"# Bindings that define prefix keys.",
"bind-key generic-main generic-meta ^[",
"bind-key main meta ^[",
"",
"create-keymap mouse universal",
"bind-key generic-main mouse ^\\\\",
"bind-key mouse mouse-goto 0",
"bind-key mouse mouse-mark 1",
"bind-key mouse mouse-mark-and-goto 2",
"",
"",
"bind-key generic-main generic-trolx ^x",
"bind-key main trolx ^x",
"",
"bind-key generic-meta generic-ansi [",
"bind-key meta ansi [",
"",
"# Misc generic commands",
"",
"bind-key universal break ^g",
"bind-key universal redraw-screen ^l",
"bind-key generic-main universal-argument ^u",
"bind-key generic-main suspend-oleo ^z",
"bind-key generic-trolx kill-oleo ^c",
"bind-key generic-trolx recalculate !",
"bind-key generic-meta execute-command x",
"",
"# Prefix argument handling",
"# This keymap is magicly invoked within command_loop in cmd.c.",
"create-keymap prefix universal",
"bind-set prefix universal-argument 0-9",
"bind-key prefix universal-argument -",
"",
"#",
"# Cursor motion",
"#",
"",
"# For EMACS users",
"# Notice that these motion commands are not bound genericly. They don't",
"# in general apply if the input area is active.",
"",
"bind-key main up-cell ^p",
"bind-key main right-cell ^f",
"bind-key main left-cell ^b",
"bind-key main down-cell ^n",
"",
"# Ansi motion.",
"bind-key generic-ansi up-cell A",
"bind-key generic-ansi down-cell B",
"bind-key generic-ansi left-cell C",
"bind-key generic-ansi right-cell D",
"",
"# These are only useful under X, but there, they are quite useful.",
"name-macro-string up-cell-and-edit \\",
"{exit-minibuffer}{up-cell}{edit-cell}",
"name-macro-string down-cell-and-edit \\",
"{exit-minibuffer}{down-cell}{edit-cell}",
"name-macro-string left-cell-and-edit \\",
"{exit-minibuffer}{left-cell}{edit-cell}",
"name-macro-string right-cell-and-edit \\",
"{exit-minibuffer}{right-cell}{edit-cell}",
"",
"create-keymap edit-ansi generic-ansi",
"bind-key edit-ansi up-cell-and-edit A",
"bind-key edit-ansi down-cell-and-edit B",
"bind-key edit-ansi forward-char C",
"bind-key edit-ansi backward-char D",
"",
"create-keymap meta-edit-ansi universal",
"bind-key edit-ansi meta-edit-ansi ^[",
"bind-key meta-edit-ansi up-cell-and-edit A",
"bind-key meta-edit-ansi down-cell-and-edit B",
"bind-key meta-edit-ansi left-cell-and-edit C",
"bind-key meta-edit-ansi right-cell-and-edit D",
"",
"bind-key trolx goto-cell j",
"bind-key meta goto-region j",
"",
"# Going to extremes",
"bind-key meta upper-left <",
"bind-key meta lower-right >",
"",
"# Marking time",
"bind-key trolx exchange-point-and-mark ^X",
"bind-key main mark-cell ^@",
"",
"# Scrolling commands.",
"bind-key meta scroll-up v",
"bind-key main scroll-down ^V",
"bind-key trolx scroll-right >",
"bind-key trolx scroll-left <",
"",
"# Other ways of moving the cell cursor.",
"",
"bind-key meta scan-up p",
"bind-key meta scan-down n",
"bind-key meta scan-left b",
"bind-key meta scan-right f",
"",
"bind-key main beginning-of-row ^a",
"bind-key main end-of-row ^e",
"bind-key meta beginning-of-col ^a",
"bind-key meta end-of-col ^e",
"",
"# Macros",
"bind-key generic-trolx start-entering-macro (",
"bind-key generic-trolx stop-entering-macro )",
"bind-key generic-trolx call-last-kbd-macro e",
"bind-key generic-trolx store-last-macro =",
"",
"# The keymap used when prompting for a key-sequence: ",
"create-keymap read-keyseq universal",
"bind-set read-keyseq self-map-command \\000-\\377",
"",
"# Help commands",
"create-keymap generic-help universal",
"create-keymap unprompted-help generic-help",
"create-keymap help generic-help",
"bind-key generic-main unprompted-help ^h",
"bind-key main help ^h",
"bind-key unprompted-help help ^h",
"bind-key unprompted-help help ?",
"",
"set-map-prompt help \\",
"Help keys (type ? for more explanation): C c f F k o v w W ^W",
"",
"bind-key generic-help help-with-command C",
"bind-key generic-help describe-key-briefly c",
"bind-key generic-help describe-function f",
"bind-key generic-help describe-formula F",
"bind-key generic-help describe-key k",
"bind-key generic-help show-options o",
"bind-key generic-help show-variable v",
"bind-key generic-help show-all-variables ^v",
"bind-key generic-help where-is w",
"",
"name-macro-string view-wallchart \\",
"{make-wallchart-info}{with-keymap view-info}{set-info wallchart}",
"bind-key generic-help view-wallchart W",
"",
"name-macro-string write-wallchart \\",
"{make-wallchart-info}{write-info wallchart}",
"bind-key generic-help write-wallchart ^w",
"",
"create-keymap verbose-help-map generic-help",
"set-map-prompt verbose-help-map \\",
"Help (+,-,ESC or one of the help characters): ",
"",
"",
"name-macro-string verbose-help \\",
" {with-keymap verbose-help-map}{builtin-help help-with-help}",
"",
"bind-key help verbose-help ^h",
"bind-key help verbose-help ?",
"",
"bind-key verbose-help-map exit-minibuffer ^[",
"bind-key verbose-help-map page-info +",
"bind-key verbose-help-map page-info-backwards -",
"",
"name-macro-string verbose-hwc {exit-minibuffer}{help-with-command}",
"name-macro-string verbose-dkb {exit-minibuffer}{describe-key-briefly}",
"name-macro-string verbose-df {exit-minibuffer}{describe-function}",
"name-macro-string verbose-dk {exit-minibuffer}{describe-key}",
"name-macro-string verbose-so {exit-minibuffer}{show-options}",
"name-macro-string verbose-sv {exit-minibuffer}{show-variable}",
"name-macro-string verbose-sav {exit-minibuffer}{show-all-variables}",
"name-macro-string verbose-w {exit-minibuffer}{where-is}",
"",
"bind-key verbose-help-map verbose-hwc C",
"bind-key verbose-help-map verbose-dkb c",
"bind-key verbose-help-map verbose-df f",
"bind-key verbose-help-map verbose-dk k",
"bind-key verbose-help-map verbose-so o",
"bind-key verbose-help-map verbose-sv v",
"bind-key verbose-help-map verbose-sav ^v",
"bind-key verbose-help-map verbose-w w",
"",
"",
"# Variables",
"bind-key trolx set-variable :",
"",
"# Files",
"",
"bind-key generic-trolx save-spreadsheet ^s",
"bind-key trolx find-alternate-spreadsheet ^v",
"bind-key trolx merge-spreadsheet i",
"",
"bind-key meta copy-region c",
"bind-key meta copy-values-in-region ^c",
"bind-key meta move-region m",
"bind-key main insert-row ^o",
"bind-key meta insert-col o",
"bind-key main delete-row ^k",
"bind-key meta delete-col k",
"",
"# Changing cell formulas",
"bind-key main edit-cell =",
"",
"# Some characters start editting the current cell and then are reinterpreted",
"# as editting commands:",
"bind-set main goto-edit-cell a-z",
"bind-set main goto-edit-cell A-Z",
"bind-set main goto-edit-cell 0-9",
"bind-key main goto-edit-cell \\",
"bind-key main goto-edit-cell +",
"bind-key main goto-edit-cell -",
"bind-key main goto-edit-cell *",
"bind-key main goto-edit-cell /",
"bind-key main goto-edit-cell (",
"bind-key main goto-edit-cell )",
"bind-key main goto-edit-cell @",
"bind-key main goto-edit-cell ^",
"bind-key main goto-edit-cell %",
"bind-key main goto-edit-cell >",
"bind-key main goto-edit-cell <",
"bind-key main goto-edit-cell !",
"bind-key main goto-edit-cell ?",
"bind-key main goto-edit-cell :",
"bind-key main goto-edit-cell #",
"bind-key main goto-edit-cell _",
"bind-key main goto-edit-cell .",
"bind-key main goto-edit-cell ,",
"bind-key main goto-edit-cell ;",
"bind-key main goto-edit-cell \"",
"bind-key meta set-region-formula =",
"bind-key main delete-cell ^?",
"bind-key meta delete-region ^?",
"",
"",
"# Window commands",
"",
"bind-key meta recenter-window ^l",
"bind-key trolx split-window-horizontally 5",
"bind-key trolx split-window-vertically 2",
"bind-key trolx delete-window 0",
"bind-key trolx delete-other-windows 1",
"bind-key meta goto-minibuffer ^",
"bind-key trolx other-window o",
"",
"# Command argument editting",
"",
"create-keymap read-string generic-main",
"create-keymap meta-read-string generic-meta",
"create-keymap trolx-read-string generic-trolx",
"",
"bind-key read-string meta-read-string ^[",
"bind-set read-string self-insert-command \\ -~",
"bind-key read-string exit-minibuffer ^m",
"bind-key read-string beginning-of-line ^a",
"bind-key read-string end-of-line ^e",
"bind-key read-string backward-char ^b",
"bind-key meta-read-string backward-word b",
"bind-key read-string backward-delete-char ^?",
"bind-key meta-read-string backward-delete-word ^?",
"bind-key read-string forward-char ^f",
"bind-key meta-read-string forward-word f",
"bind-key read-string delete-char ^d",
"bind-key meta-read-string delete-word d",
"bind-key read-string kill-line ^k",
"bind-key meta-read-string insert-cell-expression e",
"bind-key meta-read-string insert-cell-value v",
"bind-key meta-read-string insert-rel-ref r",
"bind-key meta-read-string insert-abs-ref a",
"",
"bind-key read-string trolx-read-string ^x",
"bind-key trolx-read-string other-window o",
"",
"# Reading various argument types specificly",
"create-keymap read-symbol read-string",
"create-keymap read-word read-string",
"create-keymap read-range read-string",
"create-keymap read-filename read-string",
"create-keymap read-integer read-string",
"create-keymap read-float read-string",
"create-keymap read-formula read-string",
"",
"# Special arrow key meanings for edit mode",
"create-keymap meta-read-formula meta-read-string",
"bind-key read-formula meta-read-formula ^[",
"bind-key meta-read-formula edit-ansi [",
"",
"# auto-motion",
"create-keymap set-auto-motion universal",
"set-map-prompt set-auto-motion \\",
"Set auto-motion direction [^v<>`'/\\ or SPC for none] ",
"",
"bind-key generic-trolx set-auto-motion m",
"",
"bind-key set-auto-motion auto-move-up ^",
"bind-key set-auto-motion auto-move-down v",
"bind-key set-auto-motion auto-move-down V",
"bind-key set-auto-motion auto-move-left <",
"bind-key set-auto-motion auto-move-left ,",
"bind-key set-auto-motion auto-move-right >",
"bind-key set-auto-motion auto-move-right .",
"bind-key set-auto-motion auto-move-up-right '",
"bind-key set-auto-motion auto-move-up-left `",
"bind-key set-auto-motion auto-move-down-right \\\\ ",
"bind-key set-auto-motion auto-move-down-left /",
"bind-key set-auto-motion auto-move-no-motion \\ ",
"",
"bind-key read-formula next-edit ^i",
"bind-key read-formula next-edit-set ^j",
"",
"create-keymap read-most-chars universal",
"",
"bind-set read-most-chars exit-self-inserting \\000-\\377",
"bind-key read-most-chars break ^G",
"bind-key read-most-chars redraw-screen ^L",
"",
"create-keymap press-any universal",
"set-map-prompt press-any \\",
"Press any key to continue. ",
"bind-set press-any exit-minibuffer \\000-\\377",
"bind-key press-any break ^G",
"bind-key press-any redraw-screen ^L",
"",
"create-keymap read-char read-most-chars",
"bind-key read-char exit-self-inserting ^G",
"",
"",
"# Menu driven commands use this keymap to read menu selections",
"create-keymap read-menu read-most-chars",
"bind-key read-menu help-with-command ^h",
"",
"create-keymap read-format read-string",
"",
"# These maps are used to manipulate cell attributes.",
"# They reimplement the old format-cell, format-region and",
"# set-default commands.",
"",
"create-keymap set-cell-attr universal",
"create-keymap set-region-attr universal",
"create-keymap set-default-attr universal",
"",
"set-map-prompt set-cell-attr \\",
"Set cell [A]lignment [F]ormat f[O]nt [P]rotection [H]eight [W]idth",
"set-map-prompt set-region-attr \\",
"Set region [A]lignment [F]ormat f[O]nt [P]rotection [H]eight [W]idth",
"set-map-prompt set-default-attr \\",
"Set default [A]lignment [F]ormat f[O]nt [P]rotection [H]eight [W]idth",
"",
"bind-key meta set-default-attr d",
"bind-key meta set-region-attr r",
"bind-key meta set-cell-attr a",
"",
"bind-key set-cell-attr set-cell-alignment a",
"bind-key set-cell-attr set-cell-format f",
"bind-key set-cell-attr set-cell-font o",
"bind-key set-cell-attr set-cell-protection p",
"bind-key set-cell-attr set-cell-height h",
"bind-key set-cell-attr set-cell-width w",
"bind-key set-cell-attr set-cell-alignment A",
"bind-key set-cell-attr set-cell-format F",
"bind-key set-cell-attr set-cell-font O",
"bind-key set-cell-attr set-cell-protection P",
"bind-key set-cell-attr set-cell-height H",
"bind-key set-cell-attr set-cell-width W",
"",
"bind-key set-region-attr set-region-alignment a",
"bind-key set-region-attr set-region-format f",
"bind-key set-region-attr set-region-font o",
"bind-key set-region-attr set-region-protection p",
"bind-key set-region-attr set-region-height h",
"bind-key set-region-attr set-region-width w",
"bind-key set-region-attr set-region-alignment A",
"bind-key set-region-attr set-region-format F",
"bind-key set-region-attr set-region-font O",
"bind-key set-region-attr set-region-protection P",
"bind-key set-region-attr set-region-height H",
"bind-key set-region-attr set-region-width W",
"",
"bind-key set-default-attr set-default-alignment a",
"bind-key set-default-attr set-default-format f",
"bind-key set-default-attr set-default-font o",
"bind-key set-default-attr set-default-protection p",
"bind-key set-default-attr set-default-height h",
"bind-key set-default-attr set-default-width w",
"bind-key set-default-attr set-default-alignment A",
"bind-key set-default-attr set-default-format F",
"bind-key set-default-attr set-default-font O",
"bind-key set-default-attr set-default-protection P",
"bind-key set-default-attr set-default-height H",
"bind-key set-default-attr set-default-width W",
"",
"create-keymap view-info universal",
"bind-key view-info exit-minibuffer ^[",
"bind-key view-info page-info \\ ",
"bind-key view-info page-info +",
"bind-key view-info page-info-backwards -",
"",
"set-map-prompt view-info \\",
"+ (forward page) - (backward page) ESC (return to spreadsheet editting)",
"",
"",
"",
" ",
"",
"# Verbose menu type keymaps use exit-minibuffer to move closer",
"# to the root of the menu.",
"",
"create-keymap generic-menu universal",
"bind-key generic-menu exit-minibuffer ^[",
"bind-key generic-menu exit-minibuffer ^m",
"bind-key generic-menu exit-minibuffer ^j",
"",
"# Graphing with gnuplot",
"",
"create-keymap graph-commands generic-menu",
"name-macro-string graph-setup \\",
" {with-keymap graph-commands}{builtin-help graphing}",
"bind-key generic-meta graph-setup g",
"set-map-prompt graph-commands \\",
"(R C o x y t d s p Esc)? ",
"",
"name-macro-string graph-preset-msg {display-error-msg Graph reset}",
"name-macro-string graph-presets-verbosely \\",
"{graph-presets}{graph-preset-msg}{set-info _expanded__info_graphing}",
"bind-key graph-commands graph-presets-verbosely R",
"",
"name-macro-string graph-clear-msg {display-error-msg Graph data reset}",
"name-macro-string graph-clear-verbosely \\",
"{graph-clear-datasets}{graph-clear-msg}{set-info _expanded__info_graphing}",
"bind-key graph-commands graph-clear-verbosely C",
"",
"bind-key graph-commands graph-set-data-title t",
"bind-key graph-commands graph-set-data d",
"bind-key graph-commands graph-set-style s",
"bind-key graph-commands graph-plot p",
"",
"create-keymap view-graphing-parameters view-info",
"name-macro-string graph-verify \\",
"{graph-make-info}{with-keymap view-graphing-parameters}{set-info graphing-parameters}",
"bind-key graph-commands graph-verify v",
"set-map-prompt view-graphing-parameters \\",
"+ (forward page) - (backward page) p (plot) or ESC",
"bind-key view-graphing-parameters graph-plot p",
"",
"create-keymap graph-terminal-types universal",
"name-macro-string graph-select-output \\",
"{one-command-with-keymap graph-terminal-types}{builtin-help graph-output-types}",
"bind-key graph-commands graph-select-output o",
"set-map-prompt graph-terminal-types \\",
"Graph output type (x X P): ",
"bind-key graph-terminal-types graph-x11-mono x",
"bind-key graph-terminal-types graph-x11-color X",
"bind-key graph-terminal-types graph-postscript p",
"",
"create-keymap graph-x-axis-commands generic-menu",
"name-macro-string graph-x-axis \\",
"{with-keymap graph-x-axis-commands}{builtin-help graph-x-axis-help}",
"bind-key graph-commands graph-x-axis x",
"set-map-prompt graph-x-axis-commands X-axis (s [ ] l L Esc)",
"",
"name-macro-string graph-set-x-range-low {graph-set-axis-low x}",
"name-macro-string graph-set-x-range-high {graph-set-axis-high x}",
"bind-key graph-x-axis-commands graph-set-x-range-low [",
"bind-key graph-x-axis-commands graph-set-x-range-high ]",
"bind-key graph-x-axis-commands graph-set-x-axis-symbolic s",
"name-macro-string graph-set-x-labels {graph-set-axis-labels x}",
"bind-key graph-x-axis-commands graph-set-x-labels l",
"name-macro-string graph-default-x-labels {graph-default-axis-labels x}",
"bind-key graph-x-axis-commands graph-default-x-labels L",
"",
"create-keymap graph-y-axis-commands generic-menu",
"name-macro-string graph-y-axis \\",
"{with-keymap graph-y-axis-commands}{builtin-help graph-y-axis-help}",
"bind-key graph-commands graph-y-axis y",
"set-map-prompt graph-y-axis-commands Y-axis (s [ ] l L Esc)",
"",
"name-macro-string graph-set-y-range-low {graph-set-axis-low y}",
"name-macro-string graph-set-y-range-high {graph-set-axis-high y}",
"bind-key graph-y-axis-commands graph-set-y-range-low [",
"bind-key graph-y-axis-commands graph-set-y-range-high ]",
"name-macro-string graph-set-y-labels {graph-set-axis-labels y}",
"bind-key graph-y-axis-commands graph-set-y-labels l",
"name-macro-string graph-default-y-labels {graph-default-axis-labels y}",
"bind-key graph-y-axis-commands graph-default-y-labels L",
"",
"# printing",
"",
"create-keymap print-commands universal",
"bind-key meta print-commands ^p",
"set-map-prompt print-commands \\",
"[A]scii or [P]ostscript printing? ",
"",
"bind-key print-commands print-region a",
"bind-key print-commands print-region A",
"",
"create-keymap psprint-commands universal",
"bind-key print-commands psprint-commands p",
"bind-key print-commands psprint-commands P",
"set-map-prompt psprint-commands \\",
"set default [F]ont set page [S]ize [P]rint",
"",
"bind-key psprint-commands set-page-size s",
"bind-key psprint-commands set-page-size S",
"bind-key psprint-commands set-deault-ps-font f",
"bind-key psprint-commands set-deault-ps-font F",
"bind-key psprint-commands psprint-region p",
"bind-key psprint-commands psprint-region P",
"",
"",
"# Other init commands:",
"define-font times *times-medium-r-* Times-Roman",
"define-font times-italic *times-medium-i-* Times-Italic",
"define-font times-oblique *times-medium-o-* Times-Italic",
"define-font times-bold *times-bold-r-* Times-Bold",
"define-font times-oblique-bold *times-bold-o-* Times-BoldItalic",
"define-font times-italic-bold *times-bold-i-* Times-BoldItalic",
"define-font courier *courier-medium-r-* Courier",
"define-font courier-oblique *courier-medium-o-* Courier-Italic",
"define-font courier-bold *courier-bold-r-* Courier-Bold",
"define-font courier-bold-oblique *courier-bold-o-* Courier-BoldItalic",
"define-font helvetica *helvetica-medium-r-* Helvetica",
"define-font helvetica-oblique *helvetica-medium-o-* Helvetica-Italic",
"define-font helvetica-bold *helvetica-bold-r-* Helvetica-Bold",
"define-font helvetica-bold-oblique *helvetica-bold-o-* Helvetica-BoldItalic",
"define-font fixed *fixed-medium-r-* Times-Roman",

0

};

#ifdef __STDC__
void
run_init_cmds (void)
#else
void
run_init_cmds ()
#endif
{
char **p = init_cmds;
while (*p)
{
char * cmd = strdup (*p++);
int len = strlen (cmd);
while (*p && (cmd [len - 1] == '\\'))
{
cmd [len - 1] = '\0';
len += strlen (*p);
cmd = ck_realloc (cmd, len + 1);
strcat (cmd, *p);
++p;
}
execute_command (cmd, 1);
free (cmd);
}
}
oleo-1.3/sylk.c 644 722 0 40027 5356003005 11627 0ustar lordwheel/* Copyright (C) 1990, 1992, 1993 Free Software Foundation, Inc.

This file is part of Oleo, the GNU Spreadsheet.

Oleo 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, or (at your option)
any later version.

Oleo 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 Oleo; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */

#include "funcdef.h"
#include
#include "sysdef.h"
#include "io-generic.h"
#include "io-abstract.h"
#include "global.h"
#include "cell.h"
#include "line.h"
#include "io-term.h"
#include "lists.h"
#include "io-utils.h"
#include "ref.h"
#include "regions.h"
#include "window.h"
#include "info.h"
#include "cmd.h"


/* These functions read and write Microsoft Multiplan SYLK style files
* as well as SYLK-NOA0 files. SYLK-NOA0 is the same as SYLK except that
* cell references are in rc format instead of a0 format.
*/

int sylk_a0 = 1; /* Determines sylk vs. sylk_noa0 format. */

void
sylk_read_file (fp, ismerge)
FILE *fp;
int ismerge;
{
char *ptr;
CELLREF crow = 0, ccol = 0, czrow = 0, czcol = 0;
int lineno;
char cbuf[1024];
char expbuf[1024];
char *vname, *vval;
int vlen = 0;
int cprot;
char *cexp, *cval;
CELL *cp;
struct rng rng;
int fmt = 0;
int jst = 0;
long mx_row = MAX_ROW, mx_col = MAX_COL;
int next_a0;
int old_a0;

old_a0 = a0;
next_a0 = old_a0;
a0 = sylk_a0;

lineno = 0;
if (!ismerge)
clear_spreadsheet ();
while (fgets (cbuf, sizeof (cbuf), fp))
{
lineno++;
if (lineno % 50 == 0)
io_info_msg ("Line %d", lineno);
if (ptr = (char *)index (cbuf, '\n'))
*ptr = '\0';
ptr = cbuf;
switch (*ptr)
{
case 'I': /* ID field, ignored */
if (ptr[1] != 'D' || ptr[2] != ';')
goto bad_field;
break;
case 'F': /* Format field */
vlen = 0;
ptr++;
while (*ptr)
{
if (*ptr != ';')
goto bad_field;
ptr++;
switch (*ptr++)
{
int clo, chi, cwid;
case 'C': /* Column from rows 1 to 255 */
czcol = astol (&ptr);
vlen = 2;
break;

case 'D': /* Default format */
switch (*ptr++)
{
case 'G':
default_fmt = FMT_GEN - PRC_FLT;
break;
case 'E':
default_fmt = FMT_EXP - PRC_FLT;
break;
case 'F':
default_fmt = FMT_FXT - PRC_FLT;
break;
case '$':
default_fmt = FMT_DOL - PRC_FLT;
break;
case '*': /* * format implemented as +- format */
default_fmt = FMT_GPH;
break;
case ',': /* JF */
default_fmt = FMT_CMA - PRC_FLT;
break;
case 'U':
default_fmt = FMT_USR - PRC_FLT;
break;
case '%':
default_fmt = FMT_PCT - PRC_FLT;
break;
case 'H':
default_fmt = FMT_HID;
break;
/* End of JF */
case 'C': /* Continuous not supported */
default:
io_error_msg ("Line %d: format %c not supported", lineno, ptr[-1]);
break;
}
if (*ptr == 'F')
{
default_fmt += PRC_FLT;
ptr++;
}
else
default_fmt += astol (&ptr);
switch (*ptr++)
{
case 'C':
default_jst = JST_CNT;
break;
case 'L':
default_jst = JST_LFT;
break;
case 'R':
default_jst = JST_RGT;
break;
case 'G': /* General format not supported */
default:
io_error_msg ("Line %d: Alignment %c not supported", lineno, ptr[-1]);
break;
}
default_width = astol (&ptr);
break;

case 'F':
switch (*ptr++)
{
case 'D':
fmt = FMT_DEF;
break;
case 'G':
fmt = FMT_GEN - PRC_FLT;
break;
case 'E':
fmt = FMT_EXP - PRC_FLT;
break;
case 'F':
fmt = FMT_FXT - PRC_FLT;
break;
case '$':
fmt = FMT_DOL - PRC_FLT;
break;
case '*': /* JF implemented as +- format */
fmt = FMT_GPH;
break;
case ',': /* JF */
fmt = FMT_CMA - PRC_FLT;
break;
case 'U':
fmt = FMT_USR - PRC_FLT;
break;
case '%':
fmt = FMT_PCT - PRC_FLT;
break;
case 'H':
fmt = FMT_HID;
break; /* END of JF */
case 'C':
default:
io_error_msg ("Line %d: format %c not supported", lineno, ptr[-1]);
fmt = FMT_DEF;
break;
}
if (*ptr == 'F')
{
fmt += PRC_FLT;
ptr++;
}
else
fmt += astol (&ptr);
switch (*ptr++)
{
case 'C':
jst = JST_CNT;
break;
case 'L':
jst = JST_LFT;
break;
case 'R':
jst = JST_RGT;
break;
case 'D':
jst = JST_DEF;
break;
default:
io_error_msg ("Line %d: Alignment %c not supported", lineno, ptr[-1]);
jst = JST_DEF;
break;
}
vlen = 1;
break;
case 'R': /* Row from cols 1 to 63 */
czrow = astol (&ptr);
vlen = 4;
break;

case 'W': /* Width of clo to chi is cwid */
clo = astol (&ptr);
chi = astol (&ptr);
cwid = astol (&ptr) + 1;
for (; clo <= chi; clo++)
set_width (clo, cwid);
break;

case 'H': /* JF: extension */
clo = astol (&ptr);
chi = astol (&ptr);
cwid = astol (&ptr) + 1;
for (; clo <= chi; clo++)
set_height (clo, cwid);
break;
case 'X':
ccol = astol (&ptr);
break;
case 'Y':
crow = astol (&ptr);
break;

default:
goto bad_field;
}
}
switch (vlen)
{
case 1:
cp = find_or_make_cell (crow, ccol);
SET_FMT (cp, fmt);
SET_JST (cp, jst);
break;
case 2:
rng.lr = MIN_ROW;
rng.lc = czcol;
rng.hr = mx_row;
rng.hc = czcol;
make_cells_in_range (&rng);
while (cp = next_cell_in_range ())
{
SET_FMT (cp, fmt);
SET_JST (cp, jst);
}
break;
case 4:
rng.lr = czrow;
rng.lc = MIN_COL;
rng.hr = czrow;
rng.hc = mx_col;
make_cells_in_range (&rng);
while (cp = next_cell_in_range ())
{
SET_FMT (cp, fmt);
SET_JST (cp, jst);
}
break;
default:
break;
}
break;

case 'B': /* Boundry field, ignored */
ptr++;
while (*ptr)
{
if (*ptr != ';')
goto bad_field;
ptr++;
switch (*ptr++)
{
case 'X':
mx_col = astol (&ptr);
if (mx_col > MAX_COL)
{
io_error_msg ("Boundry column %lu too large!", mx_col);
mx_col = MAX_COL;
}
break;
case 'Y':
mx_row = astol (&ptr);
if (mx_row > MAX_ROW)
{
io_error_msg ("Boundry row %lu too large!", mx_row);
mx_row = MAX_ROW;
}
break;
default:
goto bad_field;
}
}
break;

case 'N': /* A Name field */
if (ptr[1] != 'N')
goto bad_field;
ptr += 2;
vname = 0;
vval = 0;
while (*ptr)
{
if (*ptr != ';')
goto bad_field;
*ptr++ = '\0';
switch (*ptr++)
{
case 'N': /* Name is */
vname = ptr;
while (*ptr && *ptr != ';')
ptr++;
vlen = ptr - vname;
break;
case 'E': /* Expression is */
vval = ptr;
while (*ptr && *ptr != ';')
ptr++;
break;
default:
--ptr;
goto bad_field;
}
}
if (!vname || !vval)
goto bad_field;
*ptr = '\0';
ptr = new_var_value (vname, vlen, vval);
if (ptr)
io_error_msg ("Line %d: Couldn't set %.*s to %s: %s", lineno, vlen, vname, vval, ptr);
break;

case 'C': /* A Cell entry */
cprot = 0;
cval = 0;
cexp = 0;
cval = 0;
ptr++;
while (*ptr)
{
int quotes;

if (*ptr != ';')
goto bad_field;
*ptr++ = '\0';
switch (*ptr++)
{
case 'X':
ccol = astol (&ptr);
break;
case 'Y':
crow = astol (&ptr);
break;
case 'R':
czrow = astol (&ptr);
break;
case 'C':
czcol = astol (&ptr);
break;
case 'P': /* This cell is Protected */
cprot++;
break;
case 'K': /* This cell's Konstant value */
cval = ptr;
quotes = 0;
while (*ptr && (*ptr != ';' || quotes > 0))
if (*ptr++ == '"')
quotes = !quotes;
break;
case 'E': /* This cell's Expression */
cexp = ptr;
quotes = 0;
while (*ptr && (*ptr != ';' || quotes > 0))
if (*ptr++ == '"')
quotes = !quotes;

break;
case 'G':
strcpy (expbuf, cval);
break;
case 'D':
strcpy (expbuf, cexp);
break;
case 'S':
cexp = expbuf;
break;
default:
--ptr;
goto bad_field;
}
}
*ptr = '\0';
if (cexp && cval && strcmp (cexp, cval))
{
ptr = read_new_value (crow, ccol, cexp, cval);
if (ptr)
{
io_error_msg ("Line %d: %d,%d: Read '%s' %s", lineno, crow, ccol, cexp, ptr);
break;
}
}
else if (cval)
{
ptr = read_new_value (crow, ccol, 0, cval);
if (ptr)
{
io_error_msg ("Line %d: %d,%d: Val '%s' %s", lineno, crow, ccol, cexp, ptr);
break;
}
}
else if (cexp)
{
ptr = read_new_value (crow, ccol, cexp, 0);
if (ptr)
{
io_error_msg ("Line %d: %d,%d: Exp '%s' %s", lineno, crow, ccol, cexp, ptr);
break;
}
}
if (cprot)
SET_LCK (find_or_make_cell (crow, ccol), LCK_LCK);
if (ismerge)
push_cell (crow, ccol);
/* ... */
break;
case 'E':
break;
case 'W':
io_read_window_config (ptr + 2);
break;
case 'U':
/* JF extension: read user-defined formats */
read_mp_usr_fmt (ptr + 1);
break;
/* JF extension: read uset-settable options */
case 'O':
a0 = next_a0;
read_mp_options (ptr + 2);
next_a0 = a0;
a0 = sylk_a0;
break;
default:
bad_field:
a0 = old_a0;
if (!ismerge)
clear_spreadsheet ();
io_recenter_all_win ();
io_error_msg ("Line %d: Unknown SYLK line \"%s\"", lineno, cbuf);
return;
}
}
a0 = next_a0;
io_recenter_all_win ();
}



static char *
sylk_fmt_to_str (f1)
int f1;
{
static char p_buf[40];
int p1;

p_buf[1] = '\0';
switch (f1)
{
case FMT_DEF:
p_buf[0] = 'D';
break;
case FMT_HID:
p_buf[0] = 'H';
break;
case FMT_GPH:
p_buf[0] = '*';
break;
default:
p1 = GET_PRC (f1);
if (p1 == PRC_FLT)
{
p_buf[1] = 'F';
p_buf[2] = '\0';
}
else
sprintf (&p_buf[1], "%d", p1);
switch (f1 | PRC_FLT)
{
case FMT_USR:
p_buf[0] = 'U';
break;
case FMT_GEN:
p_buf[0] = 'G';
break;
case FMT_DOL:
p_buf[0] = '$';
break;
case FMT_PCT:
p_buf[0] = '%';
break;
case FMT_FXT:
p_buf[0] = 'F';
break;
case FMT_CMA:
p_buf[0] = ',';
break;
case FMT_EXP:
p_buf[0] = 'E';
break;
default:
p_buf[0] = '?';
break;
}
break;
}
return p_buf;
}

static char
jst_to_chr (just)
int just;
{
switch (just)
{
case JST_DEF:
return 'D';
case JST_LFT:
return 'L';
case JST_RGT:
return 'R';
case JST_CNT:
return 'C';
default:
return '?';
}
}

static FILE *sylk_fp;
static struct rng *sylk_rng;

static void
sylk_write_var (name, var)
char *name;
struct var *var;
{
if (var->var_flags == VAR_UNDEF && (!var->var_ref_fm || var->var_ref_fm->refs_used == 0))
return;
switch (var->var_flags)
{
case VAR_UNDEF:
break;
case VAR_CELL:
if (var->v_rng.lr >= sylk_rng->lr && var->v_rng.lr <= sylk_rng->hr && var->v_rng.lc >= sylk_rng->lc && var->v_rng.lc <= sylk_rng->hc)
(void) fprintf (sylk_fp, "NN;N%s;E%s\n", var->var_name, cell_name (var->v_rng.lr, var->v_rng.lc));
break;
case VAR_RANGE:
if (var->v_rng.lr < sylk_rng->lr || var->v_rng.hr > sylk_rng->hr || var->v_rng.lc < sylk_rng->lc || var->v_rng.hc > sylk_rng->hc)
break;

(void) fprintf (sylk_fp, "NN;N%s;E%s\n", var->var_name, range_name (&(var->v_rng)));
break;
#ifdef TEST
default:
panic ("Unknown var type %d", var->var_flags);
#endif
}
}

static void
write_mp_windows (fp)
FILE *fp;
{
struct line line;
line.alloc = 0;
line.buf = 0;
io_write_window_config (&line);
fputs (line.buf, fp);
free (line.buf);
}

void
sylk_write_file (fp, rng)
FILE *fp;
struct rng *rng;
{
CELLREF r, c;
CELL *cp;
CELLREF crow = 0, ccol = 0;
unsigned short w;

/* struct var *var; */
int old_a0;

(void) fprintf (fp, "ID;POLEO\n");

/* If no range given, write the entire file */
if (!rng)
{
int n;
int fmts;
char *data[9];

rng = &all_rng;

(void) fprintf (fp, "F;D%s%c%u\n", sylk_fmt_to_str (default_fmt),
jst_to_chr (default_jst), default_width);

fmts = usr_set_fmts ();
for (n = 0; n < 16; n++)
{
if (fmts & (1 << n))
{
get_usr_stats (n, data);
fprintf (fp, "U;N%u;P%s;S%s", n + 1, data[7], data[8]);
if (data[0][0])
fprintf (fp, ";HP%s", data[0]);
if (data[1][0])
fprintf (fp, ";HN%s", data[1]);
if (data[2][0])
fprintf (fp, ";TP%s", data[2]);
if (data[3][0])
fprintf (fp, ";TN%s", data[3]);
if (data[4][0])
fprintf (fp, ";Z%s", data[4]);
if (data[5][0])
fprintf (fp, ";C%s", data[5]);
if (data[6])
fprintf (fp, ";D%s", data[6]);
putc ('\n', fp);
}
}
write_mp_options (fp);

(void) fprintf (fp, "B;Y%u;X%u\n", highest_row (), highest_col ());

}

old_a0 = a0;
a0 = sylk_a0;

find_widths (rng->lc, rng->hc);
w = next_width (&c);
while (w)
{
CELLREF cc, ccc;
unsigned short ww;
cc = c;
do
ww = next_width (&ccc);
while (ccc == ++cc && ww == w);
(void) fprintf (fp, "F;W%u %u %u\n", c, cc - 1, w - 1);
c = ccc;
w = ww;
}

find_heights (rng->lr, rng->hr);
w = next_height (&c);
while (w)
{
CELLREF rr, rrr;
unsigned short ww;

rr = r;
do
ww = next_height (&rrr);
while (rrr == ++rr && ww == w);
(void) fprintf (fp, "F;H%u %u %u\n", r, rr - 1, w - 1);
r = rrr;
w = ww;
}

sylk_fp = fp;
sylk_rng = rng;
for_all_vars (sylk_write_var);
find_cells_in_range (rng);
while (cp = next_row_col_in_range (&r, &c))
{
char *ptr;
int f1, j1;
char p_buf[40];

f1 = GET_FMT (cp);
j1 = GET_JST (cp);
if (f1 != FMT_DEF || j1 != JST_DEF)
{
(void) fprintf (fp, "F;");
if (c != ccol)
{
(void) fprintf (fp, "X%u;", c);
ccol = c;
}
if (r != crow)
{
(void) fprintf (fp, "Y%u;", r);
crow = r;
}
(void) fprintf (fp, "F%s%c\n", sylk_fmt_to_str (f1), jst_to_chr (j1));
}

if (!GET_TYP (cp) && !cp->cell_formula)
continue;

(void) fprintf (fp, "C;");
if (c != ccol)
{
(void) fprintf (fp, "X%u;", c);
ccol = c;
}
if (r != crow)
{
(void) fprintf (fp, "Y%u;", r);
crow = r;
}

if (cp->cell_formula)
{
(void) fprintf (fp, "E%s", decomp (r, c, cp));
decomp_free ();
}

switch (GET_TYP (cp))
{
case 0:
ptr = 0;
break;
case TYP_STR:
ptr = 0;
if (cp->cell_formula)
putc (';', fp);
(void) fprintf (fp, "K\"%s\"", cp->cell_str);
break;
case TYP_FLT:
ptr = flt_to_str (cp->cell_flt);
break;
case TYP_INT:
sprintf (p_buf, "%ld", cp->cell_int);
ptr = p_buf;
break;
case TYP_BOL:
ptr = bname[cp->cell_bol];
break;
case TYP_ERR:
ptr = ename[cp->cell_err];
break;
default:
ptr = 0;
#ifdef TEST
panic ("What cell type %d", GET_TYP (cp));
#endif
}

if (ptr)
{
if (cp->cell_formula)
putc (';', fp);
(void) fprintf (fp, "K%s", ptr);
}
if (GET_LCK (cp) == LCK_LCK)
(void) fprintf (fp, ";P");

putc ('\n', fp);
}

if (rng == &all_rng)
write_mp_windows (fp);

(void) fprintf (fp, "E\n");
a0 = old_a0;
}

int
sylk_set_options (set_opt, option)
int set_opt;
char *option;
{
return -1;
}

void
sylk_show_options ()
{
io_text_line ("File format: sylk (Microsoft Multiplan interchange format)");
}
oleo-1.3/oleofile.c 644 722 0 45606 5356010555 12463 0ustar lordwheel/* Copyright (C) 1990, 1991, 1992, 1993 Free Software Foundation, Inc.

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, 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 software; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */

/* this file was derived from the file sylk.c */
#include "funcdef.h"
#include
#include
#include "sysdef.h"
#include "io-generic.h"
#include "io-abstract.h"
#include "io-utils.h"
#include "io-term.h"
#include "font.h"
#include "global.h"
#include "cell.h"
#include "line.h"
#include "sylk.h"
#include "lists.h"
#include "ref.h"
#include "regions.h"
#include "window.h"
#include "info.h"
#include "cmd.h"


/* These functions read and write OLEO style files. */

void
oleo_read_file (fp, ismerge)
FILE *fp;
int ismerge;
{
char *ptr;
CELLREF crow = 0, ccol = 0, czrow = 0, czcol = 0;
int lineno;
char cbuf[1024];
char expbuf[1024];
char *vname, *vval;
int vlen = 0;
int cprot;
char *cexp, *cval;
CELL *cp;
struct rng rng;
int fmt = 0;
int jst = 0;
struct font_memo * fnt = 0;
struct font_memo ** fnt_map = 0;
int fnt_map_size = 0;
int fnt_map_alloc = 0;
int font_spec_in_format = 1; /* Reset if we discover this is a v1.1 file. */

long mx_row = MAX_ROW, mx_col = MAX_COL;
int old_a0;
int next_a0;

old_a0 = a0;
next_a0 = old_a0;
a0 = 0;
lineno = 0;
if (!ismerge)
clear_spreadsheet ();
while (fgets (cbuf, sizeof (cbuf), fp))
{
lineno++;
if (lineno % 50 == 0)
io_info_msg ("Line %d", lineno);
if (ptr = (char *)index (cbuf, '\n'))
*ptr = '\0';

ptr = cbuf;
switch (*ptr)
{
case '#': /* comment line -- ignored */
break;
case '%': /* Font or pixel size data. */
ptr++;
switch (*ptr)
{
case 'F': /* %F font-name */
if (fnt_map_size == fnt_map_alloc)
{
fnt_map_alloc = (fnt_map_alloc + 1) * 2;
fnt_map =
((struct font_memo **)
ck_remalloc
(fnt_map, fnt_map_alloc * sizeof (struct font_memo *)));
}
fnt_map[fnt_map_size++] = parsed_matching_font (ptr + 1);
break;
case 'f': /* %f range font-name */
{
struct rng rng;
/* This field only occurs in files written by 1.1
* oleo. It's presense indicates that when parsing
* format fields, we should *not* reset cell fonts to 0.
*/
font_spec_in_format = 0;
++ptr;
while (isspace (*ptr))
++ptr;
if (!parse_cell_or_range (&ptr, &rng))
goto bad_field;
while (isspace (*ptr))
++ptr;
{
struct font_memo * fm = parsed_matching_font (ptr);
set_region_font (&rng, fm->names->oleo_name, fm->scale);
}
break;
}
default:
goto bad_field;
}
break;
case 'F': /* Format field */
vlen = 0;
ptr++;
fnt = 0; /* The font must be explicitly overriden for a cell. */
while (*ptr)
{
if (*ptr != ';')
goto bad_field;
ptr++;
switch (*ptr++)
{
int clo, chi, cwid;
case 'C': /* Column from rows 1 to 255 */
czcol = astol (&ptr);
vlen = 2;
break;

case 'D': /* Default format */
switch (*ptr++)
{
case 'G':
default_fmt = FMT_GEN - PRC_FLT;
break;
case 'E':
default_fmt = FMT_EXP - PRC_FLT;
break;
case 'F':
default_fmt = FMT_FXT - PRC_FLT;
break;
case '$':
default_fmt = FMT_DOL - PRC_FLT;
break;
case '*': /* * format implemented as +- format */
default_fmt = FMT_GPH;
break;
case ',': /* JF */
default_fmt = FMT_CMA - PRC_FLT;
break;
case 'U':
default_fmt = FMT_USR - PRC_FLT;
break;
case '%':
default_fmt = FMT_PCT - PRC_FLT;
break;
case 'H':
default_fmt = FMT_HID;
break;
/* End of JF */
default:
io_error_msg ("Line %d: format %c not supported", lineno, ptr[-1]);
break;
}
if (*ptr == 'F')
{
default_fmt += PRC_FLT;
ptr++;
}
else
default_fmt += astol (&ptr);
switch (*ptr++)
{
case 'C':
default_jst = JST_CNT;
break;
case 'L':
default_jst = JST_LFT;
break;
case 'R':
default_jst = JST_RGT;
break;
case 'G': /* General format not supported */
default:
io_error_msg ("Line %d: Alignment %c not supported", lineno, ptr[-1]);
break;
}
default_width = astol (&ptr);
break;

case 'f': /* Font specification */
{
int id;
id = astol(&ptr);
if (id < 0 || id >= fnt_map_size)
{
io_error_msg ("Line %d: Undefined font (%d)\n",
lineno, id);
break;
}
fnt = fnt_map[id];
break;
}

case 'F':
switch (*ptr++)
{
case 'D':
fmt = FMT_DEF;
break;
case 'G':
fmt = FMT_GEN - PRC_FLT;
break;
case 'E':
fmt = FMT_EXP - PRC_FLT;
break;
case 'F':
fmt = FMT_FXT - PRC_FLT;
break;
case '$':
fmt = FMT_DOL - PRC_FLT;
break;
case '*': /* JF implemented as +- format */
fmt = FMT_GPH;
break;
case ',': /* JF */
fmt = FMT_CMA - PRC_FLT;
break;
case 'U':
fmt = FMT_USR - PRC_FLT;
break;
case '%':
fmt = FMT_PCT - PRC_FLT;
break;
case 'H':
fmt = FMT_HID;
break; /* END of JF */
case 'C':
default:
io_error_msg ("Line %d: format %c not supported", lineno, ptr[-1]);
fmt = FMT_DEF;
break;
}
if (*ptr == 'F')
{
fmt += PRC_FLT;
ptr++;
}
else
fmt += astol (&ptr);
switch (*ptr++)
{
case 'C':
jst = JST_CNT;
break;
case 'L':
jst = JST_LFT;
break;
case 'R':
jst = JST_RGT;
break;
case 'D':
jst = JST_DEF;
break;
default:
io_error_msg ("Line %d: Alignment %c not supported", lineno, ptr[-1]);
jst = JST_DEF;
break;
}
vlen = 1;
break;
case 'R': /* Row from cols 1 to 63 */
czrow = astol (&ptr);
vlen = 4;
break;

case 'W': /* Width of clo to chi is cwid */
clo = astol (&ptr);
chi = astol (&ptr);
cwid = astol (&ptr) + 1;
for (; clo <= chi; clo++)
set_width (clo, cwid);
break;

case 'H': /* JF: extension */
clo = astol (&ptr);
chi = astol (&ptr);
cwid = astol (&ptr) + 1;
for (; clo <= chi; clo++)
set_height (clo, cwid);
break;
case 'c':
ccol = astol (&ptr);
break;
case 'r':
crow = astol (&ptr);
break;

default:
goto bad_field;
}
}
switch (vlen)
{
case 1:
cp = find_or_make_cell (crow, ccol);
SET_FMT (cp, fmt);
SET_JST (cp, jst);
if (font_spec_in_format)
cp->cell_font = fnt;
break;
case 2:
rng.lr = MIN_ROW;
rng.lc = czcol;
rng.hr = mx_row;
rng.hc = czcol;
make_cells_in_range (&rng);
while (cp = next_cell_in_range ())
{
SET_FMT (cp, fmt);
SET_JST (cp, jst);
if (font_spec_in_format)
cp->cell_font = fnt;
}
break;
case 4:
rng.lr = czrow;
rng.lc = MIN_COL;
rng.hr = czrow;
rng.hc = mx_col;
make_cells_in_range (&rng);
while (cp = next_cell_in_range ())
{
SET_FMT (cp, fmt);
SET_JST (cp, jst);
if (font_spec_in_format)
cp->cell_font = fnt;
}
break;
default:
break;
}
break;

case 'B': /* Boundry field, ignored */
ptr++;
while (*ptr)
{
if (*ptr != ';')
goto bad_field;
ptr++;
switch (*ptr++)
{
case 'c':
mx_col = astol (&ptr);
if (mx_col > MAX_COL)
{
io_error_msg ("Boundry column %lu too large!", mx_col);
mx_col = MAX_COL;
}
break;
case 'r':
mx_row = astol (&ptr);
if (mx_row > MAX_ROW)
{
io_error_msg ("Boundry row %lu too large!", mx_row);
mx_row = MAX_ROW;
}
break;
default:
goto bad_field;
}
}
break;

case 'N': /* A Name field */
if (ptr[1] != 'N')
goto bad_field;
ptr += 2;
vname = 0;
vval = 0;
while (*ptr)
{
if (*ptr != ';')
goto bad_field;
*ptr++ = '\0';
switch (*ptr++)
{
case 'N': /* Name is */
vname = ptr;
while (*ptr && *ptr != ';')
ptr++;
vlen = ptr - vname;
break;
case 'E': /* Expression is */
vval = ptr;
while (*ptr && *ptr != ';')
ptr++;
break;
default:
--ptr;
goto bad_field;
}
}
if (!vname || !vval)
goto bad_field;
*ptr = '\0';
ptr = new_var_value (vname, vlen, vval);
if (ptr)
io_error_msg ("Line %d: Couldn't set %.*s to %s: %s", lineno, vlen, vname, vval, ptr);
break;

case 'C': /* A Cell entry */
cprot = 0;
cval = 0;
cexp = 0;
cval = 0;
ptr++;
while (*ptr)
{
int quotes;

if (*ptr != ';')
goto bad_field;
*ptr++ = '\0';
switch (*ptr++)
{
case 'c':
ccol = astol (&ptr);
break;
case 'r':
crow = astol (&ptr);
break;
case 'R':
czrow = astol (&ptr);
break;
case 'C':
czcol = astol (&ptr);
break;
case 'P': /* This cell is Protected */
cprot++;
break;
case 'K': /* This cell's Konstant value */
cval = ptr;
quotes = 0;
while (*ptr && (*ptr != ';' || quotes > 0))
if (*ptr++ == '"')
quotes = !quotes;
break;
case 'E': /* This cell's Expression */
cexp = ptr;
quotes = 0;
while (*ptr && (*ptr != ';' || quotes > 0))
if (*ptr++ == '"')
quotes = !quotes;

break;
case 'G':
strcpy (expbuf, cval);
break;
case 'D':
strcpy (expbuf, cexp);
break;
case 'S':
cexp = expbuf;
break;
default:
--ptr;
goto bad_field;
}
}
*ptr = '\0';
if (cexp && cval && strcmp (cexp, cval))
{
ptr = read_new_value (crow, ccol, cexp, cval);
if (ptr)
{
io_error_msg ("Line %d: %d,%d: Read '%s' %s", lineno, crow, ccol, cexp, ptr);
break;
}
}
else if (cval)
{
ptr = read_new_value (crow, ccol, 0, cval);
if (ptr)
{
io_error_msg ("Line %d: %d,%d: Val '%s' %s", lineno, crow, ccol, cexp, ptr);
break;
}
}
else if (cexp)
{
ptr = read_new_value (crow, ccol, cexp, 0);
if (ptr)
{
io_error_msg ("Line %d: %d,%d: Exp '%s' %s", lineno, crow, ccol, cexp, ptr);
break;
}
}
if (cprot)
SET_LCK (find_or_make_cell (crow, ccol), LCK_LCK);
if (ismerge)
push_cell (crow, ccol);
/* ... */
break;
case 'E':
break;
case 'W':
io_read_window_config (ptr + 2);
break;
case 'U':
/* JF extension: read user-defined formats */
read_mp_usr_fmt (ptr + 1);
break;
/* JF extension: read uset-settable options */
case 'O':
a0 = next_a0;
read_mp_options (ptr + 2);
next_a0 = a0;
a0 = 0;
break;
default:
bad_field:
a0 = old_a0;
if (!ismerge)
clear_spreadsheet ();
io_recenter_all_win ();
io_error_msg ("Line %d: Unknown OLEO line \"%s\"", lineno, cbuf);
return;
}
}
if (!feof (fp))
{
if (!ismerge)
clear_spreadsheet ();
io_recenter_all_win ();
io_error_msg ("read-file: read-error near line %d.", lineno);
return;
}
a0 = next_a0;
io_recenter_all_win ();
}

static char *
oleo_fmt_to_str (f1)
int f1;
{
static char p_buf[40];
int p1;

p_buf[1] = '\0';
switch (f1)
{
case FMT_DEF:
p_buf[0] = 'D';
break;
case FMT_HID:
p_buf[0] = 'H';
break;
case FMT_GPH:
p_buf[0] = '*';
break;
default:
p1 = GET_PRC (f1);
if (p1 == PRC_FLT)
{
p_buf[1] = 'F';
p_buf[2] = '\0';
}
else
sprintf (&p_buf[1], "%d", p1);
switch (f1 | PRC_FLT)
{
case FMT_USR:
p_buf[0] = 'U';
break;
case FMT_GEN:
p_buf[0] = 'G';
break;
case FMT_DOL:
p_buf[0] = '$';
break;
case FMT_PCT:
p_buf[0] = '%';
break;
case FMT_FXT:
p_buf[0] = 'F';
break;
case FMT_CMA:
p_buf[0] = ',';
break;
case FMT_EXP:
p_buf[0] = 'E';
break;
default:
p_buf[0] = '?';
break;
}
break;
}
return p_buf;
}

static char
jst_to_chr (just)
int just;
{
switch (just)
{
case JST_DEF:
return 'D';
case JST_LFT:
return 'L';
case JST_RGT:
return 'R';
case JST_CNT:
return 'C';
default:
return '?';
}
}

static FILE *oleo_fp;
static struct rng *oleo_rng;

static void
oleo_write_var (name, var)
char *name;
struct var *var;
{
if (var->var_flags
== VAR_UNDEF && (!var->var_ref_fm || var->var_ref_fm->refs_used == 0))
return;
switch (var->var_flags)
{
case VAR_UNDEF:
break;
case VAR_CELL:
if (var->v_rng.lr >= oleo_rng->lr && var->v_rng.lr <= oleo_rng->hr && var->v_rng.lc >= oleo_rng->lc && var->v_rng.lc <= oleo_rng->hc)
(void) fprintf (oleo_fp, "NN;N%s;E%s\n", var->var_name, cell_name (var->v_rng.lr, var->v_rng.lc));
break;
case VAR_RANGE:
if (var->v_rng.lr < oleo_rng->lr || var->v_rng.hr > oleo_rng->hr || var->v_rng.lc < oleo_rng->lc || var->v_rng.hc > oleo_rng->hc)
break;

(void) fprintf (oleo_fp, "NN;N%s;E%s\n", var->var_name, range_name (&(var->v_rng)));
break;
#ifdef TEST
default:
panic ("Unknown var type %d", var->var_flags);
#endif
}
}

static void
write_mp_windows (fp)
FILE *fp;
{
struct line line;
line.alloc = 0;
line.buf = 0;
io_write_window_config (&line);
fputs (line.buf, fp);
free (line.buf);
}

void
oleo_write_file (fp, rng)
FILE *fp;
struct rng *rng;
{
CELLREF r, c;
CELL *cp;
CELLREF crow = 0, ccol = 0;
unsigned short w;
/* struct var *var; */
int old_a0;
int fnt_map_size = 0;

(void) fprintf (fp, "# This file was created by GNU Oleo\n");

/* All versions of the oleo file format should have a
* version cookie on the second line.
*/
(void) fprintf (fp, "# format 1.0\n");

/* If no range given, write the entire file */
if (!rng)
{
int n;
int fmts;
char *data[9];

rng = &all_rng;

(void) fprintf (fp, "F;D%s%c%u\n", oleo_fmt_to_str (default_fmt), jst_to_chr (default_jst), default_width);

fmts = usr_set_fmts ();
for (n = 0; n < 16; n++)
{
if (fmts & (1 << n))
{
get_usr_stats (n, data);
fprintf (fp, "U;N%u;P%s;S%s", n + 1, data[7], data[8]);
if (data[0][0])
fprintf (fp, ";HP%s", data[0]);
if (data[1][0])
fprintf (fp, ";HN%s", data[1]);
if (data[2][0])
fprintf (fp, ";TP%s", data[2]);
if (data[3][0])
fprintf (fp, ";TN%s", data[3]);
if (data[4][0])
fprintf (fp, ";Z%s", data[4]);
if (data[5][0])
fprintf (fp, ";C%s", data[5]);
if (data[6])
fprintf (fp, ";D%s", data[6]);
putc ('\n', fp);
}
}
write_mp_options (fp);
}

old_a0 = a0;
a0 = 0;

find_widths (rng->lc, rng->hc);
w = next_width (&c);
while (w)
{
CELLREF cc, ccc;
unsigned short ww;
cc = c;
do
ww = next_width (&ccc);
while (ccc == ++cc && ww == w);
(void) fprintf (fp, "F;W%u %u %u\n", c, cc - 1, w - 1);
c = ccc;
w = ww;
}

find_heights (rng->lr, rng->hr);
w = next_height (&r);
while (w)
{
CELLREF rr, rrr;
unsigned short ww;

rr = r;
do
ww = next_height (&rrr);
while (rrr == ++rr && ww == w);
(void) fprintf (fp, "F;H%u %u %u\n", r, rr - 1, w - 1);
r = rrr;
w = ww;
}

oleo_fp = fp;
oleo_rng = rng;
for_all_vars (oleo_write_var);
find_cells_in_range (rng);

{
struct font_memo * fm;
for (fm = font_list; fm; fm = fm->next)
fm->id_memo = -1;
}
while (cp = next_row_col_in_range (&r, &c))
{
char *ptr;
int f1, j1;
char p_buf[40];

f1 = GET_FMT (cp);
j1 = GET_JST (cp);
if (f1 != FMT_DEF || j1 != JST_DEF || cp->cell_font)
{
if (cp->cell_font)
{
if (cp->cell_font->id_memo < 0)
{
cp->cell_font->id_memo = fnt_map_size++;
fprintf (fp, "%%F%s,%s,%f\n",
cp->cell_font->names->x_name,
cp->cell_font->names->ps_name,
cp->cell_font->scale);
}
}
(void) fprintf (fp, "F;");
if (c != ccol)
{
(void) fprintf (fp, "c%u;", c);
ccol = c;
}
if (r != crow)
{
(void) fprintf (fp, "r%u;", r);
crow = r;
}
if (cp->cell_font)
(void) fprintf (fp, "f%d;", cp->cell_font->id_memo);
(void) fprintf (fp, "F%s%c\n",
oleo_fmt_to_str (f1), jst_to_chr (j1));
}

if (!GET_TYP (cp) && !cp->cell_formula)
continue;

(void) fprintf (fp, "C;");
if (c != ccol)
{
(void) fprintf (fp, "c%u;", c);
ccol = c;
}
if (r != crow)
{
(void) fprintf (fp, "r%u;", r);
crow = r;
}

if (cp->cell_formula)
{
(void) fprintf (fp, "E%s", decomp (r, c, cp));
decomp_free ();
}

switch (GET_TYP (cp))
{
case 0:
ptr = 0;
break;
case TYP_STR:
ptr = 0;
if (cp->cell_formula)
putc (';', fp);
(void) fprintf (fp, "K\"%s\"", cp->cell_str);
break;
case TYP_FLT:
ptr = flt_to_str (cp->cell_flt);
break;
case TYP_INT:
sprintf (p_buf, "%ld", cp->cell_int);
ptr = p_buf;
break;
case TYP_BOL:
ptr = bname[cp->cell_bol];
break;
case TYP_ERR:
ptr = ename[cp->cell_err];
break;
default:
ptr = 0;
#ifdef TEST
panic ("What cell type %d", GET_TYP (cp));
#endif
}

if (ptr)
{
if (cp->cell_formula)
putc (';', fp);
(void) fprintf (fp, "K%s", ptr);
}
if (GET_LCK (cp) == LCK_LCK)
(void) fprintf (fp, ";P");

putc ('\n', fp);
}

if (rng == &all_rng)
write_mp_windows (fp);

(void) fprintf (fp, "E\n");
a0 = old_a0;
}

int
oleo_set_options
(set_opt, option)
int set_opt;
char *option;
{
return -1;
}

void
oleo_show_options ()
{
io_text_line ("File format: oleo.");
}


#if 0
This was used in releases 1.0 and 1.1 to write fonts.
It is no longer used but is kept here for reference since 1.2 and later
versions should continue to understand the older file format for a while.

static int
oleo_write_fonts (rng, font, ignore)
struct rng *rng;
struct font_memo *font;
void *ignore;
{
struct rng r;
char *rname;
r = *rng;
if (r.lr < oleo_rng->lr)
r.lr = oleo_rng->lr;
if (r.lc < oleo_rng->lc)
r.lc = oleo_rng->lc;
if (r.hr > oleo_rng->hr)
r.hr = oleo_rng->hr;
if (r.hc > oleo_rng->hc)
r.hc = oleo_rng->hc;
rname = range_name (&r);
fprintf (oleo_fp, "%%f %s %s,%s,%f\n",
rname, font->name, font->psname, font->scale);
return 1;
}


#endif

oleo-1.3/sc.c 644 722 0 12614 5356003004 11252 0ustar lordwheel/* Copyright (C) 1990, 1992, 1993 Free Software Foundation, Inc.

This file is part of Oleo, the GNU Spreadsheet.

Oleo 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, or (at your option)
any later version.

Oleo 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 Oleo; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */

#include "funcdef.h"
#include
#include
#include "sysdef.h"
#include "global.h"
#include "cell.h"
#include "io-generic.h"
#include "io-abstract.h"
#include "io-utils.h"
#include "lists.h"
#include "ref.h"
#include "parse.h"
#include "regions.h"
#include "cmd.h"



/* This reads/writes a subset of the SC public-domain spreadsheet's
file-format. Note that since SC has no way of encoding some information
about a cell, writing a spread out in SC format, then reading it back in
will result in the loss of some information (most important: cell formats)
*/

static int
get_range (pp,rp)
char ** pp;
struct rng * rp;
{
int byte;
char *p;
struct var *v;


while(isspace(**pp))
(*pp)++;
byte=parse_cell_or_range(pp,rp);
if(byte)
return 0;
for(p= *pp;*p && !isspace(*p);p++)
;
v=find_var(*pp,p-*pp);
if(!v)
return 1;
*pp=p;
*rp=v->v_rng;
return 0;
}

void
sc_read_file (fp,ismerge)
FILE * fp;
int ismerge;
{
char buf[2048];
int lineno;
char *ptr;
int n;
struct rng rng;
int olda0;

olda0=a0;
a0=1;
lineno=0;
if(!ismerge)
clear_spreadsheet();
while(fgets(buf,sizeof(buf),fp)) {
lineno++;
if(lineno%50==0)
io_info_msg("Line %d",lineno);
if(buf[0]=='#' || buf[0]=='\n')
continue;
if(!strncmp(buf,"set ",4)) {
/* ... */
} else if(!strncmp(buf,"format ",7)) {
ptr=buf+7;
if(get_range(&ptr,&rng))
continue;
n=astol(&ptr);
set_width(rng.lc,n);
} else if(!strncmp(buf,"hide ",5)) {
ptr=buf+5;
if(get_range(&ptr,&rng))
continue;
set_width(rng.lc,0);
} else if(!strncmp(buf,"mdir ",5)) {
/* ... */
} else if(!strncmp(buf,"define ",7)) {
char *eptr;

ptr=buf+7;
while(isspace(*ptr))
ptr++;
if(*ptr!='"') {
io_error_msg("Line %d: No starting \" in define",lineno);
continue;
}
ptr++;
for(eptr=ptr; *eptr && *eptr!='"';eptr++)
;
if(!*eptr) {
io_error_msg("Line %d: No starting \" in define",lineno);
continue;
}
ptr=new_var_value(ptr,eptr-ptr,eptr+1);
if(ptr)
io_error_msg("Line %d: %s",ptr);
} else if(!strncmp(buf,"leftstring ",11) ||
!strncmp(buf,"rightstring ",12)) {
CELL *cp;

ptr=buf+11;
if(get_range(&ptr,&rng))
continue;
while(isspace(*ptr))
ptr++;
if(*ptr=='=')
ptr++;
new_value(rng.lr,rng.lc,ptr);
cp=find_cell(rng.lr,rng.lc);
if(buf[0]=='l')
SET_JST(cp,JST_LFT);
else
SET_JST(cp,JST_RGT);

} else if(!strncmp(buf,"let ",4)) {
ptr=buf+4;
if(get_range(&ptr,&rng))
continue;
while(isspace(*ptr))
ptr++;
if(*ptr=='=')
ptr++;
new_value(rng.lr,rng.lc,ptr);
} else
io_error_msg("Line %d: Can't parse %s",lineno,buf);
}
a0=olda0;
io_recenter_all_win();
}

static FILE *sc_fp;
static struct rng *sc_rng;
static void
sc_write_var (name,var)
char * name;
struct var * var;
{
if(var->var_flags==VAR_UNDEF && (!var->var_ref_fm || var->var_ref_fm->refs_used==0))
return;
switch(var->var_flags) {
case VAR_UNDEF:
break;
case VAR_CELL:
if(var->v_rng.lr>=sc_rng->lr && var->v_rng.lr<=sc_rng->hr && var->v_rng.lc>=sc_rng->lc && var->v_rng.lc<=sc_rng->hc)
(void)fprintf(sc_fp,"define \"%s\" %s\n",var->var_name,cell_name(var->v_rng.lr,var->v_rng.lc));
break;
case VAR_RANGE:
if(var->v_rng.lrlr || var->v_rng.hr>sc_rng->hr || var->v_rng.lclc || var->v_rng.hc>sc_rng->hc)
break;

(void)fprintf(sc_fp,"define \"%s\" %s\n",var->var_name,range_name(&(var->v_rng)));
break;
#ifdef TEST
default:
panic("Unknown var type %d",var->var_flags);
break;
#endif
}
}

void
sc_write_file (fp,rng)
FILE * fp;
struct rng * rng;
{
unsigned short w;
CELLREF r,c;
CELL *cp;
char *ptr;
int olda0;

if(!rng)
rng= &all_rng;

olda0=a0;
a0=1;
(void)fprintf(fp,"# This file was created by Oleo, for use by the Spreadsheet Calculator\n");
(void)fprintf(fp,"# You probably don't want to edit it.\n\n");

find_widths(rng->lc,rng->hc);
while(w=next_width(&c))
fprintf(fp,"format %s %d ???\n",cell_name(MIN_ROW,c),w);
sc_fp=fp;
sc_rng=rng;
for_all_vars(sc_write_var);
find_cells_in_range(rng);
while(cp=next_row_col_in_range(&r,&c)) {
switch(GET_TYP(cp)) {
case TYP_STR:
if((GET_JST(cp)==JST_DEF && default_jst==JST_RGT) || GET_JST(cp)==JST_RGT)
ptr="right";
else ptr="left";
fprintf(fp,"%sstring %s = %s\n",ptr,cell_name(r,c),decomp(r,c,cp));
decomp_free();
break;
case 0:
break;
default:
fprintf(fp,"let %s = %s\n",cell_name(r,c),decomp(r,c,cp));
decomp_free();
break;
}
}
a0=olda0;
}

int
sc_set_options (set_opt,option)
int set_opt;
char * option;
{
return -1;
}

void
sc_show_options ()
{
io_text_line("File format: sc (Public domain spreadsheet calculator)");
}
oleo-1.3/list.c 644 722 0 7544 5330421006 11604 0ustar lordwheel/* Copyright (C) 1990, 1992, 1993 Free Software Foundation, Inc.

This file is part of Oleo, the GNU Spreadsheet.

Oleo 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, or (at your option)
any later version.

Oleo 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 Oleo; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */

#include "funcdef.h"
#include
#include
#include "sysdef.h"
#include "global.h"
#include "cell.h"
#include "io-generic.h"
#include "io-abstract.h"
#include "regions.h"
#include "io-utils.h"
#include "cmd.h"





static char sl_sep = '\t';



/* This file reads/writes files containing values in separated lists,
sl_sep is the separating character. This isn't really a save-file
format, but it is useful for reading and writing tables written by other
programs.

Note that this format loses *most* of the information about the cells,
including formuale, formats, column widths, etc
*/
void
list_read_file (fp, ismerge)
FILE *fp;
int ismerge;
{
char cbuf[1024];
CELLREF row, col;
char *bptr;
char *eptr;
char *ptr;
char tchar;
int endit;
unsigned lineno;
int string;

lineno = 0;
if (!ismerge)
clear_spreadsheet ();
row = curow;
col = cucol;

while (fgets (&cbuf[1], sizeof (cbuf) - 3, fp))
{
lineno++;
if (lineno % 50 == 0)
io_info_msg ("Line %d", lineno);
endit = 0;
for (bptr = &cbuf[1];; bptr = eptr + 1)
{
eptr = (char *)index (bptr, sl_sep);
if (!eptr)
{
eptr = (char *)index (bptr, '\n');
endit++;
}
string = 0;
for (ptr = bptr; ptr != eptr; ptr++)
if (!isdigit (*ptr) && *ptr != '.' && *ptr != 'e' && *ptr != 'E')
{
string++;
break;
}
if (string)
{
bptr[-1] = '"';
eptr[0] = '"';
tchar = eptr[1];
eptr[1] = '\0';
new_value (row, col, &bptr[-1]);
eptr[1] = tchar;
}
else
{
eptr[0] = '\0';
new_value (row, col, bptr);
}
if (endit)
break;
col++;
}
row++;
col = cucol;
}
}

void
list_write_file (fp, rng)
FILE *fp;
struct rng *rng;
{
CELLREF row, col;
int repressed;
CELL *cp;

if (!rng)
rng = &all_rng;
for (row = rng->lr;; row++)
{
repressed = 0;
for (col = rng->lc;; col++)
{
if ((cp = find_cell (row, col)) && GET_TYP (cp))
{
while (repressed > 0)
{
putc (sl_sep, fp);
--repressed;
}
repressed = 1;
switch (GET_TYP (cp))
{
case TYP_FLT:
fputs (flt_to_str (cp->cell_flt), fp);
break;
case TYP_INT:
fprintf (fp, "%ld", cp->cell_int);
break;
case TYP_STR:
fputs (cp->cell_str, fp);
break;
case TYP_BOL:
fputs (bname[cp->cell_bol], fp);
break;
case TYP_ERR:
fputs (ename[cp->cell_err], fp);
break;
#ifdef TEST
default:
panic ("Unknown type %d in write_sl_file()", GET_TYP (cp));
break;
#endif
}
}
else
repressed++;
if (col == rng->hc)
break;
}
putc ('\n', fp);
if (row == rng->hr)
break;
}
}

int
list_set_options (set_opt, option)
int set_opt;
char *option;
{
if (set_opt && !strincmp (option, "list ", 5))
{
option += 5;
sl_sep = string_to_char (&option);
return 0;
}
return -1;
}

void
list_show_options ()
{
io_text_line ("File format: list (character separated list of cell values)");
io_text_line ("Save file element separator: %s", char_to_string (sl_sep));
}
oleo-1.3/busi.c 644 722 0 24274 5350750534 11627 0ustar lordwheel/* Copyright (C) 1990, 1992, 1993 Free Software Foundation, Inc.

This file is part of Oleo, the GNU Spreadsheet.

Oleo 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, or (at your option)
any later version.

Oleo 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 Oleo; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */

#include "funcdef.h"
#include "sysdef.h"

#include "global.h"
#include "cell.h"
#include "eval.h"
#include "errors.h"

struct value
{
int type;
union vals x;
};

#define Float x.c_d
#define String x.c_s
#define Int x.c_l
#define Value x.c_i
#define Rng x.c_r

static double
pmt (principal, rate, term)
double principal;
double rate;
double term;
{
return (principal * rate) / (1 - pow (1 + rate, -(term)));
}


static int
npv (rng, rate, putres)
struct rng *rng;
double rate;
double *putres;
{
double npv;
int i;
double f;
CELL *cell_ptr;
char *strptr;

find_cells_in_range (rng);
for (i = 1, npv = 0.0; cell_ptr = next_cell_in_range (); i++)
{
switch (GET_TYP (cell_ptr))
{
case 0:
f = 0.0;
goto know_f;

case TYP_INT:
f = (double) (cell_ptr->cell_int);
goto know_f;

case TYP_FLT:
f = cell_ptr->cell_flt;
goto know_f;

case TYP_STR:
strptr = cell_ptr->cell_str;
f = astof (&strptr);
if (*strptr)
return NON_NUMBER;
know_f:
npv += f * (1.0 / (pow (1.0 + rate, (double) i)));
break;

case TYP_ERR:
return cell_ptr->cell_err;

default:
return NON_NUMBER;
}
}

*putres = npv;
return 0;
}

static void
do_pmt (p)
struct value *p;
{
p->Float = pmt (p->Float, (p + 1)->Float, (p + 2)->Float);
}

static void
do_pv (p)
struct value *p;
{
double payment, interest, term;

payment = p[0].Float;
interest = p[1].Float;
term = p[2].Float;

p->Float = payment * ((1 - pow (1 + interest, -term)) / interest);
}

static void
do_npv (p)
struct value *p;
{
int tmp;

tmp = npv (&(p->Rng), (p + 1)->Float, &(p->Float));
if (tmp)
{
p->Value = tmp;
p->type = TYP_ERR;
}
p->type = TYP_FLT;
}

static void
do_irr (p)
struct value *p;
{
double try;
double res;
double mint, maxt;
double minr, maxr;
int i;
int tmp;

minr = maxr = 0;
mint = maxt = 0;
while (minr >= 0)
{
mint += 1;
tmp = npv (&(p->Rng), mint, &minr);
if (tmp)
{
p->Value = tmp;
p->type = TYP_ERR;
return;
}
}
while (maxr <= 0)
{
maxt -= 1;
tmp = npv (&(p->Rng), maxt, &maxr);
if (tmp)
{
p->Value = tmp;
p->type = TYP_ERR;
return;
}
}
try = (p + 1)->Float;
for (i = 0;; i++)
{
if (i == 40)
{
p->Value = BAD_INPUT;
p->type = TYP_ERR;
return;
}
tmp = npv (&(p->Rng), try, &res);
if (tmp)
{
p->Value = tmp;
p->type = TYP_ERR;
return;
}
if (fabs (res * 1000000.0) < 1)
break;
if (res > 0)
{
maxt = try;
maxr = res;
}
else if (res < 0)
{
mint = try;
minr = res;
}
if (minr / -10 > maxr)
{
/* it is quite near maxt */
try = (maxt * 10 + mint) / 11;
}
else if (minr / -2 > maxr)
{
try = (maxt * 2 + mint) / 3;
}
else if (minr * -10 < maxr)
{
/* It is quite near mint */
try = (maxt + mint * 10) / 11;
}
else if (minr * -2 < maxr)
{
try = (maxt + mint * 2) / 3;
}
else
try = (maxt + mint) / 2;
}
p->Float = try;
p->type = TYP_FLT;
}

static void
do_fv (p)
struct value *p;
{
double payment = p->Float;
double interest = (p + 1)->Float;
double term = (p + 2)->Float;

p->Float = payment * ((pow (1 + interest, term) - 1) / interest);
}

static void
do_rate (p)
struct value *p;
{
double future = p->Float;
double present = (p + 1)->Float;
double term = (p + 2)->Float;

p->Float = pow (future / present, 1 / term) - 1;
}

static void
do_term (p)
struct value *p;
{
double payment = p->Float;
double interest = (p + 1)->Float;
double future = (p + 2)->Float;

p->Float = log (1 + future * (interest / payment)) / log (1 + interest);
}

static void
do_cterm (p)
struct value *p;
{
double interest = (p)->Float;
double future = (p + 1)->Float;
double present = (p + 2)->Float;

p->Float = log (future / present) / log (1 + interest);
}

static void
do_sln (p)
struct value *p;
{
double cost = (p)->Float;
double salvage = (p + 1)->Float;
double life = (p + 2)->Float;

p->Float = (cost - salvage) / life;
}

static void
do_syd (p)
struct value *p;
{
double cost, salvage, life, period;

cost = p->Float;
salvage = (p + 1)->Float;
life = (p + 2)->Float;
period = (p + 3)->Float;

if (period > life) /* JF is this right? */
p->Float = salvage;
else
p->Float = ((cost - salvage) * (life - period + 1)) / (life * ((life + 1) / 2));
}


static void
do_ddb (p)
struct value *p;
{
double cost = (p)->Float;
double salvage = (p + 1)->Float;
long life = (p + 2)->Int;
long period = (p + 3)->Int;

double bookval, tmp;
long n;

if (period < 1 || period > life || life < 1)
{
p->Value = OUT_OF_RANGE;
p->type = TYP_ERR;
return;
}
bookval = cost;
tmp = 0;
for (n = 0; n < period; n++)
{
tmp = (bookval * 2) / life;
bookval -= tmp;
if (bookval < salvage)
{
tmp += bookval - salvage;
bookval = salvage;
}
}
p->Float = tmp;
}

static void
do_anrate (p)
struct value *p;
{
double in_pmt = (p)->Float;
double present = (p + 1)->Float;
double term = (p + 2)->Float;

double tr_lo, tr_hi;
double mytry;
double try_pmt;
int n;

if (in_pmt * term == present)
{
p->Float = 0.0;
return;
}
if (in_pmt * term < present)
{
tr_lo = -1;
tr_hi = 0;
while (pmt (present, tr_lo, term) > in_pmt)
{
tr_hi = tr_lo;
tr_lo *= 2;
}
}
else
{
tr_lo = 0;
tr_hi = 1;
while (pmt (present, tr_hi, term) < in_pmt)
{
tr_lo = tr_hi;
tr_hi *= 2;
}
}
for (n = 0; n < 40; n++)
{
mytry = (tr_lo + tr_hi) / 2;
try_pmt = pmt (present, mytry, term);
if (try_pmt < in_pmt)
tr_lo = mytry;
else if (try_pmt > in_pmt)
tr_hi = mytry;
else
break;
}
p->Float = mytry;
}

static void
do_anterm (p)
struct value *p;
{
double payment = (p)->Float;
double principal = (p + 1)->Float;
double rate = (p + 2)->Float;

p->Float = (-log (1 - principal * (rate / payment))) / log (1 + rate);
}


static void
do_balance (p)
struct value *p;
{
double principal = (p)->Float;
double rate = (p + 1)->Float;
long term = (p + 2)->Int;
long period = (p + 3)->Int;

double tmp_pmt, int_part;
long num;

if (term < period)
{
p->Value = OUT_OF_RANGE;
p->type = TYP_ERR;
return;
}
tmp_pmt = pmt (principal, rate, (double) term);
for (num = 0; num < period; num++)
{
int_part = rate * principal;
if (int_part > tmp_pmt)
{
p->Value = OUT_OF_RANGE;
p->type = TYP_ERR;
return;
}
principal -= tmp_pmt - int_part;
}
p->Float = principal;
}

static void
do_paidint (p)
struct value *p;
{
double principal = (p)->Float;
double rate = (p + 1)->Float;
long term = (p + 2)->Int;
long period = (p + 3)->Int;

double tmp_pmt, int_part, retval;
long num;

if (term < period)
{
p->Value = OUT_OF_RANGE;
p->type = TYP_ERR;
return;
}
tmp_pmt = pmt (principal, rate, (double) term);
retval = 0;
for (num = 0; num < period; num++)
{
int_part = rate * principal;
if (int_part > tmp_pmt)
{
p->Value = OUT_OF_RANGE;
p->type = TYP_ERR;
return;
}
principal -= tmp_pmt - int_part;
retval += int_part;
}
p->Float = retval;
}

static void
do_kint (p)
struct value *p;
{
double principal = (p)->Float;
double rate = (p + 1)->Float;
long term = (p + 2)->Int;
long period = (p + 3)->Int;

double tmp_pmt, int_part = 0;
long num;

if (term < period)
{
p->Value = OUT_OF_RANGE;
p->type = TYP_ERR;
return;
}

tmp_pmt = pmt (principal, rate, (double) term);
for (num = 0; num < period; num++)
{
int_part = rate * principal;
if (int_part > tmp_pmt)
{
p->Value = OUT_OF_RANGE;
p->type = TYP_ERR;
return;
}
principal -= tmp_pmt - int_part;
}
p->Float = int_part;
}

static void
do_kprin (p)
struct value *p;
{
double principal = (p)->Float;
double rate = (p + 1)->Float;
long term = (p + 2)->Int;
long period = (p + 3)->Int;
double tmp_pmt, int_part = 0;
long num;

if (term < period)
{
p->Value = OUT_OF_RANGE;
p->type = TYP_ERR;
return;
}

tmp_pmt = pmt (principal, rate, (double) term);
for (num = 0; num < period; num++)
{
int_part = rate * principal;
if (int_part > tmp_pmt)
{
p->Value = OUT_OF_RANGE;
p->type = TYP_ERR;
return;
}
principal -= tmp_pmt - int_part;
}
p->Float = tmp_pmt - int_part;
}

static void
do_compbal (p)
struct value *p;
{
double principal = (p)->Float;
double rate = (p + 1)->Float;
double term = (p + 2)->Float;

p->Float = principal * pow (1 + rate, term);
}

struct function busi_funs[] =
{
{C_FN2, X_A2, "RF", do_npv, "npv"},
{C_FN2, X_A2, "RF", do_irr, "irr"},

{C_FN3, X_A3, "FFF", do_pmt, "pmt"},
{C_FN3, X_A3, "FFF", do_pv, "pv"},
{C_FN3, X_A3, "FFF", do_fv, "fv"},
{C_FN3, X_A3, "FFF", do_rate, "rate"},
{C_FN3, X_A3, "FFF", do_term, "term"},
{C_FN3, X_A3, "FFF", do_cterm, "cterm"},
{C_FN3, X_A3, "FFF", do_sln, "sln"},
{C_FN3, X_A3, "FFF", do_anrate, "anrate"},
{C_FN3, X_A3, "FFF", do_anterm, "anterm"},
{C_FN3, X_A3, "FFF", do_compbal, "compbal"},

{C_FN4, X_A4, "FFFF", do_syd, "syd"},
{C_FN4, X_A4, "FFII", do_ddb, "ddb"},
{C_FN4, X_A4, "FFII", do_balance, "balance"},
{C_FN4, X_A4, "FFII", do_paidint, "paidint"},
{C_FN4, X_A4, "FFII", do_kint, "kint"},
{C_FN4, X_A4, "FFII", do_kprin, "kprin"},

{0, 0, "", 0, 0},
};
oleo-1.3/string.c 644 722 0 16045 5324716664 12177 0ustar lordwheel/* Copyright (C) 1990, 1992, 1993 Free Software Foundation, Inc.

This file is part of Oleo, the GNU Spreadsheet.

Oleo 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, or (at your option)
any later version.

Oleo 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 Oleo; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */

#include
#include "funcdef.h"
#define obstack_chunk_alloc ck_malloc
#define obstack_chunk_free free
#include "obstack.h"
#include "sysdef.h"

#include "global.h"
#include "cell.h"
#include "eval.h"
#include "errors.h"

struct value {
int type;
union vals x;
};

#define Float x.c_d
#define String x.c_s
#define Int x.c_l
#define Value x.c_i
#define Rng x.c_r

#define ERROR(x) \
{ \
p->Value=x; \
p->type=TYP_ERR;\
return; \
}


extern struct obstack tmp_mem;

extern char *flt_to_str();

static void
do_edit (numarg,p)
int numarg;
struct value * p;
{
int mm;
int add_len;
int tmp_len;
char *ptr1,*ptr2,*retp;
int off1,off2;

if(numarg<3)
ERROR(BAD_INPUT);
for(mm=3,add_len=0;mm add_len+=strlen((p+mm)->String);
tmp_len=strlen(p->String);
off1=(p+1)->Int;
off2=(p+2)->Int;
if(off1==0 || tmp_len < ((off1<0) ? -off1 : off1) ||
off2==0 || tmp_len < ((off2<0) ? -off2 : off2))
ERROR(OUT_OF_RANGE);
ptr1=p->String + (off1>0 ? off1-1 : tmp_len+off1);
ptr2=p->String + 1 + (off2>0 ? off2-1 : tmp_len+off2);
if(ptr1>ptr2)
ERROR(OUT_OF_RANGE);
retp=obstack_alloc(&tmp_mem,add_len+tmp_len-(ptr2-ptr1));
strncpy(retp,p->String,ptr1-p->String);
retp[ptr1-p->String]='\0';
for(mm=3;mm strcat(retp,(p+mm)->String);
strcat(retp,ptr2);
p->String=retp;
p->type=TYP_STR;
}

static void
do_repeat (p)
struct value * p;
{
char *str = (p )->String;
long num = (p+1)->Int;

char *ret;
char *strptr;
int len;

if(num<0)
ERROR(OUT_OF_RANGE);
len=strlen(str);
ret=strptr=obstack_alloc(&tmp_mem,len*num+1);
while(num--) {
bcopy(str,strptr,len);
strptr+=len;
}
*strptr=0;
p->String=ret;
}

static void
do_len (p)
struct value * p;
{
long ret;
char *ptr;

for(ret=0,ptr=p->String;*ptr;ret++,ptr++)
;
p->Int=ret;
p->type=TYP_INT;
}

static void
do_up_str (p)
struct value * p;
{
char *s1,*s2;
char *strptr;

strptr=obstack_alloc(&tmp_mem,strlen(p->String)+1);
for(s1=strptr,s2=p->String;*s2;s2++)
*s1++ = (islower(*s2) ? toupper(*s2) : *s2);
*s1=0;
p->String=strptr;
}

static void
do_dn_str (p)
struct value * p;
{
char *s1,*s2;
char *strptr;

strptr=obstack_alloc(&tmp_mem,strlen(p->String)+1);
for(s1=strptr,s2=p->String;*s2;s2++)
*s1++ = (isupper(*s2) ? tolower(*s2) : *s2);
*s1=0;
p->String=strptr;
}

static void
do_cp_str (p)
struct value * p;
{
char *strptr;
char *s1,*s2;
int wstart=1;

strptr=obstack_alloc(&tmp_mem,strlen(p->String)+1);
for(s1=strptr,s2=p->String;*s2;s2++) {
if(!isalpha(*s2)) {
wstart=1;
*s1++= *s2;
} else if(wstart) {
*s1++ = (islower(*s2) ? toupper(*s2) : *s2);
wstart=0;
} else
*s1++ = (isupper(*s2) ? tolower(*s2) : *s2);
}
*s1=0;
p->String=strptr;
}

static void
do_trim_str (p)
struct value * p;
{
char *s1,*s2;
int sstart=0;
char *strptr;

strptr=obstack_alloc(&tmp_mem,strlen(p->String)+1);
for(s1=strptr,s2=p->String;*s2;s2++) {
if(!isascii(*s2) || !isprint(*s2))
continue;
if(*s2==' ') {
if(sstart) {
*s1++= *s2;
sstart=0;
}
} else {
sstart=1;
*s1++= *s2;
}
}
*s1=0;
p->String=strptr;
}

static void
do_concat ( numarg,p)
int numarg;
struct value * p;
{
int cur_string;
char *s;
char buf[40];
CELLREF crow,ccol;
CELL *cell_ptr;

for(cur_string=0;cur_string switch(p[cur_string].type) {
case 0:
continue;
case TYP_RNG:
for(crow=p[cur_string].Rng.lr;crow<=p[cur_string].Rng.hr;crow++)
for(ccol=p[cur_string].Rng.lc;ccol<=p[cur_string].Rng.hc;ccol++) {
if(!(cell_ptr=find_cell(crow,ccol)))
continue;
switch(GET_TYP(cell_ptr)) {
case 0:
break;
case TYP_STR:
(void)obstack_grow(&tmp_mem,cell_ptr->cell_str,strlen(cell_ptr->cell_str));
break;
case TYP_INT:
sprintf(buf,"%ld",cell_ptr->cell_int);
(void)obstack_grow(&tmp_mem,buf,strlen(buf));
break;
case TYP_FLT:
s=flt_to_str(cell_ptr->cell_flt);
(void)obstack_grow(&tmp_mem,s,strlen(s));
break;
default:
(void)obstack_finish(&tmp_mem);
ERROR(NON_STRING);
}
}
break;
case TYP_STR:
s=p[cur_string].String;
(void)obstack_grow(&tmp_mem,s,strlen(s));
break;
case TYP_INT:
sprintf(buf,"%ld",p[cur_string].Int);
(void)obstack_grow(&tmp_mem,buf,strlen(buf));
break;
case TYP_FLT:
s=flt_to_str(p[cur_string].Float);
(void)obstack_grow(&tmp_mem,s,strlen(s));
break;
default:
(void)obstack_finish(&tmp_mem);
ERROR(NON_STRING);
}
}
(void)obstack_1grow(&tmp_mem,0);
p->type=TYP_STR;
p->String=(char *)obstack_finish(&tmp_mem);
}


static void
do_mid (p)
struct value * p;
{
char *str = (p )->String;
long from = (p+1)->Int;
long len = (p+2)->Int;

char *ptr1;
int tmp;

tmp=strlen(str);

if(from<0 || len<0)
ERROR(OUT_OF_RANGE);
ptr1=(char *)obstack_alloc(&tmp_mem,len+1);
if(from>=tmp || len==0)
ptr1[0]='\0';
else {
strncpy(ptr1,str+from,len);
ptr1[len]='\0';
}
p->String=ptr1;
}


static void
do_substr (p)
struct value * p;
{
long off1 = (p )->Int;
long off2 = (p+1)->Int;
char *str = (p+2)->String;

char *ptr1, *ptr2;
int tmp;
char *ret;

tmp=strlen(str);
if(off1==0 || tmp < ((off1<0) ? -off1 : off1) ||
off2==0 || tmp < ((off2<0) ? -off2 : off2))
ERROR(OUT_OF_RANGE);
ptr1=str + (off1>0 ? off1-1 : tmp+(off1));
ptr2=str + (off2>0 ? off2-1 : tmp+(off2));

if(ptr1>ptr2)
ERROR(OUT_OF_RANGE);
tmp=(ptr2-ptr1)+1;
ret=(char *)obstack_alloc(&tmp_mem,tmp+1);
strncpy(ret,ptr1,tmp);
ret[tmp]=0;
p->String=ret;
p->type=TYP_STR;
}

static void
do_strstr (p)
struct value * p;
{
char *str1 = (p )->String;
char *strptr = (p+1)->String;
long off = (p+2)->Int;
char *ret;

if(off<1 || strlen(strptr)<=off-1)
ERROR(OUT_OF_RANGE);
ret=(char *)strstr(strptr+off-1,str1);
p->Value= ret ? 1 + ret-strptr : 0;
p->type=TYP_INT;
}

struct function string_funs[] = {
{ C_FN1, X_A1, "S", do_len, "len" },
{ C_FN3, X_A3, "SSI", do_strstr, "find" },

{ C_FN1, X_A1, "S", do_up_str, "strupr" },
{ C_FN1, X_A1, "S", do_dn_str, "strlwr" },
{ C_FN1, X_A1, "S", do_cp_str, "strcap" },
{ C_FN1, X_A1, "S", do_trim_str, "trim" },

{ C_FN3, X_A3, "IIS", do_substr, "substr" },
{ C_FN3, X_A3, "SII", do_mid, "mid" },

{ C_FN2, X_A2, "SI", do_repeat, "repeat" },
{ C_FNN, X_AN, "EEEE", do_concat, "concat" },
{ C_FNN, X_AN, "SIIS", do_edit, "edit" },
{ 0, 0, {0}, 0, 0 }
};

oleo-1.3/cells.c 644 722 0 26373 5356003003 11755 0ustar lordwheel/* Copyright (C) 1990, 1992, 1993 Free Software Foundation, Inc.

This file is part of Oleo, the GNU Spreadsheet.

Oleo 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, or (at your option)
any later version.

Oleo 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 Oleo; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */

#define obstack_chunk_alloc ck_malloc
#define obstack_chunk_free free
#include "obstack.h"
#include "funcdef.h"
#include "sysdef.h"

#include "global.h"
#include "cell.h"
#include "eval.h"
#include "errors.h"
#include "lists.h"
#include "format.h"
#include "io-abstract.h"
#include "io-generic.h"
#include "io-term.h"
#include "cmd.h"

struct value
{
int type;
union vals x;
};

#define Float x.c_d
#define String x.c_s
#define Int x.c_l
#define Value x.c_i
#define Rng x.c_r

#define ERROR(x) \
{ \
p->Value=x; \
p->type=TYP_ERR;\
return; \
}


static int
cell (row, col, dowhat, p)
long row;
long col;
char *dowhat;
struct value *p;
{
struct func
{
char *name;
int typ;
};

static struct func cell_funs[] =
{
{"row", TYP_INT},
{"column", TYP_INT},
{"width", TYP_INT},
{"lock", TYP_STR},
{"protection", TYP_STR},
{"justify", TYP_STR},
{"alignment", TYP_STR},
{"fmt", TYP_STR},
{"format", TYP_STR},
{"type", TYP_STR},
{"formula", TYP_STR},
{"value", 0},
{0, 0}
};

CELL *cell_ptr;
char *strptr;
struct func *func;
struct func *f1;
int n;

n = strlen (dowhat) - 1;
f1 = 0;
for (func = cell_funs; func->name; func++)
if (func->name[0] == dowhat[0]
&& (n == 0 || !strincmp (&(func->name[1]), &dowhat[1], n)))
{
if (f1)
return BAD_INPUT;
f1 = func;
}
if (!f1)
return BAD_INPUT;
p->type = f1->typ;
switch (f1 - cell_funs)
{
case 0:
p->Int = row;
break;
case 1:
p->Int = col;
break;
case 2:
p->Int = get_width (col);
break;
case 3:
case 4:
cell_ptr = find_cell (row, col);
p->String = ( (cell_ptr ? GET_LCK (cell_ptr) : default_lock)
? "locked"
: "unlocked");
break;
case 5:
case 6:
cell_ptr = find_cell (row, col);
p->String = jst_to_str (cell_ptr ? GET_JST (cell_ptr) : default_jst);
break;
case 7:
case 8:
p->String = fmt_to_str ((cell_ptr = find_cell (row, col)) ? GET_FMT (cell_ptr) : 0);
break;
case 9:
cell_ptr = find_cell (row, col);
if (cell_ptr)
switch (GET_TYP (cell_ptr))
{
case TYP_FLT:
p->String = "float";
break;
case TYP_INT:
p->String = "integer";
break;
case TYP_STR:
p->String = "string";
break;
case TYP_BOL:
p->String = "boolean";
break;
case TYP_ERR:
p->String = "error";
break;
default:
p->String = "unknown";
}
else
p->String = "null";
break;
case 10:
cell_ptr = find_cell (row, col);
if (cell_ptr && (GET_TYP (cell_ptr) || cell_ptr->cell_formula))
{
strptr = decomp (row, col, cell_ptr);
p->String = obstack_alloc (&tmp_mem, strlen (strptr) + 1);
strcpy (p->String, strptr);
decomp_free ();
}
else
p->String = "";
break;
case 11:
cell_ptr = find_cell (row, col);
if (cell_ptr)
{
p->type = GET_TYP (cell_ptr);
p->x = cell_ptr->c_z;
}
else
p->type = 0;
break;
default:
return BAD_INPUT;
}
return 0;
}


static void
do_curcell (p)
struct value *p;
{
int tmp;

tmp = cell (curow, cucol, p->String, p);
if (tmp)
ERROR (tmp);
}

static void
do_my (p)
struct value *p;
{
int tmp;

tmp = cell (cur_row, cur_col, p->String, p);
if (tmp)
ERROR (tmp);
}

/* Note that the second argument may be *anything* including ERROR. If it is
error, we find the first occurence of that ERROR in the range */

static void
do_member (p)
struct value *p;
{
CELLREF crow;
CELLREF ccol;
int foundit;
CELL *cell_ptr;

find_cells_in_range (&(p->Rng));
while (cell_ptr = next_row_col_in_range (&crow, &ccol))
{
if (GET_TYP (cell_ptr) != (p + 1)->type)
continue;
switch ((p + 1)->type)
{
case 0:
foundit = 1;
break;
case TYP_FLT:
foundit = cell_ptr->cell_flt == (p + 1)->Float;
break;
case TYP_INT:
foundit = cell_ptr->cell_int == (p + 1)->Int;
break;
case TYP_STR:
foundit = !strcmp (cell_ptr->cell_str, (p + 1)->String);
break;
case TYP_BOL:
foundit = cell_ptr->cell_bol == (p + 1)->Value;
break;
case TYP_ERR:
foundit = cell_ptr->cell_err == (p + 1)->Value;
break;
default:
foundit = 0;
#ifdef TEST
panic ("Unknown type (%d) in member", (p + 1)->type);
#endif
}
if (foundit)
{
no_more_cells ();
p->Int = 1 + crow - p->Rng.lr + (ccol - p->Rng.lc) * (1 + p->Rng.hr - p->Rng.lr);
p->type = TYP_INT;
return;
}
}
p->Int = 0L;
p->type = TYP_INT;
}

static void
do_smember (p)
struct value *p;
{
CELLREF crow;
CELLREF ccol;
CELL *cell_ptr;
char *string;

string = (p + 1)->String;
find_cells_in_range (&(p->Rng));
while (cell_ptr = next_row_col_in_range (&crow, &ccol))
{
if (((GET_TYP (cell_ptr) == 0) && (string[0] == '\0'))
|| (cell_ptr && (GET_TYP (cell_ptr) == TYP_STR)
&& strstr (string, cell_ptr->cell_str)))
{
no_more_cells ();
p->Int = 1 + (crow - p->Rng.lr)
+ (ccol - p->Rng.lc) * (1 + (p->Rng.hr - p->Rng.lr));
p->type = TYP_INT;
return;
}
}
p->Int = 0L;
p->type = TYP_INT;
}

static void
do_members (p)
struct value *p;
{
CELLREF crow;
CELLREF ccol;
CELL *cell_ptr;
char *string;

string = (p + 1)->String;
find_cells_in_range (&(p->Rng));
while (cell_ptr = next_row_col_in_range (&crow, &ccol))
{
if (GET_TYP (cell_ptr) != TYP_STR)
continue;
if (strstr (cell_ptr->cell_str, string))
{
no_more_cells ();
p->Int = 1 + (crow - p->Rng.lr)
+ (ccol - p->Rng.lc) * (1 + (p->Rng.hr - p->Rng.lr));
p->type = TYP_INT;
return;
}
}
p->Int = 0L;
p->type = TYP_INT;
}

static void
do_pmember (p)
struct value *p;
{
CELLREF crow;
CELLREF ccol;
CELL *cell_ptr;
char *string;

string = (p + 1)->String;
find_cells_in_range (&(p->Rng));
while (cell_ptr = next_row_col_in_range (&crow, &ccol))
{
if ((GET_TYP (cell_ptr) == 0 && string[0] == '\0')
|| (cell_ptr && GET_TYP (cell_ptr) == TYP_STR && !strncmp (string, cell_ptr->cell_str, strlen (cell_ptr->cell_str))))
{
no_more_cells ();
p->Int = 1 + (crow - p->Rng.lr)
+ (ccol - p->Rng.lc) * (1 + (p->Rng.hr - p->Rng.lr));
p->type = TYP_INT;
return;
}
}
p->Int = 0L;
p->type = TYP_INT;
}

static void
do_memberp (p)
struct value *p;
{
CELLREF crow;
CELLREF ccol;
CELL *cell_ptr;
int tmp;
char *string;

string = (p + 1)->String;
find_cells_in_range (&(p->Rng));
tmp = strlen (string);
while (cell_ptr = next_row_col_in_range (&crow, &ccol))
{
if (GET_TYP (cell_ptr) != TYP_STR)
continue;
if (!strncmp (cell_ptr->cell_str, string, tmp))
{
no_more_cells ();
p->Int = 1 + (crow - p->Rng.lr)
+ (ccol - p->Rng.lc) * (1 + (p->Rng.hr - p->Rng.lr));
p->type = TYP_INT;
return;
}
}
p->Int = 0L;
p->type = TYP_INT;
}

static void
do_hlookup (p)
struct value *p;
{

struct rng *rng = &((p)->Rng);
double fltval = (p + 1)->Float;
long offset = (p + 2)->Int;

CELL *cell_ptr;
double f;
CELLREF col;
CELLREF row;
char *strptr;

row = rng->lr;
for (col = rng->lc; col <= rng->hc; col++)
{
if (!(cell_ptr = find_cell (row, col)))
ERROR (NON_NUMBER);
switch (GET_TYP (cell_ptr))
{
case TYP_FLT:
if (fltval < cell_ptr->cell_flt)
goto out;
break;
case TYP_INT:
if (fltval < cell_ptr->cell_int)
goto out;
break;
case TYP_STR:
strptr = cell_ptr->cell_str;
f = astof (&strptr);
if (!*strptr && fltval > f)
goto out;
else
ERROR (NON_NUMBER);
case 0:
case TYP_BOL:
case TYP_ERR:
default:
ERROR (NON_NUMBER);
}
}
out:
if (col == rng->lc)
ERROR (OUT_OF_RANGE);
--col;
row = rng->lr + offset;
if (row > rng->hr)
ERROR (OUT_OF_RANGE);
cell_ptr = find_cell (row, col);
if (!cell_ptr)
{
p->type = 0;
p->Int = 0;
}
else
{
p->type = GET_TYP (cell_ptr);
p->x = cell_ptr->c_z;
}
}

static void
do_vlookup (p)
struct value *p;
{

struct rng *rng = &((p)->Rng);
double fltval = (p + 1)->Float;
long offset = (p + 2)->Int;

CELL *cell_ptr;
double f;
CELLREF col;
CELLREF row;
char *strptr;

col = rng->lc;
for (row = rng->lr; row <= rng->hr; row++)
{
if (!(cell_ptr = find_cell (row, col)))
ERROR (NON_NUMBER);
switch (GET_TYP (cell_ptr))
{
case TYP_FLT:
if (fltval < cell_ptr->cell_flt)
goto out;
break;
case TYP_INT:
if (fltval < cell_ptr->cell_int)
goto out;
break;
case TYP_STR:
strptr = cell_ptr->cell_str;
f = astof (&strptr);
if (!*strptr && fltval > f)
goto out;
else
ERROR (NON_NUMBER);
case 0:
case TYP_BOL:
case TYP_ERR:
default:
ERROR (NON_NUMBER);
}
}
out:
if (row == rng->lr)
ERROR (OUT_OF_RANGE);
--row;
col = rng->lc + offset;
if (col > rng->hc)
ERROR (OUT_OF_RANGE);

cell_ptr = find_cell (row, col);
if (!cell_ptr)
{
p->type = 0;
p->Int = 0;
}
else
{
p->type = GET_TYP (cell_ptr);
p->x = cell_ptr->c_z;
}
}

static void
do_vlookup_str (p)
struct value *p;
{

struct rng *rng = &((p)->Rng);
char * key = (p + 1)->String;
long offset = (p + 2)->Int;

CELL *cell_ptr;
CELLREF col;
CELLREF row;

col = rng->lc;
for (row = rng->lr; row <= rng->hr; row++)
{
if (!(cell_ptr = find_cell (row, col)))
ERROR (NON_NUMBER);
switch (GET_TYP (cell_ptr))
{
case TYP_STR:
if (!strcmp (key, cell_ptr->cell_str))
goto out;
break;
case 0:
case TYP_FLT:
case TYP_INT:
case TYP_BOL:
case TYP_ERR:
default:
ERROR (NON_NUMBER);
}
}
out:
if (row > rng->hr)
ERROR (OUT_OF_RANGE);
col = rng->lc + offset;
if (col > rng->hc)
ERROR (OUT_OF_RANGE);

cell_ptr = find_cell (row, col);
if (!cell_ptr)
{
p->type = 0;
p->Int = 0;
}
else
{
p->type = GET_TYP (cell_ptr);
p->x = cell_ptr->c_z;
}
}


static void
do_cell (p)
struct value *p;
{
int tmp;

tmp = cell (p->Int, (p + 1)->Int, (p + 2)->String, p);
if (tmp)
ERROR (tmp);
}

struct function cells_funs[] =
{
{C_FN1 | C_T, X_A1, "S", do_curcell, "curcell"},
{C_FN1 | C_T, X_A1, "S", do_my, "my"},
{C_FN3 | C_T, X_A3, "IIS", do_cell, "cell"},

{C_FN2, X_A2, "RA", do_member, "member"},
{C_FN2, X_A2, "RS", do_smember, "smember"},
{C_FN2, X_A2, "RS", do_members, "members"},
{C_FN2, X_A2, "RS", do_pmember, "pmember"},
{C_FN2, X_A2, "RS", do_memberp, "memberp"},

{C_FN3, X_A3, "RFI", do_hlookup, "hlookup"},
{C_FN3, X_A3, "RFI", do_vlookup, "vlookup"},
{C_FN3, X_A3, "RSI", do_vlookup_str, "vlookup_str"},

{0, 0, "", 0, 0},
};
oleo-1.3/random.c 644 722 0 30566 5317505312 12141 0ustar lordwheel/*
* Copyright (c) 1983 Regents of the University of California.
* All rights reserved.
*
* Redistribution and use in source and binary forms are permitted
* provided that the above copyright notice and this paragraph are
* duplicated in all such forms and that any documentation,
* advertising materials, and other materials related to such
* distribution and use acknowledge that the software was developed
* by the University of California, Berkeley. The name of the
* University may not be used to endorse or promote products derived
* from this software without specific prior written permission.
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*/

#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)random.c 5.5 (Berkeley) 7/6/88";
#endif /* LIBC_SCCS and not lint */

#include

/*
* random.c:
* An improved random number generation package. In addition to the standard
* rand()/srand() like interface, this package also has a special state info
* interface. The initstate() routine is called with a seed, an array of
* bytes, and a count of how many bytes are being passed in; this array is then
* initialized to contain information for random number generation with that
* much state information. Good sizes for the amount of state information are
* 32, 64, 128, and 256 bytes. The state can be switched by calling the
* setstate() routine with the same array as was initiallized with initstate().
* By default, the package runs with 128 bytes of state information and
* generates far better random numbers than a linear congruential generator.
* If the amount of state information is less than 32 bytes, a simple linear
* congruential R.N.G. is used.
* Internally, the state information is treated as an array of longs; the
* zeroeth element of the array is the type of R.N.G. being used (small
* integer); the remainder of the array is the state information for the
* R.N.G. Thus, 32 bytes of state information will give 7 longs worth of
* state information, which will allow a degree seven polynomial. (Note: the
* zeroeth word of state information also has some other information stored
* in it -- see setstate() for details).
* The random number generation technique is a linear feedback shift register
* approach, employing trinomials (since there are fewer terms to sum up that
* way). In this approach, the least significant bit of all the numbers in
* the state table will act as a linear feedback shift register, and will have
* period 2^deg - 1 (where deg is the degree of the polynomial being used,
* assuming that the polynomial is irreducible and primitive). The higher
* order bits will have longer periods, since their values are also influenced
* by pseudo-random carries out of the lower bits. The total period of the
* generator is approximately deg*(2**deg - 1); thus doubling the amount of
* state information has a vast influence on the period of the generator.
* Note: the deg*(2**deg - 1) is an approximation only good for large deg,
* when the period of the shift register is the dominant factor. With deg
* equal to seven, the period is actually much longer than the 7*(2**7 - 1)
* predicted by this formula.
*/



/*
* For each of the currently supported random number generators, we have a
* break value on the amount of state information (you need at least this
* many bytes of state info to support this random number generator), a degree
* for the polynomial (actually a trinomial) that the R.N.G. is based on, and
* the separation between the two lower order coefficients of the trinomial.
*/

#define TYPE_0 0 /* linear congruential */
#define BREAK_0 8
#define DEG_0 0
#define SEP_0 0

#define TYPE_1 1 /* x**7 + x**3 + 1 */
#define BREAK_1 32
#define DEG_1 7
#define SEP_1 3

#define TYPE_2 2 /* x**15 + x + 1 */
#define BREAK_2 64
#define DEG_2 15
#define SEP_2 1

#define TYPE_3 3 /* x**31 + x**3 + 1 */
#define BREAK_3 128
#define DEG_3 31
#define SEP_3 3

#define TYPE_4 4 /* x**63 + x + 1 */
#define BREAK_4 256
#define DEG_4 63
#define SEP_4 1


/*
* Array versions of the above information to make code run faster -- relies
* on fact that TYPE_i == i.
*/

#define MAX_TYPES 5 /* max number of types above */

static int degrees[MAX_TYPES] =
{DEG_0, DEG_1, DEG_2,
DEG_3, DEG_4};

static int seps[MAX_TYPES] =
{SEP_0, SEP_1, SEP_2,
SEP_3, SEP_4};



/*
* Initially, everything is set up as if from :
* initstate( 1, &randtbl, 128 );
* Note that this initialization takes advantage of the fact that srandom()
* advances the front and rear pointers 10*rand_deg times, and hence the
* rear pointer which starts at 0 will also end up at zero; thus the zeroeth
* element of the state information, which contains info about the current
* position of the rear pointer is just
* MAX_TYPES*(rptr - state) + TYPE_3 == TYPE_3.
*/

static long randtbl[DEG_3 + 1] =
{TYPE_3,
0x9a319039, 0x32d9c024, 0x9b663182, 0x5da1f342,
0xde3b81e0, 0xdf0a6fb5, 0xf103bc02, 0x48f340fb,
0x7449e56b, 0xbeb1dbb0, 0xab5c5918, 0x946554fd,
0x8c2e680f, 0xeb3d799f, 0xb11ee0b7, 0x2d436b86,
0xda672e2a, 0x1588ca88, 0xe369735d, 0x904f35f7,
0xd7158fd6, 0x6fa6f051, 0x616e6b96, 0xac94efdc,
0x36413f93, 0xc622c298, 0xf5a42ab8, 0x8a88d77b,
0xf5ad9d0e, 0x8999220b, 0x27fb47b9};

/*
* fptr and rptr are two pointers into the state info, a front and a rear
* pointer. These two pointers are always rand_sep places aparts, as they cycle
* cyclically through the state information. (Yes, this does mean we could get
* away with just one pointer, but the code for random() is more efficient this
* way). The pointers are left positioned as they would be from the call
* initstate( 1, randtbl, 128 )
* (The position of the rear pointer, rptr, is really 0 (as explained above
* in the initialization of randtbl) because the state table pointer is set
* to point to randtbl[1] (as explained below).
*/

static long *fptr = &randtbl[SEP_3 + 1];
static long *rptr = &randtbl[1];



/*
* The following things are the pointer to the state information table,
* the type of the current generator, the degree of the current polynomial
* being used, and the separation between the two pointers.
* Note that for efficiency of random(), we remember the first location of
* the state information, not the zeroeth. Hence it is valid to access
* state[-1], which is used to store the type of the R.N.G.
* Also, we remember the last location, since this is more efficient than
* indexing every time to find the address of the last element to see if
* the front and rear pointers have wrapped.
*/

static long *state = &randtbl[1];

static int rand_type = TYPE_3;
static int rand_deg = DEG_3;
static int rand_sep = SEP_3;

static long *end_ptr = &randtbl[DEG_3 + 1];



/*
* srandom:
* Initialize the random number generator based on the given seed. If the
* type is the trivial no-state-information type, just remember the seed.
* Otherwise, initializes state[] based on the given "seed" via a linear
* congruential generator. Then, the pointers are set to known locations
* that are exactly rand_sep places apart. Lastly, it cycles the state
* information a given number of times to get rid of any initial dependencies
* introduced by the L.C.R.N.G.
* Note that the initialization of randtbl[] for default usage relies on
* values produced by this routine.
*/

srandom (x)

unsigned x;
{
register int i;
long random ();

if (rand_type == TYPE_0)
{
state[0] = x;
}
else
{
state[0] = x;
for (i = 1; i < rand_deg; i++)
{
state[i] = 1103515245 * state[i - 1] + 12345;
}
fptr = &state[rand_sep];
rptr = &state[0];
for (i = 0; i < 10 * rand_deg; i++)
random ();
}
}



/*
* initstate:
* Initialize the state information in the given array of n bytes for
* future random number generation. Based on the number of bytes we
* are given, and the break values for the different R.N.G.'s, we choose
* the best (largest) one we can and set things up for it. srandom() is
* then called to initialize the state information.
* Note that on return from srandom(), we set state[-1] to be the type
* multiplexed with the current value of the rear pointer; this is so
* successive calls to initstate() won't lose this information and will
* be able to restart with setstate().
* Note: the first thing we do is save the current state, if any, just like
* setstate() so that it doesn't matter when initstate is called.
* Returns a pointer to the old state.
*/

char *
initstate (seed, arg_state, n)

unsigned seed; /* seed for R. N. G. */
char *arg_state; /* pointer to state array */
int n; /* # bytes of state info */
{
register char *ostate = (char *) (&state[-1]);

if (rand_type == TYPE_0)
state[-1] = rand_type;
else
state[-1] = MAX_TYPES * (rptr - state) + rand_type;
if (n < BREAK_1)
{
if (n < BREAK_0)
{
fprintf (stderr, "initstate: not enough state (%d bytes) with which to do jack; ignored.\n", n);
return 0;
}
rand_type = TYPE_0;
rand_deg = DEG_0;
rand_sep = SEP_0;
}
else
{
if (n < BREAK_2)
{
rand_type = TYPE_1;
rand_deg = DEG_1;
rand_sep = SEP_1;
}
else
{
if (n < BREAK_3)
{
rand_type = TYPE_2;
rand_deg = DEG_2;
rand_sep = SEP_2;
}
else
{
if (n < BREAK_4)
{
rand_type = TYPE_3;
rand_deg = DEG_3;
rand_sep = SEP_3;
}
else
{
rand_type = TYPE_4;
rand_deg = DEG_4;
rand_sep = SEP_4;
}
}
}
}
state = &(((long *) arg_state)[1]); /* first location */
end_ptr = &state[rand_deg]; /* must set end_ptr before srandom */
srandom (seed);
if (rand_type == TYPE_0)
state[-1] = rand_type;
else
state[-1] = MAX_TYPES * (rptr - state) + rand_type;
return (ostate);
}



/*
* setstate:
* Restore the state from the given state array.
* Note: it is important that we also remember the locations of the pointers
* in the current state information, and restore the locations of the pointers
* from the old state information. This is done by multiplexing the pointer
* location into the zeroeth word of the state information.
* Note that due to the order in which things are done, it is OK to call
* setstate() with the same state as the current state.
* Returns a pointer to the old state information.
*/

char *
setstate (arg_state)

char *arg_state;
{
register long *new_state = (long *) arg_state;
register int type = new_state[0] % MAX_TYPES;
register int rear = new_state[0] / MAX_TYPES;
char *ostate = (char *) (&state[-1]);

if (rand_type == TYPE_0)
state[-1] = rand_type;
else
state[-1] = MAX_TYPES * (rptr - state) + rand_type;
switch (type)
{
case TYPE_0:
case TYPE_1:
case TYPE_2:
case TYPE_3:
case TYPE_4:
rand_type = type;
rand_deg = degrees[type];
rand_sep = seps[type];
break;

default:
fprintf (stderr, "setstate: state info has been munged; not changed.\n");
}
state = &new_state[1];
if (rand_type != TYPE_0)
{
rptr = &state[rear];
fptr = &state[(rear + rand_sep) % rand_deg];
}
end_ptr = &state[rand_deg]; /* set end_ptr too */
return (ostate);
}



/*
* random:
* If we are using the trivial TYPE_0 R.N.G., just do the old linear
* congruential bit. Otherwise, we do our fancy trinomial stuff, which is the
* same in all ther other cases due to all the global variables that have been
* set up. The basic operation is to add the number at the rear pointer into
* the one at the front pointer. Then both pointers are advanced to the next
* location cyclically in the table. The value returned is the sum generated,
* reduced to 31 bits by throwing away the "least random" low bit.
* Note: the code takes advantage of the fact that both the front and
* rear pointers can't wrap on the same call by not testing the rear
* pointer if the front one has wrapped.
* Returns a 31-bit random number.
*/

long
random ()
{
long i;

if (rand_type == TYPE_0)
{
i = state[0] = (state[0] * 1103515245 + 12345) & 0x7fffffff;
}
else
{
*fptr += *rptr;
i = (*fptr >> 1) & 0x7fffffff; /* chucking least random bit */
if (++fptr >= end_ptr)
{
fptr = state;
++rptr;
}
else
{
if (++rptr >= end_ptr)
rptr = state;
}
}
return (i);
}
oleo-1.3/vfprintf.c 644 722 0 1775 5324157622 12504 0ustar lordwheel/* Copyright (C) 1993 Free Software Foundation, Inc.

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, 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 software; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */


#include
#include
#include "sysdef.h"

#ifdef __STDC__
#define CONST const
#undef NULL
#else
#define CONST
#endif

int
vfprintf (fp, s, ap)
FILE *fp;
CONST char *s;
va_list ap;
{
int len;

len = _doprnt (s, ap, fp);
return (ferror (fp) ? EOF : len);
}



oleo-1.3/vsprintf.c 644 722 0 2255 5324472640 12513 0ustar lordwheel/* Copyright (C) 1993 Free Software Foundation, Inc.

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, 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 software; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */


#include
#include
#include "sysdef.h"

#ifdef __STDC__
#define CONST const
#undef NULL
#else
#define CONST
#endif

int
vsprintf (into, s, ap)
char *into;
CONST char *s;
va_list ap;
{
int ret;
auto FILE f;

f._cnt = 32767;
f._ptr = into;
/* I am dubious of this hack for the RS/6000. */
#ifdef _IOSTRG
f._flag = _IOWRT + _IOSTRG;
#else
f._flag = _IOWRT;
#endif
ret = _doprnt (s, ap, &f);
*f._ptr = 0;
return (ret);
}
oleo-1.3/_doprnt.c 644 722 0 41116 5323634056 12324 0ustar lordwheel/*
* Copyright (c) 1988 Regents of the University of California.
* All rights reserved.
*
* Redistribution and use in source and binary forms are permitted
* provided that the above copyright notice and this paragraph are
* duplicated in all such forms and that any documentation,
* advertising materials, and other materials related to such
* distribution and use acknowledge that the software was developed
* by the University of California, Berkeley. The name of the
* University may not be used to endorse or promote products derived
* from this software without specific prior written permission.
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*/

#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)doprnt.c 5.35 (Berkeley) 6/27/88";
#endif /* LIBC_SCCS and not lint */

#include
#include
#include
#include

#ifdef SYSV
typedef unsigned char u_char;
typedef unsigned long u_long;
#endif

/* 11-bit exponent (VAX G floating point) is 308 decimal digits */
#define MAXEXP 308
/* 128 bit fraction takes up 39 decimal digits; max reasonable precision */
#define MAXFRACT 39

#define DEFPREC 6

#define BUF (MAXEXP+MAXFRACT+1) /* + decimal point */

#define PUTC(ch) (void) putc(ch, fp)

#define ARG() \
_ulong = flags&LONGINT ? va_arg(argp, long) : \
flags&SHORTINT ? va_arg(argp, short) : va_arg(argp, int);

#define todigit(c) ((c) - '0')
#define tochar(n) ((n) + '0')

/* have to deal with the negative buffer count kludge */
#define NEGATIVE_COUNT_KLUDGE

#define LONGINT 0x01 /* long integer */
#define LONGDBL 0x02 /* long double; unimplemented */
#define SHORTINT 0x04 /* short integer */
#define ALT 0x08 /* alternate form */
#define LADJUST 0x10 /* left adjustment */
#define ZEROPAD 0x20 /* zero (as opposed to blank) pad */
#define HEXPREFIX 0x40 /* add 0x or 0X prefix */

extern double __plinf, __neinf, __nan;
/* double __plinf = 1e500; */
char *__inf_str = "#INF";

/* double __neinf = -1e500; */
char *__ninf_str = "#NINF";

/* __asm(".globl ___nan");
__asm("___nan: .double 0rnan"); */
/* double __nan = __asm("0rnan"); */
char *__nan_str = "#NAN";

static int cvt();
static char *round();
static char *exponent();

extern double modf();
extern int strlen();
extern void bcopy();

int
_doprnt(fmt0, argp, fp)
u_char *fmt0;
va_list argp;
register FILE *fp;
{
register u_char *fmt; /* format string */
register int ch; /* character from fmt */
register int cnt; /* return value accumulator */
register int n; /* random handy integer */
register char *t; /* buffer pointer */
double _double; /* double precision arguments %[eEfgG] */
u_long _ulong; /* integer arguments %[diouxX] */
int base; /* base for [diouxX] conversion */
int dprec; /* decimal precision in [diouxX] */
int fieldsz; /* field size expanded by sign, etc */
int flags; /* flags as above */
int fpprec; /* `extra' floating precision in [eEfgG] */
int prec; /* precision from format (%.3d), or -1 */
int realsz; /* field size expanded by decimal precision */
int size; /* size of converted field or string */
int width; /* width from format (%8d), or 0 */
char sign; /* sign prefix (' ', '+', '-', or \0) */
char softsign; /* temporary negative sign for floats */
char *digs; /* digits for [diouxX] conversion */
char buf[BUF]; /* space for %c, %[diouxX], %[eEfgG] */

if (fp->_flag & _IORW) {
fp->_flag |= _IOWRT;
fp->_flag &= ~(_IOEOF|_IOREAD);
}
if ((fp->_flag & _IOWRT) == 0)
return (EOF);

fmt = fmt0;
digs = "0123456789abcdef";
for (cnt = 0;; ++fmt) {
n = fp->_cnt;
for (t = (char *)fp->_ptr; (ch = *fmt) && ch != '%';
++cnt, ++fmt)
if (--n < 0
#ifdef NEGATIVE_COUNT_KLUDGE
&& (!(fp->_flag & _IOLBF) || -n >= fp->_bufsiz)
#endif
|| ch == '\n' && fp->_flag & _IOLBF) {
fp->_cnt = n;
fp->_ptr = t;
(void) _flsbuf((u_char)ch, fp);
n = fp->_cnt;
t = (char *)fp->_ptr;
} else
*t++ = ch;
fp->_cnt = n;
fp->_ptr = t;
if (!ch)
return (cnt);

flags = 0; dprec = 0; fpprec = 0; width = 0;
prec = -1;
sign = '\0';

rflag: switch (*++fmt) {
case ' ':
/*
* ``If the space and + flags both appear, the space
* flag will be ignored.''
* -- ANSI X3J11
*/
if (!sign)
sign = ' ';
goto rflag;
case '#':
flags |= ALT;
goto rflag;
case '*':
/*
* ``A negative field width argument is taken as a
* - flag followed by a positive field width.''
* -- ANSI X3J11
* They don't exclude field widths read from args.
*/
if ((width = va_arg(argp, int)) >= 0)
goto rflag;
width = -width;
/* FALLTHROUGH */
case '-':
flags |= LADJUST;
goto rflag;
case '+':
sign = '+';
goto rflag;
case '.':
if (*++fmt == '*')
n = va_arg(argp, int);
else {
n = 0;
while (isascii(*fmt) && isdigit(*fmt))
n = 10 * n + todigit(*fmt++);
--fmt;
}
prec = n < 0 ? -1 : n;
goto rflag;
case '0':
/*
* ``Note that 0 is taken as a flag, not as the
* beginning of a field width.''
* -- ANSI X3J11
*/
flags |= ZEROPAD;
goto rflag;
case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
n = 0;
do {
n = 10 * n + todigit(*fmt);
} while (isascii(*++fmt) && isdigit(*fmt));
width = n;
--fmt;
goto rflag;
case 'L':
flags |= LONGDBL;
goto rflag;
case 'h':
flags |= SHORTINT;
goto rflag;
case 'l':
flags |= LONGINT;
goto rflag;
case 'c':
*(t = buf) = va_arg(argp, int);
size = 1;
sign = '\0';
goto pforw;
case 'D':
flags |= LONGINT;
/*FALLTHROUGH*/
case 'd':
case 'i':
ARG();
if ((long)_ulong < 0) {
_ulong = -_ulong;
sign = '-';
}
base = 10;
goto number;
case 'e':
case 'E':
case 'f':
case 'g':
case 'G':
_double = va_arg(argp, double);
/*
* don't do unrealistic precision; just pad it with
* zeroes later, so buffer size stays rational.
*/
if (prec > MAXFRACT) {
if (*fmt != 'g' && *fmt != 'G' || (flags&ALT))
fpprec = prec - MAXFRACT;
prec = MAXFRACT;
}
else if (prec == -1)
prec = DEFPREC;
/*
* softsign avoids negative 0 if _double is < 0 and
* no significant digits will be shown
*/
if (_double < 0) {
softsign = '-';
_double = -_double;
}
else
softsign = 0;
/*
* cvt may have to round up past the "start" of the
* buffer, i.e. ``intf("%.2f", (double)9.999);'';
* if the first char isn't NULL, it did.
*/
*buf = NULL;
size = cvt(_double, prec, flags, &softsign, *fmt, buf,
buf + sizeof(buf));
if (softsign)
sign = '-';
t = *buf ? buf : buf + 1;
goto pforw;
case 'n':
if (flags & LONGINT)
*va_arg(argp, long *) = cnt;
else if (flags & SHORTINT)
*va_arg(argp, short *) = cnt;
else
*va_arg(argp, int *) = cnt;
break;
case 'O':
flags |= LONGINT;
/*FALLTHROUGH*/
case 'o':
ARG();
base = 8;
goto nosign;
case 'p':
/*
* ``The argument shall be a pointer to void. The
* value of the pointer is converted to a sequence
* of printable characters, in an implementation-
* defined manner.''
* -- ANSI X3J11
*/
/* NOSTRICT */
_ulong = (u_long)va_arg(argp, void *);
base = 16;
goto nosign;
case 's':
if (!(t = va_arg(argp, char *)))
t = "(null)";
if (prec >= 0) {
/*
* can't use strlen; can only look for the
* NUL in the first `prec' characters, and
* strlen() will go further.
*/
char *p, *memchr();

if (p = memchr(t, 0, prec)) {
size = p - t;
if (size > prec)
size = prec;
} else
size = prec;
} else
size = strlen(t);
sign = '\0';
goto pforw;
case 'U':
flags |= LONGINT;
/*FALLTHROUGH*/
case 'u':
ARG();
base = 10;
goto nosign;
case 'X':
digs = "0123456789ABCDEF";
/* FALLTHROUGH */
case 'x':
ARG();
base = 16;
/* leading 0x/X only if non-zero */
if (flags & ALT && _ulong != 0)
flags |= HEXPREFIX;

/* unsigned conversions */
nosign: sign = '\0';
/*
* ``... diouXx conversions ... if a precision is
* specified, the 0 flag will be ignored.''
* -- ANSI X3J11
*/
number: if ((dprec = prec) >= 0)
flags &= ~ZEROPAD;

/*
* ``The result of converting a zero value with an
* explicit precision of zero is no characters.''
* -- ANSI X3J11
*/
t = buf + BUF;
if (_ulong != 0 || prec != 0) {
do {
*--t = digs[_ulong % base];
_ulong /= base;
} while (_ulong);
digs = "0123456789abcdef";
if (flags & ALT && base == 8 && *t != '0')
*--t = '0'; /* octal leading 0 */
}
size = buf + BUF - t;

pforw:
/*
* All reasonable formats wind up here. At this point,
* `t' points to a string which (if not flags&LADJUST)
* should be padded out to `width' places. If
* flags&ZEROPAD, it should first be prefixed by any
* sign or other prefix; otherwise, it should be blank
* padded before the prefix is emitted. After any
* left-hand padding and prefixing, emit zeroes
* required by a decimal [diouxX] precision, then print
* the string proper, then emit zeroes required by any
* leftover floating precision; finally, if LADJUST,
* pad with blanks.
*/

/*
* compute actual size, so we know how much to pad
* fieldsz excludes decimal prec; realsz includes it
*/
fieldsz = size + fpprec;
if (sign)
fieldsz++;
if (flags & HEXPREFIX)
fieldsz += 2;
realsz = dprec > fieldsz ? dprec : fieldsz;

/* right-adjusting blank padding */
if ((flags & (LADJUST|ZEROPAD)) == 0 && width)
for (n = realsz; n < width; n++)
PUTC(' ');
/* prefix */
if (sign)
PUTC(sign);
if (flags & HEXPREFIX) {
PUTC('0');
PUTC((char)*fmt);
}
/* right-adjusting zero padding */
if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD)
for (n = realsz; n < width; n++)
PUTC('0');
/* leading zeroes from decimal precision */
for (n = fieldsz; n < dprec; n++)
PUTC('0');

/* the string or number proper */
if (fp->_cnt - (n = size) >= 0 &&
(fp->_flag & _IOLBF) == 0) {
fp->_cnt -= n;
bcopy(t, (char *)fp->_ptr, n);
fp->_ptr += n;
} else
while (--n >= 0)
PUTC(*t++);
/* trailing f.p. zeroes */
while (--fpprec >= 0)
PUTC('0');
/* left-adjusting padding (always blank) */
if (flags & LADJUST)
for (n = realsz; n < width; n++)
PUTC(' ');
/* finally, adjust cnt */
cnt += width > realsz ? width : realsz;
break;
case '\0': /* "%?" prints ?, unless ? is NULL */
return (cnt);
default:
PUTC((char)*fmt);
cnt++;
}
}
/* NOTREACHED */
}

static int
cvt(number, prec, flags, signp, fmtch, startp, endp)
double number;
register int prec;
int flags;
u_char fmtch;
char *signp, *startp, *endp;
{
register char *p, *t;
register double fract;
int dotrim, expcnt, gformat;
double integer, tmp, modf();

/* JF for numbers */
if(number!=number) {
t= ++startp;
p=__nan_str;
while(*p)
*t++= *p++;
return t-startp;
}
if(number==__plinf) {
t= ++startp;
p= (*signp) ? __ninf_str : __inf_str;
*signp=0;
while(*p)
*t++= *p++;
return t-startp;
}
/* if(number==__neinf) {
t= ++startp;
p=__ninf_str;
while(*p)
*t++= *p++;
return t-startp;
} */
dotrim = expcnt = gformat = 0;
fract = modf(number, &integer);

/* get an extra slot for rounding. */
t = ++startp;

/*
* get integer portion of number; put into the end of the buffer; the
* .01 is added for modf(356.0 / 10, &integer) returning .59999999...
*/
for (p = endp - 1; integer; ++expcnt) {
tmp = modf(integer / 10, &integer);
*p-- = tochar((int)((tmp + .01) * 10));
}
switch(fmtch) {
case 'f':
/* reverse integer into beginning of buffer */
if (expcnt)
for (; ++p < endp; *t++ = *p);
else
*t++ = '0';
/*
* if precision required or alternate flag set, add in a
* decimal point.
*/
if (prec || flags&ALT)
*t++ = '.';
/* if requires more precision and some fraction left */
if (fract) {
if (prec)
do {
fract = modf(fract * 10, &tmp);
*t++ = tochar((int)tmp);
} while (--prec && fract);
if (fract)
startp = round(fract, (int *)NULL, startp,
t - 1, (char)0, signp);
}
for (; prec--; *t++ = '0');
break;
case 'e':
case 'E':
eformat: if (expcnt) {
*t++ = *++p;
if (prec || flags&ALT)
*t++ = '.';
/* if requires more precision and some integer left */
for (; prec && ++p < endp; --prec)
*t++ = *p;
/*
* if done precision and more of the integer component,
* round using it; adjust fract so we don't re-round
* later.
*/
if (!prec && ++p < endp) {
fract = 0;
startp = round((double)0, &expcnt, startp,
t - 1, *p, signp);
}
/* adjust expcnt for digit in front of decimal */
--expcnt;
}
/* until first fractional digit, decrement exponent */
else if (fract) {
/* adjust expcnt for digit in front of decimal */
for (expcnt = -1;; --expcnt) {
fract = modf(fract * 10, &tmp);
if (tmp)
break;
}
*t++ = tochar((int)tmp);
if (prec || flags&ALT)
*t++ = '.';
}
else {
*t++ = '0';
if (prec || flags&ALT)
*t++ = '.';
}
/* if requires more precision and some fraction left */
if (fract) {
if (prec)
do {
fract = modf(fract * 10, &tmp);
*t++ = tochar((int)tmp);
} while (--prec && fract);
if (fract)
startp = round(fract, &expcnt, startp,
t - 1, (char)0, signp);
}
/* if requires more precision */
for (; prec--; *t++ = '0');

/* unless alternate flag, trim any g/G format trailing 0's */
if (gformat && !(flags&ALT)) {
while (t > startp && *--t == '0');
if (*t == '.')
--t;
++t;
}
t = exponent(t, expcnt, fmtch);
break;
case 'g':
case 'G':
/* a precision of 0 is treated as a precision of 1. */
if (!prec)
++prec;
/*
* ``The style used depends on the value converted; style e
* will be used only if the exponent resulting from the
* conversion is less than -4 or greater than the precision.''
* -- ANSI X3J11
*/
if (expcnt > prec || !expcnt && fract && fract < .0001) {
/*
* g/G format counts "significant digits, not digits of
* precision; for the e/E format, this just causes an
* off-by-one problem, i.e. g/G considers the digit
* before the decimal point significant and e/E doesn't
* count it as precision.
*/
--prec;
fmtch -= 2; /* G->E, g->e */
gformat = 1;
goto eformat;
}
/*
* reverse integer into beginning of buffer,
* note, decrement precision
*/
if (expcnt)
for (; ++p < endp; *t++ = *p, --prec);
else
*t++ = '0';
/*
* if precision required or alternate flag set, add in a
* decimal point. If no digits yet, add in leading 0.
*/
if (prec || flags&ALT) {
dotrim = 1;
*t++ = '.';
}
else
dotrim = 0;
/* if requires more precision and some fraction left */
if (fract) {
if (prec) {
do {
fract = modf(fract * 10, &tmp);
*t++ = tochar((int)tmp);
} while(!tmp);
while (--prec && fract) {
fract = modf(fract * 10, &tmp);
*t++ = tochar((int)tmp);
}
}
if (fract)
startp = round(fract, (int *)NULL, startp,
t - 1, (char)0, signp);
}
/* alternate format, adds 0's for precision, else trim 0's */
if (flags&ALT)
for (; prec--; *t++ = '0');
else if (dotrim) {
while (t > startp && *--t == '0');
if (*t != '.')
++t;
}
}
return(t - startp);
}

static char *
round(fract, exp, start, end, ch, signp)
double fract;
int *exp;
register char *start, *end;
char ch, *signp;
{
double tmp;

if (fract)
(void)modf(fract * 10, &tmp);
else
tmp = todigit(ch);
if (tmp > 4)
for (;; --end) {
if (*end == '.')
--end;
if (++*end <= '9')
break;
*end = '0';
if (end == start) {
if (exp) { /* e/E; increment exponent */
*end = '1';
++*exp;
}
else { /* f; add extra digit */
*--end = '1';
--start;
}
break;
}
}
/* ``"%.3f", (double)-0.0004'' gives you a negative 0. */
else if (*signp == '-')
for (;; --end) {
if (*end == '.')
--end;
if (*end != '0')
break;
if (end == start)
*signp = 0;
}
return(start);
}

static char *
exponent(p, exp, fmtch)
register char *p;
register int exp;
u_char fmtch;
{
register char *t;
char expbuf[MAXEXP];

*p++ = fmtch;
if (exp < 0) {
exp = -exp;
*p++ = '-';
}
else
*p++ = '+';
t = expbuf + MAXEXP;
if (exp > 9) {
do {
*--t = tochar(exp % 10);
} while ((exp /= 10) > 9);
*--t = tochar(exp);
for (; t < expbuf + MAXEXP; *p++ = *t++);
}
else {
*p++ = '0';
*p++ = tochar(exp);
}
return(p);
}
oleo-1.3/alloca.c 644 722 0 12354 5323644050 12107 0ustar lordwheel/*
alloca -- (mostly) portable public-domain implementation -- D A Gwyn

last edit: 86/05/30 rms
include config.h, since on VMS it renames some symbols.
Use xmalloc instead of malloc.

This implementation of the PWB library alloca() function,
which is used to allocate space off the run-time stack so
that it is automatically reclaimed upon procedure exit,
was inspired by discussions with J. Q. Johnson of Cornell.

It should work under any C implementation that uses an
actual procedure stack (as opposed to a linked list of
frames). There are some preprocessor constants that can
be defined when compiling for your specific system, for
improved efficiency; however, the defaults should be okay.

The general concept of this implementation is to keep
track of all alloca()-allocated blocks, and reclaim any
that are found to be deeper in the stack than the current
invocation. This heuristic does not reclaim storage as
soon as it becomes invalid, but it will do so eventually.

As a special case, alloca(0) reclaims storage without
allocating any. It is a good idea to use alloca(0) in
your main control loop, etc. to force garbage collection.
*/
#ifndef lint
static char SCCSid[] = "@(#)alloca.c 1.1"; /* for the "what" utility */
#endif

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#ifdef emacs
#ifdef static
/* actually, only want this if static is defined as ""
-- this is for usg, in which emacs must undefine static
in order to make unexec workable
*/
#ifndef STACK_DIRECTION
you
lose
-- must know STACK_DIRECTION at compile-time
#endif /* STACK_DIRECTION undefined */
#endif /* static */
#endif /* emacs */

#ifndef alloca /* If compiling with GCC, this file's not needed. */

#ifdef __STDC__
typedef void *pointer; /* generic pointer type */
#else
typedef char *pointer; /* generic pointer type */
#endif

#define NULL 0 /* null pointer constant */

extern void free();
extern pointer xmalloc();

/*
Define STACK_DIRECTION if you know the direction of stack
growth for your system; otherwise it will be automatically
deduced at run-time.

STACK_DIRECTION > 0 => grows toward higher addresses
STACK_DIRECTION < 0 => grows toward lower addresses
STACK_DIRECTION = 0 => direction of growth unknown
*/

#ifndef STACK_DIRECTION
#define STACK_DIRECTION 0 /* direction unknown */
#endif

#if STACK_DIRECTION != 0

#define STACK_DIR STACK_DIRECTION /* known at compile-time */

#else /* STACK_DIRECTION == 0; need run-time code */

static int stack_dir; /* 1 or -1 once known */
#define STACK_DIR stack_dir

static void
find_stack_direction (/* void */)
{
static char *addr = NULL; /* address of first
`dummy', once known */
auto char dummy; /* to get stack address */

if (addr == NULL)
{ /* initial entry */
addr = &dummy;

find_stack_direction (); /* recurse once */
}
else /* second entry */
if (&dummy > addr)
stack_dir = 1; /* stack grew upward */
else
stack_dir = -1; /* stack grew downward */
}

#endif /* STACK_DIRECTION == 0 */

/*
An "alloca header" is used to:
(a) chain together all alloca()ed blocks;
(b) keep track of stack depth.

It is very important that sizeof(header) agree with malloc()
alignment chunk size. The following default should work okay.
*/

#ifndef ALIGN_SIZE
#define ALIGN_SIZE sizeof(double)
#endif

typedef union hdr
{
char align[ALIGN_SIZE]; /* to force sizeof(header) */
struct
{
union hdr *next; /* for chaining headers */
char *deep; /* for stack depth measure */
} h;
} header;

/*
alloca( size ) returns a pointer to at least `size' bytes of
storage which will be automatically reclaimed upon exit from
the procedure that called alloca(). Originally, this space
was supposed to be taken from the current stack frame of the
caller, but that method cannot be made to work for some
implementations of C, for example under Gould's UTX/32.
*/

static header *last_alloca_header = NULL; /* -> last alloca header */

pointer
alloca (size) /* returns pointer to storage */
unsigned size; /* # bytes to allocate */
{
auto char probe; /* probes stack depth: */
register char *depth = &probe;

#if STACK_DIRECTION == 0
if (STACK_DIR == 0) /* unknown growth direction */
find_stack_direction ();
#endif

/* Reclaim garbage, defined as all alloca()ed storage that
was allocated from deeper in the stack than currently. */

{
register header *hp; /* traverses linked list */

for (hp = last_alloca_header; hp != NULL;)
if ((STACK_DIR > 0 && hp->h.deep > depth)
|| (STACK_DIR < 0 && hp->h.deep < depth))
{
register header *np = hp->h.next;

free ((pointer) hp); /* collect garbage */

hp = np; /* -> next header */
}
else
break; /* rest are not deeper */

last_alloca_header = hp; /* -> last valid storage */
}

if (size == 0)
return NULL; /* no allocation required */

/* Allocate combined header + user data storage. */

{
register pointer new = xmalloc (sizeof (header) + size);
/* address of header */

((header *)new)->h.next = last_alloca_header;
((header *)new)->h.deep = depth;

last_alloca_header = (header *)new;

/* User storage begins just after header. */

return (pointer)((char *)new + sizeof(header));
}
}

#endif /* no alloca */
oleo-1.3/cmd.c 644 722 0 150452 5356412153 11444 0ustar lordwheel/* Copyright (C) 1993 Free Software Foundation, Inc.

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, 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 software; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */



#include
#include "errno.h"
#define obstack_chunk_alloc ck_malloc
#define obstack_chunk_free free
#include "obstack.h"
#include "global.h"
#include "cmd.h"
#include "io-term.h"
#include "io-abstract.h"
#include "io-generic.h"
#include "io-utils.h"
#include "io-edit.h"
#include "stub.h"
#include "ref.h"

#undef MIN
#undef MAX
#define MIN(A,B) ((A) < (B) ? (A) : (B))
#define MAX(A,B) ((A) > (B) ? (A) : (B))

/* Bogus mapping from KEY->CODE to ranges. This is how bound
* macros are represented.
* This is bogus because the ranges will not be adjusted in
* the ways they should. Variables should be used instead.
*/
int n_bound_macros;
struct rng *bound_macros;
int bound_macro_vec;



/* Flow of control centers around a select loop. These are the
* fd's selected on.
*/
SELECT_TYPE read_fd_set;
SELECT_TYPE exception_fd_set;
SELECT_TYPE write_fd_set;

/* These are fd's returned by the last call to select.
*/
SELECT_TYPE read_pending_fd_set;
SELECT_TYPE exception_pending_fd_set;
SELECT_TYPE write_pending_fd_set;

/* Hooks for asynchronos i/o
*/

struct select_hook file_read_hooks[SELECT_SET_SIZE] = {0};
struct select_hook file_exception_hooks[SELECT_SET_SIZE] = {0};
struct select_hook file_write_hooks[SELECT_SET_SIZE] = {0};


/* The current stream from which commands are being read. */
struct input_stream * the_input_stream = 0;




#ifdef __STDC__
static struct input_stream *
default_input_stream (void)
#else
static struct input_stream *
default_input_stream ()
#endif
{
if (!the_input_stream)
{
the_input_stream =
(struct input_stream *)ck_malloc (sizeof (struct input_stream));
the_input_stream->_rmac = 0;
the_input_stream->_func_arg = 0;
obstack_init (&the_input_stream->_macro_stack);
the_input_stream->_macro = 0;
the_input_stream->_macro_start = 0;
the_input_stream->_macro_size = 0;
the_input_stream->prev_stream = 0;
the_input_stream->_last_macro = 0;
the_input_stream->_pushed_back_char = -1;
}
return the_input_stream;
}


/* This constructs an input stream that reads from a macro but never
* from a keyboard. EXECUTE_CMD uses this.
*/


#ifdef __STDC__
static struct input_stream *
macro_only_input_stream (struct rng * rng, char * first_line, int len,
struct command_frame * frame)
#else
static struct input_stream *
macro_only_input_stream (rng, first_line, len, frame)
struct rng * rng;
char * first_line;
int len;
struct command_frame * frame;
#endif
{
struct input_stream * ret;
ret = (struct input_stream *)ck_malloc (sizeof (struct input_stream));
ret->_func_arg = 0;
obstack_init (&ret->_macro_stack);
ret->_rmac =
(struct macro *) obstack_alloc (&ret->_macro_stack, sizeof (struct macro));
ret->_rmac->mac_prev = 0;
ret->_rmac->mac_rng = *rng;
ret->_rmac->mac_row = rng->lr;
ret->_rmac->mac_col = rng->lc;
(void) obstack_grow (&ret->_macro_stack, first_line, len);
(void) obstack_grow (&ret->_macro_stack, "", 1);
ret->_rmac->mac_start = ret->_rmac->mac_exe
= (unsigned char *) obstack_finish (&ret->_macro_stack);
ret->_macro = 0;
ret->_macro_start = 0;
ret->_macro_size = 0;
ret->_last_macro = 0;
ret->prev_stream = frame->input;
{
struct input_stream * key = frame->input;
while (frame->input == key)
{
frame->input = ret;
frame = frame->prev;
}
}
ret->_pushed_back_char = -1;
return ret;
}

#ifdef __STDC__
void
free_input_stream (struct input_stream * stream)
#else
void
free_input_stream (stream)
struct input_stream * stream;
#endif
{
if (stream->_macro_start)
free (stream->_macro_start);
if (stream->_last_macro)
free (stream->_last_macro);
obstack_free (&stream->_macro_stack, 0);
free (stream);
}

/* This gets rid of an input stream created by macro_only_input_stream.
* It fixes the INPUT fields of pending command frames.
*/

#ifdef __STDC__
void
pop_input_stream (void)
#else
void
pop_input_stream ()
#endif
{
if (the_cmd_frame->input->prev_stream)
{
struct command_frame * fr = the_cmd_frame;
struct input_stream * key = the_cmd_frame->input;
while (fr->input == key)
{
fr->input = key->prev_stream;
fr = fr->prev;
}
free_input_stream (key);
return;
}
}


/* Macros
* These are the commands the user has to interact with macros.
*/

#ifdef __STDC__
void
start_entering_macro (void)
#else
void
start_entering_macro ()
#endif
{
if (making_macro)
{
io_error_msg ("Can't define two macros at once");
return;
}
making_macro_size = 20;
making_macro = making_macro_start = ck_malloc (5 + making_macro_size);
}

#ifdef __STDC__
void
bound_macro (int num)
#else
void
bound_macro (num)
int num;
#endif
{
struct macro *old;
CELL *cp;

cp = find_cell (bound_macros[num].lr, bound_macros[num].lc);
if (!cp || GET_TYP (cp) != TYP_STR || cp->cell_str[0] == '\0')
return;
old = rmac;
rmac =
(struct macro *) obstack_alloc (¯o_stack, sizeof (struct macro));
rmac->mac_prev = old;
rmac->mac_rng = bound_macros[num];
rmac->mac_row = bound_macros[num].lr;
rmac->mac_col = bound_macros[num].lc;
obstack_grow (¯o_stack, cp->cell_str, 1 + strlen (cp->cell_str));
rmac->mac_start = rmac->mac_exe =
(unsigned char *) obstack_finish (¯o_stack);
}

#ifdef __STDC__
void
run_string_as_macro (char * macro, int count)
#else
void
run_string_as_macro (macro, count)
char * macro;
int count;
#endif
{
struct rng rng;
while (count--)
{
rng.lr = rng.hr = rng.lc = rng.hc = MIN_ROW;
macro_only_input_stream (&rng, macro, strlen (macro), the_cmd_frame);
command_loop (1);
}
}

#ifdef __STDC__
void
call_last_kbd_macro (int count)
#else
void
call_last_kbd_macro (count)
int count;
#endif
{
if (!last_macro)
io_error_msg ("No keyboard macro entered.");
run_string_as_macro ((char *)last_macro, count);
}

/* This command is automaticly inserted into the command stream
* when the end of a macro is reached.
*/
#ifdef __STDC__
void
end_macro (void)
#else
void
end_macro ()
#endif
{
CELL *cp;
struct macro *old;

if (!rmac)
{
io_error_msg ("Not executing a macro!");
return;
}
if ((rmac->mac_row == rmac->mac_rng.hr)
&& (rmac->mac_col == rmac->mac_rng.hc))
{
old = rmac->mac_prev;
obstack_free (¯o_stack, rmac);
rmac = old;
}
else
{
if (rmac->mac_row == rmac->mac_rng.hr)
{
rmac->mac_row = rmac->mac_rng.lr;
rmac->mac_col++;
}
else
rmac->mac_row++;

cp = find_cell (rmac->mac_row, rmac->mac_col);

if (!cp || GET_TYP (cp) != TYP_STR || cp->cell_str[0] == '\0')
{
old = rmac->mac_prev;
obstack_free (¯o_stack, rmac);
rmac = old;
}
else
{
obstack_grow (¯o_stack, cp->cell_str, 1 + strlen (cp->cell_str));
rmac->mac_exe
= (unsigned char *) obstack_finish (¯o_stack);
}
}
}


/* This command is executed by the user to stop entering a macro.
*/
#ifdef __STDC__
void
stop_entering_macro (void)
#else
void
stop_entering_macro ()
#endif
{
if (!making_macro)
{
if (rmac)
return;
io_error_msg ("Not defining a macro!");
return;
}

making_macro[0] = '\0';
making_macro = 0;
if (last_macro)
ck_free (last_macro);
last_macro = making_macro_start;
making_macro_start = 0;
free (making_macro_start);
}

#ifdef __STDC__
void
store_last_macro (struct rng * rng)
#else
void
store_last_macro (rng)
struct rng * rng;
#endif
{
union vals z;
z.c_s = (char *)last_macro;
set_new_value (rng->lr, rng->lc, TYP_STR, &z);
}



/* Scheduling
*
* Scheduling is centered around the function real_get_chr
* which is allowed to block until an input event has occured.
* Before blocking, real_get_chr may evaluate cells and/or update
* the display.
*/


/* Error messages are delivered to the user by invoking a command
* that prompts with the error message, and waits for the user's next
* keypress. This command shouldn't wait indefinitely. After a short time,
* the error message should disappear. This is accomplished by counting down
* a timer, then destorying the error message command frame and throwing an
* error. The error is thrown directly rather than with io_error_msg in order
* to avoid circularity.
*/

static void
error_alarm ()
{
if (the_cmd_frame->cmd && the_cmd_arg.timeout_seconds)
{
--the_cmd_arg.timeout_seconds;
if (!the_cmd_arg.timeout_seconds)
{
pop_unfinished_command ();
alarm_table[2].freq = 0;
longjmp (error_exception, 1);
}
}
else
alarm_table[2].freq = 0;
}

struct alarm_entry alarm_table [3] =
{
{cell_alarm, 1, 0},
{error_alarm, 0, 0},
{0, 0}
};

/* Function that get called whenever blocking times out. */

#ifdef __STDC__
static void
alarm_hooks (void)
#else
static void
alarm_hooks ()
#endif
{
int x;
time_t now = time(0);
for (x = 0; alarm_table[x].fn; ++x)
if (alarm_table[x].freq
&& ((now - alarm_table[x].last_time) >= alarm_table[x].freq))
{
alarm_table[x].last_time = now;
alarm_table[x].fn ();
}
}


#ifdef __STDC__
static void
select_hooks (void)
#else
static void
select_hooks ()
#endif
{
int x;
for (x = 0; x < SELECT_SET_SIZE; ++x)
{
if (file_read_hooks[x].hook_fn && FD_ISSET (x, &read_pending_fd_set))
file_read_hooks[x].hook_fn (x);
FD_CLR (x, &read_pending_fd_set);
if (file_write_hooks[x].hook_fn && FD_ISSET (x, &write_pending_fd_set))
file_write_hooks[x].hook_fn (x);
FD_CLR (x, &write_pending_fd_set);
if (file_exception_hooks[x].hook_fn
&& FD_ISSET (x, &exception_pending_fd_set))
file_exception_hooks[x].hook_fn (x);
FD_CLR (x, &exception_pending_fd_set);
}
}

/* Block until we get a signal (unless system calls restart),
* can do i/o or, until we timeout (timeout is specified in seconds,
* 0 means block indefinately). (Front end to select)
*/
#ifdef __STDC__
static void
block_until_excitment (int timeout_seconds)
#else
static void
block_until_excitment (timeout_seconds)
int timeout_seconds;
#endif
{
int ret;
struct timeval timeout;
struct timeval * time_p = 0;

if (timeout_seconds)
{
timeout.tv_sec = timeout_seconds;
timeout.tv_usec = 0;
time_p = &timeout;
}
bcopy ((char *)&read_fd_set, (char *)&read_pending_fd_set,
sizeof (SELECT_TYPE)) ;
bcopy ((char *)&exception_fd_set,
(char *)&exception_pending_fd_set, sizeof (SELECT_TYPE));
bcopy ((char *)&write_fd_set,
(char *)&write_pending_fd_set, sizeof (SELECT_TYPE));
ret = select (SELECT_SET_SIZE,
&read_pending_fd_set, &write_pending_fd_set,
&exception_pending_fd_set, time_p);
if (ret < 0)
{
FD_ZERO (&read_pending_fd_set);
FD_ZERO (&write_pending_fd_set);
FD_ZERO (&exception_pending_fd_set);
}
}

/* This is the main interact loop. As quickly as possible
* it returns a character from the keyboard. While waiting,
* it updates cells and the display. If a macro is being defined,
* this function save characters in the macro.
*/

#ifdef __STDC__
int
real_get_chr (void)
#else
int
real_get_chr ()
#endif
{
int ch; /* The char that will be returned. */

/* Characters with the meta bit set are returned as
* two characters: ESC and a non-meta character.
* This buffers the non-meta character between calls.
* The value is 0 if no character is buffered, C+1 if
* C is buffered.
*/
static int saved_char;

/* A buffer of characters read in one burst from the kbd. */
static char ibuf[256];
static int i_in; /* chars buffered */
static int i_cnt; /* buffer position */

alarm_hooks ();
if (saved_char)
{
ch = saved_char - 1;
saved_char = 0;
goto fini;
}

if (i_cnt)
{
ch = ibuf[i_cnt++];
if (i_cnt == i_in)
i_cnt = i_in = 0;
goto fini;
}

/* This loop until a character can be read. */
while (!io_input_avail ())
{
alarm_hooks ();
select_hooks ();
io_scan_for_input (0);
if (!io_input_avail ())
{
++current_cycle;
if (auto_recalc && eval_next_cell ())
{
if (bkgrnd_recalc)
while (!io_input_avail () && eval_next_cell ())
io_scan_for_input (0);
else
while (eval_next_cell ())
;
io_scan_for_input (0);
if (!io_input_avail ())
io_redisp ();
io_flush ();
io_scan_for_input (0);
}
else
{
int timeout = (alarm_active
? (alarm_seconds == 1
? 1
: (alarm_seconds / 2))
: 0);

--current_cycle;
io_redisp ();
io_flush ();
io_scan_for_input (0);
if (!io_input_avail ())
block_until_excitment (timeout);
}
}
}

{
int ret;
ret = io_read_kbd (ibuf, sizeof (ibuf));
if (ret == 1)
{
ch = ibuf[0];
goto fini;
}
if (ret > 1)
{
i_cnt = 1;
i_in = ret;
ch = ibuf[0];
goto fini;
}
if (ret == 0 || errno != EINTR)
return EOF;
}

fini:

if (ch & 0x80)
{
saved_char = 1 + (ch & 0x7f);
ch = CTRL ('[');
}

if (making_macro)
{
/* This is stoopid and should be fixed.
* Macros (and other cell strings) should be
* `struct line' and not c-strings. -tl
*/
if (ch == 0)
*making_macro++ = 0x80 | 'a';
else if (ch == '{')
*making_macro++ = 0x80 | 'b';
else
*making_macro++ = ch;
if (making_macro >= (making_macro_start + making_macro_size))
{
making_macro_start = ck_realloc (making_macro_start, 5
+ making_macro_size * 2);
making_macro = (making_macro_start + making_macro_size);
making_macro_size *= 2;
}
}
return ch;
}




/*****************************************************************
*
* Command loops
*
* The basic cycle is that the user or a macro selects a function
* (while oleo updates the display and evaluates cells).
* A new command_frame is allocated in which to evaluate the selected
* function. Arguments to the function will be stored in this frame.
* The command loop interprets the FUNC_ARGS string of the selected function
* and builds an argument list. If the FUNC_ARGS string specifies that
* the user must be prompted for an argument, an editting mode is entered
* and the command loop restarts. The queue of command_frames form
* a stack of recursively invoked editting modes.
*
* When all of the arguments are ready, the command loop executes
* the function and discards its frame.
*
* In principle, any number of command_frames can be created and they
* could be evaluated in any order. It is assumed in the code though that
* the frame the_cmd_frame->prev is the frame the user was in when
* the_cmd_frame was created (call it the `parent' frame). Some arguments,
* for example the prefix argument and the current row/col, are taken from the
* parent frame. This is because those values may have changed in
* the_cmd_frame as the user editted arguments to the function being called.
*/

/* The active command frame. This is the head of a queue which is used as a
* stack.
*/
struct command_frame * the_cmd_frame = 0;

/* This is a list (next field) of frames that are currently running (their
* commands are active on the c stack below the error_exception jump buffer).
*/
struct command_frame * running_frames = 0;


/* This is called when the current frame has keymapped
* down to some function (stored in the_cmd_frame->_cur_cmd.
* This pushes a new frame in which the arguments to that
* command will be stored.
*
* This can also be called when the_cmd_frame is 0. In that case,
* it will create a top-level frame.
*
*/

#ifdef __STDC__
void
push_command_frame (struct rng * rng, char * first_line, int len)
#else
void
push_command_frame (rng, first_line, len)
struct rng * rng;
struct line * first_line;
int len;
#endif
{
struct command_frame * new_cf =
(struct command_frame *)ck_malloc (sizeof (*new_cf));

new_cf->next = new_cf;
new_cf->prev = new_cf;

new_cf->input = (rng
? macro_only_input_stream (rng, first_line, len, new_cf)
: default_input_stream ());

new_cf->_setrow = NON_ROW;
new_cf->_setcol = NON_COL;
new_cf->_curow = MIN_ROW;
new_cf->_cucol = MIN_COL;
new_cf->_mkrow = NON_ROW;
new_cf->_mkcol = NON_COL;
new_cf->_input_active = 0;
new_cf->_window_after_input = -1;

/* These may be reset later. */
new_cf->top_keymap = map_id ("main");
if (new_cf->top_keymap < 0)
new_cf->top_keymap = map_id ("universal");
new_cf->saved_cur_keymap = -1;
new_cf->_cur_keymap = map_id ("main");
new_cf->_how_many = 1;
new_cf->_cur_cmd = 0;
new_cf->_cur_vector = 0;
new_cf->_cur_chr = the_cmd_frame ? cur_chr : 0;

init_line (&new_cf->_raw_prefix);
new_cf->_cmd_argc = 0;
new_cf->complex_to_user = 0;

if (!the_cmd_frame)
{
/* This is a new top-level frame. */
the_cmd_frame = new_cf;
new_cf->cmd = 0;
new_cf->top_keymap = map_id ("main");
if (new_cf->top_keymap < 0)
new_cf->top_keymap = map_id ("universal");
}
else if (cur_cmd)
{
new_cf->_cur_arg = 0;
new_cf->cmd = cur_cmd;
{
int argc = 0;
char ** prompt = new_cf->cmd->func_args;
while (prompt && *prompt)
{
new_cf->argv[argc].do_prompt = 0;
new_cf->argv[argc].is_set = 0;
new_cf->argv[argc].style = 0;
new_cf->argv[argc].arg_desc = *prompt;
new_cf->argv[argc].prompt = 0;
new_cf->argv[argc].expanded_prompt = 0;
new_cf->argv[argc].prompt_info = 0;
new_cf->argv[argc].info_line = 0;
init_line (&new_cf->argv[argc].text);
set_line (&new_cf->argv[argc].text, "");
new_cf->argv[argc].cursor = 0;
new_cf->argv[argc].overwrite = 0;
new_cf->argv[argc].inc_cmd = 0;
new_cf->argv[argc].timeout_seconds = 0;
bzero (&new_cf->argv[argc].val, sizeof (union command_arg_val));
++argc;
++prompt;
}
if (argc && new_cf->argv[0].arg_desc[0] == '+')
++new_cf->argv[0].arg_desc;
new_cf->_cmd_argc = argc;
new_cf->_curow = curow;
new_cf->_cucol = cucol;
new_cf->_mkrow = mkrow;
new_cf->_mkcol = mkcol;
new_cf->_setrow = setrow;
new_cf->_setcol = setcol;
if (!rng)
new_cf->input = the_cmd_frame->input;
}
}

new_cf->prev = the_cmd_frame;
new_cf->next = the_cmd_frame->next;
new_cf->prev->next = new_cf;
new_cf->next->prev = new_cf;
the_cmd_frame = new_cf;
}

/* Remove a frame from the queue/stack. */
#ifdef __STDC__
void
remove_cmd_frame (struct command_frame * frame)
#else
void
remove_cmd_frame (frame)
struct command_frame * frame;
#endif
{
frame->next->prev = frame->prev;
frame->prev->next = frame->next;
if (the_cmd_frame == frame)
the_cmd_frame = frame->prev;
if (the_cmd_frame == frame)
{
the_cmd_frame = 0;
push_command_frame (0, 0, 0);
}
frame->next = frame->prev = 0;
}


/* This frees all of the memory allocated to FRAME (including
* the frame itself.
*/
#ifdef __STDC__
void
free_cmd_frame (struct command_frame * frame)
#else
void
free_cmd_frame (frame)
struct command_frame * frame;
#endif
{
if (frame->next)
remove_cmd_frame (frame);

free_line (&frame->_raw_prefix);
if (frame->cmd)
{
int argc;
for (argc = 0; argc < frame->_cmd_argc; ++argc)
{
if (frame->argv[argc].is_set && frame->argv[argc].style->destroy)
frame->argv[argc].style->destroy (&frame->argv[argc]);
free_line (&frame->argv[argc].text);
if (frame->argv[argc].expanded_prompt &&
(frame->argv[argc].expanded_prompt != frame->argv[argc].prompt))
free (frame->argv[argc].expanded_prompt);
}
}
ck_free (frame);
}


/* Discard the current frame if it contains an unexecuted commnand.
* This is used, for example, to handle break.
*/
#ifdef __STDC__
void
pop_unfinished_command (void)
#else
void
pop_unfinished_command ()
#endif
{
if (the_cmd_frame->cmd)
{
int move_cursor = 0;
struct command_frame * frame = the_cmd_frame;
if ( frame->_curow != frame->prev->_curow
|| frame->_cucol != frame->prev->_cucol)
{
io_hide_cell_cursor ();
move_cursor = 1;
}
remove_cmd_frame (frame);
if (move_cursor)
io_display_cell_cursor ();
free_cmd_frame (frame);
}
}

/* This is called if an error has been signaled with io_error_msg.
* It discards any frames that the user has never interacted with
* and cancels all pending macros. This is properly followed by
* generating an error message for the user and longjmp to error_exception.
*/

#ifdef __STDC__
void
recover_from_error (void)
#else
void
recover_from_error ()
#endif
{
/* pop input streams until the bottom is reached. */
while (the_cmd_frame->input->prev_stream)
pop_input_stream ();

/* cancel the current macros */
{
struct input_stream * stream = the_cmd_frame->input;
if (stream->_macro_start)
free (stream->_macro_start);
if (stream->_last_macro)
free (stream->_last_macro);
obstack_free (&stream->_macro_stack, 0);
obstack_init (&stream->_macro_stack);
stream->_rmac = 0;
stream->_func_arg = 0;
stream->_macro = stream->_macro_start = 0;
stream->_macro_size = 0;
stream->_pushed_back_char = -1;
}

/* pop command frames until an interactive one is reached. */
while (the_cmd_frame->prev != the_cmd_frame
&& !the_cmd_frame->complex_to_user)
{
struct command_frame * fr = the_cmd_frame;
the_cmd_frame = the_cmd_frame->prev;
free_cmd_frame (fr);
}

/* Discard any frames that were executing */
while (running_frames)
{
struct command_frame * f = running_frames;
running_frames = running_frames->next;
f->next = 0;
free_cmd_frame (f);
}
}



/* When we begin editting a new argument, this function sets up the
* appropriate keymap, and then resets the state of the editting commands.
*
* The return value is 1 if the user must be prompted, 0 otherwise.
*/
#ifdef __STDC__
static int
get_argument (char * prompt, struct prompt_style * style)
#else
static int
get_argument (prompt, style)
char * prompt;
struct prompt_style * style;
#endif
{
the_cmd_arg.style = style;
the_cmd_arg.prompt = prompt;
if (!the_cmd_arg.expanded_prompt)
the_cmd_arg.expanded_prompt = expand_prompt (prompt);
the_cmd_frame->top_keymap = map_id (the_cmd_arg.style->keymap);
the_cmd_arg.is_set = 0;
the_cmd_arg.do_prompt = 1;
if (the_cmd_frame->top_keymap < 0)
the_cmd_frame->top_keymap = map_id ("universal");
if (macro_func_arg)
{
set_line (&the_cmd_arg.text, macro_func_arg);
{
char * arg_ptr;
char * error;
arg_ptr = the_cmd_arg.text.buf;
error = the_cmd_arg.style->verify (&arg_ptr, &the_cmd_arg);
if (error)
{
macro_func_arg = 0;
io_error_msg ("%s", error);
}
else
{
the_cmd_arg.is_set = 1;
if (arg_ptr)
while (isspace (*arg_ptr))
++arg_ptr;
if (arg_ptr && *arg_ptr)
macro_func_arg = arg_ptr;
else
macro_func_arg = 0;
return 0;
}
}
}
input_active = 1;
begin_edit ();

/* Functions can come with macros that initialize arguments for the user.
* As for the call to expand_prompt -- hehehehehe
*/
if (the_cmd_frame->cmd->init_code && the_cmd_frame->cmd->init_code[cur_arg])
{
char * init_code = expand_prompt(the_cmd_frame->cmd->init_code[cur_arg]);
struct rng rng;
rng.lr = rng.hr = rng.lc = rng.hc = 1;
macro_only_input_stream (&rng, init_code, strlen (init_code),
the_cmd_frame);
command_loop (1);
}

return 1;
}

#ifdef __STDC__
void
exit_minibuffer (void)
#else
void
exit_minibuffer ()
#endif
{
if (check_editting_mode ())
return;
else
{
char * extra = the_cmd_arg.text.buf;
char * error = the_cmd_arg.style->verify (&extra, &the_cmd_arg);
if (error)
{
if (*error)
io_error_msg ("%s", error);
}
else
{
if (extra)
{
while (isspace (*extra))
++extra;
if (*extra)
io_error_msg ("%s: extra characters in argument (%s)",
the_cmd_frame->cmd->func_name, extra);
}
the_cmd_arg.is_set = 1;
input_active = 0;
window_after_input = -1;
topclear = 2;
}
}
}




#ifdef __STDC__
void
setn_arg_text (struct command_arg * arg, char * text, int len)
#else
void
setn_arg_text (arg, text, len)
struct command_arg * arg;
char * text;
int len;
#endif
{
setn_line (&arg->text, text, len);
arg->cursor = len;
}

#ifdef __STDC__
void
init_arg_text (struct command_arg * arg, char * text)
#else
void
init_arg_text (arg, text)
struct command_arg * arg;
char * text;
#endif
{
setn_arg_text (arg, text, strlen (text));
}

/* This apparently useless alias is here because
* sometime in the future i want to handle defaults
* differently.
*/

#ifdef __STDC__
void
set_default_arg (struct command_arg * arg, char * text, int len)
#else
void
set_default_arg (arg, text, len)
struct command_arg * arg;
char * text;
int len;
#endif
{
setn_arg_text (arg, text, len);
}

/* This is the main loop of oleo. It reads commands and their arguments, and
* evaluates them. It (via real_get_chr) udpates the display and performs
* background recomputation.
*
* This function can also be used to evaluate a function without doing any
* interaction. This is done by pushing a macro_only command frame
* (see execute_command).
*/

#ifdef __STDC__
void
command_loop (int prefix)
#else
void
command_loop (prefix)
int prefix;
#endif
{

/* We might be re-entering after a longjmp caused by an error.
* In that case, we use an alternate entry point:
*/
if (the_cmd_frame->cmd)
goto resume_getting_arguments;

/* Commands (notably execute_command) just tweek the command_frame
* state for some other command. To accomplish this, there is an
* entry point that avoid reinitializing the command_frame.\
*/
if (prefix)
{
prefix = 0;
goto prefix_cmd_continuation;
}

while (1)
{
int ch; /* The next character to be keymapped. */

new_cycle:

if (!the_cmd_frame)
push_command_frame (0, 0, 0);

/* Reset the prefix argument. */

how_many = 1;
set_line (&raw_prefix, "");
io_update_status ();

/* Reset the keystate. */
cur_keymap = the_cmd_frame->top_keymap;

/* If the input area holds a prompt from the last command,
* erase it.
*/
io_clear_input_before ();


/* Some commands are prefix commands: they effect the
* user's state without beginnging a new command cyle.
* Those commands return here:
*/

prefix_cmd_continuation:

/* In this loop, we look for the next command to
* execute. This may involve reading from a macro,
* or the keyboard. If there is time to kill, updates
* and evalutations are done.
*
* This loop is exited by `goto got_command'.
*/

while (1)
{
/* Get the next character.
* However, if we are in a macro, and the next character
* is '{', then the macro contains a function name
* and keymapping is circumvented.
*/

get_next_char:

if (pushed_back_char >= 0)
{
ch = pushed_back_char;
pushed_back_char = -1;
}
else if (!rmac)
{
io_fix_input ();
ch = real_get_chr ();
}
else
{
int len;
unsigned char *ptr;

tryagain:
alarm_hooks ();
ch = *(rmac->mac_exe++);
switch (ch)
{
case '\0':
cur_vector = 0;
cur_cmd = end_macro_cmd;
cur_chr = 0;
goto got_command;

case 0x80 | 'a':
ch = '\0';
break;

case 0x80 | 'b':
ch = '{';
break;
case 0x80 | 'c':
ch = '}';
break;

case '{':
for (ptr = rmac->mac_exe;
*ptr && *ptr != ' ' && *ptr != '}';
ptr++);
len = ptr - rmac->mac_exe;
for (cur_vector = 0;
cur_vector < num_funcs;
cur_vector++)
for (cur_cmd =
&the_funcs[cur_vector][0];
cur_cmd->func_name;
cur_cmd++)
if (!strincmp ((char *) (rmac->mac_exe),
cur_cmd->func_name, len)
&& cur_cmd->func_name[len] == '\0')
{
cur_chr = '\0';
goto out;
}
io_error_msg ("Ignoring unknown function '%.*s' in macro",
len, rmac->mac_exe);
while (*ptr != '\0' && *ptr != '}')
ptr++;
if (*ptr == '}')
ptr++;
rmac->mac_exe = ptr;
goto tryagain;

out:
if (*ptr == ' ')
{
/* ... add argument support here ... */
if (!cur_cmd->func_args)
{
io_error_msg ("Ignoring extra operand to %s",
cur_cmd->func_name);
while (*ptr && *ptr != '}')
ptr++;
if (*ptr == '}')
ptr++;
}
else if (cur_cmd->func_args[0][0] == '+')
{
unsigned char * start = ptr;
how_many = astol ((char **) (&ptr));
setn_line (&raw_prefix, (char *)start,
ptr - start);
if (*ptr == '}')
ptr++;
}
else
{
while (isspace(*ptr))
++ptr;
macro_func_arg = (char *) ptr;
while (*ptr && *ptr != '}')
{
switch (*ptr)
{
case 0x80 | 'b':
*ptr = '{';
break;
case 0x80 | 'c':
*ptr = '}';
break;
}
ptr++;
}
if (*ptr == '}')
*ptr++ = '\0';
}
rmac->mac_exe = ptr;
}
else
rmac->mac_exe += len + 1;
goto got_command;
}
}

/* When control comes here, adjust the keystate according
* to the cur_keymap and `ch';
*/
have_character:

/* This is how keymaps are searched for a binding. */
while (1)
{
struct key * key;
key = &(the_maps[cur_keymap]->keys[ch]);
if (key->vector < 0)
{
if (key->code >= 0)
{
cur_keymap = key->code;
goto get_next_char;
}
else if (the_maps[cur_keymap]->map_next)
cur_keymap =
the_maps[cur_keymap]->map_next->id;
else
{
cur_vector = 0;
cur_cmd = 0;
cur_chr = ch;
goto got_command;
}
}
else
{
cur_vector = key->vector;
cur_cmd =
&(the_funcs[key->vector][key->code]);
cur_chr = ch;
goto got_command;
}
}
}


/* Now the next command to begin has been read from a macro
* or the keyboard.
*/
got_command:

/* If there is anything left in the input area (e.g. old error message)
* get rid of it (but only if we're not executing a macro).
*/
if (!rmac)
io_clear_input_after ();

/* There are some commands that are implemented right here. */
if (cur_cmd == break_cmd)
{
io_bell ();
set_info (0);
if (input_active)
pop_unfinished_command (); /* Abort a complex command.*/
goto new_cycle;
}

/* The binding of all keys associated with the prefix arg. */
if (cur_cmd == universal_arg_cmd)
{
char ch = cur_chr;
int prefix_map = map_id ("prefix");
/* Make sure the prefix-arg keymap is in place. */
if (cur_keymap != prefix_map)
{
the_cmd_frame->saved_cur_keymap = the_cmd_frame->top_keymap;
cur_keymap = prefix_map;
}
/* Store the last character typed in the raw-prefix.*/
catn_line (&raw_prefix, &ch, 1);
/* Recompute the numeric value of the prefix. */
{
int x = 0;
int presumed_digits = 0;
int sign = 1;

how_many = 1;
while (raw_prefix.buf[x])
{
if (isdigit (raw_prefix.buf[x]))
{
if (presumed_digits)
how_many = how_many * 10 + (raw_prefix.buf[x] - '0');
else
{
presumed_digits = 1;
how_many = raw_prefix.buf[x] - '0';
}
}
else if (raw_prefix.buf[x] == '-')
sign *= -1;
else
{
if (presumed_digits)
{
presumed_digits = 0;
how_many = 1;
}
how_many *= 4;
}
++x;
}
how_many *= sign;
io_update_status ();
goto prefix_cmd_continuation;
}
}

/* Make sure we really mapped to a command. */
if (!cur_cmd || !cur_cmd->func_func)
{
/* If a character is unmapped in the prefix map,
* retry mapping in the last-used normal keymap.
*/
if (the_cmd_frame->saved_cur_keymap >= 0)
{
cur_keymap = the_cmd_frame->saved_cur_keymap;
the_cmd_frame->saved_cur_keymap = -1;
goto have_character;
}
/* Otherwise, signal an error and start from the top keymap. */
io_bell ();
goto new_cycle;
}



/* The next step is to gather the arguments with which to call
* the function interactively.
*/
/* Whever a new command is encountered, we begin by creating a
* frame in which to store it's arguments.
* This initializes the new frame on the basis of cur_cmd in
* the_cmd_frame.
*/
push_command_frame (0, 0, 0);

/* After some other command finishes from underneath a complex command,
* flow returns here.
*/

resume_getting_arguments:

while (cur_arg < cmd_argc)
{
if (the_cmd_arg.is_set)
goto next_arg;
else if (the_cmd_arg.prompt)
{
begin_edit ();
goto new_cycle;
}
else
{
/* If we're just starting on this argument, then parse the
* FUNC_ARGS string. To continue this loop, use `goto next_arg;'.
*
* If user interaction is required, the appropriate keymap,
* editting area, etc. is set up, and the command loop resumes
* (`goto new_cycle').
*/
char * prompt = the_cmd_arg.arg_desc;

switch (*prompt)
{
case 'c':
{
++prompt;
if (*prompt == '#')
{
++prompt;
the_cmd_arg.val.integer = *prompt;
the_cmd_arg.is_set = 1;
the_cmd_arg.do_prompt = 0;
the_cmd_arg.style = &int_constant_style;
{
char c[2];
c[0] = cur_chr;
c[1] = '\0';
init_arg_text (&the_cmd_arg, c);
}
goto next_arg;
}
else if (*prompt == '\'')
{
the_cmd_arg.timeout_seconds = 30;
alarm_table[1].freq = 1;
++prompt;
}
if (get_argument (prompt, &char_style))
goto new_cycle;
goto next_arg;
}
case 'C':
{
++prompt;
if (get_argument (prompt, &command_style))
goto new_cycle;
goto next_arg;
}
case 'd':
{
++prompt;
if (get_argument (prompt, &double_style))
goto new_cycle;
goto next_arg;
}
case 'f':
{
char type;
struct prompt_style * style;
++prompt;
type = *prompt;
++prompt;
switch (type)
{
case 'r':
style = &read_file_style;
break;
case 'w':
style = &write_file_style;
break;
case 'n':
style = &file_name_style;
break;
default:
style = 0; /* shutup gcc -ansi -pendantic -Wall! */
io_error_msg ("func_args bug for %s",
the_cmd_frame->cmd->func_name);
}
if (get_argument (prompt, style))
goto new_cycle;
goto next_arg;
}
case 'F':
{
++prompt;
if (get_argument (prompt, &format_style))
goto new_cycle;
goto next_arg;
}
case 'k':
{
++prompt;
the_cmd_arg.val.key.cmd.vector = -1;
the_cmd_arg.val.key.cmd.code
= the_cmd_frame->prev->top_keymap;
the_cmd_arg.val.key.keys = &the_cmd_arg.text;
if (get_argument (prompt, &keyseq_style))
goto new_cycle;
goto next_arg;
}
case 'K':
{
++prompt;
if (get_argument (prompt, &keymap_style))
goto new_cycle;
goto next_arg;
}
case 'l':
{
the_cmd_arg.val.integer = cur_chr;
the_cmd_arg.is_set = 1;
the_cmd_arg.do_prompt = 0;
the_cmd_arg.style = &int_constant_style;
{
char c[2];
c[0] = cur_chr;
c[1] = '\0';
init_arg_text (&the_cmd_arg, c);
}
goto next_arg;
}
case 'm':
{
int want_keyseq = 0;
++prompt;
want_keyseq = (*prompt == '\'');
if (want_keyseq)
{
char * map;
++prompt;
map = expand_prompt (prompt);
the_cmd_arg.val.key.cmd.vector = -1;
the_cmd_arg.val.key.cmd.code = map_id (map);
the_cmd_arg.val.key.keys = &the_cmd_arg.text;
}
else
{
if (mode_style.keymap)
ck_free (mode_style.keymap);
mode_style.keymap = expand_prompt (prompt);
}
if (get_argument (prompt, (want_keyseq
? &keyseq_style
: &mode_style)))
goto new_cycle;
goto next_arg;
}
case 'M':
if (modified)
{
++prompt;
if (get_argument (prompt, &yes_style))
goto new_cycle;
goto next_arg;
}
else
{
the_cmd_arg.is_set = 1;
the_cmd_arg.do_prompt = 1;
the_cmd_arg.style = &yes_style;
init_arg_text (&the_cmd_arg, "yes");
goto next_arg;
}
case 'p':
{
++prompt;
switch (*prompt)
{
default:
the_cmd_arg.val.integer
= the_cmd_frame->prev->_how_many;
the_cmd_arg.is_set = 1;
the_cmd_arg.do_prompt = 0;
the_cmd_arg.style = &int_constant_style;
init_arg_text
(&the_cmd_arg,
long_to_str ((long)the_cmd_arg.val.integer));
break;

case '?': /* Command wants to know if prefix provided */
the_cmd_arg.val.integer =
(the_cmd_frame->prev->_raw_prefix.alloc
&& the_cmd_frame->prev->_raw_prefix.buf[0]);
the_cmd_arg.is_set = 1;
the_cmd_arg.do_prompt = 0;
the_cmd_arg.style = &int_constant_style;
init_arg_text (&the_cmd_arg,
the_cmd_arg.val.integer ? "1" : "0");
break;
}
goto next_arg;
}
case 'N':
case 'n':
{
long low = 0;
long high = -1;
char type = *prompt;
++prompt;
if (*prompt == '[')
{
++prompt;
low = astol (&prompt);
while (isspace (*prompt)) ++prompt;
if (*prompt == ',') ++prompt;
high = astol (&prompt);
while (isspace (*prompt)) ++prompt;
if (*prompt == ']') ++prompt;
}
if ( (type == 'N')
&& the_cmd_frame->prev->_raw_prefix.alloc
&& the_cmd_frame->prev->_raw_prefix.buf[0])
{
the_cmd_arg.val.integer
= the_cmd_frame->prev->_how_many;
the_cmd_arg.is_set = 1;
the_cmd_arg.do_prompt = 1;
the_cmd_arg.style = &number_style;
if ( (low >= high)
&& ( (low > the_cmd_arg.val.integer)
|| (high < the_cmd_arg.val.integer)))
io_error_msg
("Out of range %d (should be in [%d-%d]).");
else
init_arg_text
(&the_cmd_arg,
long_to_str ((long)the_cmd_arg.val.integer));
}
else
{
if (get_argument (prompt, &number_style))
goto new_cycle;
}
goto next_arg;
}
case 'r':
case 'R':
{
if (*prompt != 'R' && mkrow != NON_ROW)
{
the_cmd_arg.val.range.lr = MIN(mkrow, curow);
the_cmd_arg.val.range.hr = MAX(mkrow, curow);
the_cmd_arg.val.range.lc = MIN(mkcol, cucol);
the_cmd_arg.val.range.hc = MAX(mkcol, cucol);
the_cmd_arg.is_set = 1;
the_cmd_arg.do_prompt = 1;
the_cmd_arg.style = &range_style;
mkrow = NON_ROW;
mkcol = NON_COL;
init_arg_text (&the_cmd_arg,
range_name (&the_cmd_arg.val.range));
goto next_arg;
}
else
{
++prompt;
if (get_argument (prompt, &range_style))
goto new_cycle;
goto next_arg;
}
}
case 's':
{
{
++prompt;
if (get_argument (prompt, &string_style))
goto new_cycle;
goto next_arg;
}
}
case 'S':
{
{
++prompt;
if (*prompt == '\'')
++prompt;
if (get_argument (prompt, &symbol_style))
goto new_cycle;
goto next_arg;
}
}
case 'V':
{
++prompt;
the_cmd_arg.inc_cmd = io_shift_cell_cursor;
if (get_argument (prompt, &inc_cmd_style))
goto new_cycle;
goto next_arg;
}
case 'w':
{
{
++prompt;
if (*prompt == '\'')
++prompt;
if (get_argument (prompt, &word_style))
goto new_cycle;
goto next_arg;
}
}
case '#':
{
++prompt;

init_arg_text (&the_cmd_arg, prompt);
the_cmd_arg.val.integer = astol(&prompt);
the_cmd_arg.is_set = 1;
the_cmd_arg.do_prompt = 0;
the_cmd_arg.style = &int_constant_style;
goto next_arg;
}
case '=':
{
++prompt;
the_cmd_arg.expanded_prompt = expand_prompt(prompt);
init_arg_text (&the_cmd_arg, the_cmd_arg.expanded_prompt);
the_cmd_arg.val.string = the_cmd_arg.expanded_prompt;
the_cmd_arg.is_set = 1;
the_cmd_arg.do_prompt = 0;
the_cmd_arg.style = &string_style;
goto next_arg;
}
case '.':
{
++prompt;
the_cmd_arg.val.range.lr = curow;
the_cmd_arg.val.range.lc = cucol;
if (*prompt == '\'')
{
the_cmd_arg.val.range.hr = curow;
the_cmd_arg.val.range.hc = cucol;
}
else
{
the_cmd_arg.val.range.hr = mkrow;
the_cmd_arg.val.range.hc = mkcol;
}
the_cmd_arg.is_set = 1;
the_cmd_arg.do_prompt = 0;
init_arg_text (&the_cmd_arg,
range_name (&the_cmd_arg.val.range));
the_cmd_arg.style = &range_constant_style;
goto next_arg;
}
case '[':
{
++prompt;
while (*prompt && (*prompt != ']'))
if (*prompt != '\\')
++prompt;
else
{
++prompt;
if (*prompt)
++prompt;
}
if (*prompt == ']')
++prompt;

if (get_argument (prompt, &menu_style))
goto new_cycle;
goto next_arg;
}
case '$':
{
/* Edit a cell's formula. */
CELL * cp = find_cell (curow, cucol);
++prompt;
if (((!cp || GET_LCK (cp) == LCK_DEF)
&& (default_lock == LCK_LCK))
|| (cp && GET_LCK (cp) == LCK_LCK))
{
io_error_msg ("Cell %s is locked",
cell_name (curow, cucol));
pop_unfinished_command ();
goto new_cycle;
}
the_cmd_frame->prev->_setrow = curow;
the_cmd_frame->prev->_setcol = cucol;
if (get_argument (prompt, &formula_style))
{
init_arg_text (&the_cmd_arg,
decomp (curow, cucol, cp));
decomp_free ();
goto new_cycle;
}
goto next_arg;
}

default:
{
io_error_msg ("Interaction-string error!!!");
pop_unfinished_command ();
goto new_cycle;
}
}
}
next_arg:
++cur_arg;
}

/* Make sure that all the args are really there. */
for (cur_arg = 0; cur_arg < cmd_argc; ++cur_arg)
if (the_cmd_arg.do_prompt && !the_cmd_arg.is_set)
goto resume_getting_arguments;

/* If this point is reached, call the interactive function,
* destroy it's frame, and restart the cycle.
*/
{
int move_cursor = 0;
struct command_frame * frame = the_cmd_frame;
cmd_invoker stub = find_stub ();
if ( frame->_curow != frame->prev->_curow
|| frame->_cucol != frame->prev->_cucol)
{
move_cursor = 1;
io_hide_cell_cursor ();
}
remove_cmd_frame (frame);
/* Add frame to the list of frames to be freed on error. */
frame->next = running_frames;
running_frames = frame;
if (move_cursor)
io_display_cell_cursor ();
if (!stub)
io_error_msg ("Don't know how to invoke %s!!!",
frame->cmd->func_name);
else
stub (frame);
running_frames = running_frames->next;
frame->next = 0;
free_cmd_frame (frame);

/* If command_loop was called by execute_command, it should
* return as soon as there is no more macro to evaluate.
*/
if (!rmac && the_cmd_frame->input->prev_stream)
{
pop_input_stream ();
return;
}
if (the_cmd_frame->cmd)
goto resume_getting_arguments;
}
}
}

/* Exectute the command called in `string'.
* If the string begins with a proper command name,
* it is executed as if it were embedded in "{}" in
* a macro. Otherwise, if the string can be interpreted
* as a range address, the macro at that address is executed.
*/

static struct line exec_cmd_line = {0, 0};

#ifdef __STDC__
void
execute_as_macro (char * str)
#else
void
execute_as_macro (str)
char * str;
#endif
{
struct rng fake_rng;
fake_rng.lr = fake_rng.lc = fake_rng.hr = fake_rng.hc = 1;
macro_only_input_stream (&fake_rng, str, strlen (str), the_cmd_frame);
command_loop (1);
}


/* execute_command buils a macro expression of the from `{command args}'.
* This function quotes the braces in ARGS so that the macro reader knows
* they are literal rather than macro syntax.
*/
static void
quote_macro_args (args)
char * args;
{
while (*args)
{
switch (*args)
{
case '{':
*args = 0x80 | 'b';
break;
case '}':
*args = 0x80 | 'c';
break;
}
++args;
}
}

#ifdef __STDC__
void
execute_command (char *str, int count)
#else
void
execute_command (str, count)
char *str;
int count;
#endif
{
char *ptr = str;
char * run; /* The first string to execute. */
/* The address of the macro to execute. If the user typed a
* command name and not a range name, then this range will be
* set to a one cell region.
*/
struct rng rng;

/* Chop off the first word. */
while (isspace (*str))
++str;
if (!*str || *str == '#')
return;
for (ptr = str; *ptr && *ptr != ' '; ptr++);

if (*ptr)
*ptr++ = '\0';
else
ptr = 0;


/* First, look for a command name. */

{
int vector;
struct cmd_func * cmd;

if (!find_function (&vector, &cmd, str, strlen(str)))
{
if (ptr)
{
quote_macro_args (ptr);
sprint_line (&exec_cmd_line, "{%s %s}", str, ptr);
}
else
sprint_line (&exec_cmd_line, "{%s}", str);
run = exec_cmd_line.buf;
rng.lr = rng.hr = 1;
rng.lc = rng.hc = 1;
goto found_command;
}
}

{
/* Try for a range address. */
CELL *cp;
if (get_abs_rng (&str, &rng))
{
io_error_msg ("Unknown command %s", str);
return;
}
if (ptr)
{
io_error_msg ("Macros can't take arguments");
return;
}

cp = find_cell (rng.lr, rng.lc);
if (!cp
|| GET_TYP (cp) != TYP_STR
|| cp->cell_str[0] == '\0')
{
io_error_msg ("No macro found at %s.", range_name (&rng));
return;
}

run = cp->cell_str;
count = how_many;
how_many = 1;
set_line (&raw_prefix, "");
}

found_command:
while (count --)
{
macro_only_input_stream (&rng, run, strlen (run), the_cmd_frame);
command_loop (1);
}
}




/* Read a character. If we're in a macro, read from the macro. . . */
#ifdef __STDC__
int
get_chr (void)
#else
int
get_chr ()
#endif
{
int ch;

if (rmac)
{
ch = *(rmac->mac_exe++);
switch (ch)
{
case '{': /* What else can we do? */
case '\0':
--rmac->mac_exe;
break;

case (0x80 | 'a'):
ch = 0;
break;

case (0x80 | 'b'):
ch = '{';
break;
default:
break;
}
}
else
ch = real_get_chr ();
return ch;
}


/* This is an entirely magical function. All of it's work is done
* by the argument prompting system. All that remains to be done
* when this is called is to push back a character the user may have
* typed to cause the error message to go away.
*/

#ifdef __STDC__
void
display_error_msg (char * msg, int c)
#else
void
display_error_msg (msg, c)
char * msg;
int c;
#endif
{
if (c > 0)
pushed_back_char = c;
}

#ifdef __STDC__
void
io_error_msg (char *str,...)
#else
void
io_error_msg (str, va_alist)
char *str;
va_dcl
#endif
{
va_list foo;
char buf[1000];
char buf2[1000];

/* This is made robust against errors that occur before
* the io hooks have been initialized.
*/
if (display_opened)
io_bell ();

var_start (foo, str);
vsprintf (buf, str, foo);
sprintf (buf2, "display-error-msg %s", buf);
recover_from_error ();
if (display_opened)
execute_command (buf2, 1);
else
fprintf (stderr, "oleo: %s\n", buf);
longjmp (error_exception, 1);
}


#ifdef __STDC__
void
io_info_msg (char *str,...)
#else
void
io_info_msg (str, va_alist)
char *str;
va_dcl
#endif
{
va_list foo;
char buf[1000];
char buf2[1000];

var_start (foo, str);
vsprintf (buf, str, foo);
sprintf (buf2, "display-error-msg %s", buf);
execute_command (buf2, 1);
}




/* Expands a string that will be used to prompt for an argument.
* %n expands to the text of argument n (if defined -- ??? otherwise).
* %% expands to %
* %c expands to the name of the_cmd_frame->prev->_set{row,col}
* If no expansion is needed, the argument is returned. Otherwise,
* malloced memory is returned.
*/

#ifdef __STDC__
char *
expand_prompt (char * str)
#else
char *
expand_prompt (str)
char * str;
#endif
{
struct line expanded;
init_line (&expanded);
if (!str || !index (str, '%'))
return ck_savestr (str);
{
char * last_pos = str;
char * src_pos;

for (src_pos = index (str, '%'); src_pos; src_pos = index (src_pos, '%'))
{
catn_line (&expanded, last_pos, src_pos - last_pos);
++src_pos;
switch (*src_pos)
{
case '%':
catn_line (&expanded, src_pos, 1);
++src_pos;
break;
case 'c':
{
struct rng rng;
char * str;
rng.lr = rng.hr = the_cmd_frame->prev->_setrow;
rng.lc = rng.hc = the_cmd_frame->prev->_setcol;
str = range_name (&rng);
catn_line (&expanded, str, strlen(str));
++src_pos;
break;
}
case '.':
{
struct rng rng;
char * str;
rng.lr = rng.hr = the_cmd_frame->prev->_curow;
rng.lc = rng.hc = the_cmd_frame->prev->_cucol;
str = range_name (&rng);
catn_line (&expanded, str, strlen(str));
++src_pos;
break;
}
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
{
int argn = *src_pos - '0';
if ( (cmd_argc > argn)
&& the_cmd_frame->argv[argn].is_set
&& the_cmd_frame->argv[argn].text.buf)
catn_line (&expanded, the_cmd_frame->argv[argn].text.buf,
strlen (the_cmd_frame->argv[argn].text.buf));
else
catn_line (&expanded, "????", 4);
++src_pos;
break;
}
default:
catn_line (&expanded, "%", 1);
break;
}
last_pos = src_pos;
}
catn_line (&expanded, last_pos, strlen(last_pos));
}
return expanded.buf;
}




/* Info commands */

#ifdef __STDC__
void
set_info (char * name)
#else
void
set_info (name)
char * name;
#endif
{
struct info_buffer * ib = (name ? find_or_make_info (name) : 0);

if (the_cmd_frame->cmd && (the_cmd_arg.prompt_info != ib))
{
the_cmd_arg.info_line = 0;
the_cmd_arg.prompt_info = ib;
}
if (!ib && name && *name)
io_error_msg ("No information about %s.", name);
}


#ifdef __STDC__
void
page_info_backwards (int rep)
#else
void
page_info_backwards (rep)
int rep;
#endif
{
if (rep < 0)
page_info (-rep);
else if (the_cmd_frame->cmd && the_cmd_arg.prompt_info)
{
int vis_lines = (scr_lines - input_rows) / info_rows;
int next = the_cmd_arg.info_line - vis_lines * rep;
the_cmd_arg.info_line = ((next >= 0) ? next : 0);
}
else
io_error_msg ("No info to page.");
}

#undef MAX
#define MAX(A,B) (((A) >= (B)) ? (A) : (B))

#ifdef __STDC__
void
page_info (int rep)
#else
void
page_info (rep)
int rep;
#endif
{
if (rep < 0)
page_info_backwards (-rep);
else if (the_cmd_frame->cmd && the_cmd_arg.prompt_info)
{
int vis_lines = (scr_lines - input_rows) / info_rows;
int next = the_cmd_arg.info_line + vis_lines * rep;
the_cmd_arg.info_line =
((next >= the_cmd_arg.prompt_info->len)
? MAX(0, (the_cmd_arg.prompt_info->len - vis_lines))
: next);
}
else
io_error_msg ("No info to page.");
}

#ifdef __STDC__
void
view_info (char * name, int ignore)
#else
void
view_info (name, ignore)
char * name;
int ignore;
#endif
{}



/* The C part of this function is uninteresting. The interesting part
* is in defun.h.
*/

#ifdef __STDC__
void
with_keymap (char * mapname)
#else
void
with_keymap (mapname)
char * mapname;
#endif
{}

#ifdef __STDC__
void
one_cmd_with_keymap (char * mapname, struct key_sequence * keyseq)
#else
void
one_cmd_with_keymap (mapname, keyseq)
char * mapname;
struct key_sequence * keyseq;
#endif
{
if (keyseq->cmd.vector < 0 && keyseq->cmd.code < 0)
io_bell ();
else if (keyseq->cmd.vector < 0)
io_error_msg
("one-command-with-keymap: %s maps to a keymap (%s), not a command.",
keyseq->keys->buf, map_names[keyseq->cmd.code]);
else
execute_command
(the_funcs[keyseq->cmd.vector][keyseq->cmd.code].func_name, 1);
}
oleo-1.3/basic.c 644 722 0 107100 5356124713 11754 0ustar lordwheel/* Copyright (C) 1993 Free Software Foundation, Inc.

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, 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 software; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */


#include
#include "sysdef.h"
#include "global.h"
#include "basic.h"
#include "cmd.h"
#include "regions.h"
#include "window.h"
#include "io-term.h"
#include "io-generic.h"
#include "io-abstract.h"
#include "io-utils.h"
#include "io-curses.h"
#include "ref.h"
#include "format.h"
#include "lists.h"
#include "io-edit.h"
#include "eval.h"
#include "byte-compile.h"


/* Used by motion commands. */
const int colmagic[] = {0, 0, 1, -1, 1, -1, 1, -1, 0};
const int rowmagic[] = {-1, 1, 0, 0, -1, -1, 1, 1, 0};

char * motion_name[] =
{
"up",
"down",
"right",
"left",
"up right",
"up left",
"down right",
"down left",
"no motion"
};


/* This table ought to be a user parameter. */
enum motion_magic complementary_motion[] =
{
magic_right,
magic_right,
magic_down,
magic_down,
magic_right,
magic_right,
magic_right,
magic_right,
magic_no_motion,
};

enum motion_magic opposite_motion[] =
{
magic_down,
magic_up,
magic_left,
magic_right,
magic_down_left,
magic_down_right,
magic_up_left,
magic_up_right,
magic_no_motion,
};


/* Indexed by MAGIC + 1 */
const int boundrymagic[3] = { MIN_ROW, NON_ROW, MAX_ROW };




/* A very basic command. */

#ifdef __STDC__
void
noop (void)
#else
void
noop ()
#endif
{}



/* Commands that inser/delete rows/columns. */

#ifdef __STDC__
void
insert_row (int repeat)
#else
void
insert_row (repeat)
int repeat;
#endif
{
struct rng from;
struct rng to;
if ((repeat > (MAX_ROW - curow)) || (repeat < 0))
{
io_error_msg ("insert-row: prefix argument out of range.");
return;
}
from.lc = MIN_COL;
from.hc = MAX_COL;
from.lr = curow;
from.hr = MAX_ROW - repeat;
to.lc = MIN_COL;
to.hc = MIN_COL;
to.lr = curow + repeat;
to.hr = curow + repeat;
move_region (&from, &to);
}

#ifdef __STDC__
void
insert_col (int repeat)
#else
void
insert_col (repeat)
int repeat;
#endif
{
struct rng from;
struct rng to;
if ((repeat > (MAX_COL - cucol)) || (repeat < 0))
{
io_error_msg ("insert-col: prefix argument out of range.");
return;
}
from.lr = MIN_ROW;
from.hr = MAX_ROW;
from.lc = cucol;
from.hc = MAX_COL - repeat;
to.lr = MIN_ROW;
to.hr = MIN_ROW;
to.lc = cucol + repeat;
to.hc = cucol + repeat;
move_region (&from, &to);
}

#ifdef __STDC__
void
delete_row (int repeat)
#else
void
delete_row (repeat)
int repeat;
#endif
{
struct rng from;
struct rng to;
if ((repeat < 0) || (repeat > (MAX_ROW - curow + 1)))
{
io_error_msg ("delete-row: prefix argument out of range.");
return;
}
from.lc = MIN_COL;
from.hc = MAX_COL;
from.lr = curow + repeat;
from.hr = MAX_ROW;
to.lc = MIN_COL;
to.hc = MIN_COL;
to.lr = curow;
to.hr = curow;
move_region (&from, &to);
}

#ifdef __STDC__
void
delete_col (int repeat)
#else
void
delete_col (repeat)
int repeat;
#endif
{
struct rng from;
struct rng to;
if ((repeat < 0) || (repeat > (MAX_COL - cucol + 1)))
{
io_error_msg ("delete-col: prefix argument out of range.");
return;
}
from.lr = MIN_ROW;
from.hr = MAX_ROW;
from.lc = cucol + repeat;
from.hc = MAX_COL;
to.lr = MIN_ROW;
to.hr = MIN_ROW;
to.lc = cucol;
to.hc = cucol;
move_region (&from, &to);
}



/* Front end to the window functions. */

#ifdef __STDC__
void
open_window (char *text)
#else
void
open_window (text)
char *text;
#endif
{
int hv;
int where;

while (*text == ' ')
text++;

if (*text == 'h' || *text == 'H')
hv = 0;
else if (*text == 'v' || *text == 'V')
hv = 1;
else
{
io_error_msg ("Open 'h'orizontal or 'v'ertical window, not '%s'", text);
return;
}
where = atoi (text + 1);
while (isspace (*text))
++text;
while (isalnum (*text))
++text;
while (isspace (*text))
++text;
if (*text == '%')
{
where *= (hv
? (cwin->numr + (cwin->lh_wid ? label_rows : 0))
: (cwin->numc + cwin->lh_wid));
where /= 100;
}
io_win_open (hv, where);
}

#ifdef __STDC__
void
hsplit_window (void)
#else
void
hsplit_window ()
#endif
{
open_window ("h50%");
}


#ifdef __STDC__
void
vsplit_window (void)
#else
void
vsplit_window ()
#endif
{
open_window ("v50%");
}


#ifdef __STDC__
void
close_window (char *text)
#else
void
close_window (text)
char *text;
#endif
{
int num;

num = atoi (text) - 1;

if (num < 0 || num >= nwin)
{
io_error_msg ("Window %num?", text);
return;
}
if (nwin == 1)
{
io_error_msg ("You can't close the last window!");
return;
}
io_win_close (&wins[num]);
}

#ifdef __STDC__
void
delete_window (void)
#else
void
delete_window ()
#endif
{
io_win_close (cwin);
}

#ifdef __STDC__
void
delete_other_windows (void)
#else
void
delete_other_windows ()
#endif
{
if (nwin > 1)
{
CELLREF r = curow;
CELLREF c = cucol;
while (nwin > 1)
io_win_close (cwin);
io_move_cell_cursor (r, c);
}
}

#ifdef __STDC__
void
nicely_goto_window (int n)
#else
void
nicely_goto_window (n)
int n;
#endif
{
if (input_active)
{
io_cellize_cursor ();
window_after_input = n;
input_active = 0;
the_cmd_frame->top_keymap = map_id ("main");
return;
}
else
{
if ((window_after_input >= 0)
&& ((window_after_input % nwin) == n))
{
io_inputize_cursor ();
window_after_input = -1;
input_active = 1;
the_cmd_frame->top_keymap =
map_id (the_cmd_frame->cmd
? the_cmd_arg.style->keymap
: "main");
}
else
io_set_cwin (&wins[n]);
}
}

#ifdef __STDC__
void
goto_minibuffer (void)
#else
void
goto_minibuffer ()
#endif
{
if (window_after_input < 0)
{
if (!input_active)
io_error_msg ("Minibuffer not active.");
}
else
nicely_goto_window ((window_after_input % nwin));
}


#ifdef __STDC__
void
goto_window (char *text)
#else
void
goto_window (text)
char *text;
#endif
{
int n;
n = atoi (text) - 1;
if (n < 0 || n > nwin)
{
io_error_msg ("Window %s doesn't exist.", text);
return;
}
else
nicely_goto_window (n);
}


#ifdef __STDC__
void
other_window (void)
#else
void
other_window ()
#endif
{
int n = cwin - wins;
if (!input_active)
n = (n + 1) % nwin;
nicely_goto_window (n);
}

#ifdef __STDC__
int
set_window_option (int set_opt, char *text)
#else
int
set_window_option (set_opt, text)
int set_opt;
char *text;
#endif
{
int n;
int stat;
static struct opt
{
char *text;
int bits;
}
opts[] =
{
{
"reverse", WIN_EDGE_REV
}
,
{
"standout", WIN_EDGE_REV
}
,
{
"page", WIN_PAG_HZ | WIN_PAG_VT
}
,
{
"pageh", WIN_PAG_HZ
}
,
{
"pagev", WIN_PAG_VT
}
,
{
"lockh", WIN_LCK_HZ
}
,
{
"lockv", WIN_LCK_VT
}
,
{
"edges", WIN_EDGES
}
};
if ((stat = (!strincmp (text, "status", 6) && isspace (text[6])))
|| (!strincmp (text, "input", 5) && isspace (text[5])))
{
int n = set_opt ? atoi (text + 6 + stat) : 0; /* A little pun. */
int new_inp = stat ? user_input : n;
int new_stat = stat ? n : user_status;
io_set_input_status (new_inp, new_stat, 1);
}
else if (!strincmp (text, "link", 4))
{
if (set_opt)
{
n = atoi (text + 4) - 1;
if (n < 0 || n > nwin)
io_error_msg ("Can't '%s': window # out of range", text);
else
cwin->link = n;
}
else
cwin->link = -1;
}
else if (set_opt && !stricmp (text, "unlink"))
cwin->link = -1;
else if (set_opt && !strincmp (text, "row ", 4))
{
text += 4;
curow = astol (&text);
}
else if (set_opt && !strincmp (text, "col ", 4))
{
text += 4;
cucol = astol (&text);
}
else
{
for (n = 0; n < sizeof (opts) / sizeof (struct opt); n++)
if (!stricmp (text, opts[n].text))
{
if (set_opt)
cwin->flags |= opts[n].bits;
else
cwin->flags &= ~opts[n].bits;
break;
}

if (n == sizeof (opts) / sizeof (struct opt))
return 0;
}
return 1;
}

#ifdef __STDC__
void
show_window_options (void)
#else
void
show_window_options ()
#endif
{
int n;

cwin->win_curow = curow;
cwin->win_cucol = cucol;
if (user_status)
io_text_line ("Status line at %d", user_status);
else
io_text_line ("Status line disabled.");
io_text_line ("");
for (n = 0; n < nwin; n++)
{
int flags = wins[n].flags;
io_text_line ("Window #%d showing %s, with cursor at %s",
n + 1,
range_name (&wins[n].screen),
cell_name (wins[n].win_curow, wins[n].win_cucol));
io_text_line (" Options: %sedges (%sreverse)%s%s%s%s",
flags & WIN_EDGES ? "" : "no",
flags & WIN_EDGE_REV ? "" : "no",
flags & WIN_PAG_HZ ? ", pageh" : "",
flags & WIN_PAG_VT ? ", pagev" : "",
flags & WIN_LCK_HZ ? ", lockh" : "",
flags & WIN_LCK_VT ? ", lockv" : "");
if (wins[n].link != -1)
io_text_line ("Linked to window %d", wins[n].link + 1);
}
}

#ifdef __STDC__
void
recenter_window (void)
#else
void
recenter_window ()
#endif
{
io_recenter_cur_win ();
}



/* Trivial front-end commands. */


#ifdef __STDC__
void
suspend_oleo (void)
#else
void
suspend_oleo ()
#endif
{
if (using_curses)
{
stop_curses ();
kill (getpid (), SIGSTOP);
}
}

#ifdef __STDC__
void
recalculate (int all)
#else
void
recalculate (all)
int all;
#endif
{
current_cycle++;
if (all)
{
CELLREF row;
CELLREF col;
struct rng all;
all.lr = MIN_ROW;
all.hr = MAX_ROW;
all.lc = MIN_COL;
all.hc = MAX_COL;
find_cells_in_range (&all);
while (next_row_col_in_range (&row, &col))
push_cell (row, col);
}
while (eval_next_cell ())
;
}


#ifdef __STDC__
void
kill_oleo (void)
#else
void
kill_oleo ()
#endif
{
io_close_display ();
exit (0);
}


#ifdef __STDC__
void
kill_all_cmd (void)
#else
void
kill_all_cmd ()
#endif
{
clear_spreadsheet ();
io_repaint ();
}

#ifdef __STDC__
void
redraw_screen (void)
#else
void
redraw_screen ()
#endif
{
io_repaint ();
}



/* Motion commands. */

#ifdef __STDC__
void
shift_cell_cursor (int dir, int repeat)
#else
void
shift_cell_cursor (dir, repeat)
int dir;
int repeat;
#endif
{
io_shift_cell_cursor (dir, repeat);
}


#ifdef __STDC__
void
scroll_cell_cursor (int dir, int repeat)
#else
void
scroll_cell_cursor (dir, repeat)
int dir;
int repeat;
#endif
{
io_scroll_cell_cursor (dir, repeat);
}



#ifdef __STDC__
void
goto_region (struct rng *r)
#else
void
goto_region (r)
struct rng *r;
#endif
{
(void) io_move_cell_cursor (r->lr, r->lc);

if (r->hr != r->lr || r->hc != r->lc)
{
mkrow = r->hr;
mkcol = r->hc;
}
else if (mkrow != NON_ROW)
mkrow = NON_ROW;
io_update_status ();
}

#ifdef __STDC__
void
goto_cell (struct rng * rng)
#else
void
goto_cell (rng)
struct rng * rng;
#endif
{
rng->hr = mkrow;
rng->hc = mkcol;
goto_region (rng);
}

#ifdef __STDC__
void
exchange_point_and_mark (int clrmk)
#else
void
exchange_point_and_mark (clrmk)
int clrmk;
#endif
{
struct rng rng;
if (clrmk)
{
rng.lr = curow;
rng.lc = cucol;
rng.hr = NON_ROW;
rng.hc = NON_COL;
goto_region (&rng);
}
else if (mkrow != NON_ROW)
{
rng.lr = mkrow;
rng.lc = mkcol;
rng.hr = curow;
rng.hc = cucol;
goto_region (&rng);
}
}

#ifdef __STDC__
static CELLREF
first_filled_col (CELLREF row)
#else
static CELLREF
first_filled_col (row)
CELLREF row;
#endif
{
struct rng rng;
CELLREF r;
CELLREF c;
rng.lr = row;
rng.hr = row;
rng.lc = MIN_COL;
rng.hc = MAX_COL;
find_cells_in_range (&rng);
while (1)
{
CELL * cp;
cp = next_row_col_in_range (&r, &c);
if (!cp)
break;
if (GET_TYP(cp))
{
no_more_cells ();
return c;
}
}
return NON_COL;
}

#ifdef __STDC__
static CELLREF
last_filled_col (CELLREF row)
#else
static CELLREF
last_filled_col (row)
CELLREF row;
#endif
{
struct rng rng;
CELLREF r;
CELLREF c;
CELLREF bestc = MIN_COL;
rng.lr = row;
rng.hr = row;
rng.lc = MIN_COL;
rng.hc = MAX_COL;
find_cells_in_range (&rng);
while (1)
{
CELL * cp;
cp = next_row_col_in_range (&r, &c);
if (!cp)
break;
if (GET_TYP(cp))
bestc = c;
}
return bestc;
}

#ifdef __STDC__
static CELLREF
first_filled_row (CELLREF col)
#else
static CELLREF
first_filled_row (col)
CELLREF col;
#endif
{
struct rng rng;
CELLREF r;
CELLREF c;
CELL * cp;
rng.lr = MIN_ROW;
rng.hr = MAX_ROW;
rng.lc = col;
rng.hc = col;
find_cells_in_range (&rng);
while (1)
{
cp = next_row_col_in_range (&r, &c);
if (!cp)
break;
if (GET_TYP(cp))
{
no_more_cells ();
return r;
}
}
return NON_ROW;
}

#ifdef __STDC__
static CELLREF
last_filled_row (CELLREF col)
#else
static CELLREF
last_filled_row (col)
CELLREF col;
#endif
{
struct rng rng;
CELLREF r;
CELLREF c;
CELLREF bestr = MIN_ROW;
CELL * cp;
rng.lr = MIN_ROW;
rng.hr = MAX_ROW;
rng.lc = col;
rng.hc = col;
find_cells_in_range (&rng);
while (1)
{
cp = next_row_col_in_range (&r, &c);
if (!cp)
break;
if (GET_TYP(cp))
bestr = r;
}
return bestr;
}

#ifdef __STDC__
static CELLREF
max_filled_row (void)
#else
static CELLREF
max_filled_row ()
#endif
{
CELLREF max_r = highest_row ();
while (max_r != MIN_ROW)
{
CELLREF c = first_filled_col (max_r);
if (c != NON_COL)
break;
--max_r;
}
return max_r;
}


#ifdef __STDC__
static CELLREF
max_filled_col (void)
#else
static CELLREF
max_filled_col ()
#endif
{
CELLREF max_c = highest_col ();
while (max_c != MIN_COL)
{
CELLREF r = first_filled_row (max_c);
if (r != NON_COL)
break;
--max_c;
}
return max_c;
}

#ifdef __STDC__
static void
mk_for_extreme (struct rng * rng)
#else
static void
mk_for_extreme (rng)
struct rng * rng;
#endif
{
if (mkrow != NON_ROW)
{
rng->hr = mkrow;
rng->hc = mkcol;
}
else
{
rng->hc = cucol;
rng->hr = curow;
}
}

#ifdef __STDC__
void
upper_left (void)
#else
void
upper_left ()
#endif
{
struct rng rng;
rng.lr = MIN_ROW;
rng.lc = MIN_COL;
mk_for_extreme (&rng);
goto_region (&rng);
}

#ifdef __STDC__
void
lower_left (void)
#else
void
lower_left ()
#endif
{
struct rng rng;
rng.lr = max_filled_row ();
rng.lc = MIN_COL;
mk_for_extreme (&rng);
goto_region (&rng);
}

#ifdef __STDC__
void
upper_right (void)
#else
void
upper_right ()
#endif
{
struct rng rng;
rng.lr = MIN_ROW;
rng.lc = max_filled_col ();
mk_for_extreme (&rng);
goto_region (&rng);
}

#ifdef __STDC__
void
lower_right (void)
#else
void
lower_right ()
#endif
{
struct rng rng;
rng.lr = max_filled_row ();
rng.lc = max_filled_col ();
mk_for_extreme (&rng);
goto_region (&rng);
}

#ifdef __STDC__
void
mark_cell_cmd (int popmk)
#else
void
mark_cell_cmd (popmk)
int popmk;
#endif
{
if (popmk)
{
if (mkrow != NON_ROW)
{
struct rng rng;
rng.lr = mkrow;
rng.lc = mkcol;
rng.hr = NON_ROW;
rng.hc = NON_COL;
goto_region (&rng);
}
}
else
{
mkrow = curow;
mkcol = cucol;
io_update_status ();
}
}

#ifdef __STDC__
void
unmark_cmd (void)
#else
void
unmark_cmd ()
#endif
{
mkrow = NON_ROW;
mkcol = NON_COL;
io_update_status ();
}


/* This is a bit kludgey. Input line editting has its own event loop (grr!),
* and all of its state is private. These mouse commands can't entirely
* handle it when the target is in the input line. In that case, they
* save the decoded mouse event where io_get_line can pick it up:
*/
struct mouse_event last_mouse_event;

#ifdef __STDC__
void
do_mouse_goto (void)
#else
void
do_mouse_goto ()
#endif
{
if (!last_mouse_event.downp)
return;
if (last_mouse_event.location >= 0 && last_mouse_event.downp)
{
if (input_active)
{
io_cellize_cursor ();
window_after_input = last_mouse_event.location;
input_active = 0;
the_cmd_frame->top_keymap = map_id ("main");
}
io_set_cwin (&wins[last_mouse_event.location]);
io_move_cell_cursor (last_mouse_event.r, last_mouse_event.c);
}
else if (last_mouse_event.location == MOUSE_ON_INPUT)
{
goto_minibuffer ();
#ifdef HAVE_X11_X_H
if (using_x)
goto_char (io_col_to_input_pos (last_mouse_event.col));
#endif
}
else
io_bell ();
}

#ifdef __STDC__
void
do_mouse_mark (void)
#else
void
do_mouse_mark ()
#endif
{
if (last_mouse_event.location >= 0 && last_mouse_event.downp)
{
mkrow = last_mouse_event.r;
mkcol = last_mouse_event.c;
}
}


#ifdef __STDC__
void
do_mouse_mark_and_goto (void)
#else
void
do_mouse_mark_and_goto ()
#endif
{
if (last_mouse_event.location >= 0 && last_mouse_event.downp)
{
mkrow = curow;
mkcol = cucol;
}
do_mouse_goto ();
}

#ifdef __STDC__
void
do_mouse_cmd (void (*fn) ())
#else
void
do_mouse_cmd (fn)
void (*fn) ();
#endif
{
int seq = real_get_chr ();
dequeue_mouse_event (&last_mouse_event, seq);
fn ();
}

#ifdef __STDC__
void
mouse_mark_cmd (void)
#else
void
mouse_mark_cmd ()
#endif
{
do_mouse_cmd (do_mouse_mark);
}


#ifdef __STDC__
void
mouse_goto_cmd (void)
#else
void
mouse_goto_cmd ()
#endif
{
do_mouse_cmd (do_mouse_goto);
}

#ifdef __STDC__
void
mouse_mark_and_goto_cmd (void)
#else
void
mouse_mark_and_goto_cmd ()
#endif
{
do_mouse_cmd (do_mouse_mark_and_goto);
}



/* Commands used to modify cell formulas. */

#ifdef __STDC__
void
kill_cell_cmd (void)
#else
void
kill_cell_cmd ()
#endif
{
CELL *cp;

cp = find_cell (curow, cucol);
if (!cp)
return;
if ((GET_LCK (cp) == LCK_DEF && default_lock == LCK_LCK) || GET_LCK (cp) == LCK_LCK)
{
io_error_msg ("Cell %s is locked", cell_name (curow, cucol));
return;
}
new_value (curow, cucol, "");
cp->cell_flags = 0;
cp->cell_font = 0;
modified = 1;
}




/* A front end to sorting. */

#ifdef __STDC__
void
sort_region_cmd (char *ptr)
#else
void
sort_region_cmd (ptr)
char *ptr;
#endif
{
struct rng tmp_rng;

if (get_abs_rng (&ptr, &sort_rng))
{
io_error_msg ("Can't find a range to sort in %s", ptr);
return;
}

cur_row = sort_rng.lr;
cur_col = sort_rng.lc;

while (*ptr == ' ')
ptr++;
if (!*ptr)
{
sort_ele.lr = 0;
sort_ele.lc = 0;
sort_ele.hr = 0;
sort_ele.hc = 0;
}
else if (!parse_cell_or_range (&ptr, &sort_ele))
{
io_error_msg ("Can't parse elements in %s", ptr);
return;
}
else
{
sort_ele.lr -= sort_rng.lr;
sort_ele.lc -= sort_rng.lc;
sort_ele.hr -= sort_rng.lr;
sort_ele.hc -= sort_rng.lc;
}

sort_keys_num = 0;
while (*ptr == ' ')
ptr++;
for (; *ptr;)
{
if (sort_keys_num == sort_keys_alloc)
{
sort_keys_alloc++;
if (sort_keys_alloc > 1)
sort_keys = ck_realloc (sort_keys, sort_keys_alloc * sizeof (struct cmp));
else
sort_keys = ck_malloc (sizeof (struct cmp));
}
sort_keys[sort_keys_num].mult = 1;
if (*ptr == '+')
ptr++;
else if (*ptr == '-')
{
sort_keys[sort_keys_num].mult = -1;
ptr++;
}
if (!*ptr)
{
sort_keys[sort_keys_num].row = 0;
sort_keys[sort_keys_num].col = 0;
sort_keys_num++;
break;
}
if (!parse_cell_or_range (&ptr, &tmp_rng) || tmp_rng.lr != tmp_rng.hr || tmp_rng.lc != tmp_rng.hc)
{
io_error_msg ("Can't parse key #%d in %s", sort_keys_num + 1, ptr);
sort_keys_num = -1;
return;
}
sort_keys[sort_keys_num].row = tmp_rng.lr - sort_rng.lr;
sort_keys[sort_keys_num].col = tmp_rng.lc - sort_rng.lc;
sort_keys_num++;

while (*ptr == ' ')
ptr++;
}
if (sort_keys_num == 0)
{
if (sort_keys_alloc == 0)
{
sort_keys_alloc++;
sort_keys = ck_malloc (sizeof (struct cmp));
}
sort_keys[0].mult = 1;
sort_keys[0].row = 0;
sort_keys[0].col = 0;
sort_keys_num++;
}
sort_region ();
io_repaint ();
}





#ifdef __STDC__
void
imove (struct rng * rng, int ch)
#else
void
imove (rng, ch)
struct rng * rng;
int ch;
#endif
{
if ((ch > 0) && (ch != 27))
pushed_back_char = ch;

goto_region (rng);
}




/* Incremental navigation
*
* This should be called in edit mode while gathering arguments
* for a complex command. The expected the_cmd_arg.
*/

#define MIN(A,B) ((A) < (B) ? (A) : (B))

/* PAGE_RULE can be 0: page by rows, 1: cols, 2 shorter of rows/cols,
* -1: don't page at all.
*/

#ifdef __STDC__
void
inc_direction (int count, int page_rule, int hack_magic)
#else
void
inc_direction (count, page_rule, hack_magic)
int count;
int page_rule;
int hack_magic;
#endif
{
if (check_editting_mode ())
return;

if (page_rule >= 0)
{
int page_size;

switch (page_rule)
{
default:
case 0:
page_size = (cwin->screen.hr - cwin->screen.lr);
break;
case 1:
page_size = (cwin->screen.hc - cwin->screen.lc);
break;
case 2:
page_size = MIN ((cwin->screen.hr - cwin->screen.lr),
(cwin->screen.hc - cwin->screen.lc));
break;
}
count *= page_size;
}

if (the_cmd_frame->cmd && the_cmd_arg.inc_cmd)
the_cmd_arg.inc_cmd (hack_magic, count);
}




/* The commands that move to the extreme of a row[col] may also move
* forward or backward some number of col[row], according to the prefix
* arg. This is the logic of that. This function returns the new col[row]
* and operates on the presumption that MIN_ROW == MIN_COL and
* MAX_ROW == MAX_COL.
*/

#ifdef __STDC__
static CELLREF
extreme_cmd_orth_motion (int count, CELLREF current)
#else
static CELLREF
extreme_cmd_orth_motion (count, current)
int count;
CELLREF current;
#endif
{
--count;
if (count > (MAX_ROW - current))
count = (MAX_ROW - current);
else if (-count > (current - MIN_ROW))
count = (MIN_ROW - current);
return current + count;
}


#ifdef __STDC__
void
beginning_of_row (int count)
#else
void
beginning_of_row (count)
int count;
#endif
{
struct rng rng;
rng.lr = extreme_cmd_orth_motion (count, curow);
rng.lc = MIN_COL;
rng.hr = mkrow;
rng.hc = mkcol;
goto_region (&rng);
}

#ifdef __STDC__
void
end_of_row (int count)
#else
void
end_of_row (count)
int count;
#endif
{
struct rng rng;
rng.lr = extreme_cmd_orth_motion (count, curow);
rng.lc = last_filled_col (rng.lr);
rng.hr = mkrow;
rng.hc = mkcol;
goto_region (&rng);
}

#ifdef __STDC__
void
beginning_of_col (int count)
#else
void
beginning_of_col (count)
int count;
#endif
{
struct rng rng;
rng.lr = MIN_ROW;
rng.lc = extreme_cmd_orth_motion (count, cucol);
rng.hr = mkrow;
rng.hc = mkcol;
goto_region (&rng);
}

#ifdef __STDC__
void
end_of_col (int count)
#else
void
end_of_col (count)
int count;
#endif
{
struct rng rng;
rng.lc = extreme_cmd_orth_motion (count, cucol);
rng.lr = last_filled_row (rng.lc);
rng.hr = mkrow;
rng.hc = mkcol;
goto_region (&rng);
}


#ifdef __STDC__
static void
skip_empties (CELLREF * rout, CELLREF * cout, int magic)
#else
static void
skip_empties (rout, cout, magic)
CELLREF * rout;
CELLREF * cout;
int magic;
#endif
{
CELLREF r = *rout;
CELLREF c = *cout;
CELL * cp = find_cell (r, c);

while (!cp || !GET_TYP (cp))
{
if (r != boundrymagic [rowmagic [magic] + 1])
r += rowmagic [magic];
else if (rowmagic [magic])
break;
if (c != boundrymagic [colmagic [magic] + 1])
c += colmagic [magic];
else if (colmagic[magic])
break;
cp = find_cell (r, c);
}

*rout = r;
*cout = c;
}

#ifdef __STDC__
void
scan_cell_cursor (int magic, int count)
#else
void
scan_cell_cursor (magic, count)
int magic;
int count;
#endif
{
CELLREF r = curow;
CELLREF c = cucol;
CELLREF last_r = r;
CELLREF last_c = c;

skip_empties (&r, &c, magic);
{
CELL * cp = find_cell (r, c);
if (!(cp && GET_TYP (cp)))
return;
}
while (count)
{
CELL * cp = find_cell (r, c);
while (!cp || !GET_TYP (cp))
{
if (r != boundrymagic [rowmagic [magic] + 1])
r += rowmagic [magic];
else if (rowmagic [magic])
break;
if (c != boundrymagic [colmagic [magic] + 1])
c += colmagic [magic];
else if (colmagic[magic])
break;
cp = find_cell (r, c);
}
while (cp && GET_TYP (cp))
{
if (r != boundrymagic [rowmagic [magic] + 1])
r += rowmagic [magic];
else if (rowmagic[magic])
break;
if (c != boundrymagic [colmagic [magic] + 1])
c += colmagic [magic];
else if (colmagic [magic])
break;
last_r = r;
last_c = c;
cp = find_cell (r, c);
}
--count;
}
{
struct rng rng;
rng.lr = last_r;
rng.lc = last_c;
rng.hr = mkrow;
rng.hc = mkcol;
goto_region (&rng);
}
}


#ifdef __STDC__
void
edit_cell (char * new_formula)
#else
void
edit_cell (new_formula)
char * new_formula;
#endif
{
char * fail;
fail = new_value (setrow, setcol, new_formula);
if (fail)
io_error_msg (fail);
else
modified = 1;
}


#ifdef __STDC__
void
set_region_formula (struct rng * rng, char * str)
#else
void
set_region_formula (rng, str)
struct rng * rng;
char * str;
#endif
{
CELLREF row, col;

for (row = rng->lr; row <= rng->hr; ++row)
for (col = rng->lc; col <= rng->hc; ++col)
{
char * error = new_value (row, col, str);
if (!error)
modified = 1;
if (error)
{
io_error_msg (error);
return;
}
}
}

#ifdef __STDC__
void
goto_edit_cell (int c)
#else
void
goto_edit_cell (c)
int c;
#endif
{
pushed_back_char = c;
execute_command ("edit-cell", 1);
}


/* File i/o */

int sneaky_linec = 0; /* for error reporting for now (see io-term.c) */

#ifdef __STDC__
void
read_cmds_cmd (FILE *fp)
#else
void
read_cmds_cmd (fp)
FILE *fp;
#endif
{
struct line line;
char *ptr;
init_line (&line);
sneaky_linec = 0;
while (read_line (&line, fp, &sneaky_linec))
{
for (ptr = line.buf; isspace (*ptr); ptr++);
if (!*ptr || (*ptr == '#'))
continue;
execute_command (ptr, 1);
}
}


static int run_load_hooks = 1;
static char load_hooks_string[] = "load_hooks";

#ifdef __STDC__
void
read_file_and_run_hooks (FILE * fp, int ismerge, char * name)
#else
void
read_file_and_run_hooks (fp, ismerge, name)
FILE * fp;
int ismerge;
char * name;
#endif
{
if (!ismerge)
{
if (current_filename)
free (current_filename);
current_filename = name ? ck_savestr (name) : 0;
}
(*read_file)(fp, ismerge);
if (run_load_hooks)
{
struct var * v;
v = find_var (load_hooks_string, sizeof (load_hooks_string) - 1);
if (v && v->var_flags != VAR_UNDEF)
execute_command (load_hooks_string, 1);
}
}

/* If TURN_ON is 0, this toggles whether load hooks are run.
* Otherwise, it turns load hooks on.
*/

#ifdef __STDC__
void
toggle_load_hooks (int turn_on)
#else
void
toggle_load_hooks (turn_on)
int turn_on;
#endif
{
if (!turn_on && run_load_hooks)
{
run_load_hooks = 0;
io_info_msg ("load hooks turned off");
}
else
{
run_load_hooks = 1;
io_info_msg ("load hooks turned on");
}
}

#ifdef __STDC__
void
write_cmd (FILE *fp, char * name)
#else
void
write_cmd (fp, name)
FILE *fp;
char * name;
#endif
{
if (current_filename)
free (current_filename);
current_filename = name ? ck_savestr (name) : 0;
(*write_file) (fp, 0);
modified = 0;
}

#ifdef __STDC__
void
read_cmd (FILE *fp, char * name)
#else
void
read_cmd (fp, name)
FILE *fp;
char * name;
#endif
{
read_file_and_run_hooks (fp, 0, name);
}

#ifdef __STDC__
void
read_merge_cmd (FILE *fp)
#else
void
read_merge_cmd (fp)
FILE *fp;
#endif
{
(*read_file) (fp, 1);
}

#ifdef __STDC__
void
write_reg_cmd (FILE *fp, struct rng *rng)
#else
void
write_reg_cmd (fp, rng)
FILE *fp;
struct rng *rng;
#endif
{
(*write_file) (fp, rng);
}




/* Cell attributes. */
#ifdef __STDC__
void
set_region_height (struct rng * rng, char * height)
#else
void
set_region_height (rng, height)
struct rng * rng;
char * height;
#endif
{
int hgt;
char * saved_height = height;

while (isspace (*height))
++height;

if ( !*height
|| words_imatch (&height, "d")
|| words_imatch (&height, "def")
|| words_imatch (&height, "default"))
hgt = 0;
else
{
hgt = astol (&height) + 1;
if (hgt < 0)
/* noreturn */
io_error_msg ("Height (%d) can't be less than 0.", hgt);
}

if (*height)
{
io_error_msg ("Unknown height '%s'", saved_height);
/* Doesn't return */
}
{
CELLREF cc;
for (cc = rng->lr; ;cc++)
{
set_height (cc, hgt);
if (cc == rng->hr) /* This test goes here to prevent overflow. */
break;
}
io_recenter_all_win ();
}
}

#ifdef __STDC__
void
set_region_width (struct rng * rng, char * width)
#else
void
set_region_width (rng, width)
struct rng * rng;
char * width;
#endif
{
char * saved_width = width;
int wid;

while (isspace (*width))
++width;

if ( !*width
|| words_imatch (&width, "d")
|| words_imatch (&width, "def")
|| words_imatch (&width, "default"))
wid = 0;
else
{
wid = astol (&width) + 1;
if (wid < 0)
/* noreturn */
io_error_msg ("Width (%d) can't be less than 0.", wid);
}

if (*width)
{
io_error_msg ("Unknown width '%s'", saved_width);
/* No return. */
}
{
CELLREF cc;
for (cc = rng->lc; ;cc++)
{
set_width (cc, wid);
if (cc == rng->hc) /* This test goes here to prevent overflow. */
break;
}
io_recenter_all_win ();
}
}


/* PROT may be `d', `p', or `u'. */

#ifdef __STDC__
void
set_region_protection (struct rng * rng, int prot)
#else
void
set_region_protection (rng, prot)
struct rng * rng;
int prot;
#endif
{
prot = tolower (prot);
switch (prot)
{
case 'd':
lock_region (rng, LCK_DEF);
break;
case 'p':
lock_region (rng, LCK_LCK);
break;
case 'u':
lock_region (rng, LCK_UNL);
break;
default:
io_error_msg ("Bad argument to protect-region %c.", prot);
break;
}
}

#ifdef __STDC__
void
set_region_alignment (struct rng * rng, int align)
#else
void
set_region_alignment (rng, align)
struct rng * rng;
int align;
#endif
{
int fun = chr_to_jst (align);
if (fun != -1)
format_region (rng, -1, fun);
else /* if (main_map[align]!=BREAK_CMD) */
io_error_msg ("Unknown Justify '%s'", char_to_string (align));
}

#ifdef __STDC__
void
set_region_format (struct rng * rng, int fmt)
#else
void
set_region_format (rng, fmt)
struct rng * rng;
int fmt;
#endif
{
format_region (rng, fmt, -1);
}




#ifdef __STDC__
void
set_def_height (char * height)
#else
void
set_def_height (height)
char * height;
#endif
{
char * saved_height = height;
int hgt;

while (isspace (*height))
++height;

if ( !*height
|| words_imatch (&height, "d")
|| words_imatch (&height, "def")
|| words_imatch (&height, "default"))
hgt = 0;
else
{
hgt = astol (&height);
if (hgt < 0)
/* noreturn */
io_error_msg ("Height (%d) can't be less than 0.", hgt);
}

if (*height)
{
io_error_msg ("Unknown height '%s'", saved_height);
/* No return. */
}
default_height = hgt;
io_recenter_all_win ();
}

#ifdef __STDC__
void
set_def_width (char * width)
#else
void
set_def_width (width)
char * width;
#endif
{
char * saved_width = width;
int wid;

while (isspace (*width))
++width;

if ( !*width
|| words_imatch (&width, "d")
|| words_imatch (&width, "def")
|| words_imatch (&width, "default"))
wid = 8;
else
{
wid = astol (&width);
if (wid < 0)
/* noreturn */
io_error_msg ("Width (%d) can't be less than 0.", wid);
}

if (*width)
{
io_error_msg ("Unknown width '%s'", saved_width);
/* No return. */
}
default_width = wid;
io_recenter_all_win ();
}

/* PROT may be `d', `p', or `u'. */

#ifdef __STDC__
void
set_def_protection (int prot)
#else
void
set_def_protection (prot)
int prot;
#endif
{
prot = tolower (prot);
switch (prot)
{
case 'p':
default_lock = LCK_LCK;
break;
case 'u':
default_lock = LCK_UNL;
break;
default:
io_error_msg ("Bad argument to set-default-protection %c.", prot);
break;
}
}

#ifdef __STDC__
void
set_def_alignment (int align)
#else
void
set_def_alignment (align)
int align;
#endif
{
int fun = chr_to_jst (align);
if (fun == -1)
io_error_msg ("Unknown justification.");

default_jst = fun;
io_repaint ();
}

#ifdef __STDC__
void
set_def_format (int fmt)
#else
void
set_def_format (fmt)
int fmt;
#endif
{
default_fmt = fmt;
io_repaint ();
}



#ifdef __STDC__
void
define_usr_fmt (int fmt, char * pos_h, char * neg_h, char * pos_t,
char * neg_t, char * zero, char * comma, char * decimal,
char * precision, char * scale)
#else
void
define_usr_fmt (fmt, pos_h, neg_h, pos_t, neg_t, zero,
comma, decimal, precision, scale)
int fmt;
char * pos_h;
char * neg_h;
char * pos_t;
char * neg_t;
char * zero;
char * comma;
char * decimal;
char * precision;
char * scale;
#endif
{
char * usr_buf[9];
if (fmt < 1 || fmt > 16)
{
io_error_msg ("Format number out of range %d (should be in [1..16].",
fmt);
/* no return */
}
/* Vector to an older interface... */
--fmt;
usr_buf[0] = pos_h;
usr_buf[1] = neg_h;
usr_buf[2] = pos_t;
usr_buf[3] = neg_t;
usr_buf[4] = zero;
usr_buf[5] = comma;
usr_buf[6] = decimal;
usr_buf[7] = precision;
usr_buf[8] = scale;
set_usr_stats (fmt, usr_buf);
}



/* Automatic motion while editting cell's: */

/* Hmm... where should this variable *really* go? */

static int auto_motion_direction = magic_down;

#ifdef __STDC__
void
set_auto_direction (enum motion_magic magic)
#else
void
set_auto_direction (magic)
enum motion_magic magic;
#endif
{
auto_motion_direction = magic;
io_info_msg ("Auto-motion direction = %s.", motion_name[magic]);
}

#ifdef __STDC__
void
auto_move (void)
#else
void
auto_move ()
#endif
{
shift_cell_cursor (auto_motion_direction, 1);
}

#ifdef __STDC__
void
auto_next_set (void)
#else
void
auto_next_set ()
#endif
{
scan_cell_cursor (opposite_motion[auto_motion_direction], 1);
shift_cell_cursor (complementary_motion[auto_motion_direction], 1);
}


/* This decompiles and then recompiles all of the formulas of cells.
* This is never normally necessary unless you happen to have some
* spreadsheets written when the byte-code compiler had bugs that
* made your formulas produce parse errors.
*/

#ifdef __STDC__
void
recompile_spreadsheet (void)
#else
void
recompile_spreadsheet ()
#endif
{
struct rng rng;
CELL * cp;
CELLREF r;
CELLREF c;
rng.lr = MIN_ROW;
rng.lc = MIN_COL;
rng.hr = MAX_ROW;
rng.hc = MAX_COL;
find_cells_in_range (&rng);
for (cp = next_row_col_in_range (&r, &c);
cp;
cp = next_row_col_in_range(&r, &c))
{
char * form = decomp (r, c, cp);
set_cell (r, c, form);
if (my_cell)
{
update_cell (my_cell);
if (is_constant (my_cell->cell_formula))
{
byte_free (my_cell->cell_formula);
my_cell->cell_formula = 0;
}
io_pr_cell (r, c, my_cell);
my_cell = 0;
}
decomp_free ();
}
}

oleo-1.3/args.c 644 722 0 22570 5356010554 11613 0ustar lordwheel/* Copyright (C) 1993 Free Software Foundation, Inc.

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, 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 software; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */

#include
#include "global.h"
#define DEFINE_STYLES 1
#include "args.h"
#include "cmd.h"
#include "io-abstract.h"
#include "io-generic.h"
#include "io-edit.h"
#include "io-utils.h"
#include "format.h"



/* These commands define the syntax and editting modes of command arguments.
* Each _verify function parses some kind of argument and stores its value
* in a command_arg structure. An error message or NULL is returned.
* If the match succeeds, a string pointer is advanced to the end of what was
* parsed.
*
* Several arguments may be listed on one line separated only by
* whitespace. A _verify function should stop after its argument and ignore
* everything after that.
*/

#ifdef __STDC__
char *
char_verify (char ** end, struct command_arg * arg)
#else
char *
char_verify (end, arg)
char ** end;
struct command_arg * arg;
#endif
{
if (!**end)
return "No character specified";
else
{
int ch = string_to_char (end);
if (ch < 0)
{
setn_edit_line ("", 0);
return "Illegal character constant.";
}
else
{
arg->val.integer = ch;
return 0;
}
}
}

#ifdef __STDC__
char *
symbol_verify (char ** end, struct command_arg * arg)
#else
char *
symbol_verify (end, arg)
char ** end;
struct command_arg * arg;
#endif
{
char * e = *end;
char * start = *end;
if (isalpha (*e) || (*e == '-') || (*e == '_') || (*e == (a0 ? '$' : ':')))
{
while (isalpha(*e) || isdigit(*e) || (*e == '-') || (*e == '_')
|| (*e == (a0 ? '$' : ':')))
++e;
if (!isspace(*e) && *e)
goto bad_symbol;
*end = e;
arg->val.string = (char *)ck_malloc (e - start + 1);
bcopy (start, arg->val.string, e - start);
arg->val.string[e - start] = '\0';
return 0;
}
bad_symbol:
if (arg->arg_desc[1] == '\'')
{
arg->val.string = 0;
return 0;
}
else
return "Invalid symbol name.";
}

char *
word_verify (end, arg)
char ** end;
struct command_arg * arg;
{
char * e = *end;
char * start = *end;
if (!isspace (*e))
{
while (!isspace(*e))
++e;
*end = e;
arg->val.string = (char *)ck_malloc (e - start + 1);
bcopy (start, arg->val.string, e - start);
arg->val.string[e - start] = '\0';
return 0;
}
else if (arg->arg_desc[1] == '\'')
{
arg->val.string = 0;
return 0;
}
else
return "Invalid symbol name.";
}

#ifdef __STDC__
void
symbol_destroy (struct command_arg * arg)
#else
void
symbol_destroy (arg)
struct command_arg * arg;
#endif
{
if (arg->val.string)
ck_free (arg->val.string);
}

#ifdef __STDC__
char *
command_verify (char ** end, struct command_arg * arg)
#else
char *
command_verify (end, arg)
char ** end;
struct command_arg * arg;
#endif
{
char * error = symbol_verify (end, arg);
char * str;
if (error)
return error;
str = arg->val.string;
if (!(find_function (0, 0, arg->val.string, strlen(arg->val.string))
&& get_abs_rng (&str, 0)))
return 0;
else
return "Not a command or macro address.";
}

#ifdef __STDC__
char *
read_file_verify (char ** end, struct command_arg * arg)
#else
char *
read_file_verify (end, arg)
char ** end;
struct command_arg * arg;
#endif
{
FILE * fp = xopen_with_backup (arg->text.buf, "r");
*end = 0;
if (!fp)
{
io_error_msg ("Can't open file '%s':%s", arg->text.buf, err_msg ());
return "";
}
else
{
arg->val.fp = fp;
return 0;
}
}

#ifdef __STDC__
void
read_file_destroy (struct command_arg * arg)
#else
void
read_file_destroy (arg)
struct command_arg * arg;
#endif
{
int num;
num = xclose (arg->val.fp);
if (num)
io_error_msg ("Can't close '%s': Error code %d: %s",
arg->text.buf, num, err_msg ());
}


#ifdef __STDC__
char *
write_file_verify (char ** end, struct command_arg * arg)
#else
char *
write_file_verify (end, arg)
char ** end;
struct command_arg * arg;
#endif
{
FILE * fp = xopen_with_backup (arg->text.buf, "w");
*end = 0;
if (!fp)
{
io_error_msg ("Can't open file '%s':%s", arg->text.buf, err_msg ());
return "";
}
else
{
arg->val.fp = fp;
return 0;
}
}

#ifdef __STDC__
void
write_file_destroy (struct command_arg * arg)
#else
void
write_file_destroy (arg)
struct command_arg * arg;
#endif
{
int num;

num = xclose (arg->val.fp);
if (num)
io_error_msg ("Can't close '%s': Error code %d: %s",
arg->text.buf, num, err_msg ());
}

/* As a special case, cmd_loop makes sure that keyseq arguments are only read
* interactively.
*/

#ifdef __STDC__
char *
keyseq_verify (char ** end, struct command_arg * arg)
#else
char *
keyseq_verify (end, arg)
char ** end;
struct command_arg * arg;
#endif
{
*end = 0;
return 0;
}


#ifdef __STDC__
char *
keymap_verify (char ** end, struct command_arg * arg)
#else
char *
keymap_verify (end, arg)
char ** end;
struct command_arg * arg;
#endif
{
char * start = *end;
char * error = symbol_verify (end, arg);
int id;
if (error)
return error;
id = map_idn (start, *end - start);
return (id >= 0
? (char *) 0
: "No such keymap.");
}


#ifdef __STDC__
char *
number_verify (char ** end, struct command_arg * arg)
#else
char *
number_verify (end, arg)
char ** end;
struct command_arg * arg;
#endif
{
char * e = *end;

while (isspace (*e))
++e;
if (isdigit(*e) || (*e == '-'))
{
arg->val.integer = astol (end);
if (arg->arg_desc[1] == '[')
{
char * prompt = arg->arg_desc + 2;
{
long low = 0;
long high = -1;
low = astol (&prompt);
while (isspace (*prompt)) ++prompt;
if (*prompt == ',') ++prompt;
high = astol (&prompt);
while (isspace (*prompt)) ++prompt;
if (*prompt == ']') ++prompt;
if ( (low > arg->val.integer)
|| (high < arg->val.integer))
io_error_msg ("Out of range %d (should be in [%d - %d]).",
arg->val.integer, low, high); /* no return */
}
}
return 0;
}
else
return "Not a number.";
}


#ifdef __STDC__
char *
double_verify (char ** end, struct command_arg * arg)
#else
char *
double_verify (end, arg)
char ** end;
struct command_arg * arg;
#endif
{
char * e = *end;

while (isspace (*e))
++e;
if (isdigit(*e) || ((*e == '-') && isdigit (*(e + 1))))
{
arg->val.floating = astof (end);
return 0;
}
else
return "Not a number.";
}


#ifdef __STDC__
char *
range_verify (char ** end, struct command_arg * arg)
#else
char *
range_verify (end, arg)
char ** end;
struct command_arg * arg;
#endif
{
union command_arg_val * val = &arg->val;
*end = arg->text.buf;
if (get_abs_rng (end, &val->range))
return "Not a range.";
else
return 0;
}

#ifdef __STDC__
char *
string_verify (char ** end, struct command_arg * arg)
#else
char *
string_verify (end, arg)
char ** end;
struct command_arg * arg;
#endif
{
arg->val.string = arg->text.buf;
*end = 0;
return 0;
}

/* Unlike most verify functions, this
* one may destroy the command frame that it is
* operating on. It's purpose is to allow user's
* to abort commands.
*/
#ifdef __STDC__
char *
yes_verify (char ** end, struct command_arg * arg)
#else
char *
yes_verify (end, arg)
char ** end;
struct command_arg * arg;
#endif
{
if (words_imatch (end, "no"))
{
pop_unfinished_command ();
return "Aborted.";
}
else if (words_imatch (end, "yes"))
return 0;
else
{
setn_edit_line ("", 0);
return "Please answer yes or no.";
}
}

#ifdef __STDC__
char *
incremental_cmd_verify (char ** end, struct command_arg * arg)
#else
char *
incremental_cmd_verify (end, arg)
char ** end;
struct command_arg * arg;
#endif
{
return 0;
}


#ifdef __STDC__
char *
menu_verify (char ** end, struct command_arg * arg)
#else
char *
menu_verify (end, arg)
char ** end;
struct command_arg * arg;
#endif
{
char * error = char_verify (end, arg);
if (error)
return error;

{
int pick = arg->val.integer;
char * key = arg->arg_desc + 1;
while (*key && (*key != ']'))
{
if (*key == '\\')
{
++key;
if (!*key)
break;
}
if (pick == *key)
return 0;
else
++key;
}
setn_edit_line ("", 0);
return "No such menu option.";
}
}


#ifdef __STDC__
char *
format_verify (char ** end, struct command_arg * arg)
#else
char *
format_verify (end, arg)
char ** end;
struct command_arg * arg;
#endif
{
arg->val.integer = str_to_fmt (*end);
if (arg->val.integer < 0)
return "Unknown format.";
*end = 0;
return 0;
}


#ifdef __STDC__
char *
noop_verify (char ** end, struct command_arg * arg)
#else
char *
noop_verify (end, arg)
char ** end;
struct command_arg * arg;
#endif
{
return 0;
}
oleo-1.3/stub.c 644 722 0 16325 5356017732 11642 0ustar lordwheel/* Copyright (C) 1993 Free Software Foundation, Inc.

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, 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 software; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */



/* This is a collection of stubs that are used to call interactive functions.
* Their responsability is to extract arguments from a command_frame as
* constructed by the function COMMAND_LOOP.
*/

#include "global.h"
#include "cmd.h"
#include "stub.h"




#ifdef __STDC__
static void
find_args (struct command_arg ** argv_out, int argc, struct command_frame * frame)
#else
static void
find_args (argv_out, argc, frame)
struct command_arg ** argv_out;
int argc;
struct command_frame * frame;
#endif
{
int found = 0;
int pos = 0;
while (found < argc)
{
if (frame->argv[pos].style->representation != cmd_none)
argv_out[found++] = &frame->argv[pos];
++pos;
}
}


/* These macros are invoked in stubs.h and are used to define
* the stub functions. Later, these macros will be redifined
* an used to build a table of stub functions.
*/

#ifdef __STDC__
#define STUB1(STR,NAME, PRE, VAL, TYPE) \
static void \
NAME (frame) \
struct command_frame * frame; \
{ \
struct command_arg * argv; \
find_args (&argv, 1, frame); \
((void (*) (TYPE)) frame->cmd->func_func) (PRE argv->val.VAL); \
}
#else
#define STUB1(STR,NAME, PRE, VAL, TYPE) \
static void \
NAME (frame) \
struct command_frame * frame; \
{ \
int x; \
struct command_arg * argv; \
find_args (&argv, 1, frame); \
frame->cmd->func_func (PRE argv->val.VAL); \
}
#endif

#ifdef __STDC__
#define STUB2(STR,NAME,PRE1,VAL1,TYPE1,PRE2,VAL2,TYPE2) \
static void \
NAME (frame) \
struct command_frame * frame; \
{ \
struct command_arg * argv[2]; \
find_args (argv, 2, frame); \
((void (*) (TYPE1, TYPE2)) frame->cmd->func_func) \
(PRE1 argv[0]->val.VAL1, \
PRE2 argv[1]->val.VAL2); \
}
#else
#define STUB2(STR,NAME,PRE1,VAL1,TYPE1,PRE2,VAL2,TYPE2) \
static void \
NAME (frame) \
struct command_frame * frame; \
{ \
struct command_arg * argv[2]; \
find_args (argv, 2, frame); \
frame->cmd->func_func \
(PRE1 argv[0]->val.VAL1, \
PRE2 argv[1]->val.VAL2); \
}
#endif


#ifdef __STDC__
#define STUB3(STR,NAME,PRE1,VAL1,TYPE1,PRE2,VAL2,TYPE2,PRE3,VAL3,TYPE3) \
static void \
NAME (frame) \
struct command_frame * frame; \
{ \
struct command_arg * argv[3]; \
find_args (argv, 3, frame); \
frame->cmd->func_func \
(PRE1 argv[0]->val.VAL1, \
PRE2 argv[1]->val.VAL2, \
PRE3 argv[2]->val.VAL3); \
}
#else
#define STUB3(STR,NAME,PRE1,VAL1,TYPE1,PRE2,VAL2,TYPE2,PRE3,VAL3,TYPE3) \
static void \
NAME (frame) \
struct command_frame * frame; \
{ \
struct command_arg * argv[3]; \
find_args (argv, 3, frame); \
frame->cmd->func_func \
(PRE1 argv[0]->val.VAL1, \
PRE2 argv[1]->val.VAL2, \
PRE3 argv[2]->val.VAL3); \
}
#endif

#ifdef __STDC__
#define STUB4(STR,NAME,PRE1,VAL1,TYPE1,PRE2,VAL2,TYPE2,PRE3,VAL3,TYPE3,PRE4,VAL4,TYPE4) \
static void \
NAME (frame) \
struct command_frame * frame; \
{ \
struct command_arg * argv[4]; \
find_args (argv, 4, frame); \
frame->cmd->func_func \
(PRE1 argv[0]->val.VAL1, \
PRE2 argv[1]->val.VAL2, \
PRE3 argv[2]->val.VAL3, \
PRE4 argv[3]->val.VAL4); \
}
#else
#define STUB4(STR,NAME,PRE1,VAL1,TYPE1,PRE2,VAL2,TYPE2,PRE3,VAL3,TYPE3,PRE4,VAL4,TYPE4) \
static void \
NAME (frame) \
struct command_frame * frame; \
{ \
struct command_arg * argv[4]; \
find_args (argv, 4, frame); \
frame->cmd->func_func \
(PRE1 argv[0]->val.VAL1, \
PRE2 argv[1]->val.VAL2, \
PRE3 argv[2]->val.VAL3, \
PRE4 argv[3]->val.VAL4); \
}
#endif

#ifdef __STDC__
#define STUB5(STR,NAME,PRE1,VAL1,TYPE1,PRE2,VAL2,TYPE2,PRE3,VAL3,TYPE3,PRE4,VAL4,TYPE4,PRE5,VAL5,TYPE5) \
static void \
NAME (frame) \
struct command_frame * frame; \
{ \
struct command_arg * argv[5]; \
find_args (argv, 5, frame); \
frame->cmd->func_func \
(PRE1 argv[0]->val.VAL1, \
PRE2 argv[1]->val.VAL2, \
PRE3 argv[2]->val.VAL3, \
PRE4 argv[3]->val.VAL4, \
PRE5 argv[4]->val.VAL5); \
}
#else
#define STUB5(STR,NAME,PRE1,VAL1,TYPE1,PRE2,VAL2,TYPE2,PRE3,VAL3,TYPE3,PRE4,VAL4,TYPE4,PRE5,VAL5,TYPE5) \
static void \
NAME (frame) \
struct command_frame * frame; \
{ \
struct command_arg * argv[5]; \
find_args (argv, 5, frame); \
frame->cmd->func_func \
(PRE1 argv[0]->val.VAL1, \
PRE2 argv[1]->val.VAL2, \
PRE3 argv[2]->val.VAL3, \
PRE4 argv[3]->val.VAL4, \
PRE5 argv[4]->val.VAL5); \
}
#endif

/* This contains the list of stub functions. */

#include "stubs.h"

/* There is only one `STUB0' so we needn't bother with a macro. */

#ifdef __STDC__
static void
stub_void (struct command_frame * frame)
#else
static void
stub_void (frame)
struct command_frame * frame;
#endif
{
frame->cmd->func_func ();
}

/* For define_usr_fmt */
static void
stub_isssssssss (frame)
struct command_frame * frame;
{
struct command_arg * argv[10];
find_args (argv, 10, frame);
frame->cmd->func_func (argv[0]->val.integer,
argv[1]->val.string,
argv[2]->val.string,
argv[3]->val.string,
argv[4]->val.string,
argv[5]->val.string,
argv[6]->val.string,
argv[7]->val.string,
argv[8]->val.string,
argv[9]->val.string);
}





/* Single character type-codes denote the types of arguments. A string
* of type-codes maps to a stub function (hopefully).
*/
struct cmd_stub
{
char * type;
cmd_invoker stub;
};

#undef STUB1
#undef STUB2
#undef STUB3
#undef STUB4
#undef STUB5

#define STUB1(STR,NAME,PRE1,VAL1,TYPE1) { STR, NAME },
#define STUB2(STR,NAME,PRE1,VAL1,TYPE1,PRE2,VAL2,TYPE2) { STR, NAME },
#define STUB3(STR,NAME,PRE1,VAL1,TYPE1,PRE2,VAL2,TYPE2,PRE3,VAL3,TYPE3) \
{ STR, NAME },
#define STUB4(STR,NAME,PRE1,VAL1,TYPE1,PRE2,VAL2,TYPE2,PRE3,VAL3,TYPE3,PRE4,VAL4,TYPE4) \
{ STR, NAME },
#define STUB5(STR,NAME,PRE1,VAL1,TYPE1,PRE2,VAL2,TYPE2,PRE3,VAL3,TYPE3,PRE4,VAL4,TYPE4,PRE5,VAL5,TYPE5) \
{ STR, NAME },

static struct cmd_stub the_stubs[] =
{
{ "", stub_void },
#include "stubs.h"
{ "isssssssss", stub_isssssssss },
{ 0, 0 }
};



/* This looks at the arguments built for the current command and
* finds the right stub.
*/
#ifdef __STDC__
cmd_invoker
find_stub (void)
#else
cmd_invoker
find_stub ()
#endif
{
char type_buf[100];

/* Figure out a name for the stub we want. */
{
int x, bufpos;
for (x = 0, bufpos = 0; x < cmd_argc; ++x)
if (the_cmd_frame->argv[x].style->representation != cmd_none)
type_buf[bufpos++] = the_cmd_frame->argv[x].style->representation;
type_buf[bufpos] = '\0';
}

/* Look for the stub. */
{
int x;
for (x = 0; the_stubs[x].type; ++x)
if (!stricmp (the_stubs[x].type, type_buf))
break;
return the_stubs[x].stub;
}
}

oleo-1.3/input.c 644 722 0 23705 5356120114 12011 0ustar lordwheel/* Copyright (C) 1993 Free Software Foundation, Inc.

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, 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 software; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */


#include "global.h"
#include "input.h"
#include "cmd.h"
#include "window.h"
#include "io-abstract.h"


/* In the functions below, we only ever deal with one input_view at a
* time. By convention, call a pointer to it THIS_IV and use these
* macros:
*/
#define redraw_needed (this_iv->redraw_needed)
#define prompt_metric (this_iv->prompt_metric)
#define input_metric (this_iv->input_metric)
#define keymap_prompt (this_iv->keymap_prompt)
#define expanded_keymap_prompt (this_iv->expanded_keymap_prompt)
#define prompt_wid (this_iv->prompt_wid)
#define must_fix_input (this_iv->must_fix_input)
#define input_area (this_iv->input_area)
#define prompt (this_iv->prompt)
#define visibility_begin (this_iv->visibility_begin)
#define visibility_end (this_iv->visibility_end)
#define current_info (this_iv->current_info)
#define info_pos (this_iv->info_pos)
#define info_redraw_needed (this_iv->info_redraw_needed)
#define vis_wid (this_iv->vis_wid)
#define input_cursor (this_iv->input_cursor)



#define Max(A,B) ((A) < (B) ? (B) : (A))
#define Min(A,B) ((A) > (B) ? (B) : (A))


/* Decide if a keymap prompt should be displayed. If so,
* return the prompt, else 0.
*/

#ifdef __STDC__
static char *
desired_keymap_prompt (struct input_view * this_iv)
#else
static char *
desired_keymap_prompt (this_iv)
struct input_view * this_iv;
#endif
{
int map = cur_keymap;
if (the_cmd_frame->cmd && (the_cmd_arg.style == &keyseq_style))
map = the_cmd_arg.val.key.cmd.code;
return ((map >= 0) ? map_prompts[map] : 0);
}




/* In WID columns, find the first char in STR that can
* be displayed while still leaving POS visible. METRIC
* converts str->cols.
*/

#ifdef __STDC__
static int
find_vis_begin (int * wid_used, int wid,
char * str, int pos, text_measure metric)
#else
static int
find_vis_begin (wid_used, wid, str, pos, metric)
int * wid_used;
int wid;
char * str;
int pos;
text_measure metric;
#endif
{
int used; /* How many cols allocated? */
if (str[pos])
used = metric (&str[pos], 1);
else
/* POS could be just after the end of STR, in which case pretend
* that the character there is a SPC.
*/
used = metric (" ", 1);

while (pos && (used < wid))
{
int next;
next = metric (&str[pos - 1], 1);
if (used + next > wid)
break;
else
{
--pos;
used += next;
}
}
if (wid_used)
*wid_used = used;
return pos;
}



/* Find the last visible character... -1 if none are vis. */

#ifdef __STDC__
static int
find_vis_end (int * wid_used, int wid, char * str, int start, text_measure
metric)
#else
static int
find_vis_end (wid_used, wid, str, start, metric)
int * wid_used;
int wid;
char * str;
int start;
text_measure metric;
#endif
{
int used = metric (&str[start], 1); /* How many cols allocated? */
int pos = start;
int max = strlen (str) - 1;

while ((pos < max) && (used < wid))
{
int next;
next = metric (&str[pos + 1], 1);
if (used + next > wid)
break;
else
{
++pos;
used += next;
}
}
if (wid_used)
*wid_used = used;
return pos;
}

#ifdef __STDC__
static void
set_vis_wid (struct input_view * this_iv)
#else
static void
set_vis_wid (this_iv)
struct input_view * this_iv;
#endif
{
vis_wid = (input_metric (input_area->buf + visibility_begin,
visibility_end - visibility_begin)
+ ((input_cursor > visibility_end)
? input_metric (" ", 1)
: 0));
}


/* This recomputes the input area parameters of an input_view, attempting to
* center the cursor.
*/

#ifdef __STDC__
static void
iv_reset_input (struct input_view * this_iv)
#else
void
static iv_reset_input (this_iv)
struct input_view * this_iv;
#endif
{
char * km = desired_keymap_prompt (this_iv);
if (km && (km == keymap_prompt))
return;
redraw_needed = FULL_REDRAW;
keymap_prompt = km;
if (km)
{
/* A keymap prompt should be displayed. */
expanded_keymap_prompt = expand_prompt (keymap_prompt);
prompt_wid = prompt_metric (expanded_keymap_prompt,
strlen(expanded_keymap_prompt));
must_fix_input = 1;
visibility_begin = visibility_end = 0;
input_area = 0;
vis_wid = input_metric (" ", 1);
prompt = 0;
input_cursor = 0;
}
else
{
if (expanded_keymap_prompt)
{
ck_free (expanded_keymap_prompt);
expanded_keymap_prompt = 0;
}
if (!the_cmd_frame->cmd || the_cmd_arg.is_set || !the_cmd_arg.do_prompt)
{
prompt_wid = 0;
must_fix_input = 0;
input_area = 0;
vis_wid = 0;
prompt = 0;
visibility_begin = visibility_end = 0;
input_cursor = 0;
}
else
{
prompt_wid = prompt_metric (the_cmd_arg.expanded_prompt,
strlen (the_cmd_arg.expanded_prompt));
must_fix_input = 0;
input_area = &the_cmd_arg.text;
prompt = the_cmd_arg.expanded_prompt;

if ((scr_cols - prompt_wid) < input_metric ("M", 1))
prompt += find_vis_begin (&prompt_wid,
scr_cols - input_metric("M", 1),
prompt, strlen(prompt) - 1,
prompt_metric);

{
int wid_avail = scr_cols - prompt_wid;
visibility_begin =
find_vis_begin (0, wid_avail / 2, input_area->buf,
the_cmd_arg.cursor, input_metric);
visibility_end =
find_vis_end (0, wid_avail,
input_area->buf, visibility_begin,
input_metric);
}

input_cursor = the_cmd_arg.cursor;
set_vis_wid (this_iv);
}
}
}





/* This is called strategicly from the command loop and whenever
* the input area is changed by beginning a complex command.
* It may do nothing, though if the input area appeas to have changed
* it will recompute its appearence.
*
* now it also updates the info_fields of the input view.
*/

#ifdef __STDC__
void
iv_fix_input (struct input_view * this_iv)
#else
void
iv_fix_input (this_iv)
struct input_view * this_iv;
#endif
{
char * km_prompt = desired_keymap_prompt (this_iv);

if (keymap_prompt && (keymap_prompt == km_prompt))

must_fix_input = 1; /* Do nothing, keymap prompt has precedence */

else if (must_fix_input
|| (keymap_prompt != km_prompt)
|| ((the_cmd_frame->cmd
&& (the_cmd_arg.do_prompt && !the_cmd_arg.is_set))
? ((input_area != &the_cmd_arg.text)
|| (prompt != the_cmd_arg.expanded_prompt)
|| (input_cursor != the_cmd_arg.cursor))
: (input_area || prompt_wid)))
iv_reset_input (this_iv);

if (the_cmd_frame->cmd
&& ((the_cmd_arg.prompt_info != current_info)
|| (the_cmd_arg.info_line != info_pos)))
{
current_info = the_cmd_arg.prompt_info;
info_pos = the_cmd_arg.info_line;
info_redraw_needed = 1;
}
else if (current_info
&& (!the_cmd_frame->cmd || !the_cmd_arg.prompt_info))
{
current_info = 0;
io_repaint ();
}

}


/* Incremental updates:
* For simple edits it is not necessary to redraw the entire line.
* These schedule incremental updating.
*/


#ifdef __STDC__
void
iv_move_cursor (struct input_view * this_iv)
#else
void
iv_move_cursor (this_iv)
struct input_view * this_iv;
#endif
{
if ( must_fix_input
|| (visibility_begin > the_cmd_arg.cursor)
|| ( ((visibility_end + 1) < the_cmd_arg.cursor)
|| (((visibility_end + 1) == the_cmd_arg.cursor)
&& ((vis_wid + prompt_wid) < scr_cols))))

must_fix_input = 1;
else if (redraw_needed != FULL_REDRAW)
{
if ( (redraw_needed == NO_REDRAW)
|| ((redraw_needed > input_cursor)
&& (redraw_needed > the_cmd_arg.cursor)))
{
input_cursor = the_cmd_arg.cursor;
set_vis_wid (this_iv);
}
else
{
redraw_needed = Min (input_cursor, the_cmd_arg.cursor);
set_vis_wid (this_iv);
}
}
}

#ifdef __STDC__
void
iv_erase (struct input_view * this_iv, int len)
#else
void
iv_erase (this_iv, len)
struct input_view * this_iv;
int len;
#endif
{
if (must_fix_input
|| (the_cmd_arg.cursor <= visibility_begin))
{
must_fix_input = 1;
return;
}
else if (redraw_needed != FULL_REDRAW)
{
if ((redraw_needed == NO_REDRAW) || (redraw_needed > the_cmd_arg.cursor))
{
redraw_needed = the_cmd_arg.cursor;
visibility_end = find_vis_end (0, scr_cols - prompt_wid,
input_area->buf, visibility_begin,
input_metric);
input_cursor = the_cmd_arg.cursor;
}
else
redraw_needed = the_cmd_arg.cursor;
set_vis_wid (this_iv);
}
}


#ifdef __STDC__
void
iv_insert (struct input_view * this_iv, int len)
#else
void
iv_insert (this_iv, len)
struct input_view * this_iv;
int len;
#endif
{
if (!must_fix_input)
{
int new_end;
int cursor_past_end = (input_cursor + len == strlen (input_area->buf));

new_end = find_vis_end (0, scr_cols - prompt_wid,
input_area->buf, visibility_begin,
input_metric);

if ((new_end + cursor_past_end) < (input_cursor + len))
must_fix_input = 1;
else
{
if ( (redraw_needed != FULL_REDRAW)
&& ((redraw_needed == NO_REDRAW) || (redraw_needed > input_cursor)))
redraw_needed = input_cursor;
input_cursor += len;
visibility_end = new_end;
set_vis_wid (this_iv);
}
}
}

#ifdef __STDC__
void
iv_over (struct input_view * this_iv, int len)
#else
void
iv_over (this_iv, len)
struct input_view * this_iv;
int len;
#endif
{
iv_insert (this_iv, len);
}


oleo-1.3/info.c 644 722 0 7060 5356002770 11570 0ustar lordwheel/* Copyright (C) 1993 Free Software Foundation, Inc.

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, 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 software; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */

#include "global.h"
#include "info.h"
#include "hash.h"
#include "cmd.h"

struct hash_control * info_buffers;


#ifdef __STDC__
void
init_info (void)
#else
void
init_info ()
#endif
{
info_buffers = hash_new();
}

#ifdef __STDC__
struct info_buffer *
find_info (char * name)
#else
struct info_buffer *
find_info (name)
char * name;
#endif
{
return (struct info_buffer *)hash_find (info_buffers, name);
}


#ifdef __STDC__
struct info_buffer *
find_or_make_info (char * name)
#else
struct info_buffer *
find_or_make_info (name)
char * name;
#endif
{
struct info_buffer * buf =
(struct info_buffer *)hash_find (info_buffers, name);
if (buf)
return buf;

buf = ((struct info_buffer *)
ck_malloc (sizeof (struct info_buffer) + strlen(name) + 1));
buf->name = (char *)buf + sizeof (*buf);
strcpy (buf->name, name);
buf->len = 0;
buf->text = 0;
hash_insert (info_buffers, buf->name, buf);
return buf;
}

#ifdef __STDC__
void
clear_info (struct info_buffer * buf)
#else
void
clear_info (buf)
struct info_buffer * buf;
#endif
{
if (buf->text)
{
int x;
int stop = buf->len;
for (x = 0; x < stop; ++x)
ck_free (buf->text);
ck_free (buf->text);
}
buf->text = 0;
buf->len = 0;
}

#ifdef __STDC__
void
print_info (struct info_buffer * buf, char * format, ...)
#else
void
print_info (buf, format, va_alist)
struct info_buffer * buf;
char * format;
va_dcl
#endif
{
va_list ap;
char txt[1000];
int len; /* Length of the new line */

var_start (ap, format);
vsprintf (txt, format, ap);
va_end (ap);
len = strlen (txt);

++buf->len; /* Number of lines in the buffer */
buf->text = (char **)ck_remalloc (buf->text, buf->len * sizeof (char *));
buf->text[buf->len - 1] = (char *)ck_malloc (len + 1);
bcopy (txt, buf->text[buf->len - 1], len + 1);
}




/* A generic buffer for the use informational commands like show-options */
static struct info_buffer * the_text_buf;

#ifdef __STDC__
void
io_text_start (void)
#else
void
io_text_start ()
#endif
{
the_text_buf = find_or_make_info ("_text");
clear_info (the_text_buf);
}



#ifdef __STDC__
void
io_text_line (char * format, ...)
#else
void
io_text_line (format, va_alist)
char * format;
va_dcl
#endif
{
va_list ap;
char txt[1000];
int len; /* Length of the new line */

var_start (ap, format);
vsprintf (txt, format, ap);
va_end (ap);
len = strlen (txt);

++the_text_buf->len; /* Number of lines in the the_text_buf */
the_text_buf->text =
(char **)ck_remalloc (the_text_buf->text,
the_text_buf->len * sizeof (char *));
the_text_buf->text[the_text_buf->len - 1] = (char *)ck_malloc (len + 1);
bcopy (txt, the_text_buf->text[the_text_buf->len - 1], len + 1);
}

#ifdef __STDC__
void
io_text_finish (void)
#else
void
io_text_finish ()
#endif
{
run_string_as_macro ("{view-info _text}", 1);
}

oleo-1.3/help.c 644 722 0 20160 5356122530 11576 0ustar lordwheel/* Copyright (C) 1993 Free Software Foundation, Inc.

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, 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 software; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */

#include "global.h"
#include "cmd.h"
#include "key.h"
#include "info.h"
#include "forminfo.h"
#include "help.h"
#include "key.h"
#include "io-utils.h"

#ifndef alloca
#ifdef __GNUC__
#define alloca __builtin_alloca
#else /* __GNUC__ not defined. */
#if HAVE_ALLOCA_H
#include
#else /* not HAVE_ALLOCA_H */
#if defined (MSDOS) && !defined (__TURBOC__)
#include
#else /* not MSDOS, or __TURBOC__ */
#if defined(_AIX)
#include
#pragma alloca
#endif /* not _AIX */
#endif /* not MSDOS, or __TURBOC__ */
#endif /* not HAVE_ALLOCA_H */
#endif /* __GNUC__ not defined. */
#endif /* alloca not defined. */



/* This reads one info buffer, writing another. On each line,
* occurences of [COMMAND] are replaced with keysequence names,
* if COMMAND is bound.
*/

#ifdef __STDC__
void
expand_help_msg (struct info_buffer * out, struct info_buffer * in)
#else
void
expand_help_msg (out, in)
struct info_buffer * out;
struct info_buffer * in;
#endif
{
int x;
struct line line;
struct line seq_buf;
int out_offset;
int rel_map = cur_keymap;

if (the_cmd_frame->cmd && (the_cmd_arg.style == &keyseq_style))
rel_map = the_cmd_arg.val.key.cmd.code;

print_info (out, "");
out_offset = out->len;
out->len += in->len;
out->text = (char **)ck_remalloc (out->text, out->len * sizeof (char *));
init_line (&line);
init_line (&seq_buf);
for (x = 0; x < in->len; ++x)
{
char * next_burst = in->text[x];
char * end_burst = index (next_burst, '[');
set_line (&line, "");
set_line (&seq_buf, "");
while (end_burst)
{
char * fn_start = end_burst + 1;
char * fn_end = index (fn_start, ']');
int vec;
struct cmd_func * cmd;
if (fn_end && (*fn_start == '[') && fn_end[1] == ']')
{
int map = map_idn (fn_start + 1, fn_end - fn_start - 1);
if (map < 0)
map = map_id ("universal");
rel_map = map;
catn_line (&line, next_burst, end_burst - next_burst);
next_burst = fn_end + 2;
end_burst = index (next_burst, '[');
}
else if ( fn_end
&& !find_function (&vec, &cmd, fn_start, fn_end - fn_start))
{
if (search_map_for_cmd (&seq_buf, rel_map, vec,
cmd - the_funcs[vec]))
{
catn_line (&line, next_burst, end_burst - next_burst);
catn_line (&line, seq_buf.buf, strlen (seq_buf.buf));
set_line (&seq_buf, "");
next_burst = fn_end + 1;
end_burst = index (next_burst, '[');
}
else
{
catn_line (&line, "M-x ", 4);
catn_line (&line, fn_start, fn_end - fn_start);
next_burst = fn_end + 1;
end_burst = index (next_burst, '[');
}
}
else if (fn_end)
end_burst = index (fn_end + 1, '[');
}
catn_line (&line, next_burst, strlen(next_burst));
out->text[x + out_offset] = line.buf;
init_line (&line);
}
free_line (&seq_buf);
free_line (&line);
}




#ifdef __STDC__
void
describe_function (char * name)
#else
void
describe_function (name)
char * name;
#endif
{
int vector;
struct cmd_func * cmd;
if (!( !find_function (&vector, &cmd, name, strlen(name))
&& cmd->func_doc))
io_error_msg ("%s is not a function.", name); /* no return */

{
struct info_buffer * ib_disp = find_or_make_info ("help-buffer");
clear_info (ib_disp);
print_info (ib_disp, "");
print_info (ib_disp, "%s", name);
{
struct info_buffer ib;
for (ib.len = 0; cmd->func_doc[ib.len]; ++ib.len) ;
ib.text = cmd->func_doc;
ib.name = name;
expand_help_msg (ib_disp, &ib);
}
}

{
static char buf[] = "{view-info help-buffer}";
execute_as_macro (buf);
}
}



#ifdef __STDC__
void
brief_describe_key (struct key_sequence * keyseq)
#else
void
brief_describe_key (keyseq)
struct key_sequence * keyseq;
#endif
{
if (keyseq->cmd.vector < 0 && keyseq->cmd.code < 0)
io_info_msg ("%s is unbound", keyseq->keys->buf);
else
io_info_msg ("%s --> %s", keyseq->keys->buf,
the_funcs[keyseq->cmd.vector][keyseq->cmd.code].func_name);
}

#ifdef __STDC__
void
describe_key (struct key_sequence * keyseq)
#else
void
describe_key (keyseq)
struct key_sequence * keyseq;
#endif
{
if (keyseq->cmd.vector < 0 && keyseq->cmd.code < 0)
io_info_msg ("%s is unbound", keyseq->keys->buf);
else if (keyseq->cmd.vector < 0)
io_info_msg ("%s is a prefix leading to the keymap `%s'.",
keyseq->keys->buf, map_names[keyseq->cmd.code]);
else
describe_function
(the_funcs[keyseq->cmd.vector][keyseq->cmd.code].func_name);
}


#ifdef __STDC__
void
where_is (char * name)
#else
void
where_is (name)
char * name;
#endif
{
struct line seqname;
int vec;
int code;
struct cmd_func * cmd;

if (!find_function (&vec, &cmd, name, strlen(name)))
code = cmd - the_funcs[vec];
else if (map_id (name) >= 0)
{
code = map_id (name);
vec = -1;
}
else
io_error_msg ("%s is not a function.", name); /* no return */
code = cmd - the_funcs[vec];
init_line (&seqname);
set_line (&seqname, "");

if (!search_map_for_cmd (&seqname, the_cmd_frame->top_keymap, vec, code))
io_info_msg ("%s is not on any keys.", name);
else
io_info_msg ("%s is bound to %s.", name, seqname.buf);

free_line (&seqname);
}


/* Help for the context of the current complex command. */

#ifdef __STDC__
void
help_with_command (void)
#else
void
help_with_command ()
#endif
{
if (!the_cmd_frame->cmd)
io_info_msg ("help-with-command: No command is executing now.");
describe_function (the_cmd_frame->cmd->func_name);
}





/* Access to the help messages defined in forminfo.c
* These include documentation for formula functions and
* other miscelaneous doc strings.
*
* The info message NAME is permanently stored in an info-buffer
* called _info_NAME
*/

#ifdef __STDC__
void
builtin_help (char * name)
#else
void
builtin_help (name)
char * name;
#endif
{
char info_name[100];
struct info_buffer * ib;

if (strlen (name) < sizeof (info_name - 20))
io_error_msg ("No built in help for %s.", name);

sprintf (info_name, "_info_%s", name);
ib = find_info (info_name);

if (!ib)
{
char ** msg = forminfo_text (name);
if (!msg)
{
msg = (char **)ck_malloc (sizeof (char *) * 2);
msg[0] = mk_sprintf ("No built in help for %s.", name);
msg[1] = 0;
}
ib = find_or_make_info (info_name);
ib->len = parray_len (msg);
ib->text = msg;
}

{
char exp_name[200];
char command[250];
struct info_buffer * expanded;
sprintf (exp_name, "_expanded_%s", info_name);
expanded = find_or_make_info (exp_name);
clear_info (expanded);
expand_help_msg (expanded, ib);
sprintf (command, "{set-info %s}", exp_name);
execute_as_macro (command);
}
}

#ifdef __STDC__
void
make_wallchart_info (void)
#else
void
make_wallchart_info ()
#endif
{
struct info_buffer * wc = find_or_make_info ("unexpanded_wallchart");
struct info_buffer * wc_expanded = find_or_make_info ("wallchart");
if (wc->len == 0)
{
char ** txt = forminfo_text ("keybindings-wallchart");
if (!txt)
io_error_msg (" Wallchart is missing!");
wc->len = parray_len (txt);
wc->text = txt;
}
clear_info (wc_expanded);
expand_help_msg (wc_expanded, wc);
}


#ifdef __STDC__
void
write_info (char * info, FILE * fp)
#else
void
write_info (info, fp)
char * info;
FILE * fp;
#endif
{
struct info_buffer * ib = find_or_make_info (info);
int x;
for (x = 0; x < ib->len; ++x)
fprintf (fp, "%s\n", ib->text[x]);
}

oleo-1.3/graph.c 644 722 0 65462 5356020042 11760 0ustar lordwheel/* Copyright (C) 1993 Free Software Foundation, Inc.

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, 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 software; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */



#include
#include "global.h"
#include "graph.h"
#include "cmd.h"
#include "line.h"
#include "io-term.h"
#include "info.h"
#include "cell.h"
#include "regions.h"
#include "ref.h"
#include "io-utils.h"

/* Parameters for the next graph that will be drawn. */

/* This determines the type and destination of the ouput.
* It should be the argument to a `set term %s'. For posctscript graphs,
* we slip in a `set output %s' as well.
*/
static struct line graph_term_cmd;
static struct line graph_output_file;

#ifdef __STDC__
typedef void (*plotter) (void);
#else
typedef void (*plotter) ();
#endif

struct get_symbols_frame;
struct write_data_frame;
#ifdef __STDC__
static void get_symbols_thunk (struct get_symbols_frame * fr,
CELL * cell, CELLREF r, CELLREF c);
static void write_data_thunk (struct write_data_frame * fr,
CELL * y_cell, CELLREF r, CELLREF c) ;
static void spew_gnuplot (FILE * fp, struct line * data_files, char * dir,
char * dbase);
static void spew_for_x (void);
static void spew_for_ps (void);
#else
static void get_symbols_thunk ();
static void write_data_thunk ();
static void spew_gnuplot ();
static void spew_for_x ();
static void spew_for_ps ();
#endif

static plotter plot_fn = 0;

char * gnuplot_program = "gnuplot";
char * gnuplot_shell = "/bin/sh";
char * rm_program = "/bin/rm";

char * graph_axis_name [graph_num_axis] =
{
"x", "y"
};

char *
graph_order_name [graph_num_orders] =
{
"rows",
"columns",
};

char *graph_pair_order_name[graph_num_pair_orders] =
{
"rows of hz pairs",
"rows of vt pairs",
"enumerated rows",
"cols of hz pairs",
"cols of vt pairs",
"enumerated cols"
};

int graph_ornt_row_magic [graph_num_pair_orientations] = { 0, 1, 0 };
int graph_ornt_col_magic [graph_num_pair_orientations] = { 1, 0, 0 };


/* `set label %s' for each axis.
*/
static struct line graph_axis_title [graph_num_axis];

/* set logarithmic */
static int graph_logness [graph_num_axis];

/* Arguments to `set range [%s:%s]' */
static struct line graph_rng_lo [graph_num_axis];
static struct line graph_rng_hi [graph_num_axis];

/* The ranges (if any) of the symbolic names
* for integer coordinates starting at 0.
* If none, these will have lr == NON_ROW.
*/
static struct rng graph_axis_symbols [graph_num_axis];
static enum graph_ordering graph_axis_ordering [graph_num_axis];

/* Names to print along the axes */
static struct rng graph_axis_labels [graph_num_axis];
static enum graph_pair_ordering graph_axis_label_order [graph_num_axis];

/* Parameters for each dataset. */
#define NUM_DATASETS 10

/* plot .... with %s */
static struct line graph_style [NUM_DATASETS];
static struct line graph_title [NUM_DATASETS];
static struct rng graph_data [NUM_DATASETS];
static enum graph_pair_ordering graph_data_order [graph_num_axis];




#ifdef __STDC__
enum graph_axis
chr_to_axis (int c)
#else
enum graph_axis
chr_to_axis (c)
int c;
#endif
{
c = tolower (c);
switch (c)
{
case 'x':
return graph_x;
case 'y':
return graph_y;
}
io_error_msg ("Unkown graph-axis `%c' (try `x' or `y')", c);
return graph_x; /* not reached, actualy. */
}


#ifdef __STDC__
enum graph_ordering
chr_to_graph_ordering (int c)
#else
enum graph_ordering
chr_to_graph_ordering (c)
int c;
#endif
{
c = tolower (c);
switch (c)
{
case 'r':
return graph_rows;
case 'c':
return graph_cols;
}
io_error_msg ("Unknown cell ordering `%c' (try `r' or `c').", c);
return graph_rows; /* not reached */
}

#ifdef __STDC__
enum graph_pair_ordering
chrs_to_graph_pair_ordering (int pair, int dir)
#else
enum graph_pair_ordering
chrs_to_graph_pair_ordering (pair, dir)
int pair;
int dir;
#endif
{
int pair_offset;
pair = tolower (pair);
dir = tolower (dir);

switch (pair)
{
case 'h':
pair_offset = graph_hz;
break;
case 'v':
pair_offset = graph_vt;
break;
case 'i':
pair_offset = graph_implicit;
break;
default:
pair_offset = graph_implicit;
io_error_msg
("graph.c: invalid pair ording `%c' (wanted h, v, or i)", pair);
/* no deposit... */
}

return PAIR_ORDER(chr_to_graph_ordering (dir), pair_offset);
}

#ifdef __STDC__
char *
graph_quoted_str (char *str)
#else
char *
graph_quoted_str (str)
char *str;
#endif
{
static struct line buf;

set_line (&buf, "\"");
while (*str)
{
switch (*str)
{
case '"':
catn_line (&buf, "\\\"", 2);
break;
default:
catn_line (&buf, str, 1);
break;
}
++str;
}
catn_line (&buf, "\"", 1);
return buf.buf;
}



#ifdef __STDC__
void
graph_x11_mono (void)
#else
void
graph_x11_mono ()
#endif
{
set_line (&graph_term_cmd, "x11 # b/w");
set_line (&graph_output_file, "");
plot_fn = spew_for_x;
}


#ifdef __STDC__
void
graph_x11_color (void)
#else
void
graph_x11_color ()
#endif
{
set_line (&graph_term_cmd, "X11 # color");
set_line (&graph_output_file, "");
plot_fn = spew_for_x;
}


#ifdef __STDC__
void
graph_postscript (char * file, int kind, int spectrum, char * font, int pt_size)
#else
void
graph_postscript (file, kind, spectrum, font, pt_size)
char * file;
int kind;
int spectrum;
char * font;
int pt_size;
#endif
{
kind = tolower (kind);
spectrum = tolower (spectrum);
if (!index ("led", kind))
io_error_msg
("Incorrect postscript graph type %c (should be one of l, e, or c)",
kind);
if (!index ("mc", spectrum))
io_error_msg
("Incorrect postscript color type %c (should be either m or c)",
spectrum);
sprint_line (&graph_term_cmd,
"postscript %c %c %s %d # Postscript",
kind, spectrum, graph_quoted_str (font), pt_size);
set_line (&graph_output_file, file);
plot_fn = spew_for_ps;
}



#ifdef __STDC__
void
graph_set_axis_title (int axis_c, char * title)
#else
void
graph_set_axis_title (axis_c, title)
int axis_c;
char * title;
#endif
{
enum graph_axis axis = chr_to_axis (axis_c);
set_line (&graph_axis_title [axis], graph_quoted_str (title));
}

#ifdef __STDC__
void
graph_set_logness (int axis_c, int explicit, int newval)
#else
void
graph_set_logness (axis_c, explicit, newval)
int axis_c;
int explicit;
int newval;
#endif
{
enum graph_axis axis = chr_to_axis (axis_c);
static struct line msg_buf;

if (!explicit)
newval = !graph_logness [axis];
else
newval = (newval > 0);

graph_logness [axis] = newval;
sprint_line (&msg_buf, "%slogarithmic %s%s",
((graph_logness [graph_x] || graph_logness [graph_y])
? "" : "no"),
graph_logness [graph_x] ? "x" : "",
graph_logness [graph_y] ? "y" : "");
io_info_msg ("set %s", msg_buf.buf);
}

#ifdef __STDC__
void
graph_check_range (char * val)
#else
void
graph_check_range (val)
char * val;
#endif
{
if (says_default (val))
return;
while (isspace (*val)) ++val;
if (*val == '-') ++val;
while (isspace (*val)) ++val;
if (!isdigit (*val))
io_error_msg
("Illegal range specifier %s (should be a numer or `def').", val);
else
{
while (*val)
if (isspace (*val) || isdigit (*val))
++val;
else
break;
while (isspace (*val)) ++val;
if (*val == '.') ++val;
while (*val)
if (isspace (*val) || isdigit (*val))
++val;
else
io_error_msg
("Illegal range specifier %s (should be a numer or `def').", val);
}

}


#ifdef __STDC__
void
graph_set_axis_lo (int axis_c, char * val)
#else
void
graph_set_axis_lo (axis_c, val)
int axis_c;
char * val;
#endif
{
enum graph_axis axis = chr_to_axis (axis_c);
graph_check_range (val);
set_line (&graph_rng_lo [axis], val);
graph_axis_symbols [axis].lr = NON_ROW;
}


#ifdef __STDC__
void
graph_set_axis_hi (int axis_c, char * val)
#else
void
graph_set_axis_hi (axis_c, val)
int axis_c;
char * val;
#endif
{
enum graph_axis axis = chr_to_axis (axis_c);
graph_check_range (val);
set_line (&graph_rng_hi [axis], val);
graph_axis_symbols [axis].lr = NON_ROW;
}

#ifdef __STDC__
void
graph_set_axis_symbolic (int axis_c, struct rng * rng, int ordering_c)
#else
void
graph_set_axis_symbolic (axis_c, rng, ordering_c)
int axis_c;
struct rng * rng;
int ordering_c;
#endif
{
enum graph_axis axis = chr_to_axis (axis_c);
enum graph_ordering ordering = chr_to_graph_ordering (ordering_c);
int top = (rng->hr - rng->lr + 1) * (rng->hc - rng->lc + 1) - 1;
char buf [64];

sprintf (buf, "%d.5", top);
graph_set_axis_lo (axis, "-0.5");
graph_set_axis_hi (axis, buf);
graph_axis_symbols [axis] = *rng;
graph_axis_ordering [axis] = ordering;
}

#ifdef __STDC__
void
graph_set_axis_labels (int axis_c, struct rng * rng, int pair, int dir)
#else
void
graph_set_axis_labels (axis_c, rng, dir, pair)
int axis_c;
struct rng * rng;
int pair;
int dir;
#endif
{
enum graph_pair_ordering order = chrs_to_graph_pair_ordering (pair, dir);
enum graph_axis axis = chr_to_axis (axis_c);
graph_axis_labels [axis] = *rng;
graph_axis_label_order [axis] = order;
}

#ifdef __STDC__
void
graph_default_axis_labels (int axis_c)
#else
void
graph_default_axis_labels (axis_c)
int axis_c;
#endif
{
enum graph_axis axis = chr_to_axis (axis_c);
graph_axis_labels [axis].lr = NON_ROW;
}



static char * graph_plot_styles [] =
{
"lines",
"points",
"linespoints",
"impulses",
"dots",
0
};

#ifdef __STDC__
int
graph_check_style (char * name)
#else
int
graph_check_style (name)
char * name;
#endif
{
int x =
words_member (graph_plot_styles, parray_len (graph_plot_styles), name);
if (x < 0)
io_error_msg
("Invalid line style %s. (Try M-x describe-function set-graph-style).");
return x;
}


#ifdef __STDC__
void
graph_set_style (int data_set, char * style)
#else
void
graph_set_style (data_set, style)
int data_set;
char * style;
#endif
{
int x = graph_check_style (style);
if ((data_set < 0) || (data_set >= NUM_DATASETS))
io_error_msg
("set-graph-style -- data-set out of range: %d (should be in [0..%d])",
data_set, NUM_DATASETS);
set_line (&graph_style [data_set], graph_plot_styles [x]);
}

#ifdef __STDC__
void
graph_set_data_title (int data_set, char * title)
#else
void
graph_set_data_title (data_set, title)
int data_set;
char * title;
#endif
{
if ((data_set < 0) || (data_set >= NUM_DATASETS))
io_error_msg
("set-graph-title -- data-set out of range: %d (should be in [0..%d])",
data_set, NUM_DATASETS);
set_line (&graph_title [data_set], title);
}

#ifdef __STDC__
void
graph_set_data (int data_set, struct rng * rng, int pair, int dir)
#else
void
graph_set_data (data_set, rng, pair, dir)
int data_set;
struct rng * rng;
int pair;
int dir;
#endif
{
enum graph_pair_ordering order = chrs_to_graph_pair_ordering (pair, dir);
if ((data_set < 0) || (data_set >= NUM_DATASETS))
io_error_msg
("set-graph-data -- data-set out of range: %d (should be in [0..%d])",
data_set, NUM_DATASETS);
graph_data [data_set] = *rng;
graph_data_order [data_set] = order;
}




#ifdef __STDC__
void
graph_presets (void)
#else
void
graph_presets ()
#endif
{
if (using_curses)
graph_postscript ("#plot.ps", 'd', 'm', "TimesRoman", 12);
else
graph_x11_mono ();
{
enum graph_axis axis;
for (axis = graph_x; axis < graph_num_axis; ++axis)
{
int axis_c = graph_axis_name [axis][0];
graph_logness [axis] = 0;
graph_set_axis_title (axis_c, "");
graph_set_axis_lo (axis_c, "def");
graph_set_axis_hi (axis_c, "def");
graph_set_axis_title (axis_c, "");
graph_default_axis_labels (axis_c);
}
}
}





#ifdef __STDC__
void
graph_clear_datasets (void)
#else
void
graph_clear_datasets ()
#endif
{
int x;
for (x = 0; x < NUM_DATASETS; ++x)
{
graph_set_style (x, "lines");
graph_set_data_title (x, "");
graph_data [x].lr = NON_ROW;
}
}


#ifdef __STDC__
void
init_graphing (void)
#else
void
init_graphing ()
#endif
{
gnuplot_program = getenv ("GNUPLOT_PROG");
if (!gnuplot_program)
gnuplot_program = "gnuplot";
gnuplot_shell = getenv ("GNUPLOT_SHELL");
if (!gnuplot_shell)
gnuplot_shell = "/bin/sh";
rm_program = getenv ("RM_PROG");
if (!rm_program)
rm_program = "/bin/rm";
graph_presets ();
graph_clear_datasets ();
}


#ifdef __STDC__
void
graph_make_info (void)
#else
void
graph_make_info ()
#endif
{
struct info_buffer * ib = find_or_make_info ("graphing-parameters");
enum graph_axis axis;

clear_info (ib);

{
print_info
(ib,
"");
print_info
(ib,
"Parameter Value");
print_info
(ib,
"");

print_info
(ib,
"output type %s",
graph_term_cmd.buf);
}

if (graph_output_file.buf[0])
print_info
(ib,
"output file %s",
graph_output_file.buf);

for (axis = graph_x; axis <= graph_y; ++axis)
print_info
(ib,
"%s-axis title %s",
graph_axis_name [axis], graph_axis_title[axis].buf);

{
print_info
(ib,
"logarithmic axes %s",
(graph_logness [graph_x]
? (graph_logness [graph_y] ? "x,y" : "x")
: (graph_logness [graph_y] ? "y" : "-neither-")));

}
for (axis = graph_x; axis <= graph_y; ++axis)
{
if (graph_axis_symbols[axis].lr != NON_ROW)
print_info
(ib,
"%s-axis symbols %s in %s",
graph_axis_name [axis],
graph_order_name [graph_axis_ordering [axis]],
range_name (&graph_axis_symbols [axis]));
else
print_info
(ib,
"%s-axis range [%s..%s]",
graph_axis_name [axis],
graph_rng_lo [axis].buf, graph_rng_hi [axis].buf,
graph_rng_hi [axis].buf, graph_rng_hi [axis].buf);
}

for (axis = graph_x; axis <= graph_y; ++axis)
{
if (graph_axis_labels[axis].lr != NON_ROW)
print_info
(ib,
"%s-axis labels %s in %s",
graph_axis_name [axis],
graph_pair_order_name [graph_axis_label_order [axis]],
range_name (&graph_axis_labels [axis]));
}

{
int x;
for (x = 0; x < NUM_DATASETS; ++x)
if (graph_data [x].lr != NON_ROW)
{
print_info (ib, "");
print_info (ib,"Data Set %d%s%s",
x,
graph_title[x].buf[0] ? " entitled " : "",
graph_title[x].buf);
print_info (ib," data for this set: %s in %s",
graph_pair_order_name [graph_data_order [x]],
range_name (&graph_data[x]));
print_info (ib," style for this set: %s",
graph_style[x].buf);
print_info (ib,"");
}
}
}



#ifdef __STDC__
static FILE *
mk_tmp_file (struct line * line, char * dir, char * base)
#else
static FILE *
mk_tmp_file (line, dir, base)
struct line * line;
char * dir;
char * base;
#endif
{
set_line (line, tempnam (dir, base));
return fopen (line->buf, "w");
}


#ifdef __STDC__
void
for_pairs_in (struct rng * rng, enum graph_pair_ordering order, fpi_thunk thunk, void * frame)
#else
void
for_pairs_in (rng, order, thunk, frame)
struct rng * rng;
enum graph_pair_ordering order;
fpi_thunk thunk;
void * frame;
#endif
{
CELLREF r;
CELLREF c;
enum graph_pair_orientation ornt = order % graph_num_pair_orientations;
enum graph_ordering dir = ORDER_OF_PAIRS(order);
int r_inc = 1 + graph_ornt_row_magic [ornt];
int c_inc = 1 + graph_ornt_col_magic [ornt];
if (dir == graph_rows)
{
r = rng->lr;
while (1)
{
c = rng->lc;
while (1)
{
CELLREF y_r = r + graph_ornt_row_magic [ornt];
CELLREF y_c = c + graph_ornt_col_magic [ornt];
CELL * cell = find_cell (y_r, y_c);
thunk (frame, cell, y_r, y_c);
if ((rng->hc - c) < c_inc)
break;
c += c_inc;
}
if ((rng->hr - r) < r_inc)
break;
r += r_inc;
}
}
else
{
c = rng->lc;
while (1)
{
r = rng->lr;
while (1)
{
CELLREF y_r = r + graph_ornt_row_magic [ornt];
CELLREF y_c = c + graph_ornt_col_magic [ornt];
CELL * cell = find_cell (y_r, y_c);
thunk (frame, cell, y_r, y_c);
if ((rng->hr - r) < r_inc)
break;
r += r_inc;
}
if ((rng->hc - c) < c_inc)
break;
c += c_inc;
}
}
}

struct write_tics_frame
{
FILE * fp;
enum graph_axis axis;
enum graph_pair_orientation ornt;
int tic_cnt;
};

#ifdef __STDC__
static void
write_tics_thunk (struct write_tics_frame * fr, CELL * cp, CELLREF r, CELLREF c)
#else
static void
write_tics_thunk (fr, cp, r, c)
struct write_tics_frame * fr;
CELL * cp;
CELLREF r;
CELLREF c;
#endif
{
char * str = graph_quoted_str (print_cell (cp));
if (fr->tic_cnt)
fputs (", ", fr->fp);
fprintf (fr->fp, "%s ", str);
if (fr->ornt == graph_implicit)
fprintf (fr->fp, "%d", fr->tic_cnt);
else
{
CELLREF x_r = r - graph_ornt_row_magic [fr->ornt];
CELLREF x_c = c - graph_ornt_col_magic [fr->ornt];

fprintf (fr->fp, "%s", print_cell (find_cell (x_r, x_c)));
}
++fr->tic_cnt;
}


#ifdef __STDC__
static void
write_tics_command (FILE * fp, enum graph_axis axis, struct rng * rng, enum graph_pair_ordering order)
#else
static void
write_tics_command (fp, axis, rng, order)
FILE * fp;
enum graph_axis axis;
struct rng * rng;
enum graph_pair_ordering order;
#endif
{
struct write_tics_frame fr;
fr.fp = fp;
fr.axis = axis;
fr.tic_cnt = 0;
fr.ornt = order % graph_num_pair_orientations;
fprintf (fp, "set %stics (", graph_axis_name[axis]);
for_pairs_in (rng, order, (fpi_thunk)write_tics_thunk, &fr);
fputs (")\n", fp);
}

struct get_symbols_frame
{
int symbols;
char ** names;
};

#ifdef __STDC__
static void
get_symbols_thunk (struct get_symbols_frame * fr,
CELL * cell, CELLREF r, CELLREF c)
#else
static void
get_symbols_thunk (fr, cell, r, c)
struct get_symbols_frame * fr;
CELL * cell;
CELLREF r;
CELLREF c;
#endif
{
fr->names = (char **)ck_realloc (fr->names,
(fr->symbols + 1) * sizeof (char *));
fr->names [fr->symbols] = ck_savestr (print_cell (cell));
++fr->symbols;
}


struct write_data_frame
{
FILE * fp;
enum graph_pair_ordering ornt;
int data_cnt;
struct get_symbols_frame gsf;
};

#ifdef __STDC__
static void
write_data_thunk (struct write_data_frame * fr,
CELL * y_cell, CELLREF r, CELLREF c)
#else
static void
write_data_thunk (fr, y_cell, r, c)
struct write_data_frame * fr;
CELL * y_cell;
CELLREF r;
CELLREF c;
#endif
{
if (!y_cell || !GET_TYP(y_cell))
return;
if (fr->ornt == graph_implicit)
fprintf (fr->fp, "%d ", fr->data_cnt);
else
{
CELLREF x_r = r - graph_ornt_row_magic [fr->ornt];
CELLREF x_c = c - graph_ornt_col_magic [fr->ornt];
CELL * x_cell = find_cell (x_r, x_c);
if (x_cell && GET_TYP(x_cell))
{
if (graph_axis_symbols [graph_x].lr == NON_ROW)
fprintf (fr->fp, "%s ", print_cell (x_cell));
else
{
char * key = print_cell (x_cell);
int x;
for (x = 0; x < fr->gsf.symbols; ++x)
if (stricmp (key, fr->gsf.names[x]))
{
fprintf (fr->fp, "%d ", x);
break;
}
}
}
}
fprintf (fr->fp, " %s\n", print_cell (y_cell));
++fr->data_cnt;
}


#ifdef __STDC__
static void
spew_gnuplot (FILE * fp, struct line * data_files, char * dir, char * dbase)
#else
static void
spew_gnuplot (fp, data_files, dir, dbase)
FILE * fp;
struct line * data_files;
char * dir;
char * dbase;
#endif
{
fprintf (fp, "set terminal %s\n", graph_term_cmd.buf);
fprintf (fp, "set output %s\n",
(graph_output_file.buf[0]
? graph_quoted_str (graph_output_file.buf)
: ""));

{
enum graph_axis axis;
for (axis = graph_x; axis <= graph_y; ++axis)
{
fprintf (fp, "set %slabel %s\n", graph_axis_name[axis],
(graph_axis_title[axis].buf[0]
? graph_axis_title[axis].buf
: ""));

fprintf (fp, "set %srange [%s:%s]\n",
graph_axis_name [axis],
(says_default (graph_rng_lo [axis].buf)
? ""
: graph_rng_lo[axis].buf),
(says_default (graph_rng_hi [axis].buf)
? ""
: graph_rng_hi[axis].buf));
if ( (graph_axis_symbols [axis].lr != NON_ROW)
&& (graph_axis_labels [axis].lr == NON_ROW))
write_tics_command (fp, axis, &graph_axis_symbols [axis],
PAIR_ORDER(graph_axis_ordering[axis],
graph_implicit));
else if (graph_axis_labels [axis].lr != NON_ROW)
write_tics_command (fp, axis,
&graph_axis_labels [axis],
graph_axis_label_order [axis]);
else
fprintf (fp, "set %stics\n", graph_axis_name [axis]);
}
if (!(graph_logness[graph_x] && graph_logness[graph_y]))
fprintf (fp, "set nolog %s%s\n",
graph_logness[graph_x] ? "" : "x",
graph_logness[graph_y] ? "" : "y");

if (graph_logness[graph_x] || graph_logness[graph_y])
fprintf (fp, "set log %s%s\n",
graph_logness[graph_x] ? "x" : "",
graph_logness[graph_y] ? "y" : "");
}
{
int need_comma = 0;
int x;
fprintf (fp, "plot ");
for (x = 0; x < NUM_DATASETS; ++x)
{
init_line (&data_files [x]);
if (graph_data [x].lr != NON_ROW)
{
FILE * df = mk_tmp_file (&data_files [x], dir, dbase);
struct write_data_frame wdf;
if (!df)
{
/* a small core leak here... */
io_error_msg ("Error opening temp file `%s' for graph data.",
data_files [x].buf);
}
wdf.fp = df;
wdf.ornt = graph_data_order [x] % graph_num_pair_orientations;
wdf.data_cnt = 0;
wdf.gsf.symbols = 0;
wdf.gsf.names = 0;
if (graph_axis_symbols [graph_x].lr != NON_ROW)
for_pairs_in (&graph_axis_symbols [graph_x],
PAIR_ORDER (graph_axis_ordering [graph_x],
graph_implicit),
(fpi_thunk)get_symbols_thunk,
&wdf.gsf);
for_pairs_in (&graph_data [x], graph_data_order [x],
(fpi_thunk)write_data_thunk, &wdf);
if (graph_axis_symbols [graph_x].lr != NON_ROW)
{
int x;
for (x = 0; x < wdf.gsf.symbols; ++x)
free (wdf.gsf.names[x]);
ck_free (wdf.gsf.names);
}
fprintf (fp, "%s %s %s with %s",
need_comma ? "," : "",
graph_quoted_str (data_files [x].buf),
graph_title [x].buf,
graph_style [x].buf);
need_comma = 1;
fclose (df);
}
}
fprintf (fp, "\n");
}
}


#ifdef __STDC__
static void
graph_spew_with_parameters (struct line * shell_script, struct line *
gp_script, char * last_cmd, char * dir, char *
dbase, char * gbase, char * sbase, int run_gnuplot)
#else
static void
graph_spew_with_parameters (shell_script, gp_script, last_cmd, dir, dbase,
gbase, sbase, run_gnuplot)
struct line * shell_script;
struct line * gp_script;
char * last_cmd;
char * dir;
char * dbase;
char * gbase;
char * sbase;
int run_gnuplot;
#endif
{
struct line data_files [NUM_DATASETS];
FILE * fp;
fp = mk_tmp_file (gp_script, dir, gbase);
if (!fp)
{
/* coreleak filename */
io_error_msg ("Error opening tmp file `%s' for plot script.",
gp_script->buf);
}
spew_gnuplot (fp, data_files, dir, dbase);
if (last_cmd)
fputs (last_cmd, fp);
if (sbase)
{
FILE * shfp;
init_line (shell_script);
shfp = mk_tmp_file (shell_script, dir, sbase);
fprintf (shfp, "#!%s\n", gnuplot_shell);
fputs ("\n", shfp);
if (run_gnuplot)
fprintf (shfp, "%s %s\n", gnuplot_program, gp_script->buf);
fprintf (shfp, "%s %s %s ",
rm_program, gp_script->buf, shell_script->buf);
{
int x;
for (x = 0; x < NUM_DATASETS; ++x)
if (data_files[x].buf)
fprintf (shfp, "%s ", data_files [x].buf);
}
fputs ("\n", shfp);
fclose (shfp);
}
fclose (fp);
}


static FILE * pipe_to_gnuplot = 0;
static char * cleanup_script = 0;
static char * gnuplot_script = 0;

#ifdef __STDC__
static void death_to_gnuplot (void);
#else
static void death_to_gnuplot ();
#endif

#ifdef __STDC__
static void
gnuplot_exception (int fd)
#else
static void
gnuplot_exception (fd)
int fd;
#endif
{
death_to_gnuplot ();
}

#ifdef __STDC__
static void
gnuplot_writable (int fd)
#else
static void
gnuplot_writable (fd)
int fd;
#endif
{
FD_CLR (fd, &write_fd_set);
file_write_hooks [fd].hook_fn = 0;
fprintf (pipe_to_gnuplot, "\n\nload %s\n", graph_quoted_str (gnuplot_script));
fflush (pipe_to_gnuplot);
}

#ifdef __STDC__
static void
ensure_gnuplot_pipe (void)
#else
static void
ensure_gnuplot_pipe ()
#endif
{
if (!pipe_to_gnuplot)
{
pipe_to_gnuplot = popen (gnuplot_program, "w");
if (!pipe_to_gnuplot)
io_error_msg ("Can't popen gnuplot.");
}
if (gnuplot_script)
{
file_write_hooks [fileno (pipe_to_gnuplot)].hook_fn = gnuplot_writable;
file_exception_hooks [fileno (pipe_to_gnuplot)].hook_fn = gnuplot_exception;
FD_SET (fileno (pipe_to_gnuplot), &write_fd_set);
FD_SET (fileno (pipe_to_gnuplot), &exception_fd_set);
}
}

#ifdef __STDC__
static void
death_to_gnuplot (void)
#else
static void
death_to_gnuplot ()
#endif
{
if (pipe_to_gnuplot)
{
int fd = fileno (pipe_to_gnuplot);
file_write_hooks [fd].hook_fn = 0;
file_exception_hooks [fd].hook_fn = 0;
FD_CLR (fd, &write_fd_set);
FD_CLR (fd, &exception_fd_set);
pclose (pipe_to_gnuplot);
}
pipe_to_gnuplot = 0;
if (cleanup_script)
system (cleanup_script);
if (cleanup_script)
ck_free (cleanup_script);
if (gnuplot_script)
ck_free (gnuplot_script);
}





#ifdef __STDC__
static void
spew_for_x (void)
#else
static void
spew_for_x ()
#endif
{
struct line shell_script;
struct line gp_script;
init_line (&shell_script);
init_line (&gp_script);
graph_spew_with_parameters (&shell_script, &gp_script, "pause -1\n", 0,
"#data", "#plot", "#sh", 0);
splicen_line (&shell_script, " ", 1, 0);
splicen_line (&shell_script, gnuplot_shell, strlen (gnuplot_shell), 0);
if (cleanup_script)
{
system (cleanup_script);
free (cleanup_script);
}
cleanup_script = shell_script.buf;
if (gnuplot_script)
free (gnuplot_script);
gnuplot_script = gp_script.buf;
ensure_gnuplot_pipe ();
}

#ifdef __STDC__
static void
spew_for_ps (void)
#else
static void
spew_for_ps ()
#endif
{
struct line shell_script;
struct line gp_script;
init_line (&shell_script);
graph_spew_with_parameters (&shell_script, &gp_script, 0, "", "#data",
"#plot", "#sh", 1);
splicen_line (&shell_script, " ", 1, 0);
splicen_line (&shell_script, gnuplot_shell, strlen (gnuplot_shell), 0);
system (shell_script.buf);
free_line (&shell_script);
free_line (&gp_script);
}

#ifdef __STDC__
void
graph_plot (void)
#else
void
graph_plot ()
#endif
{
plot_fn ();
}

oleo-1.3/forminfo.c 644 722 0 75161 5356010551 12477 0ustar lordwheel/* Copyright (C) 1993 Free Software Foundation, Inc.

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, 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 software; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */


#include "sysdef.h"
#include "forminfo.h"

char * formula_info[] =
{
/* Syntax advice */
"*number-syntax*",
"Numbers must be entered in 'general' format:",
" [-]digits[.digits][e[-]digits]",
0,
"*string-syntax*",
"Strings are entered surrounded by double-quotes. To include unusual",
"characters, you can either quote them with backslash ",
"(e.g. \"a \\\"quoted\\\" quote\") use \\nnn where nnn is the octal code for",
"the character you want to include. ",
0,
"*expression-syntax*",
" Infix expressions:",
"",
"- num 0-num",
"! bool #TRUE if bool is #FALSE",
" #FALSE if bool is #TRUE, error otherwise.",
"",
"num1 ^ num2 Exponentiation This is *right* associative!",
"num1 * num2 Multiplication Note that these functions are not as",
"num1 / num2 Division good as they should be at detecting",
"int1 % int2 Modulus overflow. There *is* code that should",
"",
"num1 + num2 Addition force integer expressions to become",
"num1 - num2 subtraction floating-point if the result wouldn't",
" fit in an integer.",
"num1 >= num2 Arithmatic greater-or-equal",
"num1 > num2 greater-than",
"num1 < num2 less-than",
"num1 <= num2 less-than-or-equal",
"",
"val1 = val2 #TRUE if val1 and val2 can be considered equal.",
" #FALSE otherwise",
"val1 != val2 Equivelent to !(val1=val2)",
"",
"str1 & str2 Text concatination.",
"",
"bool ? val1 : val2 if(bool==#TRUE)",
" evaluate val1",
" else if(bool!=#FALSE)",
" error...",
" else",
" evaluate val2.",
"",
"(val) (To override default precedence) Note that since oleo",
" stores expressions in a byte-compiled form, excess",
" parens will mysteriously vanish.",
0,


/* Error values. */

"#TRUE",
"The logical TRUE value",
0,
"#FALSE",
"The logical FALSE value",
0,
"#ERROR",
"An unclassified error.",
0,
"#BAD_INPUT",
"Indicates an inappropriate parameter to a formula function.",
0,
"#NON_NUMBER",
"An error value.",
0,
"#NON_STRING",
"An error value.",
0,
"#NON_BOOL",
"An error value.",
0,
"#NON_RANGE",
"An error value.",
0,
"#OUT_OF_RANGE",
"An error value.",
0,
"#NO_VALUES",
"An error value.",
0,
"#DIV_BY_ZERO",
"An error value.",
0,
"#BAD_NAME",
"An error value that indicates an invalid variable name. ",
"It may be the symptom of an incorrectly written address.",
0,
"#NOT_AVAIL",
"An error value.",
0,
"#PARSE_ERROR",
"An error value.",
0,
"#NEED_OPEN",
"An error value that indicates a missing open parenthesis.",
0,
"#NEED_CLOSE",
"An error value that indicates a missing close parenthesis.",
0,
"#NEED_QUOTE",
"An error value.",
0,
"#UNK_CHAR",
"An error value.",
0,
"#UNK_FUNC",
"An error value.",
0,
"#INF",
"An error value.",
"On some machines this may be indistinguishable from other values.",
0,
"#INFINITY",
"An error value.",
"On some machines this may be indistinguishable from other values.",
0,
"#NAN",
"An error value.",
"On some machines this may be indistinguishable from other values.",
0,
"#NOT_A_NUMBER",
"An error value.",
"On some machines this may be indistinguishable from other values.",
0,
"#NINF",
"An error value.",
"On some machines this may be indistinguishable from other values.",
0,
"#MINUS_INFINITY",
"An error value.",
"On some machines this may be indistinguishable from other values.",
0,



/* Functions releated to boolean values. */

"if",
"Conditional operator if(bool,val1,val2)",
"",
"If BOOL is #TRUE, the value is VAL1;",
"if BOOL is #FALSE, the value is VAL2;",
"if BOOL is neither #TRUE or #FALSE, then the value is #NON_BOOL",
0,
"and",
"Boolean operator and(bool1,bool2)",
"",
"If both BOOL1 and BOOL2 are #TRUE, the value is #TRUE;",
"otherwise, if both are boolean values, the value is #FALSE;",
"otherwise, the value is #NON_BOOL.",
0,
"or",
"Boolean operator or(bool1,bool2)",
"",
"If both BOOL1 and BOOL2 are booleans, then the value is #TRUE if either",
"argument is #TRUE, and #FALSE if both are #FALSE.",
"If either argument is not a boolean, the value is #NON_BOOL.",
0,
"not",
"Boolean operator not(bool)",
"",
"#TRUE if BOOL is #FALSE,",
"#FALSE if BOOL is #TRUE, ",
"and otherwise, #NON_BOOL.",
0,
"iserr",
"Error predicate iserr(val)",
"",
"#TRUE if the VAL is an error, otherwise #FALSE",
0,
"isnum",
"Number predicate isnum(val)",
"",
"#TRUE if the VAL is a number, or can be automatically converted to a number.",
"Thus `isnum(\"12\")' is #TRUE, while `isnum(\"dsfjbk\") is #FALSE.",
0,


/* Functions that reflect the structure of the spreadsheet. */
"row",
"A cell's row address row()",
"",
"The row number of the cell the expression is in.",
0,
"col",
"A cell's column address col()",
"",
"The column number of the cell the expression is in.",
0,
"rows",
"Rows in a range rows(rng)",
"",
"The number of rows in RNG.",
0,
"cols",
"Columns in a range cols(rng)",
"",
"The number of columns in RNG.",
0,
"my",
"Cell reflection my(str)",
"",
"The function `my' returns information about the cell containing the formula.",
"The argument STR is a key to say what should be returned. Valid arguments are:",
"",
" KEY RETURNS",
"",
"row row address (as an integer)",
"column column address (as an integer)",
"width width, (as an integer)",
"lock \"locked\" or \"unlocked\"",
"protection (this is a synonym for \"lock\")",
"justify \"left\", \"right\", \"center\" or \"default\"",
"alignment (this is a synonym for \"justify\")",
"format \"default\", \"user-1\", etc.",
"fmt (this is a synonym for \"format\")",
"type \"error\", \"boolean\", \"float\",\"integer\", \"null\", \"Unknown\", etc.",
"formula A string of the cell's current formula.",
"value The cells current value.",
"anything-else error--> #BAD_INPUT",
0,
"curcell",
"Reflection on the current cell curcell(str)",
"",
"Curcell takes the same arguments as `my', but returns information about the ",
"current location of the cell-cursor, instead of the cell containing this",
"formula.",
"",
"Curcell is updated on a timer interrupt.",
0,
"cell",
"General cell reflection cell(row,col,str)",
"",
"`Cell' takes a ROW and COL address, and a STR that is like an argument to `my'.",
"It returns information about the cell at ROW,COL.",
0,
"member",
"Search for values member(rng,val)",
"",
"Returns the index of the first cell in RNG that contains VAL, or zero",
"if no cells contain it. It is permissable for VAL to be an error",
"value.",
0,
"smember",
"Search for a substring smember(rng,str)",
"",
"Returns the index of the first cell in RNG that contains STR as a substr.",
"Returns 0 if no cells match. If STR is empty, then it matches an",
"empty cell (see also `members').",
0,
"members",
"Search for a substring members(rng,str)",
"",
"Returns the index of the first cell in RNG that contains STR as a substr.",
"Returns 0 if no cells match. This function will never return the",
"address of an empty cell, but see `smember'.",
0,
"pmember",
"Search for an initial substring pmember(rng,str)",
"",
"Returns the index of the first cell in RNG whose value equals the",
"first few characters of STR. If STR is empty, an empty cell may be",
"matched (but see `memberp').",
0,
"memberp",
"Search for an initial substring memberp(rng,str)",
"",
"Returns the index of the first cell in RNG whose value equals the",
"first few characters of STR. This function will never return the",
"address of an empty cell, but see `pmember'.",
0,
"hlookup",
"Number-keyed table lookup hlookup(rng,num,int)",
"",
"Scan through the top row of RANGE looking for a number which is",
"greater than NUM. Then return the value in the cell that is INT rows",
"down from the top of the range.",
0,
"vlookup",
"Number-Keyed table lookup vlookup(rng,num,int)",
"",
"Scan through the left col of RANGE looking for a number which is",
"greater than NUM. Then return the value in the cell that is INT cols",
"over from the left edge of the range.",
0,
"vlookup_str",
"String-keyed table lookup vlookup_str(rng,str,num)",
"",
"Scan through the left col of RANGE looking for a cell that contains",
"STR. Then return the value in the cell that is INT columns over from",
"the left edge of the range.",
0,
"now",
"Time of day now()",
"",
"The current time in seconds since Jan 1 1970.",
0,

"ctime",
"The current time of day ctime(num)",
"",
"Convert NUM into a readable date/time string.",
"NUM should be seconds since the epoch; as returned by `now()' for example.",
0,
"index",
"Table lookup index(rng,x), index(rng,relrow,relcol)",
"",
"In the first form, the contents of a cell in RNG, at offset X. The lookup is",
"in the first column (though it may wrap to other columns).",
"",
"In the second form, the contents of a cell in RNG, RELROW rows and RELCOL",
"columns from the upper left corner of the range.",
0,



/* General arithmetic*/

"abs",
"Absolute value abs(num)",
"",
"The absolute value of NUM.",
0,
"int",
"Convesion to integer int(num)",
"",
"Convert NUM to integer (toward zero). ",
"See also `floor', and `ceil'.",
0,
"ceil",
"Conversion to integer ceil(num)",
"",
"Convert NUM to integer (round up).",
"See also `floor', and `int'.",
0,
"floor",
"Conversion to integer floor(num)",
"",
"Convert NUM to integer (round down)",
"See also `ceil', and `int'.",
0,
"fixed",
"Fixed decimal rounding fixed(num1,num2)",
"",
"NUM1 rounded to NUM2 decimal places.",
0,
"rnd",
"Random integer rnd(num)",
"",
"A random integer from 0 to NUM-1.",
0,
"negate",
"Negation negate(num)",
"",
"Equivelent to `0 - NUM'.",
0,




"exp",
"Exponential exp(num)",
"",
"The exponential function of NUM.",
0,
"log",
"Log log(num)",
"",
"The natural log of NUM.",
0,
"log10",
"Log base 10 log10(num)",
"",
"The log of NUM to base 10.",
0,
"sqrt",
"Square root sqrt(num)",
"",
"The square-root of NUM.",
0,



/* Trig functions */

"pi",
"Constant pi()",
"",
"3.14159265358979326848",
0,
"acos",
"Arc cosine acos(num)",
"",
"The arc cosine (in radians) of NUM.",
0,
"asin",
"Arc sine asin(num)",
"",
"The arc sine (in radians) of NUM.",
0,
"atan",
"Arc tangant atan(num)",
"",
"The arc tangent (in radians) of NUM.",
0,
"cos",
"Cosine cos(num)",
"",
"The cosine of NUM (NUM in radians)",
0,
"dtr",
"Degrees to radians dtr(num)",
"",
"NUM degrees converted to radians.",
0,
"rtd",
"Radians to degrees rtd(num)",
"",
"NUM radians converted to degrees.",
0,
"sin",
"Sine sin(num)",
"",
"The sine of NUM (NUM in radians).",
0,
"tan",
"Tangent tan(num)",
"",
"The tangent of NUM (NUM in radians).",
0,
"atan2",
"Expanded arc tangent atan2(num1,num2)",
"",
"Returns the arc tangent (in radians) of NUM1 / NUM2.",
"The range of atan2 is (-pi..pi). The quadrant of the angle returned",
"is determined by the signs of NUM1 and NUM2:",
"",
" (pi/2)",
" |",
" NUM2 < 0 | both > 0",
" |",
" (pi,-pi) -------------------------- (0)",
" both < 0 | NUM1 < 0",
" |",
" |",
" -(pi/2)",
0,
"hypot",
"Length of t he hypoteneus hypot(num1,num2)",
"",
"Returns `sqrt (NUM1 * NUM1 + NUM2 * NUM2)'. ",
"",
"Calling `hypot' may succeed in cases when the equivelent expression",
"might underflow or overflow.",
0,

"oneof",
"Case expression oneof(choice,val1,val2,val3...)",
"",
"If CHOICE is 1, return VAL1, if 2, VAL2, and so forth.",
"If CHOICE is not a valid integer in the appropriate range, the value is",
"#OUT_OF_RANGE. If no value arguments are supplied, the value is #NO_VALUES.",
0,

"sum",
"Sum of values sum(vr1, vr2, ...)",
"",
"The sum of VR1, VR2, etc. ",
"",
"Each value can be either a numeric type or a range. If the value is a range, ",
"the values of all numeric cells in that range are used.",
"",
"If none of the arguments include valid numbers (e.g. `sum(r1:10c1:10)'",
"where that range is empty), then the value is #NO_VALUES. To ensure",
"that the expression doesn't return an error in cases like that,",
"provide a default value as an extra argument to sum",
"(e.g. `sum(0,r1:10c1:10)').",
0,
"prod",
"Product of values prod(vr1, vr2, ...)",
"",
"The product of VR1, VR2, etc. ",
"",
"Each value can be either a numeric type or a range. If the value is a range, ",
"the values of all numeric cells in that range are used.",
"",
"If none of the arguments include valid numbers (e.g. `prod(r1:10c1)'",
"where that range is empty), then the value is #NO_VALUES. To ensure",
"that the expression doesn't return an error in cases like that,",
"provide a default value as an extra argument to product (e.g. `prod(1,",
"r1:10c1)').",
0,

"avg",
"Average avg(vr1...)",
"",
"The average of VR1, VR2, etc. ",
"",
"Each value can be either a numeric type or a range. If the value is a range, ",
"the values of all numeric cells in that range are used.",
"",
"If none of the arguments include valid numbers (e.g. `avg(r1:10c1)'",
"where that range is empty), then the value is #NO_VALUES.",
0,
"std",
"Standard deviation std(vr1...)",
"",
"The SAMPLE standard deviation. ",
"To get the population standard deviation, use sqrt(var(...))",
"",
"Each value can be either a numeric type or a range. If the value is a range, ",
"the values of all numeric cells in that range are used.",
"",
"If none of the arguments include valid numbers (e.g. `avg(r1:10c1)'",
"where that range is empty), then the value is #NO_VALUES.",
0,
"max",
"Maximum max(vr1...)",
"",
"Return the maximum value of all the arguments.",
"",
"Each value can be either a numeric type or a range. If the value is a range, ",
"the values of all numeric cells in that range are used.",
"",
"If none of the arguments include valid numbers (e.g. `max(r1:10c1)'",
"where that range is empty), then the value is #NO_VALUES. To ensure",
"that the expression doesn't return an error in cases like that,",
"provide a default value as an extra argument to maximum (e.g. `max(0,",
"r1:10c1)').",
0,
"min",
"Minimum min(vr1...)",
"",
"Return the minimum value of all the arguments.",
"",
"Each value can be either a numeric type or a range. If the value is a range, ",
"the values of all numeric cells in that range are used.",
"",
"If none of the arguments include valid numbers (e.g. `min(r1:10c1)'",
"where that range is empty), then the value is #NO_VALUES. To ensure that the",
"expression doesn't return an error in cases like that, provide a default value",
"as an extra argument to minimum (e.g. `min(99999, r1:10c1)').",
0,
"cnt",
"Count numbers cnt(vr1...)",
"",
"The number of numeric values found amongst the arguments.",
"",
"Each value can be either a numeric type or a range. If the value is a range, ",
"the values of all numeric cells in that range are used.",
0,
"var",
"Population variance var(vr1...)",
"",
"The population varianc of the arguments.",
"",
"Each value can be either a numeric type or a range. If the value is a range, ",
"the values of all numeric cells in that range are used.",
"",
"To get the sample variance, use std(...)^2",
0,

/* string functions */
"len",
"String length len(str)",
"",
"The number of characters in STR.",
0,
"strlwr",
"Conversion to lower case strlwr(str)",
"",
"STR, converted to lower case.",
0,
"strupr",
"Conversion to upper case strupr(str)",
"",
"STR, converted to upper case.",
0,
"strcap",
"String capitalization strcap(str)",
"",
"STR, with each word capitalized.",
0,
"trim",
"String beautifier trim(str)",
"",
"STR, with extra spaces and non-ascii characters removed.",
0,
"find",
"find(str1,str2,int)",
"",
"Return the location after INT where STR2 appears in STR1.",
0,
"substr",
"Extract substring by position substr(int1,int2,str)",
"",
"Extract the substring from INT1 to INT2 of STR.",
"",
"Positive indexes are counted from the beginning of STR, starting with 1.",
"Negative indexes are counted from the end of STR, starting with -1.",
"See also, `mid'.",
0,
"mid",
"Extract substring by extent mid(str,int1,int2)",
"",
"The characters in STR from INT1 and continuing for INT2 characters.",
"INT1 is counted from the beginning of the string, starting with 1.",
"See also, `substr'.",
0,
"edit",
"Delete part of a string edit(str,int1,int2,...)",
"",
"Return STR with chars INT1 through INT2 removed.",
"INT1 and INT2 behave as with `substr'.",
0,
"repeat",
"Construct a repeated string repeat(str,int)",
"",
"Return INT concatenations of STR; thus repeat(\"foo\",2) returns \"foofoo\".",
0,
"concat",
"Concatenate string concat(vr1,...)",
"",
"Return the concatenation of all strings in the arguments.",
"An argument may be a range, in which case the cell values in the range are",
"concatenated.",
0,


/* busy-ness functions */
"pmt",
"Loan payments pmt(p,r,t)",
"",
"Payment per period for a loan of principle P at rate R for T payments.",
0,
"pv",
"Present value of investment pv(pmt,int,term)",
"",
"Present value of an investment that pays $PMT at the end of each of",
"TERM periods with a discount rate (interest) of INT.",
0,
"npv",
"Net present value npv(rng,rate)",
"",
"Net Present Value of an investment which will pay uneaven payments.",
"The term is calculated from the number of cells in RNG.",
0,
"irr",
"Intrenal rate or return irr(rng,guess)",
"",
"Internal Rate of Return. This function is paticularly untested, and",
"should not be trusted.",
"",
"Returns #BAD_INPUT if it does not converge for the given input.",
0,
"fv",
"Future value of an annuity fv(pmt,int,term)",
"",
"Future Value of an annuity.",
0,
"rate",
"rate(fut,pres,term)",
"",
"Interest rate required to turn $PRES into $FUT in TERM periods.",
"",
0,
"term",
"term(pmt,int,fut)",
"",
"Number of periods required to collect $FUT in payments of $PMT, where",
"depositd payments earn at a rate of INT.",
0,
"cterm",
"cterm(int,fut,pres)",
"",
"Number of periods required to collect $FUT from a single initial",
"deposit of $PRES, at an interest rate of INT.",
"",
0,
"sln",
"sln(cost,scrap,life)",
"",
"Straight line depreciation of an asset that cost",
"$COST when new, can be sold for $SCRAP, and will last for LIFE",
"periods.",
"",
0,
"syd",
"syd(cost,scrap,life,per)",
"",
"Sum-of-the-digits depreciation of an asset that cost $COST, can be",
"sold for $SCRAP and lasts LIFE, in period PER.",
0,
"ddb",
"ddb(cost,scrap,life,per)",
"",
"Double-declining-balance deprecion, otherwise similar to syd().",
0,
"anrate",
"anrate(pmt,pres,term)",
"",
"(undocumented -- documentation from volunteers welcome).",
0,
"anterm",
"anterm(pmt,prin,rate)",
"",
"(undocumented -- documentation from volunteers welcome).",
0,
"balance",
"balance(prin,rate,term,period)",
"",
"(undocumented -- documentation from volunteers welcome).",
0,
"paidint",
"paidint(prin,rate,term,period)",
"",
"(undocumented -- documentation from volunteers welcome).",
0,
"kint",
"kint(prin,rate,term,period)",
"",
"(undocumented -- documentation from volunteers welcome).",
0,
"kprin",
"kprin(prin,rate,term,period)",
"",
"(undocumented -- documentation from volunteers welcome).",
0,
"compbal",
"compbal(print,rate,term)",
"",
"(undocumented -- documentation from volunteers welcome).",
0,

"help-with-help",
"",
"Valid help characters are:",
"",
"c -- describe-character-briefly",
" Type a command key sequence; it prints the function name that",
" sequence runs.",
"f -- describe-function",
" Type a function name and get full documentation for that function.",
"F -- describe-formula",
" Type the name of a formula function, and get full documentation.",
"k -- describe-key",
" Type a command key sequence and get full documentation for the",
" function that sequence runs.",
"o -- show-options",
" Print the current settings of all user options.",
"v -- show-variable",
" Type a variable name and get it's binding.",
"^v -- show-all-variables",
" Print a list of all variables and their bindings.",
"w -- where-is",
" Type a command name and get a keysequence that invokes that command.",
"W -- view-wallchart",
" Display a list of keybindings.",
"^W -- print-wallchart",
" Write a list of keybindings to a file.",
0,
"graphing"
"",
"[graph-presets-verbosely] -- Reset graphing parameters to default values.",
"[graph-clear-verbosely] -- Clear the datasets of their assigned ranges.",
"[graph-select-output] -- Choose the output type for graphs.",
"[graph-set-data] -- Assign a range of data to a dataset in the graph.",
"[graph-verify] -- Verify graph parameters.",
"[graph-plot] -- Plot with the current parameters.",
""
"The following control optional parameters:",
"",
"[graph-x-axis] -- Define parameters relating the X axis.",
"[graph-y-axis] -- Define parameters relating the Y axis.",
"[graph-set-data-title] -- Assign a title to a dataset.",
"[graph-set-style] -- Assign a style to a dataset.",
"",
"Esc -- End this command.",
0,
"graph-x-axis-help",
"",
"[graph-set-x-range-low] -- Set the beginning of the range of the X axis.",
"[graph-set-x-range-high] -- Set the end of the range of the X axis.",
"[graph-set-x-axis-symbolic] -- Specify a symbolic range for X.",
"[graph-set-x-labels] -- Provide labels for tic marks on the X axis.",
"[graph-default-x-labels] -- Use the default tic marks on the X axis.",
"",
"",
"Esc -- End this command.",
0,
"graph-y-axis-help",
"",
"[graph-set-y-range-low] -- Set the beginning of the range of the Y axis.",
"[graph-set-y-range-high] -- Set the end of the range of the Y axis.",
"[graph-set-y-labels] -- Provide labels for tic marks on the Y axis.",
"[graph-default-y-labels] -- Use the default tic marks on the Y axis.",
"",
"Esc -- End this command.",
0,
"graph-output-types",
"",
"[graph-x11-mono] -- Draw the graph in an X window, in black and white.",
"[graph-x11-color] -- Draw the graph in an X window, in color.",
"[graph-postscript] -- Write a file of postscript commands that draw that graph.",
0,
"keybindings-wallchart",
"",
" General Utility",
"[[main]]",
"Abort the current command, or partial keysequence [break]",
"Set repeat counts and other prefix arguments [universal-argument]",
"Jane, stop this crazy thing [kill-oleo]",
"Redraw the screen [redraw-screen]",
"Suspend Oleo [suspend-oleo]",
"Call a command by name [execute-command]",
"Recalculate [recalculate]",
"",
"",
" Help Commands",
"",
"Describe key briefly [describe-key-briefly]",
"Describe key [describe-key]",
"Describe function [describe-function]",
"Describe formula [describe-formula]",
"Where is [where-is]",
"",
"",
"When a complex command is being invoked (i.e., when Oleo is prompting",
"you for arguments), the next command displays documentation for the",
"command being invoked. This can often be used to get more information",
"about what is being prompted for:",
"",
"Help with command [help-with-command]",
"",
"",
"",
" Cell Cursor Motion",
"",
"Every window has it's own cell cursor. The most recently used window",
"defines the current cell position. There is one cell marker, global to ",
"the spreadsheet.",
"",
"Move the cell cursor to a specific address [goto-cell]",
"Set the cell cursor and the cell mark [goto-region]",
"",
"Set the cell mark to the current cell [mark-cell]",
"(to set the cell cursor equal to the mark, and clear the mark,",
" use `[universal-argument][mark-cell]').",
"",
"Exchange the cell cursor and cell mark [exchange-point-and-mark]",
"(To clear the mark, use `[universal-argument][exchange-point-and-mark]'.)",
"",
"",
"",
" Navigation",
"",
"Under X, and on some terminals (those following the ANSI standard)",
"arrow keys can be used to move the cell cursor.",
"",
"up [up-cell] down [down-cell]",
"right [right-cell] left [left-cell]",
"",
"Though they have no default bindings, there are also the commands:",
" upright-cell, upleft-cell, downright-cell, downleft-cell",
"",
"Some commands go to extremes but leave their mark (if none is already set):",
"",
"Upper left [upper-left]",
"Lower right [lower-right]",
"",
"Beginning of row [beginning-of-row]",
"Beginning of col [beginning-of-col]",
"End of row [end-of-row]",
"End of col [end-of-col]",
"",
"These commands find the boundries between filled and empty cells. They",
"are similar to word motion commands in Emacs.",
"",
"Scan up [scan-up]",
"Scan down [scan-down]",
"Scan right [scan-right]",
"Scan left [scan-left]",
"",
"",
" Scrolling commands",
"",
"These are used to change the visible range of a window.",
"",
"Scroll up [scroll-up]",
"Scroll down [scroll-down]",
"Scroll right [scroll-right]",
"Scroll left [scroll-left]",
"",
"These commands are also availble but not normally bound:",
"scroll-upright, scroll-upleft, scroll-downright, scroll-downleft",
"",
"",
"",
" Commands related to macros",
"",
"Oleo can read keystrokes, and can save keysequences in cells for later",
"re-execution.",
" ",
"Start entering macro [start-entering-macro]",
"Stop entering macro [stop-entering-macro]",
"Call last kbd macro [call-last-kbd-macro]",
"End macro [end-macro]",
"Store last macro [store-last-macro]",
"Run string as macro [run-string-as-macro]",
"",
"",
"",
" Global options",
"",
"These are global parameters under user control (e.g. The a0/noa0",
"option that selects a syntax for cell addresses (either A1 or R1C1)).",
"",
"Show options [show-options]",
"Set option [set-option]",
"",
"",
"",
" Variables",
"",
"Variables are symbolic names for regions of a spreadsheet. Once",
"defined, they can be used in cell formulas as region addresses. They",
"can also be used as arguments to any command that expects a region",
"address.",
"",
"Set variable [set-variable]",
"Show variable [show-variable]",
"Show all variables [show-all-variables]",
"",
"",
"",
" File commands",
"",
"Read a spreadsheet [find-alternate-spreadsheet]",
"Save a spreadsheet [save-spreadsheet]",
"Merge spreadsheet [merge-spreadsheet]",
"Write region to file [write-region-to-file]",
"",
"By default, if a spreadsheet defines a variable `load_hooks', the",
"macro in that region is executed when the spreadsheet is first read.",
"This behavior can be disabled or reinabled by:",
"",
"Toggle load hooks [toggle-load-hooks]",
"",
"The next command reads a file of commands (such as a .oleorc file):",
"",
"Read commands [read-commands]",
"",
"",
"",
" Printing",
"",
"Write an ascii rendition of a region [print-region]",
"Write an embedded postscript rendition of a region [psprint-region]",
"Set page size for postscript printing [set-page-size]",
"",
"",
"",
" Plotting",
"",
"The command `[graph-setup]' accesses the Oleo interface to gnuplot. If",
"you have gnuplot, you can draw graphs of Oleo data, either on the",
"screen, or in postscript.",
"",
"",
" Operations on entire regions",
"",
"Copy region [copy-region]",
"Copy values in region [copy-values-in-region]",
"Move region [move-region]",
"",
"Insert row [insert-row]",
"Insert col [insert-col]",
"",
"Delete row [delete-row]",
"Delete col [delete-col]",
"",
"Delete region [delete-region]",
"Clear spreadsheet [clear-spreadsheet]",
"",
"",
"Window Commands ",
"",
"Recenter window [recenter-window]",
"Open window [open-window]",
"Split window horizontally [split-window-horizontally]",
"Split window vertically [split-window-vertically]",
"Delete window [delete-window]",
"Delete other windows [delete-other-windows]",
"Close window [close-window]",
"Goto window [goto-window]",
"Goto minibuffer [goto-minibuffer]",
"Other window [other-window]",
"",
"",
"",
"Cell attribute commands",
"",
"Set region height [set-region-height]",
"Set region width [set-region-width]",
"Set region protection [set-region-protection]",
"Set region alignment [set-region-alignment]",
"Set region format [set-region-format]",
"Set cell height [set-cell-height]",
"Set cell width [set-cell-width]",
"Set cell protection [set-cell-protection]",
"Set cell alignment [set-cell-alignment]",
"Set cell format [set-cell-format]",
"Set default height [set-default-height]",
"Set default width [set-default-width]",
"Set default protection [set-default-protection]",
"Set default alignment [set-default-alignment]",
"Set default format [set-default-format]",
"Define user format [define-user-format]",
"",
"",
"",
" Keymaps",
"",
"Create keymap [create-keymap]",
"Set map prompt [set-map-prompt]",
"Bind key [bind-key]",
"Bind set [bind-set]",
"Bind all keys [bind-all-keys]",
"Write keys [write-keys]",
"",
"",
"",
" Editting cells",
"",
"Edit cell [edit-cell]",
"Set region formula [set-region-formula]",
"",
"Delete cell [delete-cell]",
"Delete region [delete-region]",
"",
"Clear spreadsheet [clear-spreadsheet]",
"",
"From the main keymap, typing almost any printable character begins ",
"to edit the value of a cell.",
"",
"These commands provide efficent motion while editting cells:",
"[[read-formula]]",
"Next edit [next-edit]",
"Next edit-set [next-edit-set]",
"",
"",
"These commands set the directions used by `[next-edit]' and",
"`[next-edit-set]': ",
"",
"Auto move up [auto-move-up]",
"Auto move down [auto-move-down]",
"Auto move left [auto-move-left]",
"Auto move right [auto-move-right]",
"Auto move up left [auto-move-up-left]",
"Auto move up right [auto-move-up-right]",
"Auto move down left [auto-move-down-left]",
"Auto move down right [auto-move-down-right]",
"Auto move no motion [auto-move-no-motion]",
"",
"",
" Editting in the input area",
"",
"Toggle overwrite [toggle-overwrite]",
"Beginning of line [beginning-of-line]",
"End of line [end-of-line]",
"Backward char [backward-char]",
"Backward word [backward-word]",
"Backward delete char [backward-delete-char]",
"Backward delete word [backward-delete-word]",
"Delete to start [delete-to-start]",
"Forward char [forward-char]",
"Forward word [forward-word]",
"Delete char [delete-char]",
"Delete word [delete-word]",
"Kill line [kill-line]",
"Insert cell expression [insert-cell-expression]",
"Insert cell value [insert-cell-value]",
"Insert rel ref [insert-rel-ref]",
"Insert abs ref [insert-abs-ref]",
0,
"_NON_WARRANTY_",
"",
" Copyright (C) 1990, 1991, 1992, 1993 Free Software Foundation,Inc.",
"There is ABSOLUTELY NO WARRANTY for Oleo; see the file COPYING",
"for details. Oleo is free software and you are welcome to distribute",
"copies of it under certain conditions; see the file COPYING to see the",
"conditions.",
"",
" The help character is ^H",
"",
" [Press any key to begin]",
0,
0,
};


/* Search for some formula documentation. */

#ifdef __STDC__
char **
forminfo_text (char * name)
#else
char **
forminfo_text (name)
char * name;
#endif
{
char ** pos = formula_info;
while (*pos)
if (!stricmp (name, *pos))
return pos;
else
while (*pos++) ;
return 0;
}

oleo-1.3/byte-compile.h 644 722 0 2072 5321115511 13217 0ustar lordwheel#ifndef BYTE_COMPILEH
#define BYTE_COMPILEH

/* Copyright (C) 1992, 1993 Free Software Foundation, Inc.

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, 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 software; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */

/* t. lord Wed Oct 28 00:16:13 1992 */

#ifdef __STDC__
extern unsigned char *parse_and_compile (char *);
extern void byte_free (unsigned char *);
extern int is_constant (unsigned char *);
#else
extern unsigned char *parse_and_compile ();
extern void byte_free ();
extern int is_constant ();
#endif

#endif
oleo-1.3/cell.h 644 722 0 11572 5337372611 11607 0ustar lordwheel#ifndef CELLH
#define CELLH
/* Copyright (C) 1990, 1992, 1993 Free Software Foundation, Inc.

This file is part of Oleo, the GNU Spreadsheet.

Oleo 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, or (at your option)
any later version.

Oleo 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 Oleo; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */

/* Various structures and stuff for the spreadsheet */

/* A union of possible values for a location in the spreadsheet
(or a location to evaluate to: This includes c_r, which
a VAR, etc may evaluate to, but which no cell can ever contain */
#include "global.h"
#include "font.h"

union vals
{
double c_d;
char *c_s;
long c_l;
int c_i;
struct rng c_r;
};

/* An actual cell structure. These cannot be variable-length, since they are
allocated as a variable-length array on a col structure. */

struct cell
{
/* char *cell_string; */
short cell_flags;
struct font_memo * cell_font;
struct ref_fm *cell_refs_from;
struct ref_to *cell_refs_to;
unsigned char *cell_formula;
unsigned short cell_cycle;
union vals c_z;
};

struct var
{
struct var *var_next;

short var_flags;
struct rng v_rng;

/* This is a list of the cells that reference this variable. If the
* variable changes, all the cells in the vars new range must be given
* ref_froms that point to these variables
*/
struct ref_fm *var_ref_fm;

/* A variable sized array that holds the var-name. */
char var_name[1];
};

typedef struct cell CELL;

#define VAR_UNDEF 1
#define VAR_CELL 2
#define VAR_RANGE 3
/* A var is only of this type between calls to start_shift_var and
* finish_shift_var
*/
#define VAR_DANGLING_RANGE 4

/* Shorthand for the cell union */
#define cell_flt c_z.c_d
#define cell_str c_z.c_s
#define cell_int c_z.c_l
#define cell_bol c_z.c_i
#define cell_err c_z.c_i

/* cell_flags is a 16bit value. These bits have the following values
15 14 13 12 . 11 10 9 8 . 7 6 5 4 . 3 2 1 0 .
Unused | --Lock- | ----Type---- | Justify | - Format -- | --- Precision ---
*/

#define GET_LCK(p) ((p)->cell_flags & 0x3000)
#define SET_LCK(p,x) (((p)->cell_flags &= ~0x3000),(p)->cell_flags |= x)

#define LCK_DEF (0x0000)
#define LCK_UNL (0x1000)
#define LCK_LCK (0x2000)

/* The type of a cell, or of a eval_expression() value */
#define GET_TYP(p) ((p)->cell_flags & 0x0E00)
#define SET_TYP(p,x) ((p)->cell_flags &= ~0x0E00,(p)->cell_flags|=(x))
#define TYP_FLT 0x0200
#define TYP_INT 0x0400
#define TYP_STR 0x0600
#define TYP_BOL 0x0800
#define TYP_ERR 0x0A00
/* This for the expression evaluator: NO cell should be this type */
#define TYP_RNG 0x0E00

#define GET_JST(p) ((p)->cell_flags & 0x0180)
#define SET_JST(p,x) ((p)->cell_flags &= ~0x0180,(p)->cell_flags|=(x))
#define JST_DEF 0x0000
#define JST_LFT 0x0100
#define JST_RGT 0x0080
#define JST_CNT 0x0180

#define GET_FMT(p) ((p)->cell_flags & 0x007F)
#define SET_FMT(p,x) ((p)->cell_flags &= ~0x007F,(p)->cell_flags|=(x))
#define GET_PRC(p) ((p)&0x0F)
#define PRC_FLT 0x0F
#define FMT_DEF 0x0000

#define FMT_HID 0x000E
#define FMT_GPH 0x000F

#define FMT_DOL 0x001F
#define FMT_CMA 0x002F
#define FMT_PCT 0x003F
#define FMT_USR 0x004F

#define FMT_FXT 0x005F
#define FMT_EXP 0x006F
#define FMT_GEN 0x007F

#define FMT_MAX 0x007F

/* README README README
*
* The _make_ functions may cause the addresses of cells previously returned by
* find_ functions to change. By extention, any function that calls a make_
* function can have that effect. This is particularly nasty because pointers
* to cells are stored in the global my_cell, and in various stack frames.
* Several bugs have been traced to this questionable design -- please be
* careful not to add new ones.
*/

#ifdef __STDC__
extern CELL *find_cell (CELLREF, CELLREF);
extern CELL *find_or_make_cell (CELLREF, CELLREF);
extern void find_cells_in_range (struct rng *);
extern void make_cells_in_range (struct rng *);
extern CELL *next_cell_in_range (void);
extern CELL *next_row_col_in_range (CELLREF *, CELLREF *);
extern void no_more_cells (void);
extern char *decomp (CELLREF, CELLREF, CELL *);
extern void decomp_free (void);
#else
extern CELL *find_cell ();
extern CELL *find_or_make_cell ();
extern void find_cells_in_range ();
extern void make_cells_in_range ();
extern CELL *next_cell_in_range ();
extern CELL *next_row_col_in_range ();
extern void no_more_cells ();
extern char *decomp ();
extern void decomp_free ();
#endif

#endif
oleo-1.3/cmd.h 644 722 0 26341 5355776312 11441 0ustar lordwheel#ifndef CMDH
#define CMDH

/* Copyright (C) 1992, 1993 Free Software Foundation, Inc.

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, 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 software; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
/* t. lord Wed Oct 14 12:01:37 1992 */

/*
* This file explains the generic interface to interactive functions.
* This covers how C functions are made available to the user, how
* keymaps are structured. This also describes the variables that
* hold the user's interaction state .
*/
#include "global.h"
#include "obstack.h"
#include "line.h"
#include "key.h"
#include "args.h"
#include "funcs.h"
#include "info.h"



#ifdef __STDC__
typedef void (*alarm_fn)(void);
#else
typedef void (*alarm_fn)();
#endif

struct alarm_entry
{
alarm_fn fn;
int freq; /* in seconds. */
time_t last_time;
};


extern struct alarm_entry alarm_table[];

#define cell_timer_seconds (alarm_table[0].freq)




/* Fields prefixed by _ should normally be accessed via the macros
* defined further on.
*/

struct command_frame;
struct macro;

struct input_stream
{
/* The currently executing macro. */
struct macro *_rmac;

unsigned char * _last_macro; /* The last anonymous macro. */

/* If a macro is being exectuted, arguments to a command
* are read from this string.
*/
char *_func_arg;

/* Call stack for macros. */
struct obstack _macro_stack;

/* The macro being recorded, if any. */
unsigned char *_macro;
unsigned char *_macro_start;
unsigned int _macro_size;

/* If this input stream was created only to execute a macro,
* this will point to the input_stream it suspended.
* The purpose of this stack is to give command_loop the ability to
* execute exactly one macro and then return.
*
* Note that within an input stream there is another macro stack.
* That stack is used internally to command_loop.
*/
struct input_stream * prev_stream;

int _pushed_back_char;
};


struct macro
{
struct macro *mac_prev;
unsigned char *mac_exe;
CELLREF mac_row, mac_col;
struct rng mac_rng;

int count; /* Repeat count for this macro. */
unsigned char * mac_start; /* Beginning the current cell's string (as */
/* copied to the macro stack). */
};

/* When a key is bound to a range, that range is stored here and
* the CODE field of the binding is an index. This is bogus.
* Variables should be used.
*/
extern int n_bound_macros;
extern struct rng *bound_macros;
extern int bound_macro_vec;



/* The pattern of interaction is:
* the user selects an interactive function
* a list of arguments to that function are assembled
* the function is called
*
* This type is a union of the types that arguments to interactive
* functions can have.
*/
union command_arg_val
{
char character;
FILE * fp;
int integer;
double floating;
struct key_sequence key; /* Passed as (struct keyseq *). */
struct rng range; /* Passed as (struct rng *). */
char * string;
};


#ifdef __STDC__
typedef void (*direction_function) (int magic, int repeat);
#else
typedef void (*direction_function) ();
#endif


struct command_arg
{
int do_prompt; /* If true, the user gets to edit this. */
int is_set; /* If true, a valid value is stored here. */
struct prompt_style * style; /* The editting mode for this argument. */
char * arg_desc; /* Pointer into FUNC_ARGS of CUR_CMD. */
char * prompt; /* Unexpanded prompt */
char * expanded_prompt;

struct info_buffer * prompt_info;/* Info that should be displayed while */
/* prompting for this argument. */
int info_line; /* First line visible in prompt_info */

struct line text; /* A buffer for the user to edit this value. */
int cursor; /* cursor position of this buffer. */
int overwrite; /* Is overwrite mode on? */

/* For incremental commands. */
direction_function inc_cmd;

/* For reading a character with timeout. */
int timeout_seconds;

/* The value as it will be passed to the cmd function. */
union command_arg_val val;
};

#define MAX_COMMAND_ARGS 10

/* These declarations make up the state of the command interpreter. */

struct command_frame
{
/* If `recursive' edits are enabled, there can be more than one of these. */
struct command_frame * next;
struct command_frame * prev;

struct input_stream * input;

/* The cell being editted (if any). */
CELLREF _setrow;
CELLREF _setcol;

/* The current cell and the mark. */
CELLREF _curow;
CELLREF _cucol;
CELLREF _mkrow;
CELLREF _mkcol;

/* What passes for a window configuration, for now. */
/*
* When the input area is active, it appears to be just another window,
* reachable by other-window. These values must be maintained by any
* implementation of io_get_line.
*/
int _window_after_input; /* Id of the window prior to the input area. */
int _input_active; /* Bool: is the input area selected? */


/* The current top level keymap. */
int top_keymap;

/* Current position in the keymaps. */
int _cur_keymap;

int saved_cur_keymap; /* used when building a prefix arg */

/* The about-to-begin executing command (if any). */
struct cmd_func *_cur_cmd;
short _cur_vector;

/* The last character processed .*/
int _cur_chr;

/* The prefix argument */
int _how_many;
struct line _raw_prefix;

/* This becomes true if the user is ever prompted for arguments
* for this frame.
*/
int complex_to_user;

int _cmd_argc;
int _cur_arg;
struct cmd_func * cmd;

/* The arguments to the current function.
* This is used only if the current function prompts for arguments.
*/
struct command_arg argv[MAX_COMMAND_ARGS];
};

/* When a command is executing, this points to the frame it should operate
* on:
*/

extern struct command_frame * the_cmd_frame;
extern struct command_frame * running_frames;


/* For most code, the structure of command loops and input streams
* is unimportant. To that code, we make it appear that there is just
* a set of global variables.
*/

#define setrow the_cmd_frame->_setrow
#define setcol the_cmd_frame->_setcol
#define curow the_cmd_frame->_curow
#define cucol the_cmd_frame->_cucol
#define mkrow the_cmd_frame->_mkrow
#define mkcol the_cmd_frame->_mkcol

#define window_after_input the_cmd_frame->_window_after_input
#define input_active the_cmd_frame->_input_active

#define cur_keymap the_cmd_frame->_cur_keymap
#define cur_cmd the_cmd_frame->_cur_cmd
#define cur_vector the_cmd_frame->_cur_vector
#define cur_chr the_cmd_frame->_cur_chr
#define cur_arg the_cmd_frame->_cur_arg
#define cmd_argc the_cmd_frame->_cmd_argc

#define how_many the_cmd_frame->_how_many
#define raw_prefix the_cmd_frame->_raw_prefix

#define cur_input the_cmd_frame->input
#define rmac cur_input->_rmac
#define pushed_back_char cur_input->_pushed_back_char
#define last_macro cur_input->_last_macro
#define macro_func_arg cur_input->_func_arg
#define macro_stack cur_input->_macro_stack
#define making_macro cur_input->_macro
#define making_macro_start cur_input->_macro_start
#define making_macro_size cur_input->_macro_size

#define the_cmd_arg the_cmd_frame->argv[cur_arg]



#ifdef FD_SET

#define SELECT_TYPE fd_set
#define SELECT_SET_SIZE FD_SETSIZE

#else /* no FD_SET */

/* Define the macros to access a single-int bitmap of descriptors. */
#define SELECT_SET_SIZE 32
#define SELECT_TYPE int
#define FD_SET(n, p) (*(p) |= (1 << (n)))
#define FD_CLR(n, p) (*(p) &= ~(1 << (n)))
#define FD_ISSET(n, p) (*(p) & (1 << (n)))
#define FD_ZERO(p) (*(p) = 0)

#endif /* no FD_SET */

/* The fd's that are selected on in the interact loop. */
extern SELECT_TYPE read_fd_set;
extern SELECT_TYPE exception_fd_set;
extern SELECT_TYPE write_fd_set;
extern SELECT_TYPE read_pending_fd_set; /* These are the output of select. */
extern SELECT_TYPE exception_pending_fd_set;
extern SELECT_TYPE write_pending_fd_set;

#ifdef __STDC__
typedef void (*select_hook_fn) (int fd);
#else
typedef void (*select_hook_fn) ();
#endif

struct select_hook
{
select_hook_fn hook_fn;
void * jrandom;
};

extern struct select_hook file_read_hooks[SELECT_SET_SIZE];
extern struct select_hook file_exception_hooks[SELECT_SET_SIZE];
extern struct select_hook file_write_hooks[SELECT_SET_SIZE];

#ifdef __STDC__
extern void free_input_stream (struct input_stream * stream);
extern void pop_input_stream (void);
extern void start_entering_macro (void);
extern void bound_macro (int num);
extern void run_string_as_macro (char * macro, int count);
extern void call_last_kbd_macro (int count);
extern void end_macro (void);
extern void stop_entering_macro (void);
extern void store_last_macro (struct rng * rng);
extern int real_get_chr (void);
extern void push_command_frame (struct rng * rng, char * first_line, int len);
extern void remove_cmd_frame (struct command_frame * frame);
extern void free_cmd_frame (struct command_frame * frame);
extern void pop_unfinished_command (void);
extern void recover_from_error (void);
extern void exit_minibuffer (void);
extern void setn_arg_text (struct command_arg * arg, char * text, int len);
extern void init_arg_text (struct command_arg * arg, char * text);
extern void set_default_arg (struct command_arg * arg, char * text, int len);
extern void command_loop (int prefix);
extern void execute_as_macro (char * str);
extern void execute_command (char *str, int count);
extern int get_chr (void);
extern void display_error_msg (char * msg, int c);
extern void io_error_msg (char *str,...);
extern void io_info_msg (char *str,...);
extern char * expand_prompt (char * str);
extern void set_info (char * name);
extern void page_info_backwards (int rep);
extern void page_info (int rep);
extern void view_info (char * name, int ignore);
extern void with_keymap (char * mapname);
extern void one_cmd_with_keymap (char * mapname, struct key_sequence * keyseq);

#else
extern void free_input_stream ();
extern void pop_input_stream ();
extern void start_entering_macro ();
extern void bound_macro ();
extern void run_string_as_macro ();
extern void call_last_kbd_macro ();
extern void end_macro ();
extern void stop_entering_macro ();
extern void store_last_macro ();
extern int real_get_chr ();
extern void push_command_frame ();
extern void remove_cmd_frame ();
extern void free_cmd_frame ();
extern void pop_unfinished_command ();
extern void recover_from_error ();
extern void