Testing latest pari + WASM + node.js... and it works?! Wow.
License: GPL3
ubuntu2004
/* Copyright (C) 2000-2003 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/* INITIALIZING THE SYSTEM, ERRORS, STACK MANAGEMENT */17/* */18/*******************************************************************/19/* _GNU_SOURCE is needed before first include to get RUSAGE_THREAD */20#undef _GNU_SOURCE /* avoid warning */21#define _GNU_SOURCE22#include <string.h>23#if defined(_WIN32) || defined(__CYGWIN32__)24# include "../systems/mingw/mingw.h"25# include <process.h>26#endif27#include "paricfg.h"28#if defined(STACK_CHECK) && !defined(__EMX__) && !defined(_WIN32)29# include <sys/types.h>30# include <sys/time.h>31# include <sys/resource.h>32#endif33#if defined(HAS_WAITPID) && defined(HAS_SETSID)34# include <sys/wait.h>35#endif36#ifdef HAS_MMAP37# include <sys/mman.h>38#endif39#if defined(USE_GETTIMEOFDAY) || defined(USE_GETRUSAGE) || defined(USE_TIMES)40# include <sys/time.h>41#endif42#if defined(USE_GETRUSAGE)43# include <sys/resource.h>44#endif45#if defined(USE_FTIME) || defined(USE_FTIMEFORWALLTIME)46# include <sys/timeb.h>47#endif48#if defined(USE_CLOCK_GETTIME) || defined(USE_TIMES)49# include <time.h>50#endif51#if defined(USE_TIMES)52# include <sys/times.h>53#endif54#define PARI_INIT55#include "pari.h"56#include "paripriv.h"57#include "anal.h"5859const double LOG10_2 = 0.3010299956639812; /* log_10(2) */60const double LOG2_10 = 3.321928094887362; /* log_2(10) */6162GEN gnil, gen_0, gen_1, gen_m1, gen_2, gen_m2, ghalf, err_e_STACK;6364static const ulong readonly_constants[] = {65evaltyp(t_INT) | _evallg(2), /* gen_0 */66evallgefint(2),67evaltyp(t_INT) | _evallg(2), /* gnil */68evallgefint(2),69evaltyp(t_INT) | _evallg(3), /* gen_1 */70evalsigne(1) | evallgefint(3),711,72evaltyp(t_INT) | _evallg(3), /* gen_2 */73evalsigne(1) | evallgefint(3),742,75evaltyp(t_INT) | _evallg(3), /* gen_m1 */76evalsigne(-1) | evallgefint(3),771,78evaltyp(t_INT) | _evallg(3), /* gen_m2 */79evalsigne(-1) | evallgefint(3),802,81evaltyp(t_ERROR) | _evallg(2), /* err_e_STACK */82e_STACK,83evaltyp(t_FRAC) | _evallg(3), /* ghalf */84(ulong)(readonly_constants+4),85(ulong)(readonly_constants+7)86};87THREAD GEN zetazone, bernzone, eulerzone, primetab;88byteptr diffptr;89FILE *pari_outfile, *pari_errfile, *pari_logfile, *pari_infile;90char *current_logfile, *current_psfile, *pari_datadir;91long gp_colors[c_LAST];92int disable_color;93ulong DEBUGFILES, DEBUGLEVEL, DEBUGMEM;94long DEBUGVAR;95ulong pari_mt_nbthreads;96long precreal;97ulong precdl, pari_logstyle;98gp_data *GP_DATA;99100entree **varentries;101THREAD long *varpriority;102103THREAD pari_sp avma;104THREAD struct pari_mainstack *pari_mainstack;105106static void ** MODULES;107static pari_stack s_MODULES;108const long functions_tblsz = 135; /* size of functions_hash */109entree **functions_hash, **defaults_hash;110111char *(*cb_pari_fgets_interactive)(char *s, int n, FILE *f);112int (*cb_pari_get_line_interactive)(const char*, const char*, filtre_t *F);113void (*cb_pari_quit)(long);114void (*cb_pari_init_histfile)(void);115void (*cb_pari_ask_confirm)(const char *);116int (*cb_pari_handle_exception)(long);117int (*cb_pari_err_handle)(GEN);118int (*cb_pari_whatnow)(PariOUT *out, const char *, int);119void (*cb_pari_sigint)(void);120void (*cb_pari_pre_recover)(long);121void (*cb_pari_err_recover)(long);122int (*cb_pari_break_loop)(int);123int (*cb_pari_is_interactive)(void);124void (*cb_pari_start_output)();125126const char * pari_library_path = NULL;127128static THREAD GEN global_err_data;129THREAD jmp_buf *iferr_env;130const long CATCH_ALL = -1;131132static void pari_init_timer(void);133134/*********************************************************************/135/* */136/* BLOCKS & CLONES */137/* */138/*********************************************************************/139/*#define DEBUG*/140static THREAD long next_block;141static THREAD GEN cur_block; /* current block in block list */142static THREAD GEN root_block; /* current block in block list */143#ifdef DEBUG144static THREAD long NUM;145#endif146147static void148pari_init_blocks(void)149{150next_block = 0; cur_block = NULL; root_block = NULL;151#ifdef DEBUG152NUM = 0;153#endif154}155156static void157pari_close_blocks(void)158{159while (cur_block) killblock(cur_block);160}161162static long163blockheight(GEN bl) { return bl? bl_height(bl): 0; }164165static long166blockbalance(GEN bl)167{ return bl ? blockheight(bl_left(bl)) - blockheight(bl_right(bl)): 0; }168169static void170fix_height(GEN bl)171{ bl_height(bl) = maxss(blockheight(bl_left(bl)), blockheight(bl_right(bl)))+1; }172173static GEN174bl_rotright(GEN y)175{176GEN x = bl_left(y), t = bl_right(x);177bl_right(x) = y;178bl_left(y) = t;179fix_height(y);180fix_height(x);181return x;182}183184static GEN185bl_rotleft(GEN x)186{187GEN y = bl_right(x), t = bl_left(y);188bl_left(y) = x;189bl_right(x) = t;190fix_height(x);191fix_height(y);192return y;193}194195static GEN196blockinsert(GEN x, GEN bl, long *d)197{198long b, c;199if (!bl)200{201bl_left(x)=NULL; bl_right(x)=NULL;202bl_height(x)=1; return x;203}204c = cmpuu((ulong)x, (ulong)bl);205if (c < 0)206bl_left(bl) = blockinsert(x, bl_left(bl), d);207else if (c > 0)208bl_right(bl) = blockinsert(x, bl_right(bl), d);209else return bl; /* ??? Already exist in the tree ? */210fix_height(bl);211b = blockbalance(bl);212if (b > 1)213{214if (*d > 0) bl_left(bl) = bl_rotleft(bl_left(bl));215return bl_rotright(bl);216}217if (b < -1)218{219if (*d < 0) bl_right(bl) = bl_rotright(bl_right(bl));220return bl_rotleft(bl);221}222*d = c; return bl;223}224225static GEN226blockdelete(GEN x, GEN bl)227{228long b;229if (!bl) return NULL; /* ??? Do not exist in the tree */230if (x < bl)231bl_left(bl) = blockdelete(x, bl_left(bl));232else if (x > bl)233bl_right(bl) = blockdelete(x, bl_right(bl));234else235{236if (!bl_left(bl) && !bl_right(bl)) return NULL;237else if (!bl_left(bl)) return bl_right(bl);238else if (!bl_right(bl)) return bl_left(bl);239else240{241GEN r = bl_right(bl);242while (bl_left(r)) r = bl_left(r);243bl_right(r) = blockdelete(r, bl_right(bl));244bl_left(r) = bl_left(bl);245bl = r;246}247}248fix_height(bl);249b = blockbalance(bl);250if (b > 1)251{252if (blockbalance(bl_left(bl)) >= 0) return bl_rotright(bl);253else254{ bl_left(bl) = bl_rotleft(bl_left(bl)); return bl_rotright(bl); }255}256if (b < -1)257{258if (blockbalance(bl_right(bl)) <= 0) return bl_rotleft(bl);259else260{ bl_right(bl) = bl_rotright(bl_right(bl)); return bl_rotleft(bl); }261}262return bl;263}264265static GEN266blocksearch(GEN x, GEN bl)267{268if (isclone(x)) return x;269if (isonstack(x) || is_universal_constant(x)) return NULL;270while (bl)271{272if (x >= bl && x < bl + bl_size(bl))273return bl;274bl = x < bl ? bl_left(bl): bl_right(bl);275}276return NULL; /* Unknown address */277}278279static int280check_clone(GEN x)281{282GEN bl = root_block;283if (isonstack(x) || is_universal_constant(x)) return 1;284while (bl)285{286if (x >= bl && x < bl + bl_size(bl))287return 1;288bl = x < bl ? bl_left(bl): bl_right(bl);289}290return 0; /* Unknown address */291}292293void294clone_lock(GEN x)295{296GEN y = blocksearch(x, root_block);297if (y && isclone(y))298{299if (DEBUGMEM > 2)300err_printf("locking block no %ld: %08lx from %08lx\n", bl_num(y), y, x);301++bl_refc(y);302}303}304305void306clone_unlock(GEN x)307{308GEN y = blocksearch(x, root_block);309if (y && isclone(y))310{311if (DEBUGMEM > 2)312err_printf("unlocking block no %ld: %08lx from %08lx\n", bl_num(y), y, x);313gunclone(y);314}315}316317void318clone_unlock_deep(GEN x)319{320GEN y = blocksearch(x, root_block);321if (y && isclone(y))322{323if (DEBUGMEM > 2)324err_printf("unlocking deep block no %ld: %08lx from %08lx\n", bl_num(y), y, x);325gunclone_deep(y);326}327}328329/* Return x, where:330* x[-8]: AVL height331* x[-7]: adress of left child or NULL332* x[-6]: adress of right child or NULL333* x[-5]: size334* x[-4]: reference count335* x[-3]: adress of next block336* x[-2]: adress of preceding block.337* x[-1]: number of allocated blocs.338* x[0..n-1]: malloc-ed memory. */339GEN340newblock(size_t n)341{342long d = 0;343long *x = (long *) pari_malloc((n + BL_HEAD)*sizeof(long)) + BL_HEAD;344345bl_size(x) = n;346bl_refc(x) = 1;347bl_next(x) = NULL;348bl_prev(x) = cur_block;349bl_num(x) = next_block++;350if (cur_block) bl_next(cur_block) = x;351root_block = blockinsert(x, root_block, &d);352#ifdef DEBUG353err_printf("+ %ld\n", ++NUM);354#endif355if (DEBUGMEM > 2)356err_printf("new block, size %6lu (no %ld): %08lx\n", n, next_block-1, x);357return cur_block = x;358}359360GEN361gcloneref(GEN x)362{363if (isclone(x)) { ++bl_refc(x); return x; }364else return gclone(x);365}366367void368gclone_refc(GEN x) { ++bl_refc(x); }369370void371gunclone(GEN x)372{373if (--bl_refc(x) > 0) return;374BLOCK_SIGINT_START;375root_block = blockdelete(x, root_block);376if (bl_next(x)) bl_prev(bl_next(x)) = bl_prev(x);377else378{379cur_block = bl_prev(x);380next_block = bl_num(x);381}382if (bl_prev(x)) bl_next(bl_prev(x)) = bl_next(x);383if (DEBUGMEM > 2)384err_printf("killing block (no %ld): %08lx\n", bl_num(x), x);385free((void*)bl_base(x)); /* pari_free not needed: we already block */386BLOCK_SIGINT_END;387#ifdef DEBUG388err_printf("- %ld\n", NUM--);389#endif390}391392/* Recursively look for clones in the container and kill them. Then kill393* container if clone. SIGINT could be blocked until it returns */394void395gunclone_deep(GEN x)396{397long i, lx;398GEN v;399if (isclone(x) && bl_refc(x) > 1) { --bl_refc(x); return; }400BLOCK_SIGINT_START;401switch(typ(x))402{403case t_VEC: case t_COL: case t_MAT:404lx = lg(x);405for (i=1;i<lx;i++) gunclone_deep(gel(x,i));406break;407case t_LIST:408v = list_data(x); lx = v? lg(v): 1;409for (i=1;i<lx;i++) gunclone_deep(gel(v,i));410if (v) killblock(v);411break;412}413if (isclone(x)) gunclone(x);414BLOCK_SIGINT_END;415}416417int418pop_entree_block(entree *ep, long loc)419{420GEN x = (GEN)ep->value;421if (bl_num(x) < loc) return 0; /* older */422if (DEBUGMEM>2)423err_printf("popping %s (block no %ld)\n", ep->name, bl_num(x));424gunclone_deep(x); return 1;425}426427/***************************************************************************428** **429** Export **430** **431***************************************************************************/432433static hashtable *export_hash;434static void435pari_init_export(void)436{437export_hash = hash_create_str(1,0);438}439static void440pari_close_export(void)441{442hash_destroy(export_hash);443}444445/* Exported values are blocks, but do not have the clone bit set so that they446* are not affected by clone_lock and ensure_nb, etc. */447448void449export_add(const char *str, GEN val)450{451hashentry *h;452val = gclone(val); unsetisclone(val);453h = hash_search(export_hash, (void*) str);454if (h)455{456GEN v = (GEN)h->val;457h->val = val;458setisclone(v); gunclone(v);459}460else461hash_insert(export_hash,(void*)str, (void*) val);462}463464void465export_del(const char *str)466{467hashentry *h = hash_remove(export_hash,(void*)str);468if (h)469{470GEN v = (GEN)h->val;471setisclone(v); gunclone(v);472pari_free(h);473}474}475476GEN477export_get(const char *str)478{479return hash_haskey_GEN(export_hash,(void*)str);480}481482void483unexportall(void)484{485pari_sp av = avma;486GEN keys = hash_keys(export_hash);487long i, l = lg(keys);488for (i = 1; i < l; i++) mt_export_del((const char *)keys[i]);489set_avma(av);490}491492void493exportall(void)494{495long i;496for (i = 0; i < functions_tblsz; i++)497{498entree *ep;499for (ep = functions_hash[i]; ep; ep = ep->next)500if (EpVALENCE(ep)==EpVAR) mt_export_add(ep->name, (GEN)ep->value);501}502}503504/*********************************************************************/505/* */506/* C STACK SIZE CONTROL */507/* */508/*********************************************************************/509/* Avoid core dump on deep recursion. Adapted Perl code by Dominic Dunlop */510THREAD void *PARI_stack_limit = NULL;511512#ifdef STACK_CHECK513514# ifdef __EMX__ /* Emulate */515void516pari_stackcheck_init(void *pari_stack_base)517{518if (!pari_stack_base) { PARI_stack_limit = NULL; return; }519PARI_stack_limit = get_stack(1./16, 32*1024);520}521# elif _WIN32522void523pari_stackcheck_init(void *pari_stack_base)524{525ulong size = 1UL << 21;526if (!pari_stack_base) { PARI_stack_limit = NULL; return; }527if (size > (ulong)pari_stack_base)528PARI_stack_limit = (void*)(((ulong)pari_stack_base) / 16);529else530PARI_stack_limit = (void*)((ulong)pari_stack_base - (size/16)*15);531}532# else /* !__EMX__ && !_WIN32 */533/* Set PARI_stack_limit to (a little above) the lowest safe address that can be534* used on the stack. Leave PARI_stack_limit at its initial value (NULL) to535* show no check should be made [init failed]. Assume stack grows downward. */536void537pari_stackcheck_init(void *pari_stack_base)538{539struct rlimit rip;540ulong size;541if (!pari_stack_base) { PARI_stack_limit = NULL; return; }542if (getrlimit(RLIMIT_STACK, &rip)) return;543size = rip.rlim_cur;544if (size == (ulong)RLIM_INFINITY || size > (ulong)pari_stack_base)545PARI_stack_limit = (void*)(((ulong)pari_stack_base) / 16);546else547PARI_stack_limit = (void*)((ulong)pari_stack_base - (size/16)*15);548}549# endif /* !__EMX__ */550551#else552void553pari_stackcheck_init(void *pari_stack_base)554{555(void) pari_stack_base; PARI_stack_limit = NULL;556}557#endif /* STACK_CHECK */558559/*******************************************************************/560/* HEAP TRAVERSAL */561/*******************************************************************/562struct getheap_t { long n, l; };563/* x is a block, not necessarily a clone [x[0] may not be set] */564static void565f_getheap(GEN x, void *D)566{567struct getheap_t *T = (struct getheap_t*)D;568T->n++;569T->l += bl_size(x) + BL_HEAD;570}571GEN572getheap(void)573{574struct getheap_t T = { 0, 0 };575traverseheap(&f_getheap, &T); return mkvec2s(T.n, T.l);576}577578static void579traverseheap_r(GEN bl, void(*f)(GEN, void *), void *data)580{581if (!bl) return;582traverseheap_r(bl_left(bl), f, data);583traverseheap_r(bl_right(bl), f, data);584f(bl, data);585}586587void588traverseheap( void(*f)(GEN, void *), void *data)589{590traverseheap_r(root_block,f, data);591}592593/*********************************************************************/594/* DAEMON / FORK */595/*********************************************************************/596#if defined(HAS_WAITPID) && defined(HAS_SETSID)597/* Properly fork a process, detaching from main process group without creating598* zombies on exit. Parent returns 1, son returns 0 */599int600pari_daemon(void)601{602pid_t pid = fork();603switch(pid) {604case -1: return 1; /* father, fork failed */605case 0:606(void)setsid(); /* son becomes process group leader */607if (fork()) _exit(0); /* now son exits, also when fork fails */608break; /* grandson: its father is the son, which exited,609* hence father becomes 'init', that'll take care of it */610default: /* father, fork succeeded */611(void)waitpid(pid,NULL,0); /* wait for son to exit, immediate */612return 1;613}614/* grandson. The silly '!' avoids a gcc-8 warning (unused value) */615(void)!freopen("/dev/null","r",stdin);616return 0;617}618#else619int620pari_daemon(void)621{622pari_err_IMPL("pari_daemon without waitpid & setsid");623return 0;624}625#endif626627/*********************************************************************/628/* */629/* SYSTEM INITIALIZATION */630/* */631/*********************************************************************/632static int try_to_recover = 0;633THREAD VOLATILE int PARI_SIGINT_block = 0, PARI_SIGINT_pending = 0;634635/*********************************************************************/636/* SIGNAL HANDLERS */637/*********************************************************************/638static void639dflt_sigint_fun(void) { pari_err(e_MISC, "user interrupt"); }640641#if defined(_WIN32) || defined(__CYGWIN32__)642int win32ctrlc = 0, win32alrm = 0;643void644dowin32ctrlc(void)645{646win32ctrlc = 0;647cb_pari_sigint();648}649#endif650651static void652pari_handle_SIGINT(void)653{654#ifdef _WIN32655if (++win32ctrlc >= 5) _exit(3);656#else657cb_pari_sigint();658#endif659}660661typedef void (*pari_sighandler_t)(int);662663pari_sighandler_t664os_signal(int sig, pari_sighandler_t f)665{666#ifdef HAS_SIGACTION667struct sigaction sa, oldsa;668669sa.sa_handler = f;670sigemptyset(&sa.sa_mask);671sa.sa_flags = SA_NODEFER;672673if (sigaction(sig, &sa, &oldsa)) return NULL;674return oldsa.sa_handler;675#else676return signal(sig,f);677#endif678}679680void681pari_sighandler(int sig)682{683const char *msg;684#ifndef HAS_SIGACTION685/*SYSV reset the signal handler in the handler*/686(void)os_signal(sig,pari_sighandler);687#endif688switch(sig)689{690#ifdef SIGBREAK691case SIGBREAK:692if (PARI_SIGINT_block==1)693{694PARI_SIGINT_pending=SIGBREAK;695mt_sigint();696}697else pari_handle_SIGINT();698return;699#endif700701#ifdef SIGINT702case SIGINT:703if (PARI_SIGINT_block==1)704{705PARI_SIGINT_pending=SIGINT;706mt_sigint();707}708else pari_handle_SIGINT();709return;710#endif711712#ifdef SIGSEGV713case SIGSEGV:714msg="PARI/GP (Segmentation Fault)"; break;715#endif716#ifdef SIGBUS717case SIGBUS:718msg="PARI/GP (Bus Error)"; break;719#endif720#ifdef SIGFPE721case SIGFPE:722msg="PARI/GP (Floating Point Exception)"; break;723#endif724725#ifdef SIGPIPE726case SIGPIPE:727{728pariFILE *f = GP_DATA->pp->file;729if (f && pari_outfile == f->file)730{731GP_DATA->pp->file = NULL; /* to avoid oo recursion on error */732pari_outfile = stdout; pari_fclose(f);733pari_err(e_MISC, "Broken Pipe, resetting file stack...");734}735return; /* LCOV_EXCL_LINE */736}737#endif738739default: msg="signal handling"; break;740}741pari_err_BUG(msg);742}743744void745pari_sig_init(void (*f)(int))746{747#ifdef SIGBUS748(void)os_signal(SIGBUS,f);749#endif750#ifdef SIGFPE751(void)os_signal(SIGFPE,f);752#endif753#ifdef SIGINT754(void)os_signal(SIGINT,f);755#endif756#ifdef SIGBREAK757(void)os_signal(SIGBREAK,f);758#endif759#ifdef SIGPIPE760(void)os_signal(SIGPIPE,f);761#endif762#ifdef SIGSEGV763(void)os_signal(SIGSEGV,f);764#endif765}766767/*********************************************************************/768/* STACK AND UNIVERSAL CONSTANTS */769/*********************************************************************/770static void771init_universal_constants(void)772{773gen_0 = (GEN)readonly_constants;774gnil = (GEN)readonly_constants+2;775gen_1 = (GEN)readonly_constants+4;776gen_2 = (GEN)readonly_constants+7;777gen_m1 = (GEN)readonly_constants+10;778gen_m2 = (GEN)readonly_constants+13;779err_e_STACK = (GEN)readonly_constants+16;780ghalf = (GEN)readonly_constants+18;781}782783static void784pari_init_errcatch(void)785{786iferr_env = NULL;787global_err_data = NULL;788}789790void791setalldebug(long lvl)792{793long i, l = sizeof(pari_DEBUGLEVEL_ptr)/sizeof(*pari_DEBUGLEVEL_ptr);794for (i = 0; i < l; i++) *pari_DEBUGLEVEL_ptr[i] = lvl;795}796797/*********************************************************************/798/* INIT DEFAULTS */799/*********************************************************************/800void801pari_init_defaults(void)802{803long i;804initout(1);805806#ifdef LONG_IS_64BIT807precreal = 128;808#else809precreal = 96;810#endif811812precdl = 16;813DEBUGFILES = DEBUGLEVEL = 0;814setalldebug(0);815DEBUGMEM = 1;816disable_color = 1;817pari_logstyle = logstyle_none;818819current_psfile = pari_strdup("pari.ps");820current_logfile= pari_strdup("pari.log");821pari_logfile = NULL;822823pari_datadir = os_getenv("GP_DATA_DIR");824if (!pari_datadir)825{826#if defined(_WIN32) || defined(__CYGWIN32__)827if (paricfg_datadir[0]=='@' && paricfg_datadir[1]==0)828pari_datadir = win32_datadir();829else830#endif831pari_datadir = pari_strdup(paricfg_datadir);832}833else pari_datadir= pari_strdup(pari_datadir);834for (i=0; i<c_LAST; i++) gp_colors[i] = c_NONE;835}836837/*********************************************************************/838/* FUNCTION HASHTABLES, MODULES */839/*********************************************************************/840extern entree functions_basic[], functions_default[];841static void842pari_init_functions(void)843{844pari_stack_init(&s_MODULES, sizeof(*MODULES),(void**)&MODULES);845pari_stack_pushp(&s_MODULES,functions_basic);846functions_hash = (entree**) pari_calloc(sizeof(entree*)*functions_tblsz);847pari_fill_hashtable(functions_hash, functions_basic);848defaults_hash = (entree**) pari_calloc(sizeof(entree*)*functions_tblsz);849pari_add_defaults_module(functions_default);850}851852void853pari_add_module(entree *ep)854{855pari_fill_hashtable(functions_hash, ep);856pari_stack_pushp(&s_MODULES, ep);857}858859void860pari_add_defaults_module(entree *ep)861{ pari_fill_hashtable(defaults_hash, ep); }862863/*********************************************************************/864/* PARI MAIN STACK */865/*********************************************************************/866867#ifdef HAS_MMAP868#define PARI_STACK_ALIGN (sysconf(_SC_PAGE_SIZE))869#ifndef MAP_ANONYMOUS870#define MAP_ANONYMOUS MAP_ANON871#endif872#ifndef MAP_NORESERVE873#define MAP_NORESERVE 0874#endif875static void *876pari_mainstack_malloc(size_t size)877{878void *b;879/* Check that the system allows reserving "size" bytes. This is just880* a check, we immediately free the memory. */881BLOCK_SIGINT_START;882b = mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);883BLOCK_SIGINT_END;884if (b == MAP_FAILED) return NULL;885BLOCK_SIGINT_START;886munmap(b, size);887888/* Map again, this time with MAP_NORESERVE. On some operating systems889* like Cygwin, this is needed because remapping with PROT_NONE and890* MAP_NORESERVE does not work as expected. */891b = mmap(NULL, size, PROT_READ|PROT_WRITE,892MAP_PRIVATE|MAP_ANONYMOUS|MAP_NORESERVE, -1, 0);893BLOCK_SIGINT_END;894if (b == MAP_FAILED) return NULL;895return b;896}897898static void899pari_mainstack_mfree(void *s, size_t size)900{901BLOCK_SIGINT_START;902munmap(s, size);903BLOCK_SIGINT_END;904}905906/* Completely discard the memory mapped between the addresses "from"907* and "to" (which must be page-aligned).908*909* We use mmap() with PROT_NONE, which means that the underlying memory910* is freed and that the kernel should not commit memory for it. We911* still keep the mapping such that we can change the flags to912* PROT_READ|PROT_WRITE later.913*914* NOTE: remapping with MAP_FIXED and PROT_NONE is not the same as915* calling mprotect(..., PROT_NONE) because the latter will keep the916* memory committed (this is in particular relevant on Linux with917* vm.overcommit = 2). This remains true even when calling918* madvise(..., MADV_DONTNEED). */919static void920pari_mainstack_mreset(pari_sp from, pari_sp to)921{922size_t s = to - from;923void *addr, *res;924if (!s) return;925926addr = (void*)from;927BLOCK_SIGINT_START;928res = mmap(addr, s, PROT_NONE,929MAP_FIXED|MAP_PRIVATE|MAP_ANONYMOUS|MAP_NORESERVE, -1, 0);930BLOCK_SIGINT_END;931if (res != addr) pari_err(e_MEM);932}933934/* Commit (make available) the virtual memory mapped between the935* addresses "from" and "to" (which must be page-aligned).936* Return 0 if successful, -1 if failed. */937static int938pari_mainstack_mextend(pari_sp from, pari_sp to)939{940size_t s = to - from;941int ret;942BLOCK_SIGINT_START;943ret = mprotect((void*)from, s, PROT_READ|PROT_WRITE);944BLOCK_SIGINT_END;945return ret;946}947948/* Set actual stack size to the given size. This sets st->size and949* st->bot. If not enough system memory is available, this can fail.950* Return 1 if successful, 0 if failed (in that case, st->size is not951* changed) */952static int953pari_mainstack_setsize(struct pari_mainstack *st, size_t size)954{955pari_sp newbot = st->top - size;956/* Align newbot to pagesize */957pari_sp alignbot = newbot & ~(pari_sp)(PARI_STACK_ALIGN - 1);958if (pari_mainstack_mextend(alignbot, st->top))959{960/* Making the memory available did not work: limit vsize to the961* current actual stack size. */962st->vsize = st->size;963pari_warn(warnstack, st->vsize);964return 0;965}966pari_mainstack_mreset(st->vbot, alignbot);967st->bot = newbot;968st->size = size;969return 1;970}971972#else973#define PARI_STACK_ALIGN (0x40UL)974static void *975pari_mainstack_malloc(size_t s)976{977char * tmp;978BLOCK_SIGINT_START;979tmp = malloc(s); /* NOT pari_malloc, e_MEM would be deadly */980BLOCK_SIGINT_END;981return tmp;982}983984static void985pari_mainstack_mfree(void *s, size_t size) { (void) size; pari_free(s); }986987static int988pari_mainstack_setsize(struct pari_mainstack *st, size_t size)989{990st->bot = st->top - size;991st->size = size;992return 1;993}994995#endif996997static const size_t MIN_STACK = 500032UL;998static size_t999fix_size(size_t a)1000{1001size_t ps = PARI_STACK_ALIGN;1002size_t b = a & ~(ps - 1); /* Align */1003if (b < a && b < ~(ps - 1)) b += ps;1004if (b < MIN_STACK) b = MIN_STACK;1005return b;1006}10071008static void1009pari_mainstack_alloc(int numerr, struct pari_mainstack *st, size_t rsize, size_t vsize)1010{1011size_t sizemax = vsize ? vsize: rsize, s = fix_size(sizemax);1012for (;;)1013{1014st->vbot = (pari_sp)pari_mainstack_malloc(s);1015if (st->vbot) break;1016if (s == MIN_STACK) pari_err(e_MEM); /* no way out. Die */1017s = fix_size(s >> 1);1018pari_warn(numerr, s);1019}1020st->vsize = vsize ? s: 0;1021st->rsize = minuu(rsize, s);1022st->top = st->vbot+s;1023if (!pari_mainstack_setsize(st, st->rsize))1024{1025/* This should never happen since we only decrease the allocated space */1026pari_err(e_MEM);1027}1028st->memused = 0;1029}10301031static void1032pari_mainstack_free(struct pari_mainstack *st)1033{1034pari_mainstack_mfree((void*)st->vbot, st->vsize ? st->vsize : fix_size(st->rsize));1035st->top = st->bot = st->vbot = 0;1036st->size = st->vsize = 0;1037}10381039static void1040pari_mainstack_resize(struct pari_mainstack *st, size_t rsize, size_t vsize)1041{1042BLOCK_SIGINT_START;1043pari_mainstack_free(st);1044pari_mainstack_alloc(warnstack, st, rsize, vsize);1045BLOCK_SIGINT_END;1046}10471048static void1049pari_mainstack_use(struct pari_mainstack *st)1050{1051pari_mainstack = st;1052avma = st->top; /* don't use set_avma */1053}10541055static void1056paristack_alloc(size_t rsize, size_t vsize)1057{1058pari_mainstack_alloc(warnstack, pari_mainstack, rsize, vsize);1059pari_mainstack_use(pari_mainstack);1060}10611062void1063paristack_setsize(size_t rsize, size_t vsize)1064{1065pari_mainstack_resize(pari_mainstack, rsize, vsize);1066pari_mainstack_use(pari_mainstack);1067}10681069void1070parivstack_resize(ulong newsize)1071{1072size_t s;1073if (newsize && newsize < pari_mainstack->rsize)1074pari_err_DIM("stack sizes [parisizemax < parisize]");1075if (newsize == pari_mainstack->vsize) return;1076evalstate_reset();1077paristack_setsize(pari_mainstack->rsize, newsize);1078s = pari_mainstack->vsize ? pari_mainstack->vsize : pari_mainstack->rsize;1079if (DEBUGMEM)1080pari_warn(warner,"new maximum stack size = %lu (%.3f Mbytes)",1081s, s/1048576.);1082pari_init_errcatch();1083cb_pari_err_recover(-1);1084}10851086void1087paristack_newrsize(ulong newsize)1088{1089size_t s, vsize = pari_mainstack->vsize;1090if (!newsize) newsize = pari_mainstack->rsize << 1;1091if (newsize != pari_mainstack->rsize)1092pari_mainstack_resize(pari_mainstack, newsize, vsize);1093evalstate_reset();1094s = pari_mainstack->rsize;1095if (DEBUGMEM)1096pari_warn(warner,"new stack size = %lu (%.3f Mbytes)", s, s/1048576.);1097pari_init_errcatch();1098cb_pari_err_recover(-1);1099}11001101void1102paristack_resize(ulong newsize)1103{1104long size = pari_mainstack->size;1105if (!newsize)1106newsize = 2 * size;1107newsize = minuu(newsize, pari_mainstack->vsize);1108if (newsize <= pari_mainstack->size) return;1109if (pari_mainstack_setsize(pari_mainstack, newsize))1110{1111if (DEBUGMEM)1112pari_warn(warner, "increasing stack size to %lu", pari_mainstack->size);1113}1114else1115{1116pari_mainstack_setsize(pari_mainstack, size);1117pari_err(e_STACK);1118}1119}11201121void1122parivstack_reset(void)1123{1124pari_mainstack_setsize(pari_mainstack, pari_mainstack->rsize);1125if (avma < pari_mainstack->bot)1126pari_err_BUG("parivstack_reset [avma < bot]");1127}11281129/* Enlarge the stack if needed such that the unused portion of the stack1130* (between bot and avma) is large enough to contain x longs. */1131void1132new_chunk_resize(size_t x)1133{1134if (pari_mainstack->vsize==01135|| x > (avma-pari_mainstack->vbot) / sizeof(long)) pari_err(e_STACK);1136while (x > (avma-pari_mainstack->bot) / sizeof(long))1137paristack_resize(0);1138}11391140/*********************************************************************/1141/* PARI THREAD */1142/*********************************************************************/11431144/* Initial PARI thread structure t with a stack of size s and1145* argument arg */11461147static void1148pari_thread_set_global(struct pari_global_state *gs)1149{1150push_localbitprec(gs->bitprec);1151pari_set_primetab(gs->primetab);1152pari_set_seadata(gs->seadata);1153pari_set_varstate(gs->varpriority, &gs->varstate);1154}11551156static void1157pari_thread_get_global(struct pari_global_state *gs)1158{1159gs->bitprec = get_localbitprec();1160gs->primetab = primetab;1161gs->seadata = pari_get_seadata();1162varstate_save(&gs->varstate);1163gs->varpriority = varpriority;1164}11651166void1167pari_thread_alloc(struct pari_thread *t, size_t s, GEN arg)1168{1169pari_mainstack_alloc(warnstackthread, &t->st,s,0);1170pari_thread_get_global(&t->gs);1171t->data = arg;1172}11731174/* Initial PARI thread structure t with a stack of size s and virtual size v1175* and argument arg */11761177void1178pari_thread_valloc(struct pari_thread *t, size_t s, size_t v, GEN arg)1179{1180pari_mainstack_alloc(warnstackthread, &t->st,s,v);1181pari_thread_get_global(&t->gs);1182t->data = arg;1183}11841185void1186pari_thread_free(struct pari_thread *t)1187{1188pari_mainstack_free(&t->st);1189}11901191void1192pari_thread_init(void)1193{1194long var;1195pari_stackcheck_init((void*)&var);1196pari_init_blocks();1197pari_init_errcatch();1198pari_init_rand();1199pari_init_floats();1200pari_init_parser();1201pari_init_compiler();1202pari_init_evaluator();1203pari_init_files();1204pari_init_ellcondfile();1205}12061207void1208pari_thread_close(void)1209{1210pari_thread_close_files();1211pari_close_evaluator();1212pari_close_compiler();1213pari_close_parser();1214pari_close_floats();1215pari_close_blocks();1216}12171218GEN1219pari_thread_start(struct pari_thread *t)1220{1221pari_mainstack_use(&t->st);1222pari_thread_init();1223pari_thread_set_global(&t->gs);1224return t->data;1225}12261227/*********************************************************************/1228/* LIBPARI INIT / CLOSE */1229/*********************************************************************/12301231static void1232pari_exit(void)1233{1234err_printf(" *** Error in the PARI system. End of program.\n");1235exit(1);1236}12371238static void1239dflt_err_recover(long errnum) { (void) errnum; pari_exit(); }12401241static void1242dflt_pari_quit(long err) { (void)err; /*do nothing*/; }12431244static int pari_err_display(GEN err);12451246/* initialize PARI data. Initialize [new|old]fun to NULL for default set. */1247void1248pari_init_opts(size_t parisize, ulong maxprime, ulong init_opts)1249{1250ulong u;12511252pari_mt_nbthreads = 0;1253cb_pari_quit = dflt_pari_quit;1254cb_pari_init_histfile = NULL;1255cb_pari_get_line_interactive = NULL;1256cb_pari_fgets_interactive = NULL;1257cb_pari_whatnow = NULL;1258cb_pari_handle_exception = NULL;1259cb_pari_err_handle = pari_err_display;1260cb_pari_pre_recover = NULL;1261cb_pari_break_loop = NULL;1262cb_pari_is_interactive = NULL;1263cb_pari_start_output = NULL;1264cb_pari_sigint = dflt_sigint_fun;1265if (init_opts&INIT_JMPm) cb_pari_err_recover = dflt_err_recover;12661267pari_stackcheck_init(&u);1268pari_init_homedir();1269if (init_opts&INIT_DFTm) {1270pari_init_defaults();1271GP_DATA = default_gp_data();1272pari_init_paths();1273}12741275pari_mainstack = (struct pari_mainstack *) malloc(sizeof(*pari_mainstack));1276paristack_alloc(parisize, 0);1277init_universal_constants();1278diffptr = NULL;1279if (!(init_opts&INIT_noPRIMEm))1280{1281GP_DATA->primelimit = maxprime;1282pari_init_primes(GP_DATA->primelimit);1283}1284if (!(init_opts&INIT_noINTGMPm)) pari_kernel_init();1285pari_init_graphics();1286pari_thread_init();1287pari_set_primetab(NULL);1288pari_set_seadata(NULL);1289pari_init_functions();1290pari_init_export();1291pari_var_init();1292pari_init_timer();1293pari_init_buffers();1294(void)getabstime();1295try_to_recover = 1;1296if (!(init_opts&INIT_noIMTm)) pari_mt_init();1297if ((init_opts&INIT_SIGm)) pari_sig_init(pari_sighandler);1298}12991300void1301pari_init(size_t parisize, ulong maxprime)1302{ pari_init_opts(parisize, maxprime, INIT_JMPm | INIT_SIGm | INIT_DFTm); }13031304void1305pari_close_opts(ulong init_opts)1306{1307long i;13081309BLOCK_SIGINT_START;1310if ((init_opts&INIT_SIGm)) pari_sig_init(SIG_DFL);1311if (!(init_opts&INIT_noIMTm)) pari_mt_close();13121313pari_var_close(); /* must come before destruction of functions_hash */1314for (i = 0; i < functions_tblsz; i++)1315{1316entree *ep = functions_hash[i];1317while (ep) {1318entree *EP = ep->next;1319if (!EpSTATIC(ep)) { freeep(ep); free(ep); }1320ep = EP;1321}1322}1323pari_close_mf();1324pari_thread_close();1325pari_close_export();1326pari_close_files();1327pari_close_homedir();1328if (!(init_opts&INIT_noINTGMPm)) pari_kernel_close();13291330free((void*)functions_hash);1331free((void*)defaults_hash);1332if (diffptr) pari_close_primes();1333free(current_logfile);1334free(current_psfile);1335pari_mainstack_free(pari_mainstack);1336free((void*)pari_mainstack);1337pari_stack_delete(&s_MODULES);1338if (pari_datadir) free(pari_datadir);1339if (init_opts&INIT_DFTm)1340{ /* delete GP_DATA */1341pari_close_paths();1342if (GP_DATA->hist->v) free((void*)GP_DATA->hist->v);1343if (GP_DATA->pp->cmd) free((void*)GP_DATA->pp->cmd);1344if (GP_DATA->help) free((void*)GP_DATA->help);1345if (GP_DATA->plothsizes) free((void*)GP_DATA->plothsizes);1346if (GP_DATA->colormap) pari_free(GP_DATA->colormap);1347if (GP_DATA->graphcolors) pari_free(GP_DATA->graphcolors);1348free((void*)GP_DATA->prompt);1349free((void*)GP_DATA->prompt_cont);1350free((void*)GP_DATA->histfile);1351}1352BLOCK_SIGINT_END;1353}13541355void1356pari_close(void)1357{ pari_close_opts(INIT_JMPm | INIT_SIGm | INIT_DFTm); }13581359/*******************************************************************/1360/* */1361/* ERROR RECOVERY */1362/* */1363/*******************************************************************/1364void1365gp_context_save(struct gp_context* rec)1366{1367rec->prettyp = GP_DATA->fmt->prettyp;1368rec->listloc = next_block;1369rec->iferr_env = iferr_env;1370rec->err_data = global_err_data;1371varstate_save(&rec->var);1372evalstate_save(&rec->eval);1373parsestate_save(&rec->parse);1374filestate_save(&rec->file);1375}13761377void1378gp_context_restore(struct gp_context* rec)1379{1380long i;13811382if (!try_to_recover) return;1383/* disable gp_context_restore() and SIGINT */1384try_to_recover = 0;1385BLOCK_SIGINT_START1386if (DEBUGMEM>2) err_printf("entering recover(), loc = %ld\n", rec->listloc);1387evalstate_restore(&rec->eval);1388parsestate_restore(&rec->parse);1389filestate_restore(&rec->file);1390global_err_data = rec->err_data;1391iferr_env = rec->iferr_env;1392GP_DATA->fmt->prettyp = rec->prettyp;13931394for (i = 0; i < functions_tblsz; i++)1395{1396entree *ep = functions_hash[i];1397while (ep)1398{1399entree *EP = ep->next;1400switch(EpVALENCE(ep))1401{1402case EpVAR:1403while (pop_val_if_newer(ep,rec->listloc)) /* empty */;1404break;1405case EpNEW: break;1406}1407ep = EP;1408}1409}1410varstate_restore(&rec->var);1411if (DEBUGMEM>2) err_printf("leaving recover()\n");1412BLOCK_SIGINT_END1413try_to_recover = 1;1414}14151416static void1417err_recover(long numerr)1418{1419if (cb_pari_pre_recover)1420cb_pari_pre_recover(numerr);1421evalstate_reset();1422killallfiles();1423pari_init_errcatch();1424cb_pari_err_recover(numerr);1425}14261427static void1428err_init(void)1429{1430/* make sure pari_err msg starts at the beginning of line */1431if (!pari_last_was_newline()) pari_putc('\n');1432pariOut->flush();1433pariErr->flush();1434out_term_color(pariErr, c_ERR);1435}14361437static void1438err_init_msg(int user)1439{1440const char *gp_function_name;1441out_puts(pariErr, " *** ");1442if (!user && (gp_function_name = closure_func_err()))1443out_printf(pariErr, "%s: ", gp_function_name);1444else1445out_puts(pariErr, " ");1446}14471448void1449pari_warn(int numerr, ...)1450{1451char *ch1;1452va_list ap;14531454va_start(ap,numerr);14551456err_init();1457err_init_msg(numerr==warnuser || numerr==warnstack);1458switch (numerr)1459{1460case warnuser:1461out_puts(pariErr, "user warning: ");1462out_print0(pariErr, NULL, va_arg(ap, GEN), f_RAW);1463break;14641465case warnmem:1466out_puts(pariErr, "collecting garbage in "); ch1=va_arg(ap, char*);1467out_vprintf(pariErr, ch1,ap); out_putc(pariErr, '.');1468break;14691470case warner:1471out_puts(pariErr, "Warning: "); ch1=va_arg(ap, char*);1472out_vprintf(pariErr, ch1,ap); out_putc(pariErr, '.');1473break;14741475case warnprec:1476out_vprintf(pariErr, "Warning: increasing prec in %s; new prec = %ld",1477ap);1478break;14791480case warnfile:1481out_puts(pariErr, "Warning: failed to "),1482ch1 = va_arg(ap, char*);1483out_printf(pariErr, "%s: %s", ch1, va_arg(ap, char*));1484break;14851486case warnstack:1487case warnstackthread:1488{1489ulong s = va_arg(ap, ulong);1490char buf[128];1491const char * stk = numerr == warnstackthread1492|| mt_is_thread() ? "thread": "PARI";1493sprintf(buf,"Warning: not enough memory, new %s stack %lu", stk, s);1494out_puts(pariErr,buf);1495break;1496}1497}1498va_end(ap);1499out_term_color(pariErr, c_NONE);1500out_putc(pariErr, '\n');1501pariErr->flush();1502}1503void1504pari_sigint(const char *time_s)1505{1506int recover=0;1507BLOCK_SIGALRM_START1508err_init();1509closure_err(0);1510err_init_msg(0);1511out_puts(pariErr, "user interrupt after ");1512out_puts(pariErr, time_s);1513out_term_color(pariErr, c_NONE);1514pariErr->flush();1515if (cb_pari_handle_exception)1516recover = cb_pari_handle_exception(-1);1517if (!recover && !block)1518PARI_SIGINT_pending = 0;1519BLOCK_SIGINT_END1520if (!recover) err_recover(e_MISC);1521}15221523#define retmkerr2(x,y)\1524do { GEN _v = cgetg(3, t_ERROR);\1525_v[1] = (x);\1526gel(_v,2) = (y); return _v; } while(0)1527#define retmkerr3(x,y,z)\1528do { GEN _v = cgetg(4, t_ERROR);\1529_v[1] = (x);\1530gel(_v,2) = (y);\1531gel(_v,3) = (z); return _v; } while(0)1532#define retmkerr4(x,y,z,t)\1533do { GEN _v = cgetg(5, t_ERROR);\1534_v[1] = (x);\1535gel(_v,2) = (y);\1536gel(_v,3) = (z);\1537gel(_v,4) = (t); return _v; } while(0)1538#define retmkerr5(x,y,z,t,u)\1539do { GEN _v = cgetg(6, t_ERROR);\1540_v[1] = (x);\1541gel(_v,2) = (y);\1542gel(_v,3) = (z);\1543gel(_v,4) = (t);\1544gel(_v,5) = (u); return _v; } while(0)1545#define retmkerr6(x,y,z,t,u,v)\1546do { GEN _v = cgetg(7, t_ERROR);\1547_v[1] = (x);\1548gel(_v,2) = (y);\1549gel(_v,3) = (z);\1550gel(_v,4) = (t);\1551gel(_v,5) = (u);\1552gel(_v,6) = (v); return _v; } while(0)15531554static GEN1555pari_err2GEN(long numerr, va_list ap)1556{1557switch ((enum err_list) numerr)1558{1559case e_SYNTAX:1560{1561const char *msg = va_arg(ap, char*);1562const char *s = va_arg(ap,char *);1563const char *entry = va_arg(ap,char *);1564retmkerr3(numerr,strtoGENstr(msg), mkvecsmall2((long)s,(long)entry));1565}1566case e_MISC: case e_ALARM:1567{1568const char *ch1 = va_arg(ap, char*);1569retmkerr2(numerr, gvsprintf(ch1,ap));1570}1571case e_NOTFUNC:1572case e_USER:1573retmkerr2(numerr,va_arg(ap, GEN));1574case e_FILE:1575{1576const char *f = va_arg(ap, const char*);1577retmkerr3(numerr, strtoGENstr(f), strtoGENstr(va_arg(ap, char*)));1578}1579case e_FILEDESC:1580{1581const char *f = va_arg(ap, const char*);1582retmkerr3(numerr, strtoGENstr(f), stoi(va_arg(ap, long)));1583}1584case e_OVERFLOW:1585case e_IMPL:1586case e_DIM:1587case e_CONSTPOL:1588case e_ROOTS0:1589case e_FLAG:1590case e_PREC:1591case e_BUG:1592case e_ARCH:1593case e_PACKAGE:1594retmkerr2(numerr, strtoGENstr(va_arg(ap, char*)));1595case e_MODULUS:1596case e_VAR:1597{1598const char *f = va_arg(ap, const char*);1599GEN x = va_arg(ap, GEN);1600GEN y = va_arg(ap, GEN);1601retmkerr4(numerr, strtoGENstr(f), x,y);1602}1603case e_INV:1604case e_IRREDPOL:1605case e_PRIME:1606case e_SQRTN:1607case e_TYPE:1608{1609const char *f = va_arg(ap, const char*);1610GEN x = va_arg(ap, GEN);1611retmkerr3(numerr, strtoGENstr(f), x);1612}1613case e_COPRIME: case e_OP: case e_TYPE2:1614{1615const char *f = va_arg(ap, const char*);1616GEN x = va_arg(ap, GEN);1617GEN y = va_arg(ap, GEN);1618retmkerr4(numerr,strtoGENstr(f),x,y);1619}1620case e_COMPONENT:1621{1622const char *f= va_arg(ap, const char *);1623const char *op = va_arg(ap, const char *);1624GEN l = va_arg(ap, GEN);1625GEN x = va_arg(ap, GEN);1626retmkerr5(numerr,strtoGENstr(f),strtoGENstr(op),l,x);1627}1628case e_DOMAIN:1629{1630const char *f = va_arg(ap, const char*);1631const char *v = va_arg(ap, const char *);1632const char *op = va_arg(ap, const char *);1633GEN l = va_arg(ap, GEN);1634GEN x = va_arg(ap, GEN);1635retmkerr6(numerr,strtoGENstr(f),strtoGENstr(v),strtoGENstr(op),l,x);1636}1637case e_PRIORITY:1638{1639const char *f = va_arg(ap, const char*);1640GEN x = va_arg(ap, GEN);1641const char *op = va_arg(ap, const char *);1642long v = va_arg(ap, long);1643retmkerr5(numerr,strtoGENstr(f),x,strtoGENstr(op),stoi(v));1644}1645case e_MAXPRIME:1646retmkerr2(numerr, utoi(va_arg(ap, ulong)));1647case e_STACK:1648return err_e_STACK;1649case e_STACKTHREAD:1650retmkerr3(numerr, utoi(va_arg(ap, ulong)), utoi(va_arg(ap, ulong)));1651default:1652return mkerr(numerr);1653}1654}16551656static char *1657type_dim(GEN x)1658{1659char *v = stack_malloc(64);1660switch(typ(x))1661{1662case t_MAT:1663{1664long l = lg(x), r = (l == 1)? 1: lgcols(x);1665sprintf(v, "t_MAT (%ldx%ld)", r-1,l-1);1666break;1667}1668case t_COL:1669sprintf(v, "t_COL (%ld elts)", lg(x)-1);1670break;1671case t_VEC:1672sprintf(v, "t_VEC (%ld elts)", lg(x)-1);1673break;1674default:1675v = (char*)type_name(typ(x));1676}1677return v;1678}16791680static char *1681gdisplay(GEN x)1682{1683char *s = GENtostr_raw(x);1684if (strlen(s) < 1600) return s;1685if (! GP_DATA->breakloop) return (char*)"(...)";1686return stack_sprintf("\n *** (...) Huge %s omitted; you can access it via dbg_err()", type_name(typ(x)));1687}16881689char *1690pari_err2str(GEN e)1691{1692long numerr = err_get_num(e);1693switch ((enum err_list) numerr)1694{1695case e_ALARM:1696return pari_sprintf("alarm interrupt after %Ps.",gel(e,2));1697case e_MISC:1698return pari_sprintf("%Ps.",gel(e,2));16991700case e_ARCH:1701return pari_sprintf("sorry, '%Ps' not available on this system.",gel(e,2));1702case e_BUG:1703return pari_sprintf("bug in %Ps, please report.",gel(e,2));1704case e_CONSTPOL:1705return pari_sprintf("constant polynomial in %Ps.", gel(e,2));1706case e_COPRIME:1707return pari_sprintf("elements not coprime in %Ps:\n %s\n %s",1708gel(e,2), gdisplay(gel(e,3)), gdisplay(gel(e,4)));1709case e_DIM:1710return pari_sprintf("inconsistent dimensions in %Ps.", gel(e,2));1711case e_FILE:1712return pari_sprintf("error opening %Ps: `%Ps'.", gel(e,2), gel(e,3));1713case e_FILEDESC:1714return pari_sprintf("invalid file descriptor in %Ps [%Ps]", gel(e,2), gel(e,3));1715case e_FLAG:1716return pari_sprintf("invalid flag in %Ps.", gel(e,2));1717case e_IMPL:1718return pari_sprintf("sorry, %Ps is not yet implemented.", gel(e,2));1719case e_PACKAGE:1720return pari_sprintf("package %Ps is required, please install it.", gel(e,2));1721case e_INV:1722return pari_sprintf("impossible inverse in %Ps: %s.", gel(e,2),1723gdisplay(gel(e,3)));1724case e_IRREDPOL:1725return pari_sprintf("not an irreducible polynomial in %Ps: %s.",1726gel(e,2), gdisplay(gel(e,3)));1727case e_MAXPRIME:1728{1729const char * msg = "not enough precomputed primes";1730ulong c = itou(gel(e,2));1731if (c) return pari_sprintf("%s, need primelimit ~ %lu.",msg, c);1732else return pari_strdup(msg);1733}1734case e_MEM:1735return pari_strdup("not enough memory");1736case e_MODULUS:1737{1738GEN x = gel(e,3), y = gel(e,4);1739return pari_sprintf("inconsistent moduli in %Ps: %s != %s",1740gel(e,2), gdisplay(x), gdisplay(y));1741}1742case e_NONE: return NULL;1743case e_NOTFUNC:1744return pari_strdup("not a function in function call");1745case e_OP: case e_TYPE2:1746{1747pari_sp av = avma;1748char *v;1749const char *f, *op = GSTR(gel(e,2));1750const char *what = numerr == e_OP? "inconsistent": "forbidden";1751GEN x = gel(e,3);1752GEN y = gel(e,4);1753switch(*op)1754{1755case '+': f = "addition"; break;1756case '*': f = "multiplication"; break;1757case '/': case '%': case '\\': f = "division"; break;1758case '=': op = "-->"; f = "assignment"; break;1759default: f = op; op = ","; break;1760}1761v = pari_sprintf("%s %s %s %s %s.", what,f,type_dim(x),op,type_dim(y));1762set_avma(av); return v;1763}1764case e_COMPONENT:1765{1766const char *f= GSTR(gel(e,2));1767const char *op= GSTR(gel(e,3));1768GEN l = gel(e,4);1769if (!*f)1770return pari_sprintf("nonexistent component: index %s %Ps",op,l);1771return pari_sprintf("nonexistent component in %s: index %s %Ps",f,op,l);1772}1773case e_DOMAIN:1774{1775const char *f = GSTR(gel(e,2));1776const char *v = GSTR(gel(e,3));1777const char *op= GSTR(gel(e,4));1778GEN l = gel(e,5);1779if (!*op)1780return pari_sprintf("domain error in %s: %s out of range",f,v);1781return pari_sprintf("domain error in %s: %s %s %Ps",f,v,op,l);1782}1783case e_PRIORITY:1784{1785const char *f = GSTR(gel(e,2));1786long vx = gvar(gel(e,3));1787const char *op= GSTR(gel(e,4));1788long v = itos(gel(e,5));1789return pari_sprintf("incorrect priority in %s: variable %Ps %s %Ps",f,1790pol_x(vx), op, pol_x(v));1791}1792case e_OVERFLOW:1793return pari_sprintf("overflow in %Ps.", gel(e,2));1794case e_PREC:1795return pari_sprintf("precision too low in %Ps.", gel(e,2));1796case e_PRIME:1797return pari_sprintf("not a prime number in %Ps: %s.",1798gel(e,2), gdisplay(gel(e,3)));1799case e_ROOTS0:1800return pari_sprintf("zero polynomial in %Ps.", gel(e,2));1801case e_SQRTN:1802return pari_sprintf("not an n-th power residue in %Ps: %s.",1803gel(e,2), gdisplay(gel(e,3)));1804case e_STACK:1805case e_STACKTHREAD:1806{1807const char *stack = numerr == e_STACK? "PARI": "thread";1808const char *var = numerr == e_STACK? "parisizemax": "threadsizemax";1809size_t rsize = numerr == e_STACKTHREAD && GP_DATA->threadsize ?1810GP_DATA->threadsize: pari_mainstack->rsize;1811size_t vsize = numerr == e_STACK? pari_mainstack->vsize:1812GP_DATA->threadsizemax;1813char *buf = (char *) pari_malloc(512*sizeof(char));1814if (vsize)1815{1816sprintf(buf, "the %s stack overflows !\n"1817" current stack size: %lu (%.3f Mbytes)\n"1818" [hint] you can increase '%s' using default()\n",1819stack, (ulong)vsize, (double)vsize/1048576., var);1820}1821else1822{1823sprintf(buf, "the %s stack overflows !\n"1824" current stack size: %lu (%.3f Mbytes)\n"1825" [hint] set '%s' to a nonzero value in your GPRC\n",1826stack, (ulong)rsize, (double)rsize/1048576., var);1827}1828return buf;1829}1830case e_SYNTAX:1831return pari_strdup(GSTR(gel(e,2)));1832case e_TYPE:1833return pari_sprintf("incorrect type in %Ps (%s).",1834gel(e,2), type_name(typ(gel(e,3))));1835case e_USER:1836return pari_sprint0("user error: ", gel(e,2), f_RAW);1837case e_VAR:1838{1839GEN x = gel(e,3), y = gel(e,4);1840return pari_sprintf("inconsistent variables in %Ps, %Ps != %Ps.",1841gel(e,2), pol_x(varn(x)), pol_x(varn(y)));1842}1843}1844return NULL; /*LCOV_EXCL_LINE*/1845}18461847static int1848pari_err_display(GEN err)1849{1850long numerr=err_get_num(err);1851err_init();1852if (numerr==e_SYNTAX)1853{1854const char *msg = GSTR(gel(err,2));1855const char *s = (const char *) gmael(err,3,1);1856const char *entry = (const char *) gmael(err,3,2);1857print_errcontext(pariErr, msg, s, entry);1858}1859else1860{1861char *s;1862closure_err(0);1863err_init_msg(numerr==e_USER);1864s = pari_err2str(err); pariErr->puts(s); pari_free(s);1865if (numerr==e_NOTFUNC)1866{1867GEN fun = gel(err,2);1868if (gequalX(fun))1869{1870entree *ep = varentries[varn(fun)];1871const char *t = ep->name;1872if (cb_pari_whatnow) cb_pari_whatnow(pariErr,t,1);1873}1874}1875}1876out_term_color(pariErr, c_NONE);1877pariErr->flush(); return 0;1878}18791880void1881pari_err(int numerr, ...)1882{1883va_list ap;1884GEN E;18851886va_start(ap,numerr);18871888if (numerr)1889E = pari_err2GEN(numerr,ap);1890else1891{1892E = va_arg(ap,GEN);1893numerr = err_get_num(E);1894}1895global_err_data = E;1896if (*iferr_env) longjmp(*iferr_env, numerr);1897mt_err_recover(numerr);1898va_end(ap);1899if (cb_pari_err_handle &&1900cb_pari_err_handle(E)) return;1901if (cb_pari_handle_exception &&1902cb_pari_handle_exception(numerr)) return;1903err_recover(numerr);1904}19051906GEN1907pari_err_last(void) { return global_err_data; }19081909const char *1910numerr_name(long numerr)1911{1912switch ((enum err_list) numerr)1913{1914case e_ALARM: return "e_ALARM";1915case e_ARCH: return "e_ARCH";1916case e_BUG: return "e_BUG";1917case e_COMPONENT: return "e_COMPONENT";1918case e_CONSTPOL: return "e_CONSTPOL";1919case e_COPRIME: return "e_COPRIME";1920case e_DIM: return "e_DIM";1921case e_DOMAIN: return "e_DOMAIN";1922case e_FILE: return "e_FILE";1923case e_FILEDESC: return "e_FILEDESC";1924case e_FLAG: return "e_FLAG";1925case e_IMPL: return "e_IMPL";1926case e_INV: return "e_INV";1927case e_IRREDPOL: return "e_IRREDPOL";1928case e_MAXPRIME: return "e_MAXPRIME";1929case e_MEM: return "e_MEM";1930case e_MISC: return "e_MISC";1931case e_MODULUS: return "e_MODULUS";1932case e_NONE: return "e_NONE";1933case e_NOTFUNC: return "e_NOTFUNC";1934case e_OP: return "e_OP";1935case e_OVERFLOW: return "e_OVERFLOW";1936case e_PACKAGE: return "e_PACKAGE";1937case e_PREC: return "e_PREC";1938case e_PRIME: return "e_PRIME";1939case e_PRIORITY: return "e_PRIORITY";1940case e_ROOTS0: return "e_ROOTS0";1941case e_SQRTN: return "e_SQRTN";1942case e_STACK: return "e_STACK";1943case e_SYNTAX: return "e_SYNTAX";1944case e_STACKTHREAD: return "e_STACKTHREAD";1945case e_TYPE2: return "e_TYPE2";1946case e_TYPE: return "e_TYPE";1947case e_USER: return "e_USER";1948case e_VAR: return "e_VAR";1949}1950return "invalid error number";1951}19521953long1954name_numerr(const char *s)1955{1956if (!strcmp(s,"e_ALARM")) return e_ALARM;1957if (!strcmp(s,"e_ARCH")) return e_ARCH;1958if (!strcmp(s,"e_BUG")) return e_BUG;1959if (!strcmp(s,"e_COMPONENT")) return e_COMPONENT;1960if (!strcmp(s,"e_CONSTPOL")) return e_CONSTPOL;1961if (!strcmp(s,"e_COPRIME")) return e_COPRIME;1962if (!strcmp(s,"e_DIM")) return e_DIM;1963if (!strcmp(s,"e_DOMAIN")) return e_DOMAIN;1964if (!strcmp(s,"e_FILE")) return e_FILE;1965if (!strcmp(s,"e_FILEDESC")) return e_FILEDESC;1966if (!strcmp(s,"e_FLAG")) return e_FLAG;1967if (!strcmp(s,"e_IMPL")) return e_IMPL;1968if (!strcmp(s,"e_INV")) return e_INV;1969if (!strcmp(s,"e_IRREDPOL")) return e_IRREDPOL;1970if (!strcmp(s,"e_MAXPRIME")) return e_MAXPRIME;1971if (!strcmp(s,"e_MEM")) return e_MEM;1972if (!strcmp(s,"e_MISC")) return e_MISC;1973if (!strcmp(s,"e_MODULUS")) return e_MODULUS;1974if (!strcmp(s,"e_NONE")) return e_NONE;1975if (!strcmp(s,"e_NOTFUNC")) return e_NOTFUNC;1976if (!strcmp(s,"e_OP")) return e_OP;1977if (!strcmp(s,"e_OVERFLOW")) return e_OVERFLOW;1978if (!strcmp(s,"e_PACKAGE")) return e_PACKAGE;1979if (!strcmp(s,"e_PREC")) return e_PREC;1980if (!strcmp(s,"e_PRIME")) return e_PRIME;1981if (!strcmp(s,"e_PRIORITY")) return e_PRIORITY;1982if (!strcmp(s,"e_ROOTS0")) return e_ROOTS0;1983if (!strcmp(s,"e_SQRTN")) return e_SQRTN;1984if (!strcmp(s,"e_STACK")) return e_STACK;1985if (!strcmp(s,"e_SYNTAX")) return e_SYNTAX;1986if (!strcmp(s,"e_TYPE")) return e_TYPE;1987if (!strcmp(s,"e_TYPE2")) return e_TYPE2;1988if (!strcmp(s,"e_USER")) return e_USER;1989if (!strcmp(s,"e_VAR")) return e_VAR;1990pari_err(e_MISC,"unknown error name");1991return -1; /* LCOV_EXCL_LINE */1992}19931994GEN1995errname(GEN err)1996{1997if (typ(err)!=t_ERROR) pari_err_TYPE("errname",err);1998return strtoGENstr(numerr_name(err_get_num(err)));1999}20002001/* Try f (trapping error e), recover using r (break_loop, if NULL) */2002GEN2003trap0(const char *e, GEN r, GEN f)2004{2005long numerr = CATCH_ALL;2006GEN x;2007if (!e || !*e) numerr = CATCH_ALL;2008else numerr = name_numerr(e);2009if (!f) {2010pari_warn(warner,"default handlers are no longer supported --> ignored");2011return gnil;2012}2013x = closure_trapgen(f, numerr);2014if (x == (GEN)1L) x = r? closure_evalgen(r): gnil;2015return x;2016}20172018/*******************************************************************/2019/* */2020/* CLONING & COPY */2021/* Replicate an existing GEN */2022/* */2023/*******************************************************************/2024/* lontyp[tx] = 0 (non recursive type) or number of codewords for type tx */2025const long lontyp[] = { 0,0,0,1,1,2,1,2,1,1, 2,2,0,1,1,1,1,1,1,1, 2,0,0,2,2,1 };20262027static GEN2028list_internal_copy(GEN z, long nmax)2029{2030long i, l;2031GEN a;2032if (!z) return NULL;2033l = lg(z);2034a = newblock(nmax+1);2035for (i = 1; i < l; i++) gel(a,i) = gel(z,i)? gclone(gel(z,i)): gen_0;2036a[0] = z[0]; setisclone(a); return a;2037}20382039static void2040listassign(GEN x, GEN y)2041{2042long nmax = list_nmax(x);2043GEN L = list_data(x);2044if (!nmax && L) nmax = lg(L) + 32; /* not malloc'ed yet */2045y[1] = evaltyp(list_typ(x))|evallg(nmax);2046list_data(y) = list_internal_copy(L, nmax);2047}20482049/* transform a non-malloced list (e.g. from gtolist or gtomap) to a malloced2050* list suitable for listput */2051GEN2052listinit(GEN x)2053{2054GEN y = cgetg(3, t_LIST);2055listassign(x, y); return y;2056}20572058/* copy list on the PARI stack */2059GEN2060listcopy(GEN x)2061{2062GEN y = mklist(), L = list_data(x);2063if (L) list_data(y) = gcopy(L);2064y[1] = evaltyp(list_typ(x));2065return y;2066}20672068GEN2069gcopy(GEN x)2070{2071long tx = typ(x), lx, i;2072GEN y;2073switch(tx)2074{ /* non recursive types */2075case t_INT: return signe(x)? icopy(x): gen_0;2076case t_REAL:2077case t_STR:2078case t_VECSMALL: return leafcopy(x);2079/* one more special case */2080case t_LIST: return listcopy(x);2081}2082y = cgetg_copy(x, &lx);2083if (lontyp[tx] == 1) i = 1; else { y[1] = x[1]; i = 2; }2084for (; i<lx; i++) gel(y,i) = gcopy(gel(x,i));2085return y;2086}20872088/* as gcopy, but truncate to the first lx components if recursive type2089* [ leaves use their own lg ]. No checks. */2090GEN2091gcopy_lg(GEN x, long lx)2092{2093long tx = typ(x), i;2094GEN y;2095switch(tx)2096{ /* non recursive types */2097case t_INT: return signe(x)? icopy(x): gen_0;2098case t_REAL:2099case t_STR:2100case t_VECSMALL: return leafcopy(x);2101/* one more special case */2102case t_LIST: return listcopy(x);2103}2104y = cgetg(lx, tx);2105if (lontyp[tx] == 1) i = 1; else { y[1] = x[1]; i = 2; }2106for (; i<lx; i++) gel(y,i) = gcopy(gel(x,i));2107return y;2108}21092110/* cf cgetg_copy: "allocate" (by updating first codeword only) for subsequent2111* copy of x, as if avma = *AVMA */2112INLINE GEN2113cgetg_copy_avma(GEN x, long *plx, pari_sp *AVMA) {2114GEN z;2115*plx = lg(x);2116z = ((GEN)*AVMA) - *plx;2117z[0] = x[0] & (TYPBITS|LGBITS);2118*AVMA = (pari_sp)z; return z;2119}2120INLINE GEN2121cgetlist_avma(pari_sp *AVMA)2122{2123GEN y = ((GEN)*AVMA) - 3;2124y[0] = _evallg(3) | evaltyp(t_LIST);2125*AVMA = (pari_sp)y; return y;2126}21272128/* copy x as if avma = *AVMA, update *AVMA */2129GEN2130gcopy_avma(GEN x, pari_sp *AVMA)2131{2132long i, lx, tx = typ(x);2133GEN y;21342135switch(typ(x))2136{ /* non recursive types */2137case t_INT:2138if (lgefint(x) == 2) return gen_0;2139*AVMA = (pari_sp)icopy_avma(x, *AVMA);2140return (GEN)*AVMA;2141case t_REAL: case t_STR: case t_VECSMALL:2142*AVMA = (pari_sp)leafcopy_avma(x, *AVMA);2143return (GEN)*AVMA;21442145/* one more special case */2146case t_LIST:2147y = cgetlist_avma(AVMA);2148listassign(x, y); return y;21492150}2151y = cgetg_copy_avma(x, &lx, AVMA);2152if (lontyp[tx] == 1) i = 1; else { y[1] = x[1]; i = 2; }2153for (; i<lx; i++) gel(y,i) = gcopy_avma(gel(x,i), AVMA);2154return y;2155}21562157/* [copy_bin/bin_copy:] same as gcopy_avma but use NULL to code an exact 0, and2158* make shallow copies of finalized t_LISTs */2159static GEN2160gcopy_av0(GEN x, pari_sp *AVMA)2161{2162long i, lx, tx = typ(x);2163GEN y;21642165switch(tx)2166{ /* non recursive types */2167case t_INT:2168if (!signe(x)) return NULL; /* special marker */2169*AVMA = (pari_sp)icopy_avma(x, *AVMA);2170return (GEN)*AVMA;2171case t_LIST:2172if (list_data(x) && !list_nmax(x)) break; /* not finalized, need copy */2173/* else finalized: shallow copy */2174case t_REAL: case t_STR: case t_VECSMALL:2175*AVMA = (pari_sp)leafcopy_avma(x, *AVMA);2176return (GEN)*AVMA;2177}2178y = cgetg_copy_avma(x, &lx, AVMA);2179if (lontyp[tx] == 1) i = 1; else { y[1] = x[1]; i = 2; }2180for (; i<lx; i++) gel(y,i) = gcopy_av0(gel(x,i), AVMA);2181return y;2182}21832184INLINE GEN2185icopy_avma_canon(GEN x, pari_sp AVMA)2186{2187long i, lx = lgefint(x);2188GEN y = ((GEN)AVMA) - lx;2189y[0] = evaltyp(t_INT)|evallg(lx); /* kills isclone */2190y[1] = x[1]; x = int_MSW(x);2191for (i=2; i<lx; i++, x = int_precW(x)) y[i] = *x;2192return y;2193}21942195/* [copy_bin_canon:] same as gcopy_av0, but copy integers in2196* canonical (native kernel) form and make a full copy of t_LISTs */2197static GEN2198gcopy_av0_canon(GEN x, pari_sp *AVMA)2199{2200long i, lx, tx = typ(x);2201GEN y;22022203switch(tx)2204{ /* non recursive types */2205case t_INT:2206if (!signe(x)) return NULL; /* special marker */2207*AVMA = (pari_sp)icopy_avma_canon(x, *AVMA);2208return (GEN)*AVMA;2209case t_REAL: case t_STR: case t_VECSMALL:2210*AVMA = (pari_sp)leafcopy_avma(x, *AVMA);2211return (GEN)*AVMA;22122213/* one more special case */2214case t_LIST:2215{2216long t = list_typ(x);2217GEN y = cgetlist_avma(AVMA), z = list_data(x);2218if (z) {2219list_data(y) = gcopy_av0_canon(z, AVMA);2220y[1] = evaltyp(t)|evallg(lg(z)-1);2221} else {2222list_data(y) = NULL;2223y[1] = evaltyp(t);2224}2225return y;2226}2227}2228y = cgetg_copy_avma(x, &lx, AVMA);2229if (lontyp[tx] == 1) i = 1; else { y[1] = x[1]; i = 2; }2230for (; i<lx; i++) gel(y,i) = gcopy_av0_canon(gel(x,i), AVMA);2231return y;2232}22332234/* [copy_bin/bin_copy:] size (number of words) required for2235* gcopy_av0_canon(x) */2236static long2237taille0_canon(GEN x)2238{2239long i,n,lx, tx = typ(x);2240switch(tx)2241{ /* non recursive types */2242case t_INT: return signe(x)? lgefint(x): 0;2243case t_REAL:2244case t_STR:2245case t_VECSMALL: return lg(x);22462247/* one more special case */2248case t_LIST:2249{2250GEN L = list_data(x);2251return L? 3 + taille0_canon(L): 3;2252}2253}2254n = lx = lg(x);2255for (i=lontyp[tx]; i<lx; i++) n += taille0_canon(gel(x,i));2256return n;2257}22582259/* [copy_bin/bin_copy:] size (number of words) required for gcopy_av0(x) */2260static long2261taille0(GEN x)2262{2263long i,n,lx, tx = typ(x);2264switch(tx)2265{ /* non recursive types */2266case t_INT:2267lx = lgefint(x);2268return lx == 2? 0: lx;2269case t_LIST:2270{2271GEN L = list_data(x);2272if (L && !list_nmax(x)) break; /* not finalized, deep copy */2273}2274/* else finalized: shallow */2275case t_REAL:2276case t_STR:2277case t_VECSMALL:2278return lg(x);2279}2280n = lx = lg(x);2281for (i=lontyp[tx]; i<lx; i++) n += taille0(gel(x,i));2282return n;2283}22842285static long2286gsizeclone_i(GEN x)2287{2288long i,n,lx, tx = typ(x);2289switch(tx)2290{ /* non recursive types */2291case t_INT: lx = lgefint(x); return lx == 2? 0: lx;;2292case t_REAL:2293case t_STR:2294case t_VECSMALL: return lg(x);22952296case t_LIST: return 3;2297default:2298n = lx = lg(x);2299for (i=lontyp[tx]; i<lx; i++) n += gsizeclone_i(gel(x,i));2300return n;2301}2302}23032304/* #words needed to clone x; t_LIST is a special case since list_data() is2305* malloc'ed later, in list_internal_copy() */2306static long2307gsizeclone(GEN x) { return (typ(x) == t_INT)? lgefint(x): gsizeclone_i(x); }23082309long2310gsizeword(GEN x)2311{2312long i, n, lx, tx = typ(x);2313switch(tx)2314{ /* non recursive types */2315case t_INT:2316case t_REAL:2317case t_STR:2318case t_VECSMALL: return lg(x);23192320case t_LIST:2321x = list_data(x);2322return x? 3 + gsizeword(x): 3;23232324default:2325n = lx = lg(x);2326for (i=lontyp[tx]; i<lx; i++) n += gsizeword(gel(x,i));2327return n;2328}2329}2330long2331gsizebyte(GEN x) { return gsizeword(x) * sizeof(long); }23322333/* return a clone of x structured as a gcopy */2334GENbin*2335copy_bin(GEN x)2336{2337long t = taille0(x);2338GENbin *p = (GENbin*)pari_malloc(sizeof(GENbin) + t*sizeof(long));2339pari_sp AVMA = (pari_sp)(GENbinbase(p) + t);2340p->rebase = &shiftaddress;2341p->len = t;2342p->x = gcopy_av0(x, &AVMA);2343p->base= (GEN)AVMA; return p;2344}23452346/* same, writing t_INT in canonical native form */2347GENbin*2348copy_bin_canon(GEN x)2349{2350long t = taille0_canon(x);2351GENbin *p = (GENbin*)pari_malloc(sizeof(GENbin) + t*sizeof(long));2352pari_sp AVMA = (pari_sp)(GENbinbase(p) + t);2353p->rebase = &shiftaddress_canon;2354p->len = t;2355p->x = gcopy_av0_canon(x, &AVMA);2356p->base= (GEN)AVMA; return p;2357}23582359GEN2360gclone(GEN x)2361{2362long i,lx,tx = typ(x), t = gsizeclone(x);2363GEN y = newblock(t);2364switch(tx)2365{ /* non recursive types */2366case t_INT:2367lx = lgefint(x);2368y[0] = evaltyp(t_INT)|evallg(lx);2369for (i=1; i<lx; i++) y[i] = x[i];2370break;2371case t_REAL:2372case t_STR:2373case t_VECSMALL:2374lx = lg(x);2375for (i=0; i<lx; i++) y[i] = x[i];2376break;23772378/* one more special case */2379case t_LIST:2380y[0] = evaltyp(t_LIST)|_evallg(3);2381listassign(x, y);2382break;2383default: {2384pari_sp AVMA = (pari_sp)(y + t);2385lx = lg(x);2386y[0] = x[0];2387if (lontyp[tx] == 1) i = 1; else { y[1] = x[1]; i = 2; }2388for (; i<lx; i++) gel(y,i) = gcopy_avma(gel(x,i), &AVMA);2389}2390}2391setisclone(y); return y;2392}23932394void2395shiftaddress(GEN x, long dec)2396{2397long i, lx, tx = typ(x);2398if (is_recursive_t(tx))2399{2400if (tx == t_LIST)2401{2402if (!list_data(x) || list_nmax(x)) return; /* empty or finalized */2403/* not finalized, update pointers */2404}2405lx = lg(x);2406for (i=lontyp[tx]; i<lx; i++) {2407if (!x[i]) gel(x,i) = gen_0;2408else2409{2410x[i] += dec;2411shiftaddress(gel(x,i), dec);2412}2413}2414}2415}24162417void2418shiftaddress_canon(GEN x, long dec)2419{2420long i, lx, tx = typ(x);2421switch(tx)2422{ /* non recursive types */2423case t_INT: {2424GEN y;2425lx = lgefint(x); if (lx <= 3) return;2426y = x + 2;2427x = int_MSW(x); if (x == y) return;2428while (x > y) { lswap(*x, *y); x = int_precW(x); y++; }2429break;2430}2431case t_REAL:2432case t_STR:2433case t_VECSMALL:2434break;24352436/* one more special case */2437case t_LIST:2438if (!list_data(x)) break;2439default: /* Fall through */2440lx = lg(x);2441for (i=lontyp[tx]; i<lx; i++) {2442if (!x[i]) gel(x,i) = gen_0;2443else2444{2445x[i] += dec;2446shiftaddress_canon(gel(x,i), dec);2447}2448}2449}2450}24512452/********************************************************************/2453/** **/2454/** INSERT DYNAMIC OBJECT IN STRUCTURE **/2455/** **/2456/********************************************************************/2457GEN2458obj_reinit(GEN S)2459{2460GEN s, T = leafcopy(S);2461long a = lg(T)-1;2462s = gel(T,a);2463gel(T,a) = zerovec(lg(s)-1);2464return T;2465}24662467GEN2468obj_init(long d, long n)2469{2470GEN S = cgetg(d+2, t_VEC);2471gel(S, d+1) = zerovec(n);2472return S;2473}24742475/* as obj_insert. WITHOUT cloning (for libpari, when creating a *new* obj2476* from an existing one) */2477GEN2478obj_insert(GEN S, long K, GEN O)2479{2480GEN o, v = gel(S, lg(S)-1);2481if (typ(v) != t_VEC) pari_err_TYPE("obj_insert", S);2482if (!check_clone(v))2483{2484if (DEBUGLEVEL) pari_warn(warner,"trying to update parent object");2485return gclone(O);2486}2487o = gel(v,K);2488gel(v,K) = gclone(O); /*SIGINT: before unclone(o)*/2489if (isclone(o)) gunclone(o); return gel(v,K);2490}24912492GEN2493obj_insert_shallow(GEN S, long K, GEN O)2494{2495GEN v = gel(S, lg(S)-1);2496if (typ(v) != t_VEC) pari_err_TYPE("obj_insert", S);2497gel(v,K) = O;2498return gel(v,K);2499}25002501/* Does S [last position] contain data at position K ? Return it, or NULL */2502GEN2503obj_check(GEN S, long K)2504{2505GEN O, v = gel(S, lg(S)-1);2506if (typ(v) != t_VEC || K >= lg(v)) pari_err_TYPE("obj_check", S);2507O = gel(v,K); return isintzero(O)? NULL: O;2508}25092510GEN2511obj_checkbuild(GEN S, long tag, GEN (*build)(GEN))2512{2513GEN O = obj_check(S, tag);2514if (!O)2515{ pari_sp av = avma; O = obj_insert(S, tag, build(S)); set_avma(av); }2516return O;2517}25182519GEN2520obj_checkbuild_prec(GEN S, long tag, GEN (*build)(GEN,long),2521long (*pr)(GEN), long prec)2522{2523pari_sp av = avma;2524GEN w = obj_check(S, tag);2525if (!w || pr(w) < prec) w = obj_insert(S, tag, build(S, prec));2526set_avma(av); return gcopy(w);2527}2528GEN2529obj_checkbuild_realprec(GEN S, long tag, GEN (*build)(GEN,long), long prec)2530{ return obj_checkbuild_prec(S,tag,build,gprecision,prec); }2531GEN2532obj_checkbuild_padicprec(GEN S, long tag, GEN (*build)(GEN,long), long prec)2533{ return obj_checkbuild_prec(S,tag,build,padicprec_relative,prec); }25342535/* Reset S [last position], freeing all clones */2536void2537obj_free(GEN S)2538{2539GEN v = gel(S, lg(S)-1);2540long i;2541if (typ(v) != t_VEC) pari_err_TYPE("obj_free", S);2542for (i = 1; i < lg(v); i++)2543{2544GEN o = gel(v,i);2545gel(v,i) = gen_0;2546gunclone_deep(o);2547}2548}25492550/*******************************************************************/2551/* */2552/* STACK MANAGEMENT */2553/* */2554/*******************************************************************/2555INLINE void2556dec_gerepile(pari_sp *x, pari_sp av0, pari_sp av, pari_sp tetpil, size_t dec)2557{2558if (*x < av && *x >= av0)2559{ /* update address if in stack */2560if (*x < tetpil) *x += dec;2561else pari_err_BUG("gerepile, significant pointers lost");2562}2563}25642565void2566gerepileallsp(pari_sp av, pari_sp tetpil, int n, ...)2567{2568const pari_sp av0 = avma;2569const size_t dec = av-tetpil;2570int i;2571va_list a; va_start(a, n);2572(void)gerepile(av,tetpil,NULL);2573for (i=0; i<n; i++) dec_gerepile((pari_sp*)va_arg(a,GEN*), av0,av,tetpil,dec);2574va_end(a);2575}25762577/* Takes an array of pointers to GENs, of length n.2578* Cleans up the stack between av and tetpil, updating those GENs. */2579void2580gerepilemanysp(pari_sp av, pari_sp tetpil, GEN* gptr[], int n)2581{2582const pari_sp av0 = avma;2583const size_t dec = av-tetpil;2584int i;2585(void)gerepile(av,tetpil,NULL);2586for (i=0; i<n; i++) dec_gerepile((pari_sp*)gptr[i], av0, av, tetpil, dec);2587}25882589/* Takes an array of GENs (cast to longs), of length n.2590* Cleans up the stack between av and tetpil, updating those GENs. */2591void2592gerepilecoeffssp(pari_sp av, pari_sp tetpil, long *g, int n)2593{2594const pari_sp av0 = avma;2595const size_t dec = av-tetpil;2596int i;2597(void)gerepile(av,tetpil,NULL);2598for (i=0; i<n; i++,g++) dec_gerepile((pari_sp*)g, av0, av, tetpil, dec);2599}26002601static int2602dochk_gerepileupto(GEN av, GEN x)2603{2604long i,lx,tx;2605if (!isonstack(x)) return 1;2606if (x > av)2607{2608pari_warn(warner,"bad object %Ps",x);2609return 0;2610}2611tx = typ(x);2612if (! is_recursive_t(tx)) return 1;26132614lx = lg(x);2615for (i=lontyp[tx]; i<lx; i++)2616if (!dochk_gerepileupto(av, gel(x,i)))2617{2618pari_warn(warner,"bad component %ld in object %Ps",i,x);2619return 0;2620}2621return 1;2622}2623/* check that x and all its components are out of stack, or have been2624* created after av */2625int2626chk_gerepileupto(GEN x) { return dochk_gerepileupto(x, x); }26272628/* print stack between avma & av */2629void2630dbg_gerepile(pari_sp av)2631{2632GEN x = (GEN)avma;2633while (x < (GEN)av)2634{2635const long tx = typ(x), lx = lg(x);2636GEN *a;26372638pari_printf(" [%ld] %Ps:", x - (GEN)avma, x);2639if (! is_recursive_t(tx)) { pari_putc('\n'); x += lx; continue; }2640a = (GEN*)x + lontyp[tx]; x += lx;2641for ( ; a < (GEN*)x; a++)2642{2643if (*a == gen_0)2644pari_puts(" gen_0");2645else if (*a == gen_1)2646pari_puts(" gen_1");2647else if (*a == gen_m1)2648pari_puts(" gen_m1");2649else if (*a == gen_2)2650pari_puts(" gen_2");2651else if (*a == gen_m2)2652pari_puts(" gen_m2");2653else if (*a == ghalf)2654pari_puts(" ghalf");2655else if (isclone(*a))2656pari_printf(" %Ps (clone)", *a);2657else2658pari_printf(" %Ps [%ld]", *a, *a - (GEN)avma);2659if (a+1 < (GEN*)x) pari_putc(',');2660}2661pari_printf("\n");2662}2663}2664void2665dbg_gerepileupto(GEN q)2666{2667err_printf("%Ps:\n", q);2668dbg_gerepile((pari_sp) (q+lg(q)));2669}26702671GEN2672gerepile(pari_sp av, pari_sp tetpil, GEN q)2673{2674const size_t dec = av - tetpil;2675const pari_sp av0 = avma;2676GEN x, a;26772678if (dec == 0) return q;2679if ((long)dec < 0) pari_err(e_MISC,"lbot>ltop in gerepile");26802681/* dec_gerepile(&q, av0, av, tetpil, dec), saving 1 comparison */2682if (q >= (GEN)av0 && q < (GEN)tetpil)2683q = (GEN) (((pari_sp)q) + dec);26842685for (x = (GEN)av, a = (GEN)tetpil; a > (GEN)av0; ) *--x = *--a;2686set_avma((pari_sp)x);2687while (x < (GEN)av)2688{2689const long tx = typ(x), lx = lg(x);26902691if (! is_recursive_t(tx)) { x += lx; continue; }2692a = x + lontyp[tx]; x += lx;2693for ( ; a < x; a++) dec_gerepile((pari_sp*)a, av0, av, tetpil, dec);2694}2695return q;2696}26972698void2699fill_stack(void)2700{2701GEN x = ((GEN)pari_mainstack->bot);2702while (x < (GEN)avma) *x++ = 0xfefefefeUL;2703}27042705void2706debug_stack(void)2707{2708pari_sp top = pari_mainstack->top, bot = pari_mainstack->bot;2709GEN z;2710err_printf("bot=0x%lx\ttop=0x%lx\tavma=0x%lx\n", bot, top, avma);2711for (z = ((GEN)top)-1; z >= (GEN)avma; z--)2712err_printf("%p:\t0x%lx\t%lu\n",z,*z,*z);2713}27142715void2716setdebugvar(long n) { DEBUGVAR=n; }27172718long2719getdebugvar(void) { return DEBUGVAR; }27202721long2722getstack(void) { return pari_mainstack->top-avma; }27232724/*******************************************************************/2725/* */2726/* timer_delay */2727/* */2728/*******************************************************************/27292730#if defined(USE_CLOCK_GETTIME)2731#if defined(_POSIX_THREAD_CPUTIME)2732static THREAD clockid_t time_type = CLOCK_THREAD_CPUTIME_ID;2733#else2734static const THREAD clockid_t time_type = CLOCK_PROCESS_CPUTIME_ID;2735#endif2736static void2737pari_init_timer(void)2738{2739#if defined(_POSIX_THREAD_CPUTIME)2740time_type = CLOCK_PROCESS_CPUTIME_ID;2741#endif2742}27432744void2745timer_start(pari_timer *T)2746{2747struct timespec t;2748clock_gettime(time_type,&t);2749T->us = t.tv_nsec / 1000;2750T->s = t.tv_sec;2751}2752#elif defined(USE_GETRUSAGE)2753#ifdef RUSAGE_THREAD2754static THREAD int rusage_type = RUSAGE_THREAD;2755#else2756static const THREAD int rusage_type = RUSAGE_SELF;2757#endif /*RUSAGE_THREAD*/2758static void2759pari_init_timer(void)2760{2761#ifdef RUSAGE_THREAD2762rusage_type = RUSAGE_SELF;2763#endif2764}27652766void2767timer_start(pari_timer *T)2768{2769struct rusage r;2770getrusage(rusage_type,&r);2771T->us = r.ru_utime.tv_usec;2772T->s = r.ru_utime.tv_sec;2773}2774#elif defined(USE_FTIME)27752776static void2777pari_init_timer(void) { }27782779void2780timer_start(pari_timer *T)2781{2782struct timeb t;2783ftime(&t);2784T->us = ((long)t.millitm) * 1000;2785T->s = t.time;2786}27872788#else27892790static void2791_get_time(pari_timer *T, long Ticks, long TickPerSecond)2792{2793T->us = (long) ((Ticks % TickPerSecond) * (1000000. / TickPerSecond));2794T->s = Ticks / TickPerSecond;2795}27962797# ifdef USE_TIMES2798static void2799pari_init_timer(void) { }28002801void2802timer_start(pari_timer *T)2803{2804# ifdef _SC_CLK_TCK2805long tck = sysconf(_SC_CLK_TCK);2806# else2807long tck = CLK_TCK;2808# endif2809struct tms t; times(&t);2810_get_time(T, t.tms_utime, tck);2811}2812# elif defined(_WIN32)2813static void2814pari_init_timer(void) { }28152816void2817timer_start(pari_timer *T)2818{ _get_time(T, win32_timer(), 1000); }2819# else2820# include <time.h>2821# ifndef CLOCKS_PER_SEC2822# define CLOCKS_PER_SEC 1000000 /* may be false on YOUR system */2823# endif2824static void2825pari_init_timer(void) { }28262827void2828timer_start(pari_timer *T)2829{ _get_time(T, clock(), CLOCKS_PER_SEC); }2830# endif2831#endif28322833/* round microseconds to milliseconds */2834static long2835rndus(long x) { return (x + 500) / 1000; }2836static long2837timer_aux(pari_timer *T, pari_timer *U, void (*settime)(pari_timer *))2838{2839long s = T->s, us = T->us;2840settime(U); return 1000 * (U->s - s) + rndus(U->us - us);2841}28422843/* return delay, set timer checkpoint */2844long2845timer_delay(pari_timer *T) { return timer_aux(T, T, &timer_start); }2846/* return delay, don't set checkpoint */2847long2848timer_get(pari_timer *T) {pari_timer t; return timer_aux(T, &t, &timer_start);}28492850static void2851timer_vprintf(pari_timer *T, const char *format, va_list args)2852{2853out_puts(pariErr, "Time ");2854out_vprintf(pariErr, format,args);2855out_printf(pariErr, ": %ld\n", timer_delay(T));2856pariErr->flush();2857}2858void2859timer_printf(pari_timer *T, const char *format, ...)2860{2861va_list args; va_start(args, format);2862timer_vprintf(T, format, args);2863va_end(args);2864}28652866long2867timer(void) { static THREAD pari_timer T; return timer_delay(&T);}2868long2869gettime(void) { static THREAD pari_timer T; return timer_delay(&T);}28702871static THREAD pari_timer timer2_T, abstimer_T;2872long2873timer2(void) { return timer_delay(&timer2_T);}2874void2875msgtimer(const char *format, ...)2876{2877va_list args; va_start(args, format);2878timer_vprintf(&timer2_T, format, args);2879va_end(args);2880}2881long2882getabstime(void) { return timer_get(&abstimer_T);}28832884void2885walltimer_start(pari_timer *ti)2886{2887#if defined(USE_CLOCK_GETTIME)2888struct timespec t;2889if (!clock_gettime(CLOCK_REALTIME,&t))2890{ ti->s = t.tv_sec; ti->us = rndus(t.tv_nsec); return; }2891#elif defined(USE_GETTIMEOFDAY)2892struct timeval tv;2893if (!gettimeofday(&tv, NULL))2894{ ti->s = tv.tv_sec; ti->us = tv.tv_usec; return; }2895#elif defined(USE_FTIMEFORWALLTIME)2896struct timeb tp;2897if (!ftime(&tp))2898{ ti->s = tp.time; ti->us = tp.millitm*1000; return; }2899#endif2900timer_start(ti);2901}2902/* return delay, set timer checkpoint */2903long2904walltimer_delay(pari_timer *T) { return timer_aux(T, T, &walltimer_start); }2905/* return delay, don't set checkpoint */2906long2907walltimer_get(pari_timer *T)2908{2909pari_timer t;2910return timer_aux(T, &t, &walltimer_start);2911}29122913static GEN2914timetoi(ulong s, ulong m)2915{2916pari_sp av = avma;2917return gerepileuptoint(av, addiu(muluu(s, 1000), m));2918}2919GEN2920getwalltime(void)2921{2922pari_timer ti;2923walltimer_start(&ti);2924return timetoi(ti.s, rndus(ti.us));2925}29262927/*******************************************************************/2928/* */2929/* FUNCTIONS KNOWN TO THE ANALYZER */2930/* */2931/*******************************************************************/29322933GEN2934setdebug(const char *s, long lvl)2935{2936long i, l = sizeof(pari_DEBUGLEVEL_str)/sizeof(*pari_DEBUGLEVEL_str);2937if (s)2938{2939if (lvl > 20) pari_err_DOMAIN("setdebug", "lvl", ">", utoipos(20), stoi(lvl));2940for (i=0; i<l; i++)2941if (!strcmp(s,pari_DEBUGLEVEL_str[i]))2942break;2943if (i == l)2944pari_err_DOMAIN("setdebug", "dmn", "not a valid", strtoGENstr("debug domain"), strtoGENstr(s));2945if (lvl >= 0)2946{2947*pari_DEBUGLEVEL_ptr[i] = lvl;2948return gnil;2949}2950else2951return stoi(*pari_DEBUGLEVEL_ptr[i]);2952}2953else2954{2955GEN V = cgetg(3,t_MAT), V1, V2;2956V1 = gel(V,1) = cgetg(l+1, t_COL);2957V2 = gel(V,2) = cgetg(l+1, t_COL);2958for (i = 0; i < l; i++)2959{2960gel(V1, i+1) = strtoGENstr(pari_DEBUGLEVEL_str[i]);2961gel(V2, i+1) = stoi(*pari_DEBUGLEVEL_ptr[i]);2962}2963return V;2964}2965}29662967GEN2968pari_version(void)2969{2970const ulong mask = (1UL<<PARI_VERSION_SHIFT) - 1;2971ulong major, minor, patch, n = paricfg_version_code;2972patch = n & mask; n >>= PARI_VERSION_SHIFT;2973minor = n & mask; n >>= PARI_VERSION_SHIFT;2974major = n;2975if (*paricfg_vcsversion) {2976const char *ver = paricfg_vcsversion;2977const char *s = strchr(ver, '-');2978char t[8];2979const long len = s-ver;2980GEN v;2981if (!s || len > 6) pari_err_BUG("pari_version()"); /* paranoia */2982memcpy(t, ver, len); t[len] = 0;2983v = cgetg(6, t_VEC);2984gel(v,1) = utoi(major);2985gel(v,2) = utoi(minor);2986gel(v,3) = utoi(patch);2987gel(v,4) = stoi( atoi(t) );2988gel(v,5) = strtoGENstr(s+1);2989return v;2990} else {2991GEN v = cgetg(4, t_VEC);2992gel(v,1) = utoi(major);2993gel(v,2) = utoi(minor);2994gel(v,3) = utoi(patch);2995return v;2996}2997}29982999/* List of GP functions: generated from the description system.3000* Format (struct entree) :3001* char *name : name (under GP).3002* ulong valence: (EpNEW, EpALIAS,EpVAR, EpINSTALL)|EpSTATIC3003* void *value : For PREDEFINED FUNCTIONS: C function to call.3004* For USER FUNCTIONS: pointer to defining data (block) =3005* entree*: NULL, list of entree (arguments), NULL3006* char* : function text3007* long menu : which help section do we belong to3008* 1: Standard monadic or dyadic OPERATORS3009* 2: CONVERSIONS and similar elementary functions3010* 3: functions related to COMBINATORICS3011* 4: TRANSCENDENTAL functions, etc.3012* char *code : GP prototype, aka Parser Code (see libpari's manual)3013* if NULL, use valence instead.3014* char *help : short help text (init to NULL).3015* void *pvalue : push_val history.3016* long arity : maximum number of arguments.3017* entree *next : next entree (init to NULL, used in hashing code). */3018#include "init.h"3019#include "default.h"302030213022