Sindbad~EG File Manager
/* convert a term to a string (in OEM character set) for one-line display.
Returns a string beginning and ending with $. This is necessary to
get symbols in the OEM character set handled properly by SymbolTextOut.
/*
9.13.90 original date
6.21.99 last modified.
9.2.04 changed ultoa to sprintf for ANSI C compatibility
3.20.06 modified raw_mstring to not produce OEM characters for superscript 2 and superscript n for exponents,
and to not produce OEM characters for \le and \ge, but produce those Tex codes instead.
3.27.06 corrected that modification, using ksymbol.
*/
#include <string.h>
#include <stdlib.h> /* gcvt */
#include <stdio.h> /* sprintf */
#include <assert.h>
#define MSTRING_DLL
#include "export.h"
#include "terms.h"
#include "mstring.h"
#include "dispfunc.h" /* oem_atom_string */
#include "mygcvt.h"
static int interval_as_and2(term u);
static int raw_mstring(term t, char *ans);
static int long_identifiers = 0;
/* You could possibly make this variable global in the
future; mstring uses it to control spacing, e.g. if
long_identifiers is nonzero, we get "x y z" instead
of "xyz", because "xyz" might be one identifier. */
#define ISTWO(x) (ISINTEGER(x) && INTDATA(x)==2L)
/*__________________________________________________________________*/
static int precision = 6;
/* controls number of digits in decimals displayed by mstring */
MEXPORT_MSTRING void set_mprecision(int n)
{ precision = n;
}
/*__________________________________________________________________*/
static int separator = 2;
/* controls display of bignums by mstring */
MEXPORT_MSTRING void set_mseparator(int n)
{ separator = n;
}
/*___________________________________________________________________*/
MEXPORT_MSTRING int mstring(term t, char *ans)
/* enclose the result of raw_mstring in $ signs */
/* Assumes *ans is at least long enough to hold the answer.
84 bytes will always suffice.
*/
{ int err;
ans[0] = '$';
err = raw_mstring(t,ans+1);
if(err)
return err;
strcat(ans,"$");
return 0;
}
/*___________________________________________________________________*/
static int raw_mstring(term t, char *ans)
/* nonzero return is out of space, or string longer than 80 chars */
{
/* assumed to have space allocated already. No more than 82
chars will ever be used */
char temp[83];
char temp1[83];
char temp2[83];
char *temp4;
term arg;
int i,k,k1,k2,ksymbol,stashit;
unsigned short f,hbase;
unsigned short h = FUNCTOR(t);
if (ISATOM(t))
{ temp4 = oem_atom_string(t);
if(strlen(temp4)>80)
return 1;
strcpy(ans,temp4);
return 0;
}
if (OBJECT(t))
switch(TYPE(t))
{ case DOUBLE:
my_gcvt(DOUBLEDATA(t),precision,ans);
return 0;
case INTEGER:
sprintf(ans,"%d",INTDATA(t));
return 0;
case BIGNUM:
temp4 = bignum_string(BIGNUMDATA(t),separator);
if(strlen(temp4)>80)
return 1;
strcpy(ans,temp4);
return 0;
}
if(h== '-')
{ ans[0] = '-';
if(raw_mstring(ARG(0,t),ans+1))
return 1;
/* so conceivably we might have need ans to have 82 spaces */
if(strlen(ans) > 80)
return 1;
return 0;
}
/* postfix functions */
if(h == FACTORIAL || h == DEG)
{ if(raw_mstring(ARG(0,t),ans))
return 1;
k = strlen(ans);
if(k > 79)
return 1;
switch(h)
{ case FACTORIAL :
strcpy(ans+k,"!");
return 0;
case DEG :
strcpy(ans+k,"�");
return 0;
}
}
if(ARITY(t) == 1 && h != SQRT && h != ABS && h != AND)
{ if(raw_mstring(ARG(0,t),temp))
return 1;
functor_string(h,SCREEN,ans);
k = strlen(ans);
if(ATOMIC(ARG(0,t)) && PREFIX(h))
{ ans[k] = 32;
++k;
if(strlen(temp) + k > 80)
return 1;
strcpy(ans+k,temp);
return 0;
}
else
{ ans[k] = '(';
++k;
if((stashit = strlen(temp)) +k > 79)
return 1;
strcpy(ans + k,temp);
k += stashit;
ans[k] = ')';
ans[k+1] = '\0';
return 0;
}
}
if(h==DIFF && ARITY(t)==2)
{ if(raw_mstring(ARG(0,t),temp1))
return 1;
if(raw_mstring(ARG(1,t),temp2))
return 1;
k1 = strlen(temp1);
k2 = strlen(temp2);
if(ISATOM(ARG(0,t)) && ISATOM(ARG(1,t)) ) /* du/dx */
{ if(k1+k2+3 > 80)
return 1;
ans[0] = 'd';
strcpy(ans+1,temp1);
ans[k1+1] = '/'; ans[k1+2] = 'd';
strcpy(ans+k1+3,temp2);
return 0;
}
else /* d/dx (u + v) */
{ if(k1+k2+5>80)
return 1;
strcpy(ans,"d/d");
strcpy(ans+3,temp2);
ans[k2+3]='(';
strcpy(ans + k2+4,temp1);
strcpy(ans+k1+4+k2,")");
return 0;
}
}
if(h==DIFF && ARITY(t)==3 && (ISTWO(ARG(1,t)) || (ISATOM(ARG(1,t)) && FUNCTOR(ARG(1,t))== 'n')))
{ if(raw_mstring(ARG(0,t),temp1))
return 1;
if(raw_mstring(ARG(2,t),temp2))
return 1;
k1 = strlen(temp1);
k2 = strlen(temp2);
if(ISATOM(ARG(0,t)) && ISATOM(ARG(2,t)) ) /* d^2u/dx^2 */
{ if(k1+k2+5 > 78)
return 1;
strcpy(ans, "d^2");
strcat(ans,temp1);
strcat(ans,"/d");
strcat(ans,temp2);
strcat(ans,"^2");
return 0;
}
else /* d^2/dx^2 (u + v) */
{ if(k1+k2+7>78)
return 1;
if(ISTWO(ARG(1,t)))
{ strcpy(ans,"d^2/d");
strcat(ans,temp2);
strcat(ans,"^2");
return 0;
}
if(ISATOM(ARG(1,t)))
{ char buffer[20];
functor_string(FUNCTOR(ARG(1,t)),1,buffer);
if(strlen(buffer) == 1)
{ strcpy(ans,"d^");
strcat(ans,buffer);
strcat(ans,"/d");
strcat(ans,temp2);
strcat(ans,"^");
strcat(ans,buffer);
return 0;
}
else
{ strcpy(ans,"d^(");
strcat(ans,buffer);
strcat(ans,")");
strcat(ans,"/d");
strcat(ans,temp2);
strcat(ans,"^(");
strcat(ans,buffer);
strcat(ans,")");
return 0;
}
}
else /* usually an integer exponent, but this code handles more complicated exponents */
{ char buffer[84];
raw_mstring(ARG(1,t),buffer);
if(strlen(buffer) == 1)
{ strcpy(ans,"d^");
strcat(ans,buffer);
strcat(ans,"/d");
strcat(ans,temp2);
strcat(ans,"^");
strcat(ans,buffer);
return 0;
}
else if(strlen(buffer) <= 30)
{ strcpy(ans,"d^(");
strcat(ans,buffer);
strcat(ans,")/d");
strcat(ans,buffer);
strcat(ans,"^(");
strcat(ans,temp2);
strcat(ans,")");
return 0;
}
else
return 1; /* too long */
}
}
}
if(h == INTEGRAL && ARITY(t) == 2) /* indefinite integral */
{ if(raw_mstring(ARG(0,t),temp))
return 1;
k = strlen(temp);
if(raw_mstring(ARG(1,t),temp2))
return 1;
k2 = strlen(temp2);
if (k + k2 + 3 > 80)
return 1;
ans[0] = (char) 244; /* top half of integral sign, best we can do */
strcpy(ans+1,temp);
ans[k+1] = 32;
ans[k+2] = 'd';
strcpy(ans + k + 3, temp2);
return 0;
}
if(h==ROOT) /* produce ^(index)�arg */
{ int kk;
if(raw_mstring(ARG(1,t),temp))
return 1;
ans[0] = '^';
if(ISINTEGER(ARG(0,t)) && INTDATA(ARG(0,t)) < 10)
{ ans[1] = (char) (48 + INTDATA(ARG(0,t)));
ans[2] = (char) 251; /* sqrt in OEM character set */
ans[3] = 0; /* so strlen will work below */
}
else
{ ans[1] = '(';
if(raw_mstring(ARG(0,t),ans+2))
return 1;
kk = strlen(ans);
ans[kk] = ')';
ans[kk+1] = (char) 251;
ans[kk + 2] = 0; /* so strlen will work below */
}
kk = strlen(ans);
if(!ATOMIC(ARG(1,t)))
{ ans[kk] = '(';
if(raw_mstring(ARG(1,t),ans+kk+1))
return 1;
strcat(ans,")");
return 0;
}
return raw_mstring(ARG(1,t),ans+kk);
}
switch(h) /* now it's a compound term */
{ case LE: /* fall-through */
case GE:
case '<':
case '>':
case NE :
case '=':
case ARROW:
ksymbol = (h == LE || h == GE) ? 3 : 1;
if(raw_mstring(ARG(0,t),temp1))
return 1;
if(raw_mstring(ARG(1,t),temp2))
return 1;
k1 = strlen(temp1);
k2 = strlen(temp2);
if(k1+k2+ksymbol + 2>80)
return 1;
strcpy(ans,temp1);
switch(h)
{ case '<' :
strcpy(ans + k1, " < ");
break;
case LE :
strcpy(ans + k1, " \\le ");
break;
case GE :
strcpy(ans + k1, " \\ge ");
break;
case '>' :
strcpy(ans + k1, " > ");
break;
case '=' :
strcpy(ans + k1, " = ");
break;
case NE :
strcpy(ans + k1, " # ");
break;
case ARROW:
ans[k1] = -16; /* SymbolTextOut expects OEM character set; but in this case OEM
character is 26, which is also end-of-file, so we use 240,
which SymbolTextOut knows how to handle. */
ans[k1+1] = 0;
strcat(ans,temp2);
return 0;
}
strcpy(ans+k1+ksymbol+2,temp2);
return 0;
case '/' :
if(raw_mstring(ARG(0,t),temp1))
return 1;
if(raw_mstring(ARG(1,t),temp2))
return 1;
k1 = strlen(temp1);
k2 = strlen(temp2);
if( ARITY(ARG(1,t))==1 || ATOMIC(ARG(1,t))) /* no parens in denom */
if(FUNCTOR(ARG(0,t))=='+')
{ if(k1+k2+3>80)
return 1;
ans[0] = '(';
strcpy(ans + 1, temp1);
strcpy(ans + 1 + k1, ")/");
strcpy(ans + 1 + k1 + 2, temp2);
return 0;
}
else
{ if(k1+k2+1>80)
return 1;
strcpy(ans,temp1);
ans[k1] = '/';
strcpy(ans + k1+1,temp2);
return 0;
}
/* now denom needs parens */
if( FUNCTOR(ARG(0,t))== '+')
{ if(k1+k2+5>80)
return 1;
ans[0] = '(';
strcpy(ans + 1, temp1);
strcpy(ans + 1 + k1, ")/(");
strcpy(ans + 1 + k1 + 3, temp2);
strcpy(ans + 1 + k1 + 3 + k2,")");
return 0;
}
else
{ if(k1+k2+3>80)
return 1;
strcpy(ans,temp1);
strcpy(ans+k1,"/(");
strcpy(ans+k1+2,temp2);
strcpy(ans+k1+2+k2,")");
return 0;
}
case ABS :
ans[0] = (char) 179;
if(raw_mstring(ARG(0,t),ans+1))
return 1;
k = strlen(ans);
ans[k] = (char) 179;
ans[k+1] = '\0';
return 0;
case SQRT:
raw_mstring(ARG(0,t),temp);
k = strlen(temp);
if(k + 3 > 80)
return 1;
if(ATOMIC(ARG(0,t)))
{ ans[0] = '�' ;
strcpy(ans+1,temp);
return 0;
}
strcpy(ans,"�(");
strcpy(ans+2,temp);
strcpy(ans+2+k,")");
return 0;
case '^':
hbase = FUNCTOR(ARG(0,t));
if(ISTWO(ARG(1,t)) && TRIGFUNCTOR(hbase))
{ functor_string(hbase,SCREEN,ans);
if(ATOMIC(ARG(0,ARG(0,t))))
strcat(ans,"^2 ");
else
strcat(ans,"^2(");
k = strlen(ans);
if(raw_mstring(ARG(0,ARG(0,t)),ans+k))
return 1;
if(!ATOMIC(ARG(0,ARG(0,t))))
strcat(ans,")");
if(strlen(ans) > 80)
return 1;
return 0;
}
if(FUNCTOR(ARG(1,t)) == 'n' && TRIGFUNCTOR(hbase))
{ functor_string(hbase,SCREEN,ans);
if(ATOMIC(ARG(0,ARG(0,t))))
strcat(ans,"� ");
else
strcat(ans,"�(");
k = strlen(ans);
if(raw_mstring(ARG(0,ARG(0,t)),ans+k))
return 1;
if(!ATOMIC(ARG(0,ARG(0,t))))
strcat(ans,")");
if(strlen(ans) > 80)
return 1;
return 0;
}
if(ISTWO(ARG(1,t)))
{ raw_mstring(ARG(0,t),temp);
k = strlen(temp);
if(ATOMIC(ARG(0,t)))
{ if (k > 79)
return 1;
strcpy(ans,temp);
strcpy(ans+k,"^2");
return 0;
}
else
{ if(k + 3 > 80)
return 1;
ans[0] = '(';
strcpy(ans+1,temp);
strcpy(ans+1+k,")^2");
return 0;
}
}
if(ISATOM(ARG(1,t)) && FUNCTOR(ARG(1,t))=='n')
{ raw_mstring(ARG(0,t),temp);
k = strlen(temp);
if(ATOMIC(ARG(0,t)))
{ if (k > 79)
return 1;
strcpy(ans,temp);
strcpy(ans+k,"�");
return 0;
}
else
{ if(k + 3 > 80)
return 1;
ans[0] = '(';
strcpy(ans+1,temp);
strcpy(ans+1+k,")�");
return 0;
}
}
/* now dealing with a^b where b isn't 2 or 'n' */
if(raw_mstring(ARG(0,t),temp1))
return 1;
if(raw_mstring(ARG(1,t),temp2))
return 1;
k1 = strlen(temp1);
k2 = strlen(temp2);
if( ATOMIC(ARG(0,t)) && ATOMIC(ARG(1,t)))
{ if(k1 + k2 + 1 > 80 )
return 1;
strcpy(ans,temp1);
ans[k1] = '^';
strcpy(ans+1+k1,temp2);
ans[k1+k2+1]= '\0';
return 0;
}
if( ATOMIC(ARG(0,t)))
{ if(k1 + k2 + 3 > 80)
return 1;
strcpy(ans,temp1);
strcpy(ans+k1,"^(");
strcpy(ans + k1 + 2, temp2);
strcpy(ans + k1 + 2 + k2, ")");
return 0;
}
if( ATOMIC(ARG(1,t)))
{ if(k1 + k2 + 3 > 80)
return 1;
ans[0] = '(';
strcpy(ans+1,temp1);
strcpy(ans+1+k1,")^");
strcpy(ans+1+k1 + 2, temp2);
return 0;
}
else
{ if(k1+k2+5 > 80)
return 1;
ans[0] = '(';
strcpy(ans+1,temp1);
strcpy(ans+1+k1,")^(");
strcpy(ans+1+k1+3,temp2);
strcpy(ans+1+k1+3+k2,")");
return 0;
}
case AND :
if(interval_as_and2(t))
{ /* print as x < y < z */
unsigned short ff;
if(raw_mstring(ARG(0,t),temp))
return 1;
if(80 < (k = strlen(temp)))
return 1;
strcpy(ans, temp);
ff = FUNCTOR(ARG(1,t));
strcat(ans, ff == '<' ? " < " :
ff == '>' ? " > " :
ff == LE ? " � " :
" � ");
k += 3;
if(raw_mstring(ARG(1,ARG(1,t)),temp))
return 1;
if(80-k < (stashit = strlen(temp)))
return 1;
strcat(ans,temp);
return 0;
}
/* print as arg0, arg1, arg2 */
for(i=k=0;i<ARITY(t);i++)
{ if(raw_mstring(ARG(i,t),temp))
return 1;
if(i>0)
{ ans[k] = ',';
ans[k+1] = 32;
k+=2;
}
if(80-k < (stashit = strlen(temp)))
return 1;
strcpy(ans+k,temp);
k += stashit;
}
return 0;
case OR: /* print as arg0; arg1; arg2 */
for(i=k=0;i<ARITY(t);i++)
{ if(raw_mstring(ARG(i,t),temp))
return 1;
if(i>0)
{ ans[k] = ';';
ans[k] = ' ';
k += 2;
}
if(80-k < (stashit = strlen(temp)))
return 1;
strcpy(ans+k,temp);
k += stashit;
}
return 0;
case '*' :
for(i=k=0;i<ARITY(t);i++)
{ if(raw_mstring(ARG(i,t),temp))
return 1;
f = FUNCTOR(ARG(i,t));
if( /* parentheses required */
!ATOMIC(ARG(i,t)) &&
(f == '*' ||
(PREFIX(f) && f != SQRT && f != ABS && k < ARITY(t) - 1)
|| f == '+' || f== '-' || f == '/' || f == FACTORIAL
|| (f == LIMIT && k < ARITY(t)-1)
)
)
{ ans[k] = '(';
k++;
if(79-k < (stashit = strlen(temp)))
return 1;
strcpy(ans+k,temp);
k += stashit;
strcpy(ans+k,")");
k++;
}
else
{ if(80-k-2 < (stashit = strlen(temp)))
return 1;
if(i>0 && ans[k-1] != ')' &&
(UNARY(f) || (long_identifiers && !ISINTEGER(ARG(i-1,t))))
)
{ ans[k] = 32; /* space if no parens,
but not after an integer,
unless what follows the integer
is a unary function, e.g.
2 sin x rather than 2sin x */
k++;
}
strcpy(ans+k,temp);
k+= stashit;
}
}
return 0;
case '+' :
for(i=k=0;i<ARITY(t);i++)
{ arg = ARG(i,t);
if(FUNCTOR(arg) == '-')
{ ans[k] = '-';
k++;
arg = ARG(0,arg);
}
else if(i>0)
{ ans[k] = '+';
k++;
}
if( raw_mstring(arg,temp))
return 1;
if( /* parentheses required */
FUNCTOR(arg) == '+'
|| FUNCTOR(arg) == '/'
|| FUNCTOR(arg) == LIMIT
)
{ ans[k] = '(';
k++;
if(79-k < (stashit = strlen(temp)))
return 1;
strcpy(ans+k,temp);
k += stashit;
ans[k] = ')'; /* wiping out the null terminator */
k++;
ans[k] = '\0'; /* restore a null terminator */
}
else
{ if(80-k < (stashit = strlen(temp)))
return 1;
strcpy(ans+k,temp);
k+= stashit;
}
}
return 0;
case PR:
assert(ISINTEGER(ARG(1,t)));
if(ISATOM(ARG(0,t)))
{ if(raw_mstring(ARG(0,t),temp1))
return 1;
k = strlen(temp1);
if(k + INTDATA(ARG(1,t)) > 80)
return 1;
strcpy(ans,temp1);
for(i=0;i<INTDATA(ARG(1,t));i++)
ans[i+k] = 39; /* ascii code of apostrophe */
ans[i+k] = '\0'; /* don't forget to make it a string */
return 0;
}
functor_string(FUNCTOR(ARG(0,t)),SCREEN,ans);
k = strlen(ans);
for(i=0;i<INTDATA(ARG(1,t));i++)
{ if(i+k > 80)
return 1;
ans[i+k] = 39; /* ascii code of apostrophe */
}
i = i+k;
ans[i] = '\0';
assert(ARITY(ARG(0,t))==1);
if(raw_mstring(ARG(0,ARG(0,t)),temp))
return 1;
if(strlen(temp) + i > 78)
return 1;
strcat(ans,"(");
strcat(ans,temp);
strcat(ans,")");
return 0;
case LIMIT:
strcpy(ans,"lim(");
k=4;
for(i=0;i<ARITY(t);i++)
{ if(ARITY(t)==3 && i==1)
{ ans[k] = (char)(FUNCTOR(ARG(1,t)) == RIGHT ? '+' : '-');
++k;
ans[k] = ',';
++k;
continue;
}
if( raw_mstring(ARG(i,t),temp))
return 1;
if(80-k < (stashit = strlen(temp)))
return 1;
strcpy(ans+k,temp);
k += stashit;
if(ARITY(t)==2 && i==0)
{ ans[k] = ',';
++k;
}
else if(i==ARITY(t)-1)
{ ans[k] = ')';
++k;
}
}
ans[k] = '\0';
return 0;
default:
functor_string(h,SCREEN,ans);
k= strlen(ans);
ans[k] = '(';
k++;
for(i=0;i<ARITY(t);i++)
{ if( raw_mstring(ARG(i,t),temp))
return 1;
if(80-k < (stashit = strlen(temp)))
return 1;
strcpy(ans+k,temp);
k += stashit;
if(i < ARITY(t)-1)
ans[k] = ',';
else
ans[k] = ')';
k++;
}
ans[k] = '\0';
return 0;
}
}
/*_____________________________________________________________*/
MEXPORT_MSTRING int mstrlen(char *x)
/* return an estimate of the length string x will take when printed by
SymbolTextOut. This differs from strlen(x) in the following ways:
Don't count '$' and '^';
subtract an extra 3 for every "^(" that occurs in the string (one for the
^ and one each for two parentheses).
Don't count isalpha characters after a backslash;
*/
{ unsigned char *marker;
int count = 0;
int doublecount = 0;
int ans;
for(marker = (unsigned char *) x; *marker; ++marker)
{ if(*marker == '^' && marker[1] == '(')
++doublecount;
if(*marker == '_' && marker[1] == '(')
++doublecount;
if(*marker != '^' && *marker != '_' && *marker != '$')
++count;
if(*marker == '\\') /* example: \sqrt counts only 1 */
{ ++marker;
while(isalpha(*marker))
++marker;
if(*marker == 32)
++marker; /* skip one space after \sqrt */
}
}
ans = count - 3*doublecount;
assert(ans >= 0);
return ans;
}
/*___________________________________________________________________*/
static int interval_as_and2(term u)
/* static copy of interval_as_and in prover.c */
/* return 1 if u is an interval, that is, an AND of two inequalities
with the same middle term, as a < x && x < b. Return 0 if not. */
{ unsigned short f,g;
if(FUNCTOR(u) != AND)
return 0;
if(ARITY(u) != 2)
return 0;
f = FUNCTOR(ARG(0,u));
if(f != '<' && f != LE)
return 0;
g = FUNCTOR(ARG(1,u));
if(g != '<' && g != LE)
return 0;
return equals(ARG(1,ARG(0,u)),ARG(0,ARG(1,u)));
}
Sindbad File Manager Version 1.0, Coded By Sindbad EG ~ The Terrorists