Testing latest pari + WASM + node.js... and it works?! Wow.
License: GPL3
ubuntu2004
/* Copyright (C) 2000 The PARI group.12This file is part of the PARI/GP package.34PARI/GP is free software; you can redistribute it and/or modify it under the5terms of the GNU General Public License as published by the Free Software6Foundation; either version 2 of the License, or (at your option) any later7version. It is distributed in the hope that it will be useful, but WITHOUT8ANY WARRANTY WHATSOEVER.910Check the License for details. You should have received a copy of it, along11with the package; see the file 'COPYING'. If not, write to the Free Software12Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */1314/*******************************************************************/15/** **/16/** LIBRARY ROUTINES FOR PARI CALCULATOR **/17/** **/18/*******************************************************************/19#ifdef _WIN3220# include "../systems/mingw/pwinver.h"21# include <windows.h>22# include "../systems/mingw/mingw.h"23# include <process.h>24#endif2526#include "pari.h"27#include "paripriv.h"28#ifdef __EMSCRIPTEN__29#include "../systems/emscripten/emscripten.h"30#endif3132/********************************************************************/33/** **/34/** STRINGS **/35/** **/36/********************************************************************/3738void39pari_skip_space(char **s) {40char *t = *s;41while (isspace((int)*t)) t++;42*s = t;43}44void45pari_skip_alpha(char **s) {46char *t = *s;47while (isalpha((int)*t)) t++;48*s = t;49}5051/*******************************************************************/52/** **/53/** BUFFERS **/54/** **/55/*******************************************************************/56static Buffer **bufstack;57static pari_stack s_bufstack;58void59pari_init_buffers(void)60{ pari_stack_init(&s_bufstack, sizeof(Buffer*), (void**)&bufstack); }6162void63pop_buffer(void)64{65if (s_bufstack.n)66delete_buffer( bufstack[ --s_bufstack.n ] );67}6869/* kill all buffers until B is met or nothing is left */70void71kill_buffers_upto(Buffer *B)72{73while (s_bufstack.n) {74if (bufstack[ s_bufstack.n-1 ] == B) break;75pop_buffer();76}77}78void79kill_buffers_upto_including(Buffer *B)80{81while (s_bufstack.n) {82if (bufstack[ s_bufstack.n-1 ] == B) { pop_buffer(); break; }83pop_buffer();84}85}8687static int disable_exception_handler = 0;88#define BLOCK_EH_START \89{ \90int block=disable_exception_handler;\91disable_exception_handler = 1;9293#define BLOCK_EH_END \94disable_exception_handler = block;\95}96/* numerr < 0: from SIGINT */97int98gp_handle_exception(long numerr)99{100if (disable_exception_handler)101disable_exception_handler = 0;102else if (GP_DATA->breakloop && cb_pari_break_loop103&& cb_pari_break_loop(numerr))104return 1;105return 0;106}107108/********************************************************************/109/** **/110/** HELP **/111/** **/112/********************************************************************/113void114pari_hit_return(void)115{116int c;117if (GP_DATA->flags & (gpd_EMACS|gpd_TEXMACS)) return;118BLOCK_EH_START119pari_puts("/*-- (type RETURN to continue) --*/");120pari_flush();121/* if called from a readline callback, may be in a funny TTY mode */122do c = fgetc(stdin); while (c >= 0 && c != '\n' && c != '\r');123pari_putc('\n');124BLOCK_EH_END125}126127static int128has_ext_help(void) { return (GP_DATA->help && *GP_DATA->help); }129130static int131compare_str(char **s1, char **s2) { return strcmp(*s1, *s2); }132133/* Print all elements of list in columns, pausing every nbli lines134* if nbli is nonzero. list is a NULL terminated list of function names */135void136print_fun_list(char **list, long nbli)137{138long i=0, j=0, maxlen=0, nbcol,len, w = term_width();139char **l;140141while (list[i]) i++;142qsort (list, i, sizeof(char *), (QSCOMP)compare_str);143144for (l=list; *l; l++)145{146len = strlen(*l);147if (len > maxlen) maxlen=len;148}149maxlen++; nbcol= w / maxlen;150if (nbcol * maxlen == w) nbcol--;151if (!nbcol) nbcol = 1;152153pari_putc('\n'); i=0;154for (l=list; *l; l++)155{156pari_puts(*l); i++;157if (i >= nbcol)158{159i=0; pari_putc('\n');160if (nbli && j++ > nbli) { j = 0; pari_hit_return(); }161continue;162}163len = maxlen - strlen(*l);164while (len--) pari_putc(' ');165}166if (i) pari_putc('\n');167}168169static const long MAX_SECTION = 16;170static void171commands(long n)172{173long i;174entree *ep;175char **t_L;176pari_stack s_L;177178pari_stack_init(&s_L, sizeof(*t_L), (void**)&t_L);179for (i = 0; i < functions_tblsz; i++)180for (ep = functions_hash[i]; ep; ep = ep->next)181{182long m;183switch (EpVALENCE(ep))184{185case EpVAR:186if (typ((GEN)ep->value) == t_CLOSURE) break;187/* fall through */188case EpNEW: continue;189}190m = ep->menu;191if (m == n || (n < 0 && m && m <= MAX_SECTION))192pari_stack_pushp(&s_L, (void*)ep->name);193}194pari_stack_pushp(&s_L, NULL);195print_fun_list(t_L, term_height()-4);196pari_stack_delete(&s_L);197}198199void200pari_center(const char *s)201{202pari_sp av = avma;203long i, l = strlen(s), pad = term_width() - l;204char *buf, *u;205206if (pad<0) pad=0; else pad >>= 1;207u = buf = stack_malloc(l + pad + 2);208for (i=0; i<pad; i++) *u++ = ' ';209while (*s) *u++ = *s++;210*u++ = '\n'; *u = 0;211pari_puts(buf); set_avma(av);212}213214static void215community(void)216{217print_text("The PARI/GP distribution includes a reference manual, a \218tutorial, a reference card and quite a few examples. They have been installed \219in the directory ");220pari_puts(" ");221pari_puts(pari_datadir);222pari_puts("\nYou can also download them from http://pari.math.u-bordeaux.fr/.\223\n\nThree mailing lists are devoted to PARI:\n\224- pari-announce (moderated) to announce major version changes.\n\225- pari-dev for everything related to the development of PARI, including\n\226suggestions, technical questions, bug reports and patch submissions.\n\227- pari-users for everything else!\n\228To subscribe, send an empty message to\n\229<pari_list_name>[email protected]\n\230with a Subject: field containing the word 'subscribe'.\n\n");231print_text("An archive is kept at the WWW site mentioned above. You can also \232reach the authors at [email protected] (answer not guaranteed)."); }233234static void235gentypes(void)236{237pari_puts("List of the PARI types:\n\238t_INT : long integers [ cod1 ] [ cod2 ] [ man_1 ] ... [ man_k ]\n\239t_REAL : long real numbers [ cod1 ] [ cod2 ] [ man_1 ] ... [ man_k ]\n\240t_INTMOD : integermods [ code ] [ mod ] [ integer ]\n\241t_FRAC : irred. rationals [ code ] [ num. ] [ den. ]\n\242t_FFELT : finite field elt. [ code ] [ cod2 ] [ elt ] [ mod ] [ p ]\n\243t_COMPLEX: complex numbers [ code ] [ real ] [ imag ]\n\244t_PADIC : p-adic numbers [ cod1 ] [ cod2 ] [ p ] [ p^r ] [ int ]\n\245t_QUAD : quadratic numbers [ cod1 ] [ mod ] [ real ] [ imag ]\n\246t_POLMOD : poly mod [ code ] [ mod ] [ polynomial ]\n\247-------------------------------------------------------------\n\248t_POL : polynomials [ cod1 ] [ cod2 ] [ man_1 ] ... [ man_k ]\n\249t_SER : power series [ cod1 ] [ cod2 ] [ man_1 ] ... [ man_k ]\n\250t_RFRAC : irred. rat. func. [ code ] [ num. ] [ den. ]\n\251t_QFB : qfb [ code ] [ a ] [ b ] [ c ] [ disc ]\n\252t_VEC : row vector [ code ] [ x_1 ] ... [ x_k ]\n\253t_COL : column vector [ code ] [ x_1 ] ... [ x_k ]\n\254t_MAT : matrix [ code ] [ col_1 ] ... [ col_k ]\n\255t_LIST : list [ cod1 ] [ cod2 ][ vec ]\n\256t_STR : string [ code ] [ man_1 ] ... [ man_k ]\n\257t_VECSMALL: vec. small ints [ code ] [ x_1 ] ... [ x_k ]\n\258t_CLOSURE: functions [ code ] [ arity ] [ code ] [ operand ] [ data ] [ text ]\n\259t_ERROR : error context [ code ] [ errnum ] [ dat_1 ] ... [ dat_k ]\n\260t_INFINITY: a*infinity [ code ] [ a ]\n\261\n");262}263264static void265menu_commands(void)266{267ulong i;268const char *s[] = {269"user-defined functions (aliases, installed and user functions)",270"PROGRAMMING under GP",271"Standard monadic or dyadic OPERATORS",272"CONVERSIONS and similar elementary functions",273"functions related to COMBINATORICS",274"NUMBER THEORETICAL functions",275"POLYNOMIALS and power series",276"Vectors, matrices, LINEAR ALGEBRA and sets",277"TRANSCENDENTAL functions",278"SUMS, products, integrals and similar functions",279"General NUMBER FIELDS",280"Associative and central simple ALGEBRAS",281"ELLIPTIC CURVES",282"L-FUNCTIONS",283"MODULAR FORMS",284"MODULAR SYMBOLS",285"GRAPHIC functions",286"The PARI community"287};288pari_puts("Help topics: for a list of relevant subtopics, type ?n for n in\n");289for (i = 0; i < numberof(s); i++) pari_printf(" %2lu: %s\n", i, s[i]);290pari_puts("Also:\n\291? functionname (short on-line help)\n\292?\\ (keyboard shortcuts)\n\293?. (member functions)\n");294if (has_ext_help()) pari_puts("\295Extended help (if available):\n\296?? (opens the full user's manual in a dvi previewer)\n\297?? tutorial / refcard / libpari (tutorial/reference card/libpari manual)\n\298?? refcard-ell (or -lfun/-mf/-nf: specialized reference card)\n\299?? keyword (long help text about \"keyword\" from the user's manual)\n\300??? keyword (a propos: list of related functions).");301}302303static void304slash_commands(void)305{306pari_puts("# : enable/disable timer\n\307## : print time for last result\n\308\\\\ : comment up to end of line\n\309\\a {n} : print result in raw format (readable by PARI)\n\310\\B {n} : print result in beautified format\n\311\\c : list all commands (same effect as ?*)\n\312\\d : print all defaults\n\313\\e {n} : enable/disable echo (set echo=n)\n\314\\g {n} : set debugging level\n\315\\gf{n} : set file debugging level\n\316\\gm{n} : set memory debugging level\n\317\\h {m-n}: hashtable information\n\318\\l {f} : enable/disable logfile (set logfile=f)\n\319\\m {n} : print result in prettymatrix format\n\320\\o {n} : set output method (0=raw, 1=prettymatrix, 2=prettyprint, 3=2-dim)\n\321\\p {n} : change real precision\n\322\\pb{n} : change real bit precision\n\323\\ps{n} : change series precision\n\324\\q : quit completely this GP session\n\325\\r {f} : read in a file\n\326\\s : print stack information\n\327\\t : print the list of PARI types\n\328\\u : print the list of user-defined functions\n\329\\um : print the list of user-defined member functions\n\330\\v : print current version of GP\n\331\\w {nf} : write to a file\n\332\\x {n} : print complete inner structure of result\n\333\\y {n} : disable/enable automatic simplification (set simplify=n)\n\334\n\335{f}=optional filename. {n}=optional integer\n");336}337338static void339member_commands(void)340{341pari_puts("\342Member functions, followed by relevant objects\n\n\343a1-a6, b2-b8, c4-c6 : coeff. of the curve. ell\n\344area : area ell\n\345bid : big ideal bid, bnr\n\346bnf : big number field bnf,bnr\n\347clgp : class group bid, bnf,bnr\n\348cyc : cyclic decomposition (SNF) bid, clgp,ell, bnf,bnr\n\349diff, codiff: different and codifferent nf,bnf,bnr\n\350disc : discriminant ell,nf,bnf,bnr,rnf\n\351e, f : inertia/residue degree prid\n\352fu : fundamental units bnf\n\353gen : generators bid,prid,clgp,ell, bnf,bnr, gal\n\354group: group ell, gal\n\355index: index nf,bnf,bnr\n\356j : j-invariant ell\n");357/* split: some compilers can't handle long constant strings */358pari_puts("\359mod : modulus bid, bnr, gal\n\360nf : number field nf,bnf,bnr,rnf\n\361no : number of elements bid, clgp,ell, bnf,bnr\n\362omega, eta: [w1,w2] and [eta1, eta2] ell\n\363orders: relative orders of generators gal\n\364p : rational prime prid, ell,nf,bnr,bnr,rnf,gal\n\365pol : defining polynomial nf,bnf,bnr, gal\n\366polabs: defining polynomial over Q rnf\n\367reg : regulator bnf\n\368roots: roots ell,nf,bnf,bnr, gal\n\369sign,r1,r2 : signature nf,bnf,bnr\n\370t2 : t2 matrix nf,bnf,bnr\n\371tate : Tate's [u^2, u, q, [a,b], L, Ei] ell\n\372tu : torsion unit and its order bnf\n\373zk : integral basis nf,bnf,bnr,rnf\n\374zkst : structure of (Z_K/m)* bid, bnr\n");375}376377#define QUOTE "_QUOTE"378#define DOUBQUOTE "_DOUBQUOTE"379#define BACKQUOTE "_BACKQUOTE"380381static char *382_cat(char *s, const char *t)383{384*s = 0; strcat(s,t); return s + strlen(t);385}386387static char *388filter_quotes(const char *s)389{390int i, l = strlen(s);391int quote = 0;392int backquote = 0;393int doubquote = 0;394char *str, *t;395396for (i=0; i < l; i++)397switch(s[i])398{399case '\'': quote++; break;400case '`' : backquote++; break;401case '"' : doubquote++;402}403str = (char*)pari_malloc(l + quote * (strlen(QUOTE)-1)404+ doubquote * (strlen(DOUBQUOTE)-1)405+ backquote * (strlen(BACKQUOTE)-1) + 1);406t = str;407for (i=0; i < l; i++)408switch(s[i])409{410case '\'': t = _cat(t, QUOTE); break;411case '`' : t = _cat(t, BACKQUOTE); break;412case '"' : t = _cat(t, DOUBQUOTE); break;413default: *t++ = s[i];414}415*t = 0; return str;416}417418static int419nl_read(char *s) { size_t l = strlen(s); return s[l-1] == '\n'; }420421/* query external help program for s. num < 0 [keyword] or chapter number */422static void423external_help(const char *s, int num)424{425long nbli = term_height()-3, li = 0;426char buf[256], *str;427const char *opt = "", *ar = "";428char *t, *help = GP_DATA->help;429pariFILE *z;430FILE *f;431#ifdef __EMSCRIPTEN__432pari_emscripten_help(s);433#endif434435if (!has_ext_help()) pari_err(e_MISC,"no external help program");436t = filter_quotes(s);437if (num < 0)438opt = "-k";439else if (t[strlen(t)-1] != '@')440ar = stack_sprintf("@%d",num);441#ifdef _WIN32442if (*help == '@')443{444const char *basedir = win32_basedir();445help = stack_sprintf("%c:& cd %s & %s", *basedir, basedir, help+1);446}447#endif448str = stack_sprintf("%s -fromgp %s %c%s%s%c",449help, opt, SHELL_Q, t, ar, SHELL_Q);450z = try_pipe(str,0); f = z->file;451pari_free(t);452while (fgets(buf, numberof(buf), f))453{454if (!strncmp("ugly_kludge_done",buf,16)) break;455pari_puts(buf);456if (nl_read(buf) && ++li > nbli) { pari_hit_return(); li = 0; }457}458pari_fclose(z);459}460461const char **462gphelp_keyword_list(void)463{464static const char *L[]={465"operator",466"libpari",467"member",468"integer",469"real",470"readline",471"refcard",472"refcard-nf",473"refcard-ell",474"refcard-mf",475"refcard-lfun",476"tutorial",477"tutorial-mf",478"mf",479"nf",480"bnf",481"bnr",482"ell",483"rnf",484"bid",485"modulus",486"prototype",487"Lmath",488"Ldata",489"Linit",490NULL};491return L;492}493494static int495ok_external_help(char **s)496{497const char **L;498long n;499if (!**s) return 1;500if (!isalpha((int)**s)) return 3; /* operator or section number */501if (!strncmp(*s,"t_",2)) { *s += 2; return 2; } /* type name */502503L = gphelp_keyword_list();504for (n=0; L[n]; n++)505if (!strcmp(*s,L[n])) return 3;506return 0;507}508509static void510cut_trailing_garbage(char *s)511{512char c;513while ( (c = *s++) )514{515if (c == '\\' && ! *s++) return; /* gobble next char, return if none. */516if (!is_keyword_char(c) && c != '@') { s[-1] = 0; return; }517}518}519520static void521digit_help(char *s, long flag)522{523long n = atoi(s);524if (n < 0 || n > MAX_SECTION+4)525pari_err(e_SYNTAX,"no such section in help: ?",s,s);526if (n == MAX_SECTION+1)527community();528else if (flag & h_LONG)529external_help(s,3);530else531commands(n);532return;533}534535long536pari_community(void)537{538return MAX_SECTION+1;539}540541static void542simple_help(const char *s1, const char *s2) { pari_printf("%s: %s\n", s1, s2); }543544static void545default_help(char *s, long flag)546{547if (flag & h_LONG)548external_help(stack_strcat("se:def,",s),3);549else550simple_help(s,"default");551}552553static void554help(const char *s0, int flag)555{556const long long_help = flag & h_LONG;557long n;558entree *ep;559char *s = get_sep(s0);560561if (isdigit((int)*s)) { digit_help(s,flag); return; }562if (flag & h_APROPOS) { external_help(s,-1); return; }563/* Get meaningful answer on '\ps 5' (e.g. from <F1>) */564if (*s == '\\' && isalpha((int)*(s+1)))565{ char *t = s+1; pari_skip_alpha(&t); *t = '\0'; }566if (isalpha((int)*s))567{568char *t = s;569if (!strncmp(s, "default", 7))570{ /* special-case ?default(dft_name), e.g. default(log) */571t += 7; pari_skip_space(&t);572if (*t == '(')573{574t++; pari_skip_space(&t);575cut_trailing_garbage(t);576if (pari_is_default(t)) { default_help(t,flag); return; }577}578}579if (!strncmp(s, "refcard-", 8)) t += 8;580else if (!strncmp(s, "tutorial-", 9)) t += 9;581cut_trailing_garbage(t);582}583584if (long_help && (n = ok_external_help(&s))) { external_help(s,n); return; }585switch (*s)586{587case '*' : commands(-1); return;588case '\0': menu_commands(); return;589case '\\': slash_commands(); return;590case '.' : member_commands(); return;591}592ep = is_entry(s);593if (!ep)594{595if (pari_is_default(s))596default_help(s,flag);597else if (long_help)598external_help(s,3);599else if (!cb_pari_whatnow || !cb_pari_whatnow(pariOut, s,1))600simple_help(s,"unknown identifier");601return;602}603604if (EpVALENCE(ep) == EpALIAS)605{606pari_printf("%s is aliased to:\n\n",s);607ep = do_alias(ep);608}609switch(EpVALENCE(ep))610{611case EpVAR:612if (!ep->help)613{614if (typ((GEN)ep->value)!=t_CLOSURE)615simple_help(s, "user defined variable");616else617{618GEN str = closure_get_text((GEN)ep->value);619if (typ(str) == t_VEC)620pari_printf("%s =\n %Ps\n", ep->name, ep->value);621}622return;623}624break;625626case EpINSTALL:627if (!ep->help) { simple_help(s, "installed function"); return; }628break;629630case EpNEW:631if (!ep->help) { simple_help(s, "new identifier"); return; };632break;633634default: /* built-in function */635if (!ep->help) pari_err_BUG("gp_help (no help found)"); /*paranoia*/636if (long_help) { external_help(ep->name,3); return; }637}638print_text(ep->help);639}640641void642gp_help(const char *s, long flag)643{644pari_sp av = avma;645if ((flag & h_RL) == 0)646{647if (*s == '?') { flag |= h_LONG; s++; }648if (*s == '?') { flag |= h_APROPOS; s++; }649}650term_color(c_HELP); help(s,flag); term_color(c_NONE);651if ((flag & h_RL) == 0) pari_putc('\n');652set_avma(av);653}654655/********************************************************************/656/** **/657/** GP HEADER **/658/** **/659/********************************************************************/660static char *661what_readline(void)662{663#ifdef READLINE664const char *v = READLINE;665char *s = stack_malloc(3 + strlen(v) + 8);666(void)sprintf(s, "v%s %s", v, GP_DATA->use_readline? "enabled": "disabled");667return s;668#else669return (char*)"not compiled in";670#endif671}672673static char *674what_cc(void)675{676char *s;677#ifdef GCC_VERSION678# ifdef __cplusplus679s = stack_malloc(6 + strlen(GCC_VERSION) + 1);680(void)sprintf(s, "(C++) %s", GCC_VERSION);681# else682s = stack_strdup(GCC_VERSION);683# endif684#else685# ifdef _MSC_VER686s = stack_malloc(32);687(void)sprintf(s, "MSVC-%i", _MSC_VER);688# else689s = NULL;690# endif691#endif692return s;693}694695static char *696convert_time(char *s, long delay)697{698if (delay >= 3600000)699{700sprintf(s, "%ldh, ", delay / 3600000); s+=strlen(s);701delay %= 3600000;702}703if (delay >= 60000)704{705sprintf(s, "%ldmin, ", delay / 60000); s+=strlen(s);706delay %= 60000;707}708if (delay >= 1000)709{710sprintf(s, "%ld,", delay / 1000); s+=strlen(s);711delay %= 1000;712if (delay < 100)713{714sprintf(s, "%s", (delay<10)? "00": "0");715s+=strlen(s);716}717}718sprintf(s, "%ld ms", delay); s+=strlen(s);719return s;720}721722/* Format a time of 'delay' ms */723const char *724gp_format_time(long delay)725{726char *buf = stack_malloc(64), *s = buf;727term_get_color(s, c_TIME);728s = convert_time(s + strlen(s), delay);729term_get_color(s, c_NONE); return buf;730}731732GEN733strtime(long delay)734{735long n = nchar2nlong(64);736GEN x = cgetg(n+1, t_STR);737char *buf = GSTR(x), *t = buf + 64, *s = convert_time(buf, delay);738s++; while (s < t) *s++ = 0; /* pacify valgrind */739return x;740}741742/********************************************************************/743/* */744/* GPRC */745/* */746/********************************************************************/747/* LOCATE GPRC */748static void749err_gprc(const char *s, char *t, char *u)750{751err_printf("\n");752pari_err(e_SYNTAX,s,t,u);753}754755/* return $HOME or the closest we can find */756static const char *757get_home(int *free_it)758{759char *drv, *pth = os_getenv("HOME");760if (pth) return pth;761if ((drv = os_getenv("HOMEDRIVE"))762&& (pth = os_getenv("HOMEPATH")))763{ /* looks like WinNT */764char *buf = (char*)pari_malloc(strlen(pth) + strlen(drv) + 1);765sprintf(buf, "%s%s",drv,pth);766*free_it = 1; return buf;767}768pth = pari_get_homedir("");769return pth? pth: ".";770}771772static FILE *773gprc_chk(const char *s)774{775FILE *f = fopen(s, "r");776if (f && !(GP_DATA->flags & gpd_QUIET)) err_printf("Reading GPRC: %s\n", s);777return f;778}779780/* Look for [._]gprc: $GPRC, then in $HOME, ., /etc, pari_datadir */781static FILE *782gprc_get(void)783{784FILE *f = NULL;785const char *gprc = os_getenv("GPRC");786if (gprc) f = gprc_chk(gprc);787if (!f)788{789int free_it = 0;790const char *home = get_home(&free_it);791char *str, *s, c;792long l;793l = strlen(home); c = home[l-1];794/* + "/gprc.txt" + \0*/795str = strcpy((char*)pari_malloc(l+10), home);796if (free_it) pari_free((void*)home);797s = str + l;798if (c != '/' && c != '\\') *s++ = '/';799#ifndef _WIN32800strcpy(s, ".gprc");801#else802strcpy(s, "gprc.txt");803#endif804f = gprc_chk(str); /* in $HOME */805if (!f) f = gprc_chk(s); /* in . */806#ifndef _WIN32807if (!f) f = gprc_chk("/etc/gprc");808#else809if (!f) /* in basedir */810{811const char *basedir = win32_basedir();812char *t = (char *) pari_malloc(strlen(basedir)+strlen(s)+2);813sprintf(t, "%s/%s", basedir, s);814f = gprc_chk(t); free(t);815}816#endif817pari_free(str);818}819return f;820}821822/* PREPROCESSOR */823824static ulong825read_uint(char **s)826{827long v = atol(*s);828if (!isdigit((int)**s)) err_gprc("not an integer", *s, *s);829while (isdigit((int)**s)) (*s)++;830return v;831}832static ulong833read_dot_uint(char **s)834{835if (**s != '.') return 0;836(*s)++; return read_uint(s);837}838/* read a.b.c */839static long840read_version(char **s)841{842long a, b, c;843a = read_uint(s);844b = read_dot_uint(s);845c = read_dot_uint(s);846return PARI_VERSION(a,b,c);847}848849static int850get_preproc_value(char **s)851{852if (!strncmp(*s,"EMACS",5)) {853*s += 5;854return GP_DATA->flags & (gpd_EMACS|gpd_TEXMACS);855}856if (!strncmp(*s,"READL",5)) {857*s += 5;858return GP_DATA->use_readline;859}860if (!strncmp(*s,"VERSION",7)) {861int less = 0, orequal = 0;862long d;863*s += 7;864switch(**s)865{866case '<': (*s)++; less = 1; break;867case '>': (*s)++; less = 0; break;868default: return -1;869}870if (**s == '=') { (*s)++; orequal = 1; }871d = paricfg_version_code - read_version(s);872if (!d) return orequal;873return less? (d < 0): (d > 0);874}875if (!strncmp(*s,"BITS_IN_LONG",12)) {876*s += 12;877if ((*s)[0] == '=' && (*s)[1] == '=')878{879*s += 2;880return BITS_IN_LONG == read_uint(s);881}882}883return -1;884}885886/* PARSE GPRC */887888/* 1) replace next separator by '\0' (t must be writable)889* 2) return the next expression ("" if none)890* see get_sep() */891static char *892next_expr(char *t)893{894int outer = 1;895char *s = t;896897for(;;)898{899char c;900switch ((c = *s++))901{902case '"':903if (outer || (s >= t+2 && s[-2] != '\\')) outer = !outer;904break;905case '\0':906return (char*)"";907default:908if (outer && c == ';') { s[-1] = 0; return s; }909}910}911}912913Buffer *914filtered_buffer(filtre_t *F)915{916Buffer *b = new_buffer();917init_filtre(F, b);918pari_stack_pushp(&s_bufstack, (void*)b);919return b;920}921922/* parse src of the form s=t (or s="t"), set *ps to s, and *pt to t.923* modifies src (replaces = by \0) */924void925parse_key_val(char *src, char **ps, char **pt)926{927char *s_end, *t;928t = src; while (*t && *t != '=') t++;929if (*t != '=') err_gprc("missing '='",t,src);930s_end = t;931t++;932if (*t == '"') (void)pari_translate_string(t, t, src);933*s_end = 0; *ps = src; *pt = t;934}935936void937gp_initrc(pari_stack *p_A)938{939FILE *file = gprc_get();940Buffer *b;941filtre_t F;942VOLATILE long c = 0;943jmp_buf *env;944pari_stack s_env;945946if (!file) return;947b = filtered_buffer(&F);948pari_stack_init(&s_env, sizeof(*env), (void**)&env);949(void)pari_stack_new(&s_env);950for(;;)951{952char *nexts, *s, *t;953if (setjmp(env[s_env.n-1])) err_printf("...skipping line %ld.\n", c);954c++;955if (!get_line_from_file(NULL,&F,file)) break;956s = b->buf;957if (*s == '#')958{ /* preprocessor directive */959int z, NOT = 0;960s++;961if (strncmp(s,"if",2)) err_gprc("unknown directive",s,b->buf);962s += 2;963if (!strncmp(s,"not",3)) { NOT = !NOT; s += 3; }964if (*s == '!') { NOT = !NOT; s++; }965t = s;966z = get_preproc_value(&s);967if (z < 0) err_gprc("unknown preprocessor variable",t,b->buf);968if (NOT) z = !z;969if (!*s)970{ /* make sure at least an expr follows the directive */971if (!get_line_from_file(NULL,&F,file)) break;972s = b->buf;973}974if (!z) continue; /* dump current line */975}976/* parse line */977for ( ; *s; s = nexts)978{979nexts = next_expr(s);980if (!strncmp(s,"read",4) && (s[4] == ' ' || s[4] == '\t' || s[4] == '"'))981{ /* read file */982s += 4;983t = (char*)pari_malloc(strlen(s) + 1);984if (*s == '"') (void)pari_translate_string(s, t, s-4); else strcpy(t,s);985pari_stack_pushp(p_A,t);986}987else988{ /* set default */989parse_key_val(s, &s,&t);990(void)setdefault(s,t,d_INITRC);991}992}993}994pari_stack_delete(&s_env);995pop_buffer();996if (!(GP_DATA->flags & gpd_QUIET)) err_printf("GPRC Done.\n\n");997fclose(file);998}9991000void1001gp_load_gprc(void)1002{1003pari_stack sA;1004char **A;1005long i;1006pari_stack_init(&sA,sizeof(*A),(void**)&A);1007gp_initrc(&sA);1008for (i = 0; i < sA.n; pari_free(A[i]),i++)1009{1010pari_CATCH(CATCH_ALL) { err_printf("... skipping file '%s'\n", A[i]); }1011pari_TRY { gp_read_file(A[i]); } pari_ENDCATCH;1012}1013pari_stack_delete(&sA);1014}10151016/********************************************************************/1017/* */1018/* PROMPTS */1019/* */1020/********************************************************************/1021/* if prompt is coloured, tell readline to ignore the ANSI escape sequences */1022/* s must be able to store 14 chars (including final \0) */1023#ifdef READLINE1024static void1025readline_prompt_color(char *s, int c)1026{1027#ifdef _WIN321028(void)s; (void)c;1029#else1030*s++ = '\001'; /*RL_PROMPT_START_IGNORE*/1031term_get_color(s, c);1032s += strlen(s);1033*s++ = '\002'; /*RL_PROMPT_END_IGNORE*/1034*s = 0;1035#endif1036}1037#endif1038/* s must be able to store 14 chars (including final \0) */1039static void1040brace_color(char *s, int c, int force)1041{1042if (disable_color || (gp_colors[c] == c_NONE && !force)) return;1043#ifdef READLINE1044if (GP_DATA->use_readline)1045readline_prompt_color(s, c);1046else1047#endif1048term_get_color(s, c);1049}10501051/* strlen(prompt) + 28 chars */1052static const char *1053color_prompt(const char *prompt)1054{1055long n = strlen(prompt);1056char *t = stack_malloc(n + 28), *s = t;1057*s = 0;1058/* escape sequences bug readline, so use special bracing (if available) */1059brace_color(s, c_PROMPT, 0);1060s += strlen(s); memcpy(s, prompt, n);1061s += n; *s = 0;1062brace_color(s, c_INPUT, 1);1063return t;1064}10651066const char *1067gp_format_prompt(const char *prompt)1068{1069if (GP_DATA->flags & gpd_TEST)1070return prompt;1071else1072{1073char b[256]; /* longer is truncated */1074strftime_expand(prompt, b, sizeof(b));1075return color_prompt(b);1076}1077}10781079/********************************************************************/1080/* */1081/* GP MAIN LOOP */1082/* */1083/********************************************************************/1084static int1085is_interactive(void)1086{ return cb_pari_is_interactive? cb_pari_is_interactive(): 0; }10871088static char *1089strip_prompt(const char *s)1090{1091long l = strlen(s);1092char *t, *t0 = stack_malloc(l+1);1093t = t0;1094for (; *s; s++)1095{1096/* RL_PROMPT_START_IGNORE / RL_PROMPT_END_IGNORE */1097if (*s == 1 || *s == 2) continue;1098if (*s == '\x1b') /* skip ANSI color escape sequence */1099{1100while (*++s != 'm')1101if (!*s) goto end;1102continue;1103}1104*t = *s; t++;1105}1106end:1107*t = 0; return t0;1108}1109static void1110update_logfile(const char *prompt, const char *s)1111{1112pari_sp av;1113const char *p;1114if (!pari_logfile) return;1115av = avma;1116p = strip_prompt(prompt); /* raw prompt */11171118switch (pari_logstyle) {1119case logstyle_TeX:1120fprintf(pari_logfile,1121"\\PARIpromptSTART|%s\\PARIpromptEND|%s\\PARIinputEND|%%\n",1122p, s);1123break;1124case logstyle_plain:1125fprintf(pari_logfile,"%s%s\n",p, s);1126break;1127case logstyle_color:1128fprintf(pari_logfile,"%s%s%s%s%s\n",term_get_color(NULL,c_PROMPT), p,1129term_get_color(NULL,c_INPUT), s,1130term_get_color(NULL,c_NONE));1131break;1132}1133set_avma(av);1134}11351136void1137gp_echo_and_log(const char *prompt, const char *s)1138{1139if (!is_interactive())1140{1141if (!GP_DATA->echo) return;1142/* not pari_puts(): would duplicate in logfile */1143fputs(prompt, pari_outfile);1144fputs(s, pari_outfile);1145fputc('\n', pari_outfile);1146pari_set_last_newline(1);1147}1148update_logfile(prompt, s);1149pari_flush();1150}11511152/* prompt = NULL --> from gprc. Return 1 if new input, and 0 if EOF */1153int1154get_line_from_file(const char *prompt, filtre_t *F, FILE *file)1155{1156char *s;1157input_method IM;11581159IM.file = (void*)file;1160if (file==stdin && cb_pari_fgets_interactive)1161IM.myfgets = (fgets_t)cb_pari_fgets_interactive;1162else1163IM.myfgets = (fgets_t)&fgets;1164IM.getline = &file_input;1165IM.free = 0;1166if (! input_loop(F,&IM))1167{1168if (file==stdin && cb_pari_start_output) cb_pari_start_output();1169return 0;1170}1171s = F->buf->buf;1172/* don't log if from gprc or empty input */1173if (*s && prompt && GP_DATA->echo != 2) gp_echo_and_log(prompt, s);1174return 1;1175}11761177/* return 0 if no line could be read (EOF). If PROMPT = NULL, expand and1178* color default prompt; otherwise, use PROMPT as-is. */1179int1180gp_read_line(filtre_t *F, const char *PROMPT)1181{1182static const char *DFT_PROMPT = "? ";1183Buffer *b = (Buffer*)F->buf;1184const char *p;1185int res, interactive;1186if (b->len > 100000) fix_buffer(b, 100000);1187interactive = is_interactive();1188if (interactive || pari_logfile || GP_DATA->echo)1189{1190p = PROMPT;1191if (!p) {1192p = F->in_comment? GP_DATA->prompt_comment: GP_DATA->prompt;1193p = gp_format_prompt(p);1194}1195}1196else1197p = DFT_PROMPT;11981199if (interactive)1200{1201BLOCK_EH_START1202if (!pari_last_was_newline()) pari_putc('\n');1203if (cb_pari_get_line_interactive)1204res = cb_pari_get_line_interactive(p, GP_DATA->prompt_cont, F);1205else {1206pari_puts(p); pari_flush();1207res = get_line_from_file(p, F, pari_infile);1208}1209BLOCK_EH_END1210}1211else1212{ /* in case UI fakes noninteractivity, e.g. TeXmacs */1213if (cb_pari_start_output && cb_pari_get_line_interactive)1214res = cb_pari_get_line_interactive(p, GP_DATA->prompt_cont, F);1215else1216res = get_line_from_file(p, F, pari_infile);1217}12181219if (!disable_color && p != DFT_PROMPT &&1220(gp_colors[c_PROMPT] != c_NONE || gp_colors[c_INPUT] != c_NONE))1221{1222term_color(c_NONE); pari_flush();1223}1224return res;1225}12261227/********************************************************************/1228/* */1229/* EXCEPTION HANDLER */1230/* */1231/********************************************************************/1232static THREAD pari_timer ti_alarm;12331234#if defined(_WIN32) || defined(SIGALRM)1235static void1236gp_alarm_fun(void) {1237char buf[64];1238if (cb_pari_start_output) cb_pari_start_output();1239convert_time(buf, timer_get(&ti_alarm));1240pari_err(e_ALARM, buf);1241}1242#endif /* SIGALRM */12431244void1245gp_sigint_fun(void) {1246char buf[150];1247#if defined(_WIN32)1248if (win32alrm) { win32alrm = 0; gp_alarm_fun(); return;}1249#endif1250if (cb_pari_start_output) cb_pari_start_output();1251convert_time(buf, timer_get(GP_DATA->T));1252if (pari_mt_nbthreads > 1)1253{1254sprintf(buf + strlen(buf), " cpu time, ");1255convert_time(buf + strlen(buf), walltimer_get(GP_DATA->Tw));1256sprintf(buf + strlen(buf), " real time");1257}1258pari_sigint(buf);1259}12601261#ifdef SIGALRM1262void1263gp_alarm_handler(int sig)1264{1265#ifndef HAS_SIGACTION1266/*SYSV reset the signal handler in the handler*/1267(void)os_signal(sig,gp_alarm_handler);1268#endif1269if (PARI_SIGINT_block) PARI_SIGINT_pending=sig;1270else gp_alarm_fun();1271return;1272}1273#endif /* SIGALRM */12741275/********************************************************************/1276/* */1277/* GP-SPECIFIC ROUTINES */1278/* */1279/********************************************************************/1280void1281gp_allocatemem(GEN z)1282{1283ulong newsize;1284if (!z) newsize = 0;1285else {1286if (typ(z) != t_INT) pari_err_TYPE("allocatemem",z);1287newsize = itou(z);1288if (signe(z) < 0) pari_err_DOMAIN("allocatemem","size","<",gen_0,z);1289}1290if (pari_mainstack->vsize)1291paristack_resize(newsize);1292else1293paristack_newrsize(newsize);1294}12951296GEN1297gp_input(void)1298{1299filtre_t F;1300Buffer *b = filtered_buffer(&F);1301GEN x;13021303while (! get_line_from_file("",&F,pari_infile))1304if (popinfile()) { err_printf("no input ???"); cb_pari_quit(1); }1305x = readseq(b->buf);1306pop_buffer(); return x;1307}13081309static GEN1310closure_alarmer(GEN C, long s)1311{1312struct pari_evalstate state;1313VOLATILE GEN x;1314if (!s) { pari_alarm(0); return closure_evalgen(C); }1315evalstate_save(&state);1316#if !defined(HAS_ALARM) && !defined(_WIN32)1317pari_err(e_ARCH,"alarm");1318#endif1319pari_CATCH(CATCH_ALL) /* We need to stop the timer after any error */1320{1321GEN E = pari_err_last();1322if (err_get_num(E) != e_ALARM) { pari_alarm(0); pari_err(0, E); }1323x = evalstate_restore_err(&state);1324}1325pari_TRY { pari_alarm(s); x = closure_evalgen(C); pari_alarm(0); } pari_ENDCATCH;1326return x;1327}13281329void1330pari_alarm(long s)1331{1332if (s < 0) pari_err_DOMAIN("alarm","delay","<",gen_0,stoi(s));1333if (s) timer_start(&ti_alarm);1334#ifdef _WIN321335win32_alarm(s);1336#elif defined(HAS_ALARM)1337alarm(s);1338#else1339if (s) pari_err(e_ARCH,"alarm");1340#endif1341}13421343GEN1344gp_alarm(long s, GEN code)1345{1346if (!code) { pari_alarm(s); return gnil; }1347return closure_alarmer(code,s);1348}13491350/*******************************************************************/1351/** **/1352/** EXTERNAL PRETTYPRINTER **/1353/** **/1354/*******************************************************************/1355/* Wait for prettinprinter to finish, to prevent new prompt from overwriting1356* the output. Fill the output buffer, wait until it is read.1357* Better than sleep(2): give possibility to print */1358static void1359prettyp_wait(FILE *out)1360{1361const char *s = " \n";1362long i = 2000;13631364fputs("\n\n", out); fflush(out); /* start translation */1365while (--i) fputs(s, out);1366fputs("\n", out); fflush(out);1367}13681369/* initialise external prettyprinter (tex2mail) */1370static int1371prettyp_init(void)1372{1373gp_pp *pp = GP_DATA->pp;1374if (!pp->cmd) return 0;1375if (pp->file || (pp->file = try_pipe(pp->cmd, mf_OUT))) return 1;13761377pari_warn(warner,"broken prettyprinter: '%s'",pp->cmd);1378pari_free(pp->cmd); pp->cmd = NULL;1379sd_output("1", d_SILENT);1380return 0;1381}13821383/* n = history number. if n = 0 no history */1384int1385tex2mail_output(GEN z, long n)1386{1387pariout_t T = *(GP_DATA->fmt); /* copy */1388FILE *log = pari_logfile, *out;13891390if (!prettyp_init()) return 0;1391out = GP_DATA->pp->file->file;1392/* Emit first: there may be lines before the prompt */1393if (n) term_color(c_OUTPUT);1394pari_flush();1395T.prettyp = f_TEX;1396/* history number */1397if (n)1398{1399pari_sp av = avma;1400const char *c_hist = term_get_color(NULL, c_HIST);1401const char *c_out = term_get_color(NULL, c_OUTPUT);1402if (!(GP_DATA->flags & gpd_QUIET))1403{1404if (*c_hist || *c_out)1405fprintf(out, "\\LITERALnoLENGTH{%s}\\%%%ld =\\LITERALnoLENGTH{%s} ",1406c_hist, n, c_out);1407else1408fprintf(out, "\\%%%ld = ", n);1409}1410if (log) {1411switch (pari_logstyle) {1412case logstyle_plain:1413fprintf(log, "%%%ld = ", n);1414break;1415case logstyle_color:1416fprintf(log, "%s%%%ld = %s", c_hist, n, c_out);1417break;1418case logstyle_TeX:1419fprintf(log, "\\PARIout{%ld}", n);1420break;1421}1422}1423set_avma(av);1424}1425/* output */1426fputGEN_pariout(z, &T, out);1427/* flush and restore, output to logfile */1428prettyp_wait(out);1429if (log) {1430if (pari_logstyle == logstyle_TeX) {1431T.TeXstyle |= TEXSTYLE_BREAK;1432fputGEN_pariout(z, &T, log);1433fputc('%', log);1434} else {1435T.prettyp = f_RAW;1436fputGEN_pariout(z, &T, log);1437}1438fputc('\n', log); fflush(log);1439}1440if (n) term_color(c_NONE);1441pari_flush(); return 1;1442}14431444/*******************************************************************/1445/** **/1446/** GP-SPECIFIC DEFAULTS **/1447/** **/1448/*******************************************************************/14491450static long1451atocolor(const char *s)1452{1453long l = atol(s);1454if (l & ~0xff) pari_err(e_MISC, "invalid 8bit RGB code: %ld", l);1455return l;1456}14571458GEN1459sd_graphcolormap(const char *v, long flag)1460{1461char *p, *q;1462long i, j, l, a, s, *lp;14631464if (v)1465{1466pari_sp av = avma;1467char *t = gp_filter(v);1468if (*t != '[' || t[strlen(t)-1] != ']')1469pari_err(e_SYNTAX, "incorrect value for graphcolormap", t, t);1470for (s = 0, p = t+1, l = 2, a=0; *p; p++)1471if (*p == '[')1472{1473a++;1474while (*++p != ']')1475if (!*p || *p == '[')1476pari_err(e_SYNTAX, "incorrect value for graphcolormap", p, t);1477}1478else if (*p == '"')1479{1480s += sizeof(long)+1;1481while (*p && *++p != '"') s++;1482if (!*p) pari_err(e_SYNTAX, "incorrect value for graphcolormap", p, t);1483s = (s+sizeof(long)-1) & ~(sizeof(long)-1);1484}1485else if (*p == ',')1486l++;1487if (l < 4)1488pari_err(e_MISC, "too few colors (< 4) in graphcolormap");1489if (GP_DATA->colormap) pari_free(GP_DATA->colormap);1490GP_DATA->colormap = (GEN)pari_malloc((l+4*a)*sizeof(long) + s);1491GP_DATA->colormap[0] = evaltyp(t_VEC)|evallg(l);1492for (p = t+1, i = 1, lp = GP_DATA->colormap+l; i < l; p++)1493switch(*p)1494{1495case '"':1496gel(GP_DATA->colormap, i) = lp;1497q = ++p; while (*q != '"') q++;1498*q = 0;1499j = 1 + nchar2nlong(q-p+1);1500lp[0] = evaltyp(t_STR)|evallg(j);1501strncpy(GSTR(lp), p, q-p+1);1502lp += j; p = q;1503break;1504case '[': {1505const char *ap[3];1506gel(GP_DATA->colormap, i) = lp;1507lp[0] = evaltyp(t_VECSMALL)|_evallg(4);1508for (ap[0] = ++p, j=0; *p && *p != ']'; p++)1509if (*p == ',' && j<2) { *p++ = 0; ap[++j] = p; }1510while (j<2) ap[++j] = "0";1511if (j>2 || *p != ']')1512{1513char buf[100];1514sprintf(buf, "incorrect value for graphcolormap[%ld]: ", i);1515pari_err(e_SYNTAX, buf, p, t);1516}1517*p = '\0';1518lp[1] = atocolor(ap[0]);1519lp[2] = atocolor(ap[1]);1520lp[3] = atocolor(ap[2]);1521lp += 4;1522break;1523}1524case ',':1525case ']':1526i++;1527break;1528default:1529pari_err(e_SYNTAX, "incorrect value for graphcolormap", p, t);1530}1531set_avma(av);1532}1533if (flag == d_RETURN || flag == d_ACKNOWLEDGE)1534{1535GEN C = cgetg(lg(GP_DATA->colormap), t_VEC);1536long i, l = lg(C);1537for (i = 1; i < l; i++)1538{1539GEN c = gel(GP_DATA->colormap, i);1540gel(C, i) = (typ(c) == t_STR)? gcopy(c): zv_to_ZV(c);1541}1542if (flag == d_RETURN) return C;1543pari_printf(" graphcolormap = %Ps\n", C);1544}1545return gnil;1546}15471548GEN1549sd_graphcolors(const char *v, long flag)1550{ return sd_intarray(v, flag, &(GP_DATA->graphcolors), "graphcolors"); }1551GEN1552sd_plothsizes(const char *v, long flag)1553{ return sd_intarray(v, flag, &(GP_DATA->plothsizes), "plothsizes"); }15541555GEN1556sd_help(const char *v, long flag)1557{1558const char *str;1559if (v)1560{1561if (GP_DATA->secure)1562pari_err(e_MISC,"[secure mode]: can't modify 'help' default (to %s)",v);1563if (GP_DATA->help) pari_free((void*)GP_DATA->help);1564#ifndef _WIN321565GP_DATA->help = path_expand(v);1566#else1567GP_DATA->help = pari_strdup(v);1568#endif1569}1570str = GP_DATA->help? GP_DATA->help: "none";1571if (flag == d_RETURN) return strtoGENstr(str);1572if (flag == d_ACKNOWLEDGE)1573pari_printf(" help = \"%s\"\n", str);1574return gnil;1575}15761577static GEN1578sd_prompt_set(const char *v, long flag, const char *how, char **p)1579{1580if (v) {1581if (*p) free(*p);1582*p = pari_strdup(v);1583}1584if (flag == d_RETURN) return strtoGENstr(*p);1585if (flag == d_ACKNOWLEDGE)1586pari_printf(" prompt%s = \"%s\"\n", how, *p);1587return gnil;1588}1589GEN1590sd_prompt(const char *v, long flag)1591{ return sd_prompt_set(v, flag, "", &(GP_DATA->prompt)); }1592GEN1593sd_prompt_cont(const char *v, long flag)1594{ return sd_prompt_set(v, flag, "_cont", &(GP_DATA->prompt_cont)); }15951596GEN1597sd_breakloop(const char *v, long flag)1598{ return sd_toggle(v,flag,"breakloop", &(GP_DATA->breakloop)); }1599GEN1600sd_echo(const char *v, long flag)1601{ return sd_ulong(v,flag,"echo", &(GP_DATA->echo), 0,2,NULL); }1602GEN1603sd_timer(const char *v, long flag)1604{ return sd_toggle(v,flag,"timer", &(GP_DATA->chrono)); }1605GEN1606sd_recover(const char *v, long flag)1607{ return sd_toggle(v,flag,"recover", &(GP_DATA->recover)); }16081609GEN1610sd_psfile(const char *v, long flag)1611{ return sd_string(v, flag, "psfile", ¤t_psfile); }16121613GEN1614sd_lines(const char *v, long flag)1615{ return sd_ulong(v,flag,"lines",&(GP_DATA->lim_lines), 0,LONG_MAX,NULL); }1616GEN1617sd_linewrap(const char *v, long flag)1618{1619ulong old = GP_DATA->linewrap, n = GP_DATA->linewrap;1620GEN z = sd_ulong(v,flag,"linewrap",&n, 0,LONG_MAX,NULL);1621if (old)1622{ if (!n) resetout(1); }1623else1624{ if (n) init_linewrap(n); }1625GP_DATA->linewrap = n; return z;1626}16271628/* readline-specific defaults */1629GEN1630sd_readline(const char *v, long flag)1631{1632const char *msg[] = {1633"(bits 0x2/0x4 control matched-insert/arg-complete)", NULL};1634ulong state = GP_DATA->readline_state;1635GEN res = sd_ulong(v,flag,"readline", &GP_DATA->readline_state, 0, 7, msg);16361637if (state != GP_DATA->readline_state)1638(void)sd_toggle(GP_DATA->readline_state? "1": "0", d_SILENT, "readline", &(GP_DATA->use_readline));1639return res;1640}1641GEN1642sd_histfile(const char *v, long flag)1643{1644char *old = GP_DATA->histfile;1645GEN r = sd_string(v, flag, "histfile", &GP_DATA->histfile);1646if (v && !*v)1647{1648free(GP_DATA->histfile);1649GP_DATA->histfile = NULL;1650}1651else if (GP_DATA->histfile != old && (!old || strcmp(old,GP_DATA->histfile)))1652{1653if (cb_pari_init_histfile) cb_pari_init_histfile();1654}1655return r;1656}16571658/********************************************************************/1659/** **/1660/** METACOMMANDS **/1661/** **/1662/********************************************************************/1663void1664pari_print_version(void)1665{1666pari_sp av = avma;1667char *buf, *ver = what_cc();1668const char *kver = pari_kernel_version();1669const char *date = paricfg_compiledate;16701671pari_center(paricfg_version);1672buf = stack_malloc(strlen(paricfg_buildinfo) + 2 + strlen(kver));1673(void)sprintf(buf, paricfg_buildinfo, kver);1674pari_center(buf);1675buf = stack_malloc(strlen(date) + 32 + (ver? strlen(ver): 0));1676if (ver) (void)sprintf(buf, "compiled: %s, %s", date, ver);1677else (void)sprintf(buf, "compiled: %s", date);1678pari_center(buf);1679sprintf(buf, "threading engine: %s",paricfg_mt_engine);1680pari_center(buf);1681ver = what_readline();1682buf = stack_malloc(strlen(ver) + 64);1683(void)sprintf(buf, "(readline %s, extended help%s enabled)", ver,1684has_ext_help()? "": " not");1685pari_center(buf); set_avma(av);1686}16871688static int1689cmp_epname(void *E, GEN e, GEN f)1690{1691(void)E;1692return strcmp(((entree*)e)->name, ((entree*)f)->name);1693}1694static void1695print_all_user_fun(int member)1696{1697pari_sp av = avma;1698long iL = 0, lL = 1024;1699GEN L = cgetg(lL+1, t_VECSMALL);1700entree *ep;1701int i;1702for (i = 0; i < functions_tblsz; i++)1703for (ep = functions_hash[i]; ep; ep = ep->next)1704{1705const char *f;1706int is_member;1707if (EpVALENCE(ep) != EpVAR || typ((GEN)ep->value)!=t_CLOSURE) continue;1708f = ep->name;1709is_member = (f[0] == '_' && f[1] == '.');1710if (member != is_member) continue;17111712if (iL >= lL)1713{1714GEN oL = L;1715long j;1716lL *= 2; L = cgetg(lL+1, t_VECSMALL);1717for (j = 1; j <= iL; j++) gel(L,j) = gel(oL,j);1718}1719L[++iL] = (long)ep;1720}1721if (iL)1722{1723setlg(L, iL+1);1724gen_sort_inplace(L, NULL, &cmp_epname, NULL);1725for (i = 1; i <= iL; i++)1726{1727ep = (entree*)L[i];1728pari_printf("%s =\n %Ps\n\n", ep->name, ep->value);1729}1730}1731set_avma(av);1732}17331734static char *1735get_name(const char *s)1736{1737char *t = get_sep(s);1738if (*t == '"')1739{1740long n = strlen(t)-1;1741if (t[n] == '"') { t[n] = 0; t++; }1742}1743return t;1744}17451746static void1747escape(const char *tch, int ismain)1748{1749const char *s = tch;1750char c;1751switch ((c = *s++))1752{1753case 'w': case 'x': case 'a': case 'b': case 'B': case 'm':1754{ /* history things */1755long d;1756GEN x;1757if (c != 'w' && c != 'x') d = get_int(s,0);1758else1759{1760d = atol(s); if (*s == '-') s++;1761while (isdigit((int)*s)) s++;1762}1763x = pari_get_hist(d);1764switch (c)1765{1766case 'B': /* prettyprinter */1767if (tex2mail_output(x,0)) break;1768case 'b': /* fall through */1769case 'm': matbrute(x, GP_DATA->fmt->format, -1); break;1770case 'a': brute(x, GP_DATA->fmt->format, -1); break;1771case 'x': dbgGEN(x, get_int(s, -1)); break;1772case 'w':1773s = get_name(s); if (!*s) s = current_logfile;1774write0(s, mkvec(x)); return;1775}1776pari_putc('\n'); return;1777}17781779case 'c': commands(-1); break;1780case 'd': (void)setdefault(NULL,NULL,d_SILENT); break;1781case 'e':1782s = get_sep(s);1783if (!*s) s = (GP_DATA->echo)? "0": "1";1784(void)sd_echo(s,d_ACKNOWLEDGE); break;1785case 'g':1786switch (*s)1787{1788case 'm': s++; (void)sd_debugmem(*s? s: NULL,d_ACKNOWLEDGE); break;1789case 'f': s++; (void)sd_debugfiles(*s? s: NULL,d_ACKNOWLEDGE); break;1790default : (void)sd_debug(*s? s: NULL,d_ACKNOWLEDGE); break;1791}1792break;1793case 'h': print_functions_hash(s); break;1794case 'l':1795s = get_name(s);1796if (*s)1797{1798if (pari_logfile) { (void)sd_logfile(s,d_ACKNOWLEDGE);break; }1799(void)sd_logfile(s,d_SILENT);1800}1801(void)sd_log(pari_logfile?"0":"1",d_ACKNOWLEDGE);1802break;1803case 'o': (void)sd_output(*s? s: NULL,d_ACKNOWLEDGE); break;1804case 'p':1805switch (*s)1806{1807case 's': s++;1808(void)sd_seriesprecision(*s? s: NULL,d_ACKNOWLEDGE); break;1809case 'b' : s++;1810(void)sd_realbitprecision(*s? s: NULL,d_ACKNOWLEDGE); break;1811default :1812(void)sd_realprecision(*s? s: NULL,d_ACKNOWLEDGE); break;1813}1814break;1815case 'q': cb_pari_quit(0); break;1816case 'r':1817s = get_name(s);1818if (!ismain) { (void)gp_read_file(s); break; }1819switchin(s);1820if (file_is_binary(pari_infile))1821{1822pari_sp av = avma;1823int vector;1824GEN x = readbin(s,pari_infile, &vector);1825popinfile();1826if (!x) pari_err_FILE("input file",s);1827if (vector) /* many BIN_GEN */1828{1829long i, l = lg(x);1830pari_warn(warner,"setting %ld history entries", l-1);1831for (i=1; i<l; i++) pari_add_hist(gel(x,i), 0, 0);1832}1833set_avma(av);1834}1835break;1836case 's': dbg_pari_heap(); break;1837case 't': gentypes(); break;1838case 'u':1839print_all_user_fun((*s == 'm')? 1: 0);1840break;1841case 'v': pari_print_version(); break;1842case 'y':1843s = get_sep(s);1844if (!*s) s = (GP_DATA->simplify)? "0": "1";1845(void)sd_simplify(s,d_ACKNOWLEDGE); break;1846default: pari_err(e_SYNTAX,"unexpected character", tch,tch-1);1847}1848}18491850static int1851chron(const char *s)1852{1853if (*s)1854{ /* if "#" or "##" timer metacommand. Otherwise let the parser get it */1855const char *t;1856if (*s == '#') s++;1857if (*s) return 0;1858t = gp_format_time(pari_get_histtime(0));1859if (pari_mt_nbthreads==1)1860pari_printf(" *** last result computed in %s.\n", t);1861else1862{1863const char *r = gp_format_time(pari_get_histrtime(0));1864pari_printf(" *** last result: cpu time %s, real time %s.\n", t,r);1865}1866}1867else { GP_DATA->chrono ^= 1; (void)sd_timer(NULL,d_ACKNOWLEDGE); }1868return 1;1869}18701871/* return 0: can't interpret *buf as a metacommand1872* 1: did interpret *buf as a metacommand or empty command */1873int1874gp_meta(const char *buf, int ismain)1875{1876switch(*buf++)1877{1878case '?': gp_help(buf, h_REGULAR); break;1879case '#': return chron(buf);1880case '\\': escape(buf, ismain); break;1881case '\0': break;1882default: return 0;1883}1884return 1;1885}188618871888