/*******************************************************************/ /** **/ /** INPUT/OUTPUT SUBROUTINES **/ /** **/ /*******************************************************************/ /* $Id: es.c,v 1.2 1999/09/23 17:50:57 karim Exp $ */ #include "pari.h" #include "anal.h" GEN confrac(GEN x); /* should be static here, but use hiremainder */ GEN convi(GEN x); static void bruti(GEN g, long n); static void texi(GEN g, long nosign); static void sori(GEN g); static char format; static long decimals, chmp, initial; /* output a space or do nothing depending on original caller */ static void (*sp)(); /********************************************************************/ /** **/ /** INPUT FILTER **/ /** **/ /********************************************************************/ #define ONE_LINE_COMMENT 2 #define MULTI_LINE_COMMENT 1 /* filter s in place. If status not a query, return pointer to ending '\0'. * return s / NULL otherwise */ char * filtre(char *s, int status) { static int in_string, in_comment = 0; char c, *t; int downcase; if (status & f_INIT) in_string = 0; switch(status) { case f_ENDFILE: if (in_string) { err(warner,"run-away string. Closing it"); in_string = 0; } if (in_comment) { err(warner,"run-away comment. Closing it"); in_comment = 0; } /* fall through */ case f_INIT: case f_COMMENT: return in_comment? s: NULL; } downcase = ((status & f_KEEPCASE) == 0 && compatible == OLDALL); t = s; while ((c = *s++)) { if (in_string) *t++ = c; /* copy verbatim */ else if (in_comment) { if (in_comment == MULTI_LINE_COMMENT) { while (c != '*' || *s != '/') { if (!*s) { *t=0; return t; } c = *s++; } s++; } else while (c != '\n') { if (!*s) { if (status == f_READL) in_comment=0; *t=0; return t; } c = *s++; } in_comment=0; continue; } else { /* weed out comments and spaces */ if (c=='\\' && *s=='\\') { in_comment = ONE_LINE_COMMENT; continue; } if (isspace((int)c)) continue; *t++ = downcase? tolower(c): c; } switch(c) { case '/': if (*s != '*' || in_string) break; /* start multi-line comment */ t--; in_comment = MULTI_LINE_COMMENT; break; case '\\': if (!in_string) break; if (!*s) return t; /* this will result in an error */ *t++ = *s++; break; /* in strings, \ is the escape character */ /* \" does not end a string. But \\" does */ case '"': in_string = !in_string; } } *t = 0; return t; } #undef ONE_LINE_COMMENT #undef MULTI_LINE_COMMENT GEN lisGEN(FILE *fi) { long size = 512, n = size; char *buf = gpmalloc(n), *s = buf; for(;;) if (fgets(s, n, fi)) { if (s[strlen(s)-1] == '\n') { GEN x = flisexpr(buf); free(buf); return x; } buf = gprealloc(buf, size<<1, size); s = buf + (size-1); n = size+1; size <<= 1; } } /********************************************************************/ /** **/ /** GENERAL PURPOSE PRINTING **/ /** **/ /********************************************************************/ PariOUT *pariOut, *pariErr; static void normalOutC(char c) { putc(c, pari_outfile); if (logfile) putc(c, logfile); } static void normalOutS(char *s) { fputs(s, pari_outfile); if (logfile) { fputs(s, logfile); } } static void normalOutF(void) { fflush(pari_outfile); if (logfile) fflush(logfile); } PariOUT defaultOut = {normalOutC, normalOutS, normalOutF, NULL}; static void normalErrC(char c) { putc(c, errfile); if (logfile) putc(c, logfile); } static void normalErrS(char *s) { fputs(s, errfile); if (logfile) fputs(s, logfile); } static void normalErrF(void) { fflush(errfile); if (logfile) fflush(logfile); } PariOUT defaultErr = {normalErrC, normalErrS, normalErrF, NULL}; void initout(void) { pariOut = &defaultOut; pariErr = &defaultErr; } void pariputc(char c) { pariOut->putch(c); } void pariputs(char *s) { pariOut->puts(s); } void pariflush(void) { pariOut->flush(); } void flusherr() { pariErr->flush(); } /* format is standard printf format, except %Z is a GEN (cast to long) */ void vpariputs(char* format, va_list args) { char buf[1024], str[1024], *f = format, *s = str; long nb = 0; while (*f) { if (*f != '%') *s++ = *f++; else { if (f[1] != 'Z') { *s++ = *f++; *s++ = *f++; } else { strcpy(s,"\003%016ld\003"); /* brace with unprobable characters */ nb++; s += 8; f += 2; /* skip %Z */ } } } *s = 0; vsprintf(buf,str,args); s = buf; if (nb) for (f=s; *f; f++) if (*f == '\003' && f[17] == '\003') { *f = 0; f[17] = 0; /* remove the bracing chars */ pariOut->puts(s); bruteall((GEN)atol(f+1),'g',-1,1); f += 18; s = f; nb--; if (!nb) break; } pariOut->puts(s); } void pariputsf(char *format, ...) { va_list args; va_start(args,format); vpariputs(format,args); va_end(args); } /* start printing in "color" c */ /* terminal has to support ANSI color escape sequences */ void term_color(int c) { pariputs(term_get_color(c)); } void decode_color(int n, int *c) { if (n < 0) n = -n; c[1] = n & 0xf; n >>= 4; /* foreground */ c[2] = n & 0xf; n >>= 4; /* background */ c[0] = n & 0xf; /* attribute */ } char * term_get_color(int n) { static char s[16]; int c[3], a; if (disable_color) return ""; if (n == c_NONE || (a = gp_colors[n]) == c_NONE) return "\033[0m"; /* reset */ decode_color(a,c); if (c[1]<8) c[1] += 30; else c[1] += 82; if (a < 0) sprintf(s, "\033[%d;%dm", c[0], c[1]); else { if (c[2]<8) c[2] += 40; else c[2] += 92; sprintf(s, "\033[%d;%d;%dm", c[0], c[1], c[2]); } return s; } /********************************************************************/ /** **/ /** PRINTING BASED ON SCREEN WIDTH **/ /** **/ /********************************************************************/ static int col_index, lin_index, max_width, max_lin; void init_lim_lines(char *s, long max); #ifdef HAS_TIOCGWINSZ # include # include #endif static int term_width_intern() { #ifdef WINCE return 0; #endif #ifdef HAS_TIOCGWINSZ { struct winsize s; if (!under_emacs && !ioctl(0, TIOCGWINSZ, &s)) return s.ws_col; } #endif #ifdef UNIX { char *str; if ((str = getenv("COLUMNS"))) return atoi(str); } #endif #ifdef __EMX__ { int scrsize[2]; _scrsize(scrsize); return scrsize[0]; } #endif return 0; } static int term_height_intern() { #ifdef HAS_TIOCGWINSZ { struct winsize s; if (!under_emacs && !ioctl(0, TIOCGWINSZ, &s)) return s.ws_row; } #endif #ifdef UNIX { char *str; if ((str = getenv("LINES"))) return atoi(str); } #endif #ifdef __EMX__ { int scrsize[2]; _scrsize(scrsize); return scrsize[1]; } #endif return 0; } #define DFT_TERM_WIDTH 80 #define DFT_TERM_HEIGHT 20 int term_width() { int n = term_width_intern(); return (n>1)? n: DFT_TERM_WIDTH; } int term_height() { int n = term_height_intern(); return (n>1)? n: DFT_TERM_HEIGHT; } #define MAX_WIDTH 76 /* output string wrapped after MAX_WIDTH characters (for gp -test) */ static void putc80(char c) { if (c == '\n') col_index = -1; else if (col_index == MAX_WIDTH) { putc('\n',pari_outfile); col_index = 0; } putc(c, pari_outfile); col_index++; } #undef MAX_WIDTH static void puts80(char *s) { while (*s) putc80(*s++); } PariOUT pariOut80= {putc80, puts80, normalOutF, NULL}; void init80(long n) { col_index = n; pariOut = &pariOut80; } /* output stopped after max_line have been printed (for default(lines,)) */ static void putc_lim_lines(char c) { if (lin_index > max_lin) return; if (lin_index == max_lin) if (c == '\n' || col_index >= max_width-5) { normalOutS(term_get_color(c_ERR)); normalOutS("[+++]"); lin_index++; return; } if (c == '\n') { col_index = -1; lin_index++; } else if (col_index == max_width) { col_index = 0; lin_index++; } col_index++; normalOutC(c); } static void puts_lim_lines(char *s) { long i,len; if (lin_index > max_lin) return; len = strlen(s); for(i=0; i< s wrapped at EOL > * < ... > * ^--- * If str is NULL, omit the arrow * If prefix is NULL, use "" */ void print_prefixed_text(char *s, char *prefix, char *str) { long prelen = prefix? strlen(prefix): 0; long oldwlen=0, linelen=prelen, w = term_width(); char word[MAX_WORD_LEN+1], oldword[MAX_WORD_LEN+1], *u=word; if (prefix) pariputs(prefix); oldword[0]='\0'; while ((*u++ = *s++)) { if (is_blank_or_null(*s)) { while (is_blank(*s)) s++; linelen += oldwlen; if (linelen > w) { _new_line(prefix); linelen = oldwlen + prelen; } pariputs(oldword); *u++ = ' '; *u = '\0'; oldwlen = u-word; if (*s) { strcpy(oldword,word); u = word; } } } if (!str) { if (u[-2] != '.') u[-2] = '.'; } else { *(u-2) = 0; oldwlen--; } linelen += oldwlen; if (linelen > w) { _new_line(prefix); linelen = prelen + oldwlen; } pariputs(word); if (str) { long i,len = strlen(str); int space = (*str == ' ' && str[1]); if (linelen + len > w) { _new_line(prefix); linelen = prelen; if (space) { str++; len--; space = 0; } } pariputs(str); if (str[len-1] != '\n') pariputc('\n'); if (space) { linelen++; len--; } for (i=0; i CHARACTER STRINGS **/ /** **/ /********************************************************************/ typedef struct outString { char *string; ulong len,size; } outString; static outString *OutStr, *ErrStr; #define STEPSIZE 1024 #define check_output_length(str,l) { \ const ulong s = str->size; \ if (str->len + l >= s) { \ ulong t = s + l + STEPSIZE; \ str->string = gprealloc(str->string, t, s); \ str->size = t; \ } \ } #define str_putc(str, c) { \ check_output_length(str,1); \ str->string[str->len++] = c; \ } static void outstr_putc(char c) { str_putc(OutStr, c); } static void errstr_putc(char c) { str_putc(ErrStr, c); } #define str_puts(str, s) {\ const long len=strlen(s); \ check_output_length(str,len); \ strcpy(str->string+str->len,s); \ str->len += len; \ } static void outstr_puts(char *s) { str_puts(OutStr, s); } static void errstr_puts(char *s) { str_puts(ErrStr, s); } static void outstr_flush(void) { /* empty */ } PariOUT pariOut2Str = {outstr_putc, outstr_puts, outstr_flush, NULL}; PariOUT pariErr2Str = {errstr_putc, errstr_puts, outstr_flush, NULL}; #undef STEPSIZE char * pari_strdup(char *s) { int n = strlen(s)+1; char *t = gpmalloc(n); memcpy(t,s,n); return t; } /* returns a malloc-ed string, which should be freed after usage */ char * GENtostr0(GEN x, void(*do_out)(GEN)) { PariOUT *tmp = pariOut; outString *tmps = OutStr, newStr; if (typ(x) == t_STR) return pari_strdup(GSTR(x)); pariOut = &pariOut2Str; OutStr = &newStr; OutStr->len = 0; OutStr->size=0; OutStr->string=NULL; do_out(x); OutStr->string[OutStr->len] = 0; pariOut = tmp; OutStr = tmps; return newStr.string; } char * GENtostr(GEN x) { return GENtostr0(x,outbrute); } /********************************************************************/ /** **/ /** TEXMACS INTERFACE **/ /** **/ /********************************************************************/ extern jmp_buf environnement; #include "TeXmacs.h" static TeXmacs_exports_1 *TeXmacs; static char * pari_evaluate(char *s, char *session, char **fail) { static PariOUT *tmp; static outString *tmps; outString newStr; long av = avma; char *t; tmp = pariErr; pariErr = &pariErr2Str; tmps = ErrStr; ErrStr = &newStr; ErrStr->len = 0; ErrStr->size=0; ErrStr->string=NULL; if (setjmp(environnement)) t = NULL; else { t = GENtostr(flisexpr(s)); avma = av; } if (ErrStr->string) ErrStr->string[ErrStr->len] = 0; *fail = ErrStr->string; pariErr = tmp; ErrStr = tmps; return t; } static char * pari_install(TeXmacs_exports_1* _TeXmacs, char *options, char **fail) { *TeXmacs = *_TeXmacs; pari_init(1000000, 500000); if (setjmp(environnement)) { *fail = pari_strdup("Pari Error"); return NULL; } else { *fail = NULL; return pari_strdup("Pari Ready"); } } static char * pari_execute(char *s, char *session, char **fail) { *fail = NULL; return pari_strdup(""); } static package_exports_1 PARI_exports_1 = { "TeXmacs communication protocol 1", PARIVERSION, &pari_install, &pari_evaluate, &pari_execute }; package_exports_1 * get_my_package(int i) { return &PARI_exports_1; } /********************************************************************/ /** **/ /** WRITE AN INTEGER **/ /** **/ /********************************************************************/ #define putsigne(x) pariputs((x>0)? " + " : " - ") #define sp_sign_sp(x) sp(), pariputc(x>0? '+': '-'), sp() #define sp_plus_sp() sp(), pariputc('+'), sp() #define comma_sp() pariputc(','), sp() static void wr_space() {pariputc(' ');} static void no_space() {} static void blancs(long nb) { while (nb-- > 0) pariputc(' '); } static void zeros(long nb) { while (nb-- > 0) pariputc('0'); } static long coinit(long x) { char cha[10], *p = cha + 9; *p = 0; do { *--p = x%10 + '0'; x /= 10; } while (x); pariputs(p); return 9 - (p - cha); } static void comilieu(long x) { char cha[10], *p = cha + 9; for (*p = 0; p > cha; x /= 10) *--p = x%10 + '0'; pariputs(cha); } static void cofin(long x, long decim) { char cha[10], *p = cha + 9; for (; p > cha; x /= 10) *--p = x%10 + '0'; cha[decim] = 0; pariputs(cha); } static long nbdch(long l) { if (l<100000) { if (l<10) return 1; if (l<100) return 2; if (l<1000) return 3; if (l<10000) return 4; return 5; } if (l<1000000) return 6; if (l<10000000) return 7; if (l<100000000) return 8; if (l<1000000000) return 9; return 10; /* not reached */ } /* write an int. fw = field width (pad with ' ') */ static void wr_int(GEN x, long fw, long nosign) { long *res,*re,i, sx=signe(x); if (!sx) { blancs(fw-1); pariputc('0'); return; } setsigne(x,1); re = res = convi(x); setsigne(x,sx); i = nbdch(*--re); while (*--re >= 0) i+=9; if (nosign || sx>0) blancs(fw-i); else { i++; blancs(fw-i); pariputc('-'); } coinit(*--res); while (*--res >= 0) comilieu(*res); } static void wr_vecsmall(GEN g) { long i,l; pariputc('['); l = lg(g); for (i=1; i0) /* round if needed */ { GEN arrondi = cgetr(3); arrondi[1] = (long) (x[1]-((double)BITS_IN_LONG/pariK)*dec-2); arrondi[2] = x[2]; x = addrr(x,arrondi); } ex = expo(x); if (ex >= bit_accuracy(lg(x))) { wr_exp(x); return; } /* integer part */ p1 = gcvtoi(x,&e); s = signe(p1); if (e > 0) err(bugparier,"wr_float"); if (!s) { pariputc('0'); d=1; } else { setsigne(p1,1); res = convi(p1); d = coinit(*--res); setsigne(p1,s); while (*(--res) >= 0) { d += 9; comilieu(*res); } x = subri(x,p1); } pariputc('.'); /* fractional part: 0 < x < 1 */ if (!signe(x)) { if (dec<0) dec=(long) (-expo(x)*L2SL10+1); dec -= d; if (dec>0) zeros(dec); return; } if (!s) { for(;;) { p1=mulsr(1000000000,x); if (expo(p1)>=0) break; pariputs("000000000"); x=p1; } for(;;) { p1=mulsr(10,x); if (expo(p1)>=0) break; pariputc('0'); x=p1; } d=0; } res = (long *) confrac(x); decmax = d + *res++; if (dec<0) dec=decmax; deceff = dec-decmax; dec -= d; while (dec>8) { if (dec>deceff) comilieu(*res++); else pariputs("000000000"); dec -= 9; } if (dec>0) { if (dec>deceff) cofin(*res,dec); else zeros(dec); } } /* as above in exponential format */ static void wr_exp(GEN x) { GEN dix = cgetr(lg(x)+1); long ex = expo(x); ex = (ex>=0)? (long)(ex*L2SL10): (long)(-(-ex*L2SL10)-1); affsr(10,dix); if (ex) x = mulrr(x,gpuigs(dix,-ex)); if (absr_cmp(x, dix) >= 0) { x=divrr(x,dix); ex++; } wr_float(x); sp(); pariputsf("E%ld",ex); } /* Write real number x. * format: e (exponential), f (floating point), g (as f unless x too small) * if format isn't correct (one of the above) act as e. * decimals: number of decimals to print (all if <0). */ #define print_float(fo,ex) ((fo == 'g' && ex >= -32) || fo == 'f') static void wr_real(GEN x, long nosign) { long ltop, sx = signe(x), ex = expo(x); if (!sx) /* real 0 */ { if (print_float(format,ex)) { if (decimals<0) { long d = 1+((-ex)>>TWOPOTBITS_IN_LONG); if (d < 0) d = 0; decimals=(long)(pariK*d); } pariputs("0."); zeros(decimals); } else { ex = (ex>=0)? (long)(ex*L2SL10): (long)(-(-ex*L2SL10)-1); pariputsf("0.E%ld", ex+1); } return; } if (!nosign && sx < 0) pariputc('-'); /* print sign if needed */ ltop = avma; if (print_float(format,ex)) wr_float(x); else wr_exp(x); avma = ltop; } #undef print_float void ecrire(GEN x, char f, long d, long fw) { if (typ(x)==t_INT) wr_int(x,fw,0); else { sp = &wr_space; format = f; decimals = d; wr_real(x,0); } } /********************************************************************/ /** **/ /** HEXADECIMAL OUTPUT **/ /** **/ /********************************************************************/ static void sorstring(char* b, long x) { #ifdef LONG_IS_64BIT pariputsf(b,(ulong)x>>32,x & MAXHALFULONG); #else pariputsf(b,x); #endif } /* English ordinal numbers -- GN1998Apr17 */ static const char *ordsuff[4] = {"st","nd","rd","th"}; const char* eng_ord(long i) /* i > 0 assumed */ { switch (i%10) { case 1: if (i%100==11) return ordsuff[3]; /* xxx11-th */ return ordsuff[0]; /* xxx01-st, xxx21-st,... */ case 2: if (i%100==12) return ordsuff[3]; /* xxx12-th */ return ordsuff[1]; /* xxx02-nd, xxx22-nd,... */ case 3: if (i%100==13) return ordsuff[3]; /* xxx13-th */ return ordsuff[2]; /* xxx03-rd, xxx23-rd,... */ default: return ordsuff[3]; /* xxxx4-th,... */ } } static void voir2(GEN x, long nb, long bl) { long tx=typ(x),i,j,e,dx,lx=lg(x); sorstring(VOIR_STRING1,(ulong)x); if (! is_recursive_t(tx)) /* t_SMALL, t_INT, t_REAL, t_STR, t_VECSMALL */ { if (nb<0) nb = (tx==t_INT)? lgefint(x): lx; if (tx == t_SMALL) x = (GEN)&x; for (i=0; iname; if (v==MAXVARN) return "#"; sprintf(buf,"#<%d>",(int)v); return buf; } static char * get_texvar(long v, char *buf) { entree *ep = varentries[v]; char *s, *t = buf; if (!ep) err(talker, "this object uses debugging variables"); s = ep->name; if (strlen(s)>=64) err(talker, "TeX variable name too long"); while(isalpha((int)*s)) *t++ = *s++; *t = 0; if (isdigit((int)*s) || *s++ == '_') sprintf(t,"_{%s}",s); return buf; } static void monome(char *v, long deg) { if (deg) { pariputs(v); if (deg!=1) pariputsf("^%ld",deg); } else pariputc('1'); } static void texnome(char *v, long deg) { if (deg) { pariputs(v); if (deg!=1) pariputsf("^{%ld}",deg); } else pariputc('1'); } #define padic_nome(p,e) {pariputs(p); if (e != 1) pariputsf("^%ld",e);} #define padic_texnome(p,e) {pariputs(p); if (e != 1) pariputsf("^{%ld}",e);} void etatpile(unsigned int n) { long av=avma,nu,i,l,m; GEN adr,adr1; double r; nu = (top-avma)/BYTES_IN_LONG; l = (top-bot)/BYTES_IN_LONG; r = 100.0*nu/l; pariputsf("\n Top : %lx Bottom : %lx Current stack : %lx\n", top, bot, avma); pariputsf(" Used : %ld long words (%ld K)\n", nu, nu/1024*BYTES_IN_LONG); pariputsf(" Available : %ld long words (%ld K)\n", (l-nu), (l-nu)/1024*BYTES_IN_LONG); pariputsf(" Occupation of the PARI stack : %6.2f percent\n",r); adr=getheap(); pariputsf(" %ld objects on heap occupy %ld long words\n\n", itos((GEN)adr[1]), itos((GEN)adr[2])); avma=av; pariputsf(" %ld variable names used out of %d\n\n",manage_var(3,NULL),MAXVARN); if (!n) return; if (n>nu) n=nu; adr=(GEN)avma; adr1=adr+n; while (adr1; i--) if (!isnull((GEN)g[i])) return 0; return 1; } return 0; } /* return 1 or -1 if g is 1 or -1, 0 otherwise*/ static long isone(GEN g) { long i; switch (typ(g)) { case t_SMALL: switch(smalltos(g)) { case 1: return 1; case -1: return -1; } break; case t_INT: return (signe(g) && is_pm1(g))? signe(g): 0; case t_COMPLEX: return isnull((GEN)g[2])? isone((GEN)g[1]): 0; case t_QUAD: return isnull((GEN)g[3])? isone((GEN)g[2]): 0; case t_FRAC: case t_FRACN: case t_RFRAC: case t_RFRACN: return isone((GEN)g[1]) * isone((GEN)g[2]); case t_POL: if (!signe(g)) return 0; for (i=lgef(g)-1; i>2; i--) if (!isnull((GEN)g[i])) return 0; return isone((GEN)g[2]); } return 0; } /* if g is a "monomial", return its sign, 0 otherwise */ static long isfactor(GEN g) { long i,deja,sig; switch(typ(g)) { case t_INT: case t_REAL: return (signe(g)<0)? -1: 1; case t_FRAC: case t_FRACN: case t_RFRAC: case t_RFRACN: return isfactor((GEN)g[1]); case t_COMPLEX: if (isnull((GEN)g[1])) return isfactor((GEN)g[2]); if (isnull((GEN)g[2])) return isfactor((GEN)g[1]); return 0; case t_PADIC: return !signe((GEN)g[4]); case t_QUAD: if (isnull((GEN)g[2])) return isfactor((GEN)g[3]); if (isnull((GEN)g[3])) return isfactor((GEN)g[2]); return 0; case t_POL: deja = 0; sig = 1; for (i=lgef(g)-1; i>1; i--) if (!isnull((GEN)g[i])) { if (deja) return 0; sig=isfactor((GEN)g[i]); deja=1; } return sig? sig: 1; case t_SER: for (i=lg(g)-1; i>1; i--) if (!isnull((GEN)g[i])) return 0; } return 1; } /* return 1 if g is a "truc" (see anal.c) */ static long isdenom(GEN g) { long i,deja; switch(typ(g)) { case t_FRAC: case t_FRACN: case t_RFRAC: case t_RFRACN: return 0; case t_COMPLEX: return isnull((GEN)g[2]); case t_PADIC: return !signe((GEN)g[4]); case t_QUAD: return isnull((GEN)g[3]); case t_POL: deja = 0; for (i=lgef(g)-1; i>1; i--) if (!isnull((GEN)g[i])) { if (deja) return 0; if (i==2) return isdenom((GEN)g[2]); if (!isone((GEN)g[i])) return 0; deja=1; } return 1; case t_SER: for (i=lg(g)-1; i>1; i--) if (!isnull((GEN)g[i])) return 0; } return 1; } /* write a * v^d */ static void wr_monome(GEN a, char *v, long d) { long sig = isone(a); if (sig) { sp_sign_sp(sig); monome(v,d); } else { sig = isfactor(a); if (sig) { sp_sign_sp(sig); bruti(a,sig); } else { sp_plus_sp(); pariputc('('); bruti(a,sig); pariputc(')'); } if (d) { pariputc('*'); monome(v,d); } } } static void wr_texnome(GEN a, char *v, long d) { long sig = isone(a); if (sig) { putsigne(sig); texnome(v,d); } else { sig = isfactor(a); if (sig) { putsigne(sig); texi(a,sig); } else { pariputs("+("); texi(a,sig); pariputc(')'); } if (d) texnome(v,d); } } static void wr_lead_monome(GEN a, char *v, long d, long nosign) { long sig = isone(a); if (sig) { if (!nosign && sig<0) pariputc('-'); monome(v,d); } else { if (isfactor(a)) bruti(a,nosign); else { pariputc('('); bruti(a,0); pariputc(')'); } if (d) { pariputc('*'); monome(v,d); } } } static void wr_lead_texnome(GEN a, char *v, long d, long nosign) { long sig = isone(a); if (sig) { if (!nosign && sig<0) pariputc('-'); texnome(v,d); } else { if (isfactor(a)) texi(a,nosign); else { pariputc('('); texi(a,0); pariputc(')'); } if (d) texnome(v,d); } } static void bruti(GEN g, long nosign) { long tg,l,i,j,r; GEN a,b; char *v, buf[32]; if (!g) { pariputs("NULL"); return; } if (isnull(g)) { pariputc('0'); return; } r = isone(g); if (r) { if (!nosign && r<0) pariputc('-'); pariputc('1'); return; } tg = typ(g); switch(tg) { case t_SMALL: pariputsf("%ld",smalltos(g)); break; case t_INT: wr_int(g,0,nosign); break; case t_REAL: wr_real(g,nosign); break; case t_INTMOD: case t_POLMOD: pariputs(new_fun_set? "Mod(": "mod("); bruti((GEN)g[2],0); comma_sp(); bruti((GEN)g[1],0); pariputc(')'); break; case t_FRAC: case t_FRACN: case t_RFRAC: case t_RFRACN: r = isfactor((GEN)g[1]); if (!r) pariputc('('); bruti((GEN)g[1],nosign); if (!r) pariputc(')'); pariputc('/'); r = isdenom((GEN)g[2]); if (!r) pariputc('('); bruti((GEN)g[2],0); if (!r) pariputc(')'); break; case t_COMPLEX: case t_QUAD: r = (tg==t_QUAD); a = (GEN)g[r+1]; b = (GEN)g[r+2]; v = r? "w": "I"; if (isnull(a)) { wr_lead_monome(b,v,1,nosign); return; } bruti(a,nosign); if (!isnull(b)) wr_monome(b,v,1); break; case t_POL: v = get_var(ordvar[varn(g)], buf); /* hack: we want g[i] = coeff of degree i. */ i = lgef(g)-3; g += 2; while (isnull((GEN)g[i])) i--; wr_lead_monome((GEN)g[i],v,i,nosign); while (i--) { a = (GEN)g[i]; if (!isnull_for_pol(a)) wr_monome(a,v,i); } break; case t_SER: v = get_var(ordvar[varn(g)], buf); i = valp(g); if (signe(g)) { /* hack: we want g[i] = coeff of degree i. */ l = i + lg(g)-2; g += (2-i); wr_lead_monome((GEN)g[i],v,i,nosign); while (++i < l) { a = (GEN)g[i]; if (!isnull_for_pol(a)) wr_monome(a,v,i); } sp_plus_sp(); } pariputs("O("); monome(v,i); pariputc(')'); break; case t_PADIC: { GEN p = (GEN)g[2]; i = valp(g); l = precp(g)+i; g = (GEN)g[4]; v = GENtostr(p); for (; i wd) { pariputs(v1); pariputs("\n\n"); for (j=0; j> 1; else sd = (n-d) >> 1; blancs(sn+1); pariputs(v1); pariputs("\n\n"); for (j=0; j1) { l = lg(g[1]); for (i=1; i # ifdef __EMX__ # include # endif # define HAVE_PIPES #endif pariFILE * newfile(FILE *f, char *name, int type) { pariFILE *file = (pariFILE*) gpmalloc(strlen(name) + 1 + sizeof(pariFILE)); file->type = type; file->name = strcpy((char*)(file+1), name); file->file = f; file->prev = last_file; file->next = NULL; if (last_file) last_file->next = file; if (DEBUGFILES) fprintferr("I/O: opening file %s (code %d) \n",name,type); return last_file = file; } static void pari_kill_file(pariFILE *f) { if ((f->type & mf_PIPE) == 0) { if (fclose(f->file)) err(warnfile, "close", f->name); } #ifdef HAVE_PIPES else { if (f->type & mf_FALSE) { if (fclose(f->file)) err(warnfile, "close", f->name); if (unlink(f->name)) err(warnfile, "delete", f->name); } else if (pclose(f->file) < 0) err(warnfile, "close pipe", f->name); } #endif if (DEBUGFILES) fprintferr("I/O: closing file %s (code %d) \n",f->name,f->type); free(f); } void pari_fclose(pariFILE *f) { if (f->next) (f->next)->prev = f->prev; else last_file = f->prev; if (f->prev) (f->prev)->next = f->next; pari_kill_file(f); } pariFILE * pari_fopen(char *s, char *mode) { FILE *f = fopen(s, mode); if (!f) err(talker, "could not open requested file %s", s); if (DEBUGFILES) fprintferr("I/O: opening file %s (mode %s)\n", s, mode); return newfile(f,s,0); } void pari_unlink(char *s) { if (unlink(s)) err(warner, "I/O: can\'t remove file %s", s); else if (DEBUGFILES) fprintferr("I/O: removed file %s\n", s); } /* Remove one INFILE from the stack. Reset infile (to the most recent infile) * Return -1, if we're trying to pop out stdin itself; 0 otherwise */ int popinfile() { pariFILE *f; filtre(NULL, f_ENDFILE); for (f = last_file; f; f = f->prev) { if (f->type & mf_IN) break; err(warner, "I/O: leaked file descriptor (%d): %s", f->type, f->name); pari_fclose(f); } last_file = f; if (!last_file) return -1; pari_fclose(last_file); for (f = last_file; f; f = f->prev) if (f->type & mf_IN) { infile = f->file; return 0; } infile = stdin; return 0; } void killallfiles(int check) { if (check) popinfile(); /* look for leaks */ while (last_file) { pariFILE *f = last_file->prev; pari_kill_file(last_file); last_file = f; } infile = stdin; } pariFILE * try_pipe(char *cmd, int flag) { #ifndef HAVE_PIPES err(archer); return NULL; #else FILE *file; char *f; # ifdef __EMX__ if (_osmode == DOS_MODE) /* no pipes under DOS */ { char *s; f = pari_unique_filename("pipe"); s = gpmalloc(strlen(cmd)+strlen(f)+4); sprintf(s,"%s > %s",cmd,f); if (system(s)) file = NULL; else { file = (FILE *) fopen(f,"r"); flag |= mf_FALSE; } free(s); } else # endif { file = (FILE *) popen(cmd,"r"); f = ""; } if (!file) err(talker,"%s failed !",cmd); return newfile(file, f, mf_PIPE|flag); #endif } /*******************************************************************/ /** **/ /** GP STANDARD INPUT AND OUTPUT **/ /** **/ /*******************************************************************/ static char *last_filename = NULL; static char **dir_list = NULL; /* expand tildes in filenames, return a malloc'ed buffer */ static char * _expand_tilde(char *s) { #if !defined(UNIX) && !defined(__EMX__) return pari_strdup(s); #else struct passwd *p; char *u; int len; if (*s != '~') return pari_strdup(s); s++; u = s; /* skip ~ */ if (!*s || *s == '/') p = getpwuid(geteuid()); else { char *tmp; while (*u && *u != '/') u++; len = u-s; tmp = strncpy(gpmalloc(len+1),s,len); tmp[len] = 0; p = getpwnam(tmp); free(tmp); } if (!p) err(talker2,"unknown user ",s,s-1); s = gpmalloc(strlen(p->pw_dir) + strlen(u) + 1); sprintf(s,"%s%s",p->pw_dir,u); return s; #endif } /* expand environment variables in str, return a malloc'ed buffer * assume no \ remain */ static char * _expand_env(char *str) { #ifdef WINCE return str; #elif defined(macintosh) return s; #else long i, l, len = 0, xlen = 16, xnum = 0; char *s = str, *s0 = s, *env; char **x = (char **)gpmalloc(xlen * sizeof(char*)); while (*s) { if (*s != '$') { s++; continue; } l = s - s0; if (l) { s0 = strncpy(gpmalloc(l+1), s0, l); s0[l] = 0; x[xnum++] = s0; len += l; } if (xnum > xlen - 3) /* need room for possibly two more elts */ { long xnew = xlen << 1; x = (char **)gprealloc((void*)x, xlen * sizeof(char*), xnew * sizeof(char*)); xlen = xnew; } s0 = ++s; /* skip $ */ while (is_keyword_char(*s)) s++; l = s - s0; env = strncpy(gpmalloc(l+1), s0, l); env[l] = 0; s0 = getenv(env); if (!s0) { err(warner,"undefined environment variable: %s",env); s0 = ""; } l = strlen(s0); if (l) { s0 = strncpy(gpmalloc(l+1), s0, l); s0[l] = 0; x[xnum++] = s0; len += l; } free(env); s0 = s; } l = s - s0; if (l) { s0 = strncpy(gpmalloc(l+1), s0, l); s0[l] = 0; x[xnum++] = s0; len += l; } s = gpmalloc(len+1); *s = 0; for (i = 0; i < xnum; i++) { (void)strcat(s, x[i]); free(x[i]); } free(str); free(x); return s; #endif } char * expand_tilde(char *s) { return _expand_env(_expand_tilde(s)); } #if defined __EMX__ || defined _WIN32 # define PATH_SEPARATOR ';' #else # define PATH_SEPARATOR ':' #endif void gp_expand_path(char *v) { char **path, **old, *s; int i, n = 0; v = pari_strdup(v); for (s=v; *s; s++) if (*s == PATH_SEPARATOR) { *s = 0; n++; } path = (char**) gpmalloc((n + 2)*sizeof(char *)); for (s=v, i=0; i<=n; i++) { char *end = s + strlen(s), *f = end; while (f > s && *--f == '/') *f = 0; path[i] = expand_tilde(s); s = end + 1; /* next path component */ } path[i] = NULL; old = dir_list; dir_list = path; if (old) { for (path=old; *path; path++) free(*path); free(old); } } /* name is a malloc'ed (existing) filename. Accept it (unzip if needed). */ static FILE * accept_file(char *name, FILE *file) { if (! last_file) { /* empty file stack, record this name */ if (last_filename) free(last_filename); last_filename = pari_strdup(name); } #ifdef ZCAT { long l = strlen(name); char *end = name + l-1; if (l > 2 && (!strncmp(end-1,".Z",2) #ifdef GNUZCAT || !strncmp(end-2,".gz",3) #endif )) { /* compressed file (compress or gzip) */ char *cmd = gpmalloc(strlen(ZCAT) + l + 2); sprintf(cmd,"%s %s",ZCAT,name); fclose(file); infile = try_pipe(cmd, mf_IN)->file; free(cmd); return infile; } } #endif return infile = newfile(file, name, mf_IN)->file; } /* If a file called "name" exists (possibly after appending ".gp") * record it in the file_stack (as a pipe if compressed). * name is malloc'ed, we free it before returning */ static FILE * try_name(char *name) { FILE *file = fopen(name, "r"); if (file) return accept_file(name,file); { /* try appending ".gp" to name */ char *s = gpmalloc(strlen(name)+4); sprintf(s, "%s.gp", name); file = fopen(s, "r"); if (file) file = accept_file(s,file); free(s); } free(name); return file; } /* If name = "", re-read last file */ void switchin(char *name0) { char *s, *name; if (*name0) name = expand_tilde(name0); else { if (last_filename == NULL) err(talker,"You never gave me anything to read!"); name0 = last_filename; name = pari_strdup(name0); } /* if name contains '/', don't use dir_list */ s=name; while (*s && *s != '/') s++; if (*s) { if (try_name(name)) return; } else { char **tmp = dir_list; for ( ; *tmp; tmp++) { /* make room for '/' and '\0', try_name frees it */ s = gpmalloc(2 + strlen(*tmp) + strlen(name)); sprintf(s,"%s/%s",*tmp,name); if (try_name(s)) return; } } err(openfiler,"input",name0); } void switchout(char *name) { if (name) { FILE *f = fopen(name, "a"); if (!f) err(openfiler,"output",name); pari_outfile = f; } else if (pari_outfile != stdout) { fclose(pari_outfile); pari_outfile = stdout; } } /*******************************************************************/ /** **/ /** TEMPORARY FILES **/ /** **/ /*******************************************************************/ #ifdef __WIN32 # include /* for getpid */ #endif #ifndef R_OK # define R_OK 4 # define W_OK 2 # define X_OK 1 # define F_OK 0 #endif #ifdef __EMX__ #include static int unix_shell() { char *base, *sh = getenv ("EMXSHELL"); if (sh == NULL) sh = getenv ("COMSPEC"); if (sh == NULL) return 0; base = _getname (sh); if (stricmp (base, "cmd.exe") == 0 || stricmp (base, "4os2.exe") == 0 || stricmp (base, "command.com") == 0 || stricmp (base, "4dos.com") == 0) return 0; return 1; } #endif /* check if s has rwx permissions for us */ static int pari_is_rwx(char *s) { #if defined(UNIX) || defined (__EMX__) /* TODO: ok for macintosh? */ return access(s, R_OK | W_OK | X_OK) == 0; #else return 1; #endif } static int pari_file_exists(char *s) { #if defined(UNIX) || defined (__EMX__) return access(s, F_OK) == 0; #else return 0; #endif } #ifndef macintosh char * env_ok(char *s) { #ifdef WINCE return NULL; #else char *t = getenv(s); if (t && pari_is_rwx(t) == 0) { err(warner,"%s is set (%s), but is not writeable", s,t); t = NULL; } return t; #endif } #endif static char* pari_tmp_dir() { #ifdef WINCE char *s; s = env_ok("TEMP"); if (s) return s; return "\\temp"; #else #ifndef macintosh char *s; s = env_ok("GPTMPDIR"); if (s) return s; s = env_ok("TMPDIR"); if (s) return s; #ifdef __EMX__ s = env_ok("TMP"); if (s) return s; s = env_ok("TEMP"); if (s) return s; #endif #endif #if defined(UNIX) || defined(__EMX__) if (pari_is_rwx("/var/tmp")) return "/var/tmp"; if (pari_is_rwx("/tmp")) return "/tmp"; #endif return "."; #endif } /* Return a "unique filename" built from the string s, possibly the user id * and the process pid (on Unix systems). A "temporary" directory name is * prepended. The name returned is stored in a static buffer (gpmalloc'ed * permanently). It is DOS-safe (s truncated to 8 chars) */ char* pari_unique_filename(char *s) { static char *buf, *pre, *post = NULL; if (!post || !s) /* initialize */ { char suf[64]; int lpre, lsuf; if (post) free(post); pre = pari_tmp_dir(); #ifdef UNIX sprintf(suf,".%ld.%ld", (long)getuid(), (long)getpid()); #else sprintf(suf,".gpa"); #endif lsuf = strlen(suf); lpre = strlen(pre); /* room for suffix + '\0 + prefix + '/' + s + suffix '\0' */ /* ^- post ^- buf ^- pre */ post = (char*) gpmalloc(lpre + 1 + 8 + 2*(lsuf + 1)); strcpy(post, suf); buf = post + lsuf; *buf = 0; buf++; strcpy(buf, pre); if (buf[lpre-1] != '/') { (void)strcat(buf, "/"); lpre++; } #ifdef __EMX__ if (!unix_shell()) for (pre=buf; *pre; pre++) if (*pre == '/') *pre = '\\'; #endif #ifdef WINCE for (pre=buf; *pre; pre++) if (*pre == '/') *pre = '\\'; #endif pre = buf + lpre; if (!s) return s; } sprintf(pre, "%.8s%s", s, post); if (pari_file_exists(buf)) { char c, *end = buf + strlen(buf) - 1; for (c='a'; c<='z'; c++) { *end = c; if (! pari_file_exists(buf)) break; } if (c > 'z') err(talker,"couldn't find a suitable name for a tempfile (%s)",s); } return buf; }