Annotation of OpenXM/src/ox_python/ox_python.c, Revision 1.2
1.2 ! takayama 1: /* $OpenXM: OpenXM/src/ox_python/ox_python.c,v 1.1 2018/09/08 00:16:19 takayama Exp $
1.1 takayama 2: */
3:
4: #include <stdio.h>
5: #include <stdlib.h>
6: #include <setjmp.h>
7: #include <string.h>
8: #include <unistd.h>
9: #include <signal.h>
10: #include <math.h>
11: #include "ox_python.h"
12:
13: OXFILE *fd_rw;
14:
15: #define INIT_S_SIZE 2048
16: #define EXT_S_SIZE 2048
17:
18: static int stack_size = 0;
19: static int stack_pointer = 0;
20: static cmo **stack = NULL;
21:
22: int Debug=1;
23:
24: void show_stack_top() {
25: cmo *data;
26: if (stack_pointer > 0) {
27: data=stack[stack_pointer-1];
28: print_cmo(data); printf("\n");
29: }else {
30: printf("The stack is empty.\n");
31: }
32: }
33:
34: void *gc_realloc(void *p,size_t osize,size_t nsize)
35: { return (void *)GC_realloc(p,nsize);}
36:
37: void gc_free(void *p,size_t size)
38: { GC_free(p);}
39:
40: void init_gc()
41: { GC_INIT();
42: mp_set_memory_functions(GC_malloc,gc_realloc,gc_free);
43: }
44:
45: void initialize_stack()
46: {
47: stack_pointer = 0;
48: stack_size = INIT_S_SIZE;
49: stack = GC_malloc(stack_size*sizeof(cmo*));
50: }
51:
52: static void extend_stack()
53: {
54: int size2 = stack_size + EXT_S_SIZE;
55: cmo **stack2 = malloc(size2*sizeof(cmo*));
56: memcpy(stack2, stack, stack_size*sizeof(cmo *));
57: free(stack);
58: stack = stack2;
59: stack_size = size2;
60: }
61:
62: void push(cmo* m)
63: {
64: stack[stack_pointer] = m;
65: stack_pointer++;
66: if (stack_pointer >= stack_size) {
67: extend_stack();
68: }
69: }
70:
71: cmo* pop()
72: {
73: if (stack_pointer > 0) {
74: stack_pointer--;
75: return stack[stack_pointer];
76: }
77: return new_cmo_null();
78: }
79:
80: void pops(int n)
81: {
82: stack_pointer -= n;
83: if (stack_pointer < 0) {
84: stack_pointer = 0;
85: }
86: }
87:
88: #define OX_PYTHON_VERSION 2018090701
89: #define ID_STRING "2018/09/07 17:47:00"
90:
91: int sm_mathcap()
92: {
93: int available_cmo[]={
94: CMO_NULL,
95: CMO_INT32,
96: // CMO_DATUM,
97: CMO_STRING,
98: CMO_MATHCAP,
99: CMO_LIST,
100: // CMO_MONOMIAL32,
101: CMO_ZZ,
102: // CMO_QQ,
103: CMO_BIGFLOAT32,
104: CMO_COMPLEX,
105: CMO_IEEE_DOUBLE_FLOAT,
106: CMO_ZERO,
107: // CMO_DMS_GENERIC,
108: // CMO_RING_BY_NAME,
109: // CMO_INDETERMINATE,
110: // CMO_DISTRIBUTED_POLYNOMIAL,
111: // CMO_RECURSIVE_POLYNOMIAL,
112: // CMO_POLYNOMIAL_IN_ONE_VARIABLE,
113: CMO_TREE,
114: CMO_ERROR2,
115: 0};
116: int available_sm_command[]={
117: SM_popCMO,
118: SM_popString,
119: SM_mathcap,
120: SM_pops,
121: SM_executeStringByLocalParser,
122: SM_executeFunction,
123: SM_setMathCap,
124: SM_shutdown,
125: SM_control_kill,
126: SM_control_reset_connection,
127: SM_control_spawn_server,
128: SM_control_terminate_server,
129: 0};
130: mathcap_init(OX_PYTHON_VERSION, ID_STRING, "ox_python", available_cmo,available_sm_command);
131: push((cmo *)oxf_cmo_mathcap(fd_rw));
132: return 0;
133: }
134:
135: int sm_popCMO()
136: {
137: cmo* m = pop();
138:
139: if (m != NULL) {
140: send_ox_cmo(fd_rw, m);
141: return 0;
142: }
143: return SM_popCMO;
144: }
145:
146: cmo *make_error2(const char *reason,const char *fname,int line,int code)
147: {
148: // gsl_error_handler_t void handler(const char *reason,const char *file,int line, int gsl_errno)
149: cmo *ms;
150: cmo *err;
151: cmo *m;
152: cmo **argv;
153: int n;
154: char *s;
155: n = 5;
156: argv = (cmo **) GC_malloc(sizeof(cmo *)*n);
157: ms = (cmo *)new_cmo_string("Error"); argv[0] = ms;
158: if (reason != NULL) {s = (char *)GC_malloc(strlen(reason)+1); strcpy(s,reason);
159: }else strcpy(s,"");
160: ms = (cmo *) new_cmo_string(s); argv[1] = ms;
161: if (fname != NULL) {s = (char *)GC_malloc(strlen(fname)+1); strcpy(s,fname);
162: }else strcpy(s,"");
163: ms = (cmo *) new_cmo_string(s); argv[2] = ms;
164: err = (cmo *)new_cmo_int32(line); argv[3] = err;
165: err = (cmo *)new_cmo_int32(code); argv[4] = err;
166:
167: m = (cmo *)new_cmo_list_array((void *)argv,n);
168: return (m);
169: }
170:
171: int get_i()
172: {
173: cmo *c = pop();
174: if (c->tag == CMO_INT32) {
175: return ((cmo_int32 *)c)->i;
176: }else if (c->tag == CMO_ZZ) {
177: return mpz_get_si(((cmo_zz *)c)->mpz);
178: }else if (c->tag == CMO_NULL) {
179: return(0);
180: }else if (c->tag == CMO_ZERO) {
181: return(0);
182: }
183: myhandler("get_i: not an integer",NULL,0,-1);
184: return 0;
185: }
186:
187: void get_xy(int *x, int *y)
188: {
189: pop();
190: *x = get_i();
191: *y = get_i();
192: }
193:
194: void my_add_int32()
195: {
196: int x, y;
197: get_xy(&x, &y);
198: push((cmo *)new_cmo_int32(x+y));
199: }
200:
201: double get_double()
202: {
203: #define mympz(c) (((cmo_zz *)c)->mpz)
204: cmo *c = pop();
205: if (c->tag == CMO_INT32) {
206: return( (double) (((cmo_int32 *)c)->i) );
207: }else if (c->tag == CMO_IEEE_DOUBLE_FLOAT) {
208: return (((cmo_double *)c)->d); // see ox_toolkit.h
209: }else if (c->tag == CMO_ZZ) {
210: if ((mpz_cmp_si(mympz(c),(long int) 0x7fffffff)>0) ||
211: (mpz_cmp_si(mympz(c),(long int) -0x7fffffff)<0)) {
212: myhandler("get_double: out of int32",NULL,0,-1);
213: return(NAN);
214: }
215: return( (double) mpz_get_si(((cmo_zz *)c)->mpz));
216: }else if (c->tag == CMO_NULL) {
217: return(0);
218: }else if (c->tag == CMO_ZERO) {
219: return(0);
220: }
221: myhandler("get_double: not a double",NULL,0,-1);
222: return(NAN);
223: }
224: /* get_double() will be obsolted and will be replaced by cmo2double(c) */
225: double cmo2double(cmo *c)
226: {
227: #define mympz(c) (((cmo_zz *)c)->mpz)
228: if (c == NULL) c = pop();
229: if (c->tag == CMO_INT32) {
230: return( (double) (((cmo_int32 *)c)->i) );
231: }else if (c->tag == CMO_IEEE_DOUBLE_FLOAT) {
232: return (((cmo_double *)c)->d); // see ox_toolkit.h
233: }else if (c->tag == CMO_ZZ) {
234: if ((mpz_cmp_si(mympz(c),(long int) 0x7fffffff)>0) ||
235: (mpz_cmp_si(mympz(c),(long int) -0x7fffffff)<0)) {
236: myhandler("get_double: out of int32",NULL,0,-1);
237: return(NAN);
238: }
239: return( (double) mpz_get_si(((cmo_zz *)c)->mpz));
240: }else if (c->tag == CMO_NULL) {
241: return(0);
242: }else if (c->tag == CMO_ZERO) {
243: return(0);
244: }
245: myhandler("cmo2double: not a double",NULL,0,-1);
246: return(NAN);
247: }
248:
249: void my_add_double() {
250: double x,y;
251: pop();
252: y = get_double();
253: x = get_double();
254: push((cmo *)new_cmo_double(x+y));
255: }
256:
257: double *get_double_list(int *length) {
258: cmo *c;
259: cmo *entry;
260: cell *cellp;
261: double *d;
262: int n,i;
263: c = pop();
264: if (c->tag != CMO_LIST) {
265: // make_error2("get_double_list",NULL,0,-1);
266: *length=-1; return(0);
267: }
268: n = *length = list_length((cmo_list *)c);
269: d = (double *) GC_malloc(sizeof(double)*(*length+1));
270: cellp = list_first((cmo_list *)c);
271: entry = cellp->cmo;
272: for (i=0; i<n; i++) {
273: if (Debug) {
274: printf("entry[%d]=",i); print_cmo(entry); printf("\n");
275: }
276: if (entry->tag == CMO_INT32) {
277: d[i]=( (double) (((cmo_int32 *)entry)->i) );
278: }else if (entry->tag == CMO_IEEE_DOUBLE_FLOAT) {
279: d[i]=((cmo_double *)entry)->d;
280: }else if (entry->tag == CMO_ZZ) {
281: d[i]=( (double) mpz_get_si(((cmo_zz *)entry)->mpz));
282: }else if (entry->tag == CMO_NULL) {
283: d[i]= 0;
284: }else {
285: fprintf(stderr,"entries of the list should be int32 or zz or double\n");
286: *length = -1;
287: myhandler("get_double_list",NULL,0,-1);
288: return(NULL);
289: }
290: cellp = list_next(cellp);
291: entry = cellp->cmo;
292: }
293: return(d);
294: }
295: /* get_double_list will be obsolted and will be replaced by cmo2double_list() */
296: double *cmo2double_list(int *length,cmo *c) {
297: cmo *entry;
298: cell *cellp;
299: double *d;
300: int n,i;
301: if (c == NULL) c = pop();
302: if (c->tag != CMO_LIST) {
303: // make_error2("get_double_list",NULL,0,-1);
304: *length=-1; return(0);
305: }
306: n = *length = list_length((cmo_list *)c);
307: d = (double *) GC_malloc(sizeof(double)*(*length+1));
308: cellp = list_first((cmo_list *)c);
309: entry = cellp->cmo;
310: for (i=0; i<n; i++) {
311: if (Debug) {
312: printf("entry[%d]=",i); print_cmo(entry); printf("\n");
313: }
314: if (entry->tag == CMO_INT32) {
315: d[i]=( (double) (((cmo_int32 *)entry)->i) );
316: }else if (entry->tag == CMO_IEEE_DOUBLE_FLOAT) {
317: d[i]=((cmo_double *)entry)->d;
318: }else if (entry->tag == CMO_ZZ) {
319: d[i]=( (double) mpz_get_si(((cmo_zz *)entry)->mpz));
320: }else if (entry->tag == CMO_NULL) {
321: d[i]= 0;
322: }else {
323: fprintf(stderr,"entries of the list should be int32 or zz or double\n");
324: *length = -1;
325: myhandler("get_double_list",NULL,0,-1);
326: return(NULL);
327: }
328: cellp = list_next(cellp);
329: entry = cellp->cmo;
330: }
331: return(d);
332: }
333: void show_double_list() {
334: int n;
335: double *d;
336: int i;
337: pop(); // pop argument number;
338: d = get_double_list(&n);
339: if (n < 0) fprintf(stderr,"Error in the double list\n");
340: printf("show_double_list: length=%d\n",n);
341: for (i=0; i<n; i++) {
342: printf("%lg, ",d[i]);
343: }
344: printf("\n");
345: }
346:
347: char *get_string() {
348: cmo *c;
349: c = pop();
350: if (c->tag == CMO_STRING) {
351: return (((cmo_string *)c)->s);
352: }
353: // make_error2(-1);
354: return(NULL);
355: }
356:
357:
358: int sm_executeFunction()
359: {
360: cmo_string *func = (cmo_string *)pop();
361: if (func->tag != CMO_STRING) {
362: push(make_error2("sm_executeFunction, not CMO_STRING",NULL,0,-1));
363: return -1;
364: }
365: // Test functions
366: if (strcmp(func->s, "add_int32") == 0) {
367: my_add_int32();
368: }else if (strcmp(func->s,"add_double")==0) {
369: my_add_double();
370: }else if (strcmp(func->s,"show_double_list")==0) {
371: show_double_list();
372: }else if (strcmp(func->s,"restart")==0) {
373: pop(); restart();
1.2 ! takayama 374: }else if (strcmp(func->s,"PyRun_String")==0) {
! 375: my_PyRun_String();
! 376: }else if (strcmp(func->s,"eval")==0) {
! 377: my_eval();
1.1 takayama 378: }else {
379: push(make_error2("sm_executeFunction, unknown function",NULL,0,-1));
380: return -1;
381: }
382: return(0);
383: }
384:
385: int sm_executeStringByLocalParser()
386: {
387: int status;
388: cmo_string *cmd = (cmo_string *)pop();
389: if (cmd->tag != CMO_STRING) {
390: push(make_error2("sm_executeStringByLocalParser, not CMO_STRING",NULL,0,-1));
391: return -1;
392: }
393: status=PyRun_SimpleString(cmd->s);
394: // push(make_error2("sm_executeStringByLocalParser",NULL,0,-1));
395: push((cmo *)new_cmo_int32(status));
396: return(0);
1.2 ! takayama 397: /* Todo, set the flag by Py_InspectFlag to avoid exit after exception.
! 398: See PyRun_SimpleStringFlags, https://docs.python.jp/2.7/c-api/veryhigh.html
! 399: */
1.1 takayama 400: }
401:
402:
403: int receive_and_execute_sm_command()
404: {
405: int code = receive_int32(fd_rw);
406: switch(code) {
407: case SM_popCMO:
408: sm_popCMO();
409: break;
410: case SM_executeFunction:
411: sm_executeFunction();
412: break;
413: case SM_mathcap:
414: sm_mathcap();
415: break;
416: case SM_setMathCap:
417: pop();
418: break;
419: case SM_executeStringByLocalParser:
420: sm_executeStringByLocalParser();
421: break;
422: default:
423: ;
424: }
425: return(0);
426: }
427:
428: int receive()
429: {
430: int tag;
431:
432: tag = receive_ox_tag(fd_rw);
433: switch(tag) {
434: case OX_DATA:
435: push(receive_cmo(fd_rw));
436: if (Debug) show_stack_top();
437: break;
438: case OX_COMMAND:
439: if (Debug) show_stack_top();
440: receive_and_execute_sm_command();
441: break;
442: default:
443: ;
444: }
445: return 0;
446: }
447:
448: jmp_buf Ox_env;
449: int Ox_intr_usr1=0;
450: void usr1_handler(int sig)
451: {
452: Ox_intr_usr1=1;
453: longjmp(Ox_env,1);
454: }
455: void restart() {
456: Ox_intr_usr1=0;
457: longjmp(Ox_env,1);
458: }
459:
460: void myhandler(const char *reason,const char *file,int line, int gsl_errno) {
461: cmo *m;
462: FILE *fp;
463: char logname[1024];
1.2 ! takayama 464: sprintf(logname,"/tmp/ox_python-%d.txt",(int) getpid());
1.1 takayama 465: fp = fopen(logname,"w");
466: fprintf(fp,"%d\n",gsl_errno);
467: fprintf(fp,"%d\n",line);
468: if (file != NULL) fprintf(fp,"%s\n",file); else fprintf(fp,"file?\n");
469: if (reason != NULL) fprintf(fp,"%s\n",reason); else fprintf(fp,"reason?\n");
470: fflush(NULL); fclose(fp);
471: // m = make_error2(reason,file,line,gsl_errno);
472: // send_ox_cmo(fd_rw, m); ox_flush(fd_rw);
473: // send error packet even it is not asked. Todo, OK? --> no
474: restart();
475: }
476: void push_error_from_file() {
477: FILE *fp;
478: #define BUF_SIZE 1024
479: char logname[BUF_SIZE];
480: char cmd[BUF_SIZE];
481: char file[BUF_SIZE];
482: char reason[BUF_SIZE];
483: int gsl_errno, line;
484: cmo *m;
485: fprintf(stderr,"push_error_from_file()\n");
1.2 ! takayama 486: sprintf(logname,"/tmp/ox_python-%d.txt",(int) getpid());
1.1 takayama 487: fp = fopen(logname,"r");
488: if (fp == NULL) {
489: fprintf(stderr,"open %s is failed\n",logname); return;
490: }
491: fgets(cmd,BUF_SIZE-2,fp); sscanf(cmd,"%d",&gsl_errno);
492: fgets(cmd,BUF_SIZE-2,fp); sscanf(cmd,"%d",&line);
493: #define remove_newline(s) {char *tmp_pos; if ((tmp_pos=strchr(s,'\n')) != NULL) *tmp_pos = '\0';}
494: fgets(file,BUF_SIZE-2,fp); remove_newline(file);
495: fgets(reason,BUF_SIZE-2,fp); remove_newline(reason);
496: fclose(fp);
497: m = make_error2(reason,file,line,gsl_errno);
498: push(m);
499: sprintf(cmd,"rm -f %s",logname);
500: system(cmd);
501: }
502: int main(int argc,char *argv[])
503: {
504: if ( setjmp(Ox_env) ) {
505: fprintf(stderr,"resetting libgsl ...");
506: initialize_stack();
507: if (Ox_intr_usr1) {
508: fprintf(stderr,"and sending OX_SYNC_BALL...");
509: send_ox_tag(fd_rw,OX_SYNC_BALL);
510: }
511: fprintf(stderr,"done\n");
512: Ox_intr_usr1=0;
513: push_error_from_file();
514: }else{
515: ox_stderr_init(stderr);
516: initialize_stack();
517: init_gc();
518: fd_rw = oxf_open(3);
519: oxf_determine_byteorder_server(fd_rw);
520: }
521: #if defined(__CYGWIN__)
522: void *mysignal(int sig,void (*handler)(int m));
523: mysignal(SIGUSR1,usr1_handler);
524: #else
525: signal(SIGUSR1,usr1_handler);
526: #endif
527:
1.2 ! takayama 528: /* Initialize python */
1.1 takayama 529: Py_SetProgramName(argv[0]); /* optional but recommended */
530: Py_Initialize();
531:
532:
533: while(1) {
534: receive();
535: }
536: Py_Finalize();
537: return(0);
538: }
539:
540: cmo *element_of_at(cmo *list,int k) {
541: int length;
542: static cmo * saved_list = NULL;
543: static cmo **dic;
544: int i;
545: cell *cellp;
546: if (list == NULL) {
547: ox_printf("element_of_at: list is NULL.\n");
548: return( (cmo *)NULL);
549: }
550: if (list->tag != CMO_LIST) {
551: ox_printf("element_of_at: list is not list.\n");
552: return((cmo *)NULL);
553: }
554: length = list_length((cmo_list *)list);
555: if ((k < 0) || (k >= length)) {
556: ox_printf("element_of_at: out of bound length=%d, k=%d.\n",length,k);
557: return((cmo *)NULL);
558: }
559: if (list == saved_list) return(dic[k]);
560: saved_list = list;
561: dic = (cmo **)GC_malloc(sizeof(cmo *)*(length+1));
562: if (dic == NULL) return((cmo *)NULL); // no more memory.
563: cellp = list_first((cmo_list *)list);
564: for (i=0; i<length; i++) {
565: dic[i] = cellp->cmo;
566: cellp = list_next(cellp);
567: }
568: return(dic[k]);
569: }
570:
571: int get_length(cmo *c) {
572: if (c->tag != CMO_LIST) {
573: return(-1);
574: }
575: return(list_length((cmo_list *)c));
576: }
1.2 ! takayama 577:
! 578: int my_PyRun_String() {
! 579: static PyObject *py_main=NULL;
! 580: static PyObject *py_dict=NULL;
! 581: PyObject *pyRes;
! 582: char *cmd;
! 583: pop(); // pop argc
! 584: cmd = get_string();
! 585: if (cmd == NULL) {
! 586: push(make_error2("my_PyRun_Sring: argument is not a string",NULL,0,-1));
! 587: return(-1);
! 588: }
! 589: printf("cmd=%s\n",cmd);
! 590: if (py_main == NULL) py_main = PyImport_AddModule("__main__");
! 591: if (py_dict == NULL) py_dict = PyModule_GetDict(py_main);
! 592: pyRes = PyRun_String(cmd,Py_single_input,py_dict,py_dict);
! 593: if (pyRes==NULL) {
! 594: push(make_error2("PyRun_String: exception",NULL,0,-1));
! 595: PyRun_SimpleString("\n");
! 596: /* https://stackoverflow.com/questions/12518435/pyrun-string-stop-sending-result-to-stdout-after-any-error
! 597: */
! 598: return(-1);
! 599: }
! 600: return push_python_result(pyRes);
! 601: }
! 602:
! 603: int push_python_result(PyObject *pyRes) {
! 604: if (PyString_Check(pyRes)) {
! 605: push((cmo *)new_cmo_string(PyString_AsString(pyRes)));
! 606: return(0);
! 607: }else if (PyInt_Check(pyRes)) {
! 608: push((cmo *)new_cmo_int32((int) PyInt_AS_LONG(pyRes)));
! 609: return(0);
! 610: }else {
! 611: push((cmo *)new_cmo_string(PyString_AsString(PyObject_Str(pyRes))));
! 612: return(0);
! 613: // push(make_error2("PyRun_String returns an object which as not been implemented.",NULL,0,-1));
! 614: // return(-1);
! 615: }
! 616: }
! 617:
! 618:
! 619: int my_eval() {
! 620: static PyObject *pName=NULL;
! 621: static PyObject *pModule=NULL;
! 622: static PyObject *pDict=NULL;
! 623: static PyObject *pFunc=NULL;
! 624: PyObject *pArgs, *pValue;
! 625: char *cmd;
! 626: int i;
! 627: pop(); // pop argc
! 628: cmd = get_string();
! 629: if (cmd == NULL) {
! 630: push(make_error2("my_PyRun_Sring: argument is not a string",NULL,0,-1));
! 631: return(-1);
! 632: }
! 633: printf("my_eval cmd=%s\n",cmd);
! 634:
! 635: // code from https://docs.python.jp/2.7/extending/embedding.html
! 636: if (pName==NULL) pName = PyString_FromString("__builtin__");
! 637: if (pModule==NULL) pModule = PyImport_Import(pName);
! 638:
! 639: if (pModule != NULL) {
! 640: if (pFunc==NULL) pFunc = PyObject_GetAttrString(pModule, "eval");
! 641: if (pFunc && PyCallable_Check(pFunc)) {
! 642: pArgs = PyTuple_New(1);
! 643: PyTuple_SetItem(pArgs,0,PyString_FromString(cmd));
! 644: pValue = PyObject_CallObject(pFunc, pArgs);
! 645: Py_DECREF(pArgs);
! 646: if (pValue != NULL) {
! 647: push_python_result(pValue);
! 648: // Py_DECREF(pValue);
! 649: return(0);
! 650: }
! 651: else {
! 652: PyErr_Print();
! 653: push(make_error2("Fail to call PyObjedct_CallObject(eval,...)",NULL,0,-1));
! 654: return(-1);
! 655: }
! 656: }
! 657: else {
! 658: if (PyErr_Occurred())
! 659: PyErr_Print();
! 660: fprintf(stderr, "Cannot find function eval\n");
! 661: }
! 662: return(-1);
! 663: }
! 664: else {
! 665: PyErr_Print();
! 666: fprintf(stderr, "Failed to load __builtin__\n");
! 667: return -1;
! 668: }
! 669: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>