1 /*
2 * python.c -- Calling Python from epic.
3 *
4 * Copyright 2016 EPIC Software Labs.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notices, the above paragraph (the one permitting redistribution),
14 * this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. The names of the author(s) may not be used to endorse or promote
17 * products derived from this software without specific prior written
18 * permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
21 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
22 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
23 * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
24 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
25 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
26 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
27 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 */
32 /* Python commit #14 */
33
34 #include <Python.h>
35 #include "irc.h"
36 #include "ircaux.h"
37 #include "array.h"
38 #include "alias.h"
39 #include "commands.h"
40 #include "functions.h"
41 #include "output.h"
42 #include "ifcmd.h"
43 #include "extlang.h"
44 #include "newio.h"
45 #include "server.h"
46
47 void output_traceback (void);
48
49 static int p_initialized = 0;
50 static PyObject *global_vars = NULL;
51
52 /*
53 * ObRant
54 *
55 * So Python is a language like ircII where there is a distinction made between
56 * "statements" and "expressions". In both languages, a "statement" is a call
57 * that does not result in a return value, and expression is. I can't blame
58 * python for this. But it is different from Perl, Ruby, and TCL, which treat
59 * everything as a "callable" and then you either get a return value (for an
60 * expression) or an empty string (for a statement).
61 *
62 * In order to make python support work, though, we have to honor this
63 * distinction. I've chosen to do this through the /PYTHON command and the
64 * $python() function
65 *
66 * You can only use the /PYTHON command to run statements.
67 * Using /PYTHON with an expression results in an exception being thrown.
68 *
69 * You can only use the $python() function to evaluate expressions
70 * Using $python() with a statement results in an exception being thrown.
71 *
72 * How do you know whether what you're doing is an expression or a statement,
73 * when if you just throw everything into one file you don't have to worry
74 * about it? Good question. I don't know. Good luck!
75 */
76
77 /*
78 * I owe many thanks to
79 * https://docs.python.org/3.6/extending/embedding.html
80 * https://docs.python.org/3.6/c-api/veryhigh.html
81 * https://docs.python.org/3/c-api/init.html
82 * https://docs.python.org/3/c-api/exceptions.html
83 * https://www6.software.ibm.com/developerworks/education/l-pythonscript/l-pythonscript-ltr.pdf
84 * http://boost.cppll.jp/HEAD/libs/python/doc/tutorial/doc/using_the_interpreter.html
85 * (for explaining what the "start" flag is to PyRun_String)
86 * for teaching how to embed and extend Python in a C program.
87 */
88
89 /*
90 * I owe many many thanks to skully for working with me on this
91 * and giving me good advice on how to make this not suck.
92 */
93
94 /*************************************************************************/
95 /*
96 * Extended Python by creating an "import epic" module.
97 */
98 /*
99 * Psuedo-code of how to create a python module that points at your C funcs
100 *
101 * These functions provide the basic facilities of ircII.
102 * All of these functions take one string argument.
103 * epic.echo - yell() -- Like /echo, unconditionally output to screen
104 * epic.say - say() -- Like /xecho -s, output if not suppressed with ^
105 * epic.cmd - runcmds() -- Run a block of code,
106 * but don't expand $'s (like from the input line)
107 * epic.eval - runcmds() -- Run a block of code,
108 * expand $'s, but $* is [] (this is lame)
109 * epic.expr - parse_inline() -- Evaluate an expression string
110 * and return the result
111 * epic.call - call_function() -- Evaluate a "funcname(argument list)"
112 * string and return the result
113 *
114 * These functions provide a route-around of ircII, if that's what you want.
115 * All of these functions take a symbol name ("name") and a string containing
116 * the arguments (if appropriate)
117 * NONE OF THESE FUNCTIONS UNDERGO $-EXPANSION!
118 * (If you need that, use the stuff ^^^ above)
119 *
120 * epic.run_command - run an alias (preferentially) or a builtin command.
121 * Example: epic.run_command("xecho", "-w 0 hi there! This does not get expanded")
122 * epic.call_function - call an alias (preferentially) or a builtin function
123 * Example: epic.call_function("windowctl", "refnums")
124 * epic.get_set - get a /SET value (only)
125 * Example: epic.get_set("mail")
126 * epic.get_assign - get an /ASSIGN value (only)
127 * Example: epic.get_assign("myvar")
128 * epic.get_var - get an /ASSIGN value (preferentially) or a /SET
129 * epic.set_set - set a /SET value (only)
130 * Example: epic.set_set("mail", "ON")
131 * epic.set_assign - set a /ASSIGN value
132 * Example: epic.set_assign("myvar", "5")
133 *
134 * These functions allow you to register file descriptors (like socket)
135 * with epic, which will call back your method when they're interesting.
136 *
137 * epic.callback_when_readable(python_file, python_function, python_object)
138 * epic.callback_when_writable(python_file, python_function, python_object)
139 * When 'python_function' is None, it cancels the callback.
140 * The 'python_function' needs to be a static function (?)
141 * The 'python_object' can be anything, i guess.
142 */
143
144 /********************** Higher level interface to things *********************/
145
146 /*
147 * epic.echo("hello, world") -- Output something without a banner (like /echo)
148 *
149 * Arguments:
150 * self - ignored (the "epic" module)
151 * args - A tuple containing
152 * 1. A string containing stuff to output
153 *
154 * Return value:
155 * NULL - PyArg_ParseTuple() didn't like your tuple
156 * 0 - The stuff was displayed successfully.
157 */
epic_echo(PyObject * self,PyObject * args)158 static PyObject * epic_echo (PyObject *self, PyObject *args)
159 {
160 char * str;
161
162 /*
163 * https://docs.python.org/3/extending/extending.html
164 * tells me that if PyArg_ParseTuple() doesn't like the
165 * argument list, it will set an exception and return
166 * NULL. And all i should do is return NULL.
167 * So that is why i do that here (and everywhere)
168 */
169 if (!PyArg_ParseTuple(args, "z", &str)) {
170 return NULL;
171 }
172
173 yell("%s", str);
174 return PyLong_FromLong(0L);
175 }
176
177 /*
178 * epic.say("Warning, WIll Robinson") -- Output something with a banner
179 * (like internal commands do)
180 *
181 * Arguments:
182 * self - ignored (the "epic" module)
183 * args - A tuple containing
184 * 1. A string containing stuff to output
185 *
186 * Notes:
187 * The banner is (of course) /SET BANNER.
188 *
189 * Return value:
190 * NULL - PyArg_ParseTuple() didn't like your tuple (and threw exception)
191 * 0 - The stuff was displayed successfully.
192 */
epic_say(PyObject * self,PyObject * args)193 static PyObject * epic_say (PyObject *self, PyObject *args)
194 {
195 char * str;
196
197 if (!PyArg_ParseTuple(args, "z", &str)) {
198 return NULL;
199 }
200
201 say("%s", str);
202 return PyLong_FromLong(0L);
203 }
204
205 /*
206 * epic.cmd("join #epic") -- Run an ircII command like at the input line
207 *
208 * Arguments:
209 * self - ignored (the "epic" module)
210 * args - A tuple containing
211 * 1. A string containing an ircII command statement
212 *
213 * Notes:
214 * 'args' is run as a single ircII statement (as if you had typed
215 * it at the command line). $'s are not expanded; semicolons are
216 * not treated as statement separates, and braces have no special
217 * meaning.
218 *
219 * Return value:
220 * NULL - PyArg_ParseTuple() didn't like your tuple (and threw exception)
221 * 0 - The stuff was run successfully.
222 */
epic_cmd(PyObject * self,PyObject * args)223 static PyObject * epic_cmd (PyObject *self, PyObject *args)
224 {
225 char * str;
226
227 if (!PyArg_ParseTuple(args, "z", &str)) {
228 return NULL;
229 }
230
231 runcmds("$*", str);
232 return PyLong_FromLong(0L);
233 }
234
235 /*
236 * epic.eval("echo My nick is $N") -- Run an ircII command line in an alias
237 *
238 * Arguments:
239 * self - ignored (the "epic" module)
240 * args - A tuple containing
241 * 1. A string containing an ircII statement
242 *
243 * Notes:
244 * $* is treated as the empty string ([]) and so any $0, $1 type
245 * expansions will expand to the empty string. Maybe this will
246 * change in the future, and you'll be permitted to pass in $*.
247 *
248 * Return value:
249 * NULL - PyArg_ParseTuple() didn't like your tuple (and threw exception)
250 * 0 - The stuff ran successfully.
251 */
epic_eval(PyObject * self,PyObject * args)252 static PyObject * epic_eval (PyObject *self, PyObject *args)
253 {
254 char * str;
255
256 if (!PyArg_ParseTuple(args, "z", &str)) {
257 return NULL;
258 }
259
260 runcmds(str, "");
261 return PyLong_FromLong(0L);
262 }
263
264 /*
265 * epic.expr("var + 2 * numonchannel()") -- Return the result of an expression
266 *
267 * Arguments:
268 * self - ignored (the "epic" module)
269 * args - A tuple containing
270 * 1. A string containing an ircII expression
271 *
272 * Notes:
273 * $* is treated as the empty string ([]) and so any $0, $1 type
274 * expansions will expand to the empty string. Maybe this will
275 * change in the future, and you'll be permitted to pass in $*.
276 *
277 * Return value:
278 * NULL - PyArg_ParseTuple() didn't like your tuple (and threw exception)
279 * NULL - Py_BuildValue() threw an exception converting the expr
280 * result (a string) into a python string.
281 * A string - The result of the expression
282 * - All ircII expressions result in a string, even if that
283 * string contains an integer or whatever.
284 * ie, "2 + 2" is "4" == a string containing the number 4.
285 */
epic_expr(PyObject * self,PyObject * args)286 static PyObject * epic_expr (PyObject *self, PyObject *args)
287 {
288 char * str;
289 char * exprval;
290 PyObject *retval;
291
292 if (!PyArg_ParseTuple(args, "z", &str)) {
293 return NULL;
294 }
295
296 exprval = parse_inline(str, "");
297 if (!(retval = Py_BuildValue("z", exprval))) {
298 return NULL;
299 }
300 new_free(&exprval);
301 return retval;
302 }
303
304 /*
305 * epic.expand("text with ${2+2} $vars in it") -- Expand a string and return it
306 *
307 * Arguments:
308 * self - ignored (the "epic" module)
309 * args - A tuple containing
310 * 1. A string containing an ircII string
311 *
312 * Notes:
313 * $* is treated as the empty string ([]) and so any $0, $1 type
314 * expansions will expand to the empty string. Maybe this will
315 * change in the future, and you'll be permitted to pass in $*.
316 *
317 * Return value:
318 * NULL - PyArg_ParseTuple() didn't like your tuple (and threw exception)
319 * NULL - Py_BuildValue() couldn't convert the retval to python string (throws exception)
320 * A string - The result of the expansion
321 */
epic_expand(PyObject * self,PyObject * args)322 static PyObject * epic_expand (PyObject *self, PyObject *args)
323 {
324 char * str;
325 char * expanded;
326 PyObject *retval;
327
328 if (!PyArg_ParseTuple(args, "z", &str)) {
329 return NULL;
330 }
331
332 expanded = expand_alias(str, "");
333 retval = Py_BuildValue("z", expanded);
334 new_free(&expanded);
335 return retval;
336 }
337
338 /*
339 * epic.call("function(arglist)") -- Call a function directly (with $-expansion)
340 *
341 * Arguments:
342 * self - ignored (the "epic" module)
343 * args - A tuple containing
344 * 1. A string containing a function call, with parenthesis
345 *
346 * Notes:
347 * The 'arglist' will be expanded ($-expandos will be honored)
348 * $* will be treated as the empty string (see the caveats above)
349 *
350 * Return value:
351 * NULL - PyArg_ParseTuple() didn't like your tuple (and threw exception)
352 * NULL - Py_BuildValue() couldn't convert the retval to python string
353 * (throws exception)
354 * A string - The return value of the function call
355 * All function calls return exactly one string, even if
356 * that string contains a number or a list of words.
357 * You may need to process the string in python.
358 */
epic_call(PyObject * self,PyObject * args)359 static PyObject * epic_call (PyObject *self, PyObject *args)
360 {
361 char * str;
362 char * funcval;
363 PyObject *retval;
364
365 if (!PyArg_ParseTuple(args, "z", &str)) {
366 return NULL;
367 }
368
369 funcval = call_function(str, "");
370 retval = Py_BuildValue("z", funcval);
371 new_free(&funcval);
372 return retval;
373 }
374
375 /* Lower level interfaces to things */
376
377
378 /*
379 * epic.run_command("COMMAND", "arglist") - Call a command (alias or builtin)
380 * directly WITHOUT expansion
381 *
382 * Arguments:
383 * self - ignored (the "epic" module)
384 * args - A tuple containing:
385 * 1. A string containing an alias name or a built in command name
386 * 2. A string representing the argument list
387 *
388 * Note: All ircII commands take one string as the argument, even if that string
389 * contains some serialization of a collection. Technically each command
390 * is permitted to do whatever it wants with its arguments; but the
391 * convention is to accept a space separated list of words. Again, this
392 * is not a requirement, justthe way most things work.
393 *
394 * Note: The argument list is _NOT_ expanded; it is passed literally in to
395 * the cmd.
396 * Note: XXX - The $* that is passed in is NULL; I'm not sure if this is
397 * correct or not.
398 * Note: Aliases are prefered to builtin commands, just like ircII does it.
399 *
400 * Return Value:
401 * NULL - PyArg_ParseTuple() didn't like your tuple
402 * (and threw exception)
403 * NULL / NameError - The command you tried to run doesn't exist.
404 * None - The command was run successfully
405 */
epic_run_command(PyObject * self,PyObject * args)406 static PyObject * epic_run_command (PyObject *self, PyObject *args)
407 {
408 char * symbol;
409 char * my_args;
410 PyObject *retval;
411 void (*builtin) (const char *, char *, const char *) = NULL;
412 const char * alias = NULL;
413 void * arglist = NULL;
414
415 if (!PyArg_ParseTuple(args, "zz", &symbol, &my_args)) {
416 return NULL;
417 }
418
419 upper(symbol);
420 alias = get_cmd_alias(symbol, &arglist, &builtin);
421 if (alias)
422 call_user_command(symbol, alias, my_args, arglist);
423 else if (builtin)
424 builtin(symbol, my_args, empty_string);
425 else
426 {
427 PyErr_Format(PyExc_NameError, "%s : Command does not exist", symbol);
428 return NULL;
429 }
430
431 /* Success! */
432 Py_INCREF(Py_None);
433 return Py_None;
434 }
435
436
437 /*
438 * epic.call_function("FUNCTION", "arglist") -- Call a function
439 * (alias or builtin) directly WITHOUT expansion
440 *
441 * Arguments:
442 * self - ignored (the "epic" module)
443 * args - A tuple containing:
444 * 1. A string containing an alias name or built in function name
445 * 2. A string representing the argument list
446 *
447 * Note: All ircII functions take one string as their argument, even if that
448 * string contains some representation of a collection. Technically each
449 * function is permitted to do whatever it wants with its arguments; but
450 * the convention is to accept a space separated list of words. Again,
451 * this is not a requirement, just the way most things work.
452 *
453 * Note: The argument list is _NOT_ expanded; it is passed literally to the fn.
454 * Note: XXX - The $* that is passed in is NULL;
455 * I'm not sure if this is correct or not.
456 * Note: Aliases are preferred to builtins, just like ircII.
457 *
458 * Return Value:
459 * NULL - PyArg_ParseTuple() didn't like your tuple
460 * (and threw exception)
461 * NULL / NameError - The function you tried to run doesn't exist.
462 * A string - the return value of the function (which may be zero-length for its own reasons)
463 */
epic_call_function(PyObject * self,PyObject * args)464 static PyObject * epic_call_function (PyObject *self, PyObject *args)
465 {
466 char * symbol;
467 char * my_args;
468 PyObject *retval;
469 const char *alias;
470 void * arglist;
471 char * (*builtin) (char *) = NULL;
472 char * funcval = NULL;
473
474 if (!PyArg_ParseTuple(args, "zz", &symbol, &my_args)) {
475 return PyLong_FromLong(-1);
476 }
477
478 upper(symbol);
479 alias = get_func_alias(symbol, &arglist, &builtin);
480 if (alias)
481 funcval = call_user_function(symbol, alias, my_args, arglist);
482 else if (builtin)
483 funcval = builtin(my_args);
484 else
485 {
486 PyErr_Format(PyExc_NameError, "%s : Function does not exist", symbol);
487 return NULL;
488 }
489
490 retval = Py_BuildValue("z", funcval);
491 new_free(&funcval);
492 return retval;
493 }
494
495 /*
496 * epic.get_set("SETNAME") - Return the value of /SET SETNAME
497 *
498 * Arguments:
499 * self - ignored (the "epic" module)
500 * args - A tuple containing:
501 * 1. A /SET name (ie, "AUTO_REJOIN")
502 *
503 * Note: Although /SETs have types (integer, boolean, string), the
504 * value of a SET is always a string.
505 *
506 * Return value:
507 * NULL - PyArg_ParseTuple() didn't like your tuple
508 * (and threw exception)
509 * NULL / NameError - The set you tried to fetch doesn't exist.
510 * A string - the value of /SET SETNAME
511 */
epic_get_set(PyObject * self,PyObject * args)512 static PyObject * epic_get_set (PyObject *self, PyObject *args)
513 {
514 char * symbol;
515 PyObject *retval;
516 char * funcval = NULL;
517
518 if (!PyArg_ParseTuple(args, "z", &symbol)) {
519 return NULL;
520 }
521
522 upper(symbol);
523 if (make_string_var2(symbol, &funcval) < 0)
524 {
525 PyErr_Format(PyExc_NameError, "%s : SET variable does not exist", symbol);
526 return NULL;
527 }
528
529 retval = Py_BuildValue("z", funcval);
530 new_free(&funcval);
531 return retval;
532 }
533
534 /*
535 * epic.get_assign("VARNAME") - Return the value of /ASSIGN VARNAME
536 *
537 * Arguments:
538 * self - ignored (the "epic" module)
539 * args - A tuple containing:
540 * 1. A /ASSIGN name (ie, "MYVAR")
541 *
542 * Note: Variables are always strings, even if they contain a number.
543 *
544 * Return value:
545 * NULL - PyArg_ParseTuple() didn't like your tuple
546 * (and threw exception)
547 * NULL / NameError - The set you tried to fetch doesn't exist.
548 * A string - the value of /ASSIGN VARNAME (or empty if it does not exist)
549 * XXX - This is probably wrong, asking for an unknown
550 * assign should probably return None or throw an
551 * exception or something.
552 */
epic_get_assign(PyObject * self,PyObject * args)553 static PyObject * epic_get_assign (PyObject *self, PyObject *args)
554 {
555 char * symbol;
556 PyObject *retval;
557 char * funcval = NULL;
558 char * (*efunc) (void) = NULL;
559 IrcVariable * sfunc = NULL;
560 const char * assign = NULL;
561
562 if (!PyArg_ParseTuple(args, "z", &symbol)) {
563 return NULL;
564 }
565
566 upper(symbol);
567 if (!(assign = get_var_alias(symbol, &efunc, &sfunc)))
568 {
569 PyErr_Format(PyExc_NameError, "%s : ASSIGN variable does not exist", symbol);
570 return NULL;
571 }
572
573 retval = Py_BuildValue("z", assign);
574 /* _DO NOT_ FREE 'assign'! */
575 return retval;
576 }
577
578 /*
579 * epic.get_var("NAME") - Return the value of a variable [see notes]
580 *
581 * Arguments:
582 * self - ignored (the "epic" module)
583 * args - A tuple containing:
584 * 1. A variable symbol name of some sort
585 *
586 * Note: A variable name can be a local variable, a global variable, or a set
587 * variable. The return value is what you would get if you did $<NAME>.
588 * Note: XXX - Because of how this is implemented, this supports ":local" and
589 * "::global", although I'm not sure it will stay this way forever.
590 *
591 * Return value:
592 * NULL - PyArg_ParseTuple() didn't like your tuple
593 * (and threw exception)
594 * A string - The value of $<NAME>
595 * The zero-length string if $<NAME> does not exist.
596 *
597 * Note: Because of how ircII does this, it is not possible to differentiate
598 * between a variable that does not exist and a variable that is unset.
599 * If you need that level of granularity (which should be unusual)
600 * you should use epic.get_var(), epic.get_assign(), etc.
601 */
epic_get_var(PyObject * self,PyObject * args)602 static PyObject * epic_get_var (PyObject *self, PyObject *args)
603 {
604 char * symbol;
605 PyObject *retval;
606 char * funcval = NULL;
607
608 if (!PyArg_ParseTuple(args, "z", &symbol)) {
609 return NULL;
610 }
611
612 upper(symbol);
613 funcval = get_variable(symbol);
614 retval = Py_BuildValue("z", funcval);
615 new_free(&funcval);
616 return retval;
617 }
618
619 /*
620 * epic.set_set("setname", "value") -- do a /SET
621 * XXX - TODO - XXX
622 *
623 * Arguments:
624 * self - ignored (the "epic" module)
625 * args - A tuple containing
626 * 1. A string - the SET to be set
627 * 2. A string - the value to be SET
628 * Note:
629 * SETs have types, which are not currently exposed through this
630 * interface. You need to pass in a string that contains a value
631 * of the correct type (ie, if the SET is an integer, you need to
632 * pass in a string containing an integer. If the SET is a boolean,
633 * you need to pass in a string containing "TRUE" or "FALSE".)
634 * Who knows -- this may improve in the future.
635 *
636 * Return value:
637 * NULL - PyArg_ParseTuple() didn't like your tuple
638 * (and threw exception)
639 * NULL / NotImplelmentedError - This function is not implemented yet
640 */
epic_set_set(PyObject * self,PyObject * args)641 static PyObject * epic_set_set (PyObject *self, PyObject *args)
642 {
643 char * symbol;
644 char * value;
645 PyObject *retval;
646
647 if (!PyArg_ParseTuple(args, "zz", &symbol, &value)) {
648 return NULL;
649 }
650
651 /* XXX - TODO - /SET symbol value */
652 PyErr_Format(PyExc_NotImplementedError, "Not Implemented Yet");
653 return NULL;
654
655 return PyLong_FromLong(0);
656 }
657
658 /*
659 * epic.set_assign("varname", "value") -- do an /ASSIGN
660 * XXX - TODO - XXX
661 *
662 * Arguments:
663 * self - ignored (the "epic" module)
664 * args - A tuple containing
665 * 1. A string -- the variable to be /ASSIGNed
666 * 2. A string -- the value to be /ASSIGNED
667 *
668 * Return value:
669 * NULL - PyArg_ParseTuple() didn't like your tuple
670 * (and threw exception)
671 * NULL / NotImplelmentedError - This function is not implemented yet
672 */
epic_set_assign(PyObject * self,PyObject * args)673 static PyObject * epic_set_assign (PyObject *self, PyObject *args)
674 {
675 char * symbol;
676 char * value;
677 PyObject *retval;
678
679 if (!PyArg_ParseTuple(args, "zz", &symbol, &value)) {
680 return NULL;
681 }
682
683 /* XXX - TODO - /ASSIGN symbol value */
684 PyErr_Format(PyExc_NotImplementedError, "Not Implemented Yet");
685 return NULL;
686
687 }
688
689 /* * * * * * * * * */
690 typedef struct {
691 int vfd;
692 PyObject * read_callback;
693 PyObject * write_callback;
694 PyObject * except_callback;
695 int flags;
696 } PythonFDCallback;
697
698 /* This should be in a header file somewhere... */
699 #if defined(HAVE_SYSCONF) && defined(_SC_OPEN_MAX)
700 # define IO_ARRAYLEN sysconf(_SC_OPEN_MAX)
701 #else
702 # if defined(FD_SETSIZE)
703 # define IO_ARRAYLEN FD_SETSIZE
704 # else
705 # define IO_ARRAYLEN NFDBITS
706 # endif
707 #endif
708
709 PythonFDCallback **python_vfd_callback = NULL;
710
init_python_fd_callbacks(void)711 void init_python_fd_callbacks (void)
712 {
713 int vfd;
714 int max_fd = IO_ARRAYLEN;
715
716 if (python_vfd_callback)
717 return; /* Panic is so 12008 */
718
719 python_vfd_callback = (PythonFDCallback **)new_malloc(sizeof(PythonFDCallback *) * max_fd);
720 for (vfd = 0; vfd < max_fd; vfd++)
721 python_vfd_callback[vfd] = NULL;
722 }
723
get_python_vfd_callback(int vfd)724 PythonFDCallback * get_python_vfd_callback (int vfd)
725 {
726 if (vfd < 0 || vfd > IO_ARRAYLEN)
727 return NULL;
728
729 return python_vfd_callback[vfd];
730 }
731
set_python_vfd_callback(int vfd,PythonFDCallback * callback)732 int set_python_vfd_callback (int vfd, PythonFDCallback *callback)
733 {
734 if (callback == NULL)
735 return -1;
736
737 if (python_vfd_callback[vfd] && python_vfd_callback[vfd] != callback)
738 return -1;
739
740 if (callback->vfd == -1)
741 callback->vfd = vfd;
742
743 if (vfd != callback->vfd)
744 return -1;
745
746 python_vfd_callback[vfd] = callback;
747 return 0;
748 }
749
new_python_fd_callback(int vfd)750 PythonFDCallback * new_python_fd_callback (int vfd)
751 {
752 PythonFDCallback *callback;
753
754 callback= (PythonFDCallback *)new_malloc(sizeof(PythonFDCallback));
755 callback->vfd = vfd;
756 callback->read_callback = NULL;
757 callback->write_callback = NULL;
758 callback->except_callback = NULL;
759 callback->flags = 0;
760 set_python_vfd_callback(vfd, callback);
761 return callback;
762 }
763
destroy_python_fd_callback(int vfd)764 int destroy_python_fd_callback (int vfd)
765 {
766 PythonFDCallback *callback;
767
768 if (!(callback = python_vfd_callback[vfd]))
769 return -1;
770
771 callback->vfd = -1;
772 callback->read_callback = NULL;
773 callback->write_callback = NULL;
774 callback->except_callback = NULL;
775 callback->flags = 0;
776 python_vfd_callback[vfd] = NULL;
777 new_free((void **)&callback);
778 return 0;
779 }
780
781
782
783 /*
784 * call_python_function_1arg - Call a python function to handle IO callbacks
785 *
786 * Python IO callbacks take one argument - the file descriptor.
787 * Python IO callbacks _may not throw exceptions_.
788 * Exceptions are considered a "broken" situation and will result in
789 * a call to the except_callback to repair the situation.
790 * If the except_callback fails, then it's game over for this fd.
791 *
792 * Retval
793 * -1 - The callback failed (threw an exception)
794 * 0 - The callback did not fail
795 */
call_python_function_1arg(PyObject * pFunc,int vfd)796 int call_python_function_1arg (PyObject *pFunc, int vfd)
797 {
798 PyObject *args_py = NULL;
799 PyObject *pArgs = NULL, *pRetVal = NULL;
800 /* PyObject *retval_repr = NULL; */
801 char *r = NULL, *retvalstr = NULL;
802
803 if (!PyCallable_Check(pFunc))
804 {
805 my_error("python_fd_callback: The callback was not a function");
806 goto c_p_f_error;
807 }
808
809 if (!(pArgs = PyTuple_New(1)))
810 goto c_p_f_error;
811
812 if (!(args_py = Py_BuildValue("i", vfd)))
813 goto c_p_f_error;
814
815 if ((PyTuple_SetItem(pArgs, 0, args_py)))
816 goto c_p_f_error;
817 args_py = NULL; /* args_py now belongs to the tuple! */
818
819 if (!(pRetVal = PyObject_CallObject(pFunc, pArgs)))
820 goto c_p_f_error;
821
822 if (!(/*retval_repr = */PyObject_Repr(pRetVal)))
823 goto c_p_f_error;
824
825 goto c_p_f_cleanup;
826
827 c_p_f_error:
828 output_traceback();
829 return -1;
830
831 c_p_f_cleanup:
832 Py_XDECREF(pArgs);
833 Py_XDECREF(pRetVal);
834 return 0;
835 }
836
do_python_fd(int vfd)837 void do_python_fd (int vfd)
838 {
839 PythonFDCallback *callback;
840 char buffer[BIG_BUFFER_SIZE];
841 int n;
842
843 if (!((callback = get_python_vfd_callback(vfd))))
844 {
845 yell("do_python_fd: FD %d doesn't belong to me - new_close()ing it.", vfd);
846 new_close(vfd);
847 return;
848 }
849
850 if ((n = dgets(vfd, buffer, BIG_BUFFER_SIZE, -1)) > 0)
851 {
852 if (callback->read_callback)
853 {
854 if ((call_python_function_1arg(callback->read_callback, vfd)))
855 {
856 if ((call_python_function_1arg(callback->except_callback, vfd)))
857 {
858 yell("do_python_fd: FD %d failed: both ordinary and error callback failed.", vfd);
859 new_close(vfd);
860 }
861 }
862 }
863
864 else if (callback->write_callback)
865 {
866 if ((call_python_function_1arg(callback->write_callback, vfd)))
867 {
868 if ((call_python_function_1arg(callback->except_callback, vfd)))
869 {
870 yell("do_python_fd: FD %d failed: both ordinary and error callback failed.", vfd);
871 new_close(vfd);
872 }
873 }
874 }
875
876 }
877 else if (n < 0)
878 {
879 if (callback->except_callback)
880 {
881 if ((call_python_function_1arg(callback->except_callback, vfd)))
882 {
883 yell("do_python_fd: FD %d failed: both ordinary and error callback failed.", vfd);
884 new_close(vfd);
885 }
886 }
887 }
888 }
889
890
do_python_fd_failure(int vfd,int error)891 void do_python_fd_failure (int vfd, int error)
892 {
893 PythonFDCallback *callback;
894
895 if (!((callback = get_python_vfd_callback(vfd))))
896 {
897 yell("do_python_fd_failure: FD %d doesn't belong to me - new_close()ing it myself.", vfd);
898 new_close(vfd);
899 return;
900 }
901
902 if (callback->except_callback)
903 call_python_function_1arg(callback->except_callback, vfd);
904 }
905
906
907 /*
908 * epic.callback_when_readable(fd, read_callback, except_function, flags)
909 *
910 * Arguments:
911 * self - ignored (the "epic" module)
912 * args - A tuple containing
913 * 1. fd - An integer - a unix file descriptor (from python)
914 * 2. read_callback - A CallableObject (ie, a method) - A python
915 * method that takes one integer argument. It will
916 * be called each time the 'fd' is readable.
917 * You must "handle" the fd, or it will busy-loop.
918 * If you block while handling the fd, epic
919 * will block.
920 * Arg1 - fd
921 * 3. except_callback - A CallableObject (ie, a method) - A python
922 * method that takes two integer arguments. It will
923 * be called if the 'fd' becomes invalid. This
924 * would happen if somneone close()d the FD, but
925 * didn't call _epic.cancel_callback().
926 * You should call _epic.cancel_callback(), or
927 * it will busy-loop. If you block while handling
928 * the fd, epic will block.
929 * Arg1 - fd, Arg2 - error code
930 * 4. flags - Reserved for future expansion. Pass in 0 for now.
931 *
932 * Return value:
933 * NULL - PyArg_ParseTuple() didn't like your tuple
934 * (and threw exception)
935 * 0 - The command succeeded
936 */
epic_callback_when_readable(PyObject * self,PyObject * args)937 static PyObject * epic_callback_when_readable (PyObject *self, PyObject *args)
938 {
939 long vfd, flags;
940 PyObject *read_callback, *except_callback;
941 PythonFDCallback *callback;
942
943 /*
944 * https://docs.python.org/3/extending/extending.html
945 * tells me that if PyArg_ParseTuple() doesn't like the
946 * argument list, it will set an exception and return
947 * NULL. And all i should do is return NULL.
948 * So that is why i do that here (and everywhere)
949 */
950 if (!PyArg_ParseTuple(args, "lOOl", &vfd, &read_callback, &except_callback, &flags)) {
951 return NULL;
952 }
953
954 /*
955 * 1. Look up python fd record, create if necessary
956 * 2. Set read_callback in the python fd record
957 * 3. Call new_open() if necessary
958 */
959 if (!(callback = get_python_vfd_callback(vfd)))
960 callback = new_python_fd_callback(vfd);
961 else
962 {
963 if (callback->write_callback)
964 new_close_with_option(vfd, 1);
965 }
966
967 callback->write_callback = NULL;
968 callback->read_callback = read_callback;
969 callback->except_callback = except_callback;
970 callback->flags = flags;
971
972 new_open(vfd, do_python_fd, NEWIO_PASSTHROUGH_READ, 0, from_server);
973 new_open_failure_callback(vfd, do_python_fd_failure);
974 return PyLong_FromLong(0L);
975 }
976
977 /*
978 * epic.callback_when_writable(fd, write_callback, except_function, flags)
979 *
980 * Arguments:
981 * self - ignored (the "epic" module)
982 * args - A tuple containing
983 * 1. fd - An integer - a unix file descriptor (from python)
984 * 2. read_callback - A CallableObject (ie, a method) - A python
985 * method that takes one integer argument. It will
986 * be called each time the 'fd' is writable.
987 * You must "handle" the fd, or it will busy-loop.
988 * If you block while handling the fd, epic
989 * will block.
990 * 3. except_callback - A CallableObject (ie, a method) - A python
991 * method that takes one integer argument. It will
992 * be called if the 'fd' becomes invalid. This
993 * would happen if somneone close()d the FD, but
994 * didn't call _epic.cancel_callback().
995 * You should call _epic.cancel_callbacks(), or
996 * it will busy-loop. If you block while handling
997 * the fd, epic will block.
998 * 4. flags - Reserved for future expansion. Pass in 0 for now.
999 *
1000 * Return value:
1001 * NULL - PyArg_ParseTuple() didn't like your tuple
1002 * (and threw exception)
1003 * 0 - The command succeeded
1004 */
epic_callback_when_writable(PyObject * self,PyObject * args)1005 static PyObject * epic_callback_when_writable (PyObject *self, PyObject *args)
1006 {
1007 long vfd, flags;
1008 PyObject *write_callback, *except_callback;
1009 PythonFDCallback *callback;
1010
1011 /*
1012 * https://docs.python.org/3/extending/extending.html
1013 * tells me that if PyArg_ParseTuple() doesn't like the
1014 * argument list, it will set an exception and return
1015 * NULL. And all i should do is return NULL.
1016 * So that is why i do that here (and everywhere)
1017 */
1018 if (!PyArg_ParseTuple(args, "lOOl", &vfd, &write_callback, &except_callback, &flags)) {
1019 return NULL;
1020 }
1021
1022 /*
1023 * 1. Look up python fd record, create if necessary
1024 * 2. Set write_callback in the python fd record
1025 * 3. Call new_open() if necessary.
1026 */
1027 if (!(callback = get_python_vfd_callback(vfd)))
1028 callback = new_python_fd_callback(vfd);
1029 else
1030 {
1031 if (callback->read_callback)
1032 new_close_with_option(vfd, 1);
1033 }
1034
1035 callback->read_callback = NULL;
1036 callback->write_callback = write_callback;
1037 callback->except_callback = except_callback;
1038 callback->flags = flags;
1039
1040 new_open(vfd, do_python_fd, NEWIO_PASSTHROUGH_WRITE, 0, from_server);
1041 new_open_failure_callback(vfd, do_python_fd_failure);
1042 return PyLong_FromLong(0L);
1043 }
1044
1045 /*
1046 * epic.cancel_callback(fd)
1047 *
1048 * Arguments:
1049 * self - ignored (the "epic" module)
1050 * args - A tuple containing
1051 * 1. fd - An integer - a unix file descriptor (from python)
1052 *
1053 * Return value:
1054 * NULL - PyArg_ParseTuple() didn't like your tuple
1055 * (and threw exception)
1056 * 0 - The command succeeded
1057 */
epic_cancel_callback(PyObject * self,PyObject * args)1058 static PyObject * epic_cancel_callback (PyObject *self, PyObject *args)
1059 {
1060 long vfd;
1061 PythonFDCallback *callback;
1062
1063 /*
1064 * https://docs.python.org/3/extending/extending.html
1065 * tells me that if PyArg_ParseTuple() doesn't like the
1066 * argument list, it will set an exception and return
1067 * NULL. And all i should do is return NULL.
1068 * So that is why i do that here (and everywhere)
1069 */
1070 if (!PyArg_ParseTuple(args, "l", &vfd)) {
1071 return NULL;
1072 }
1073
1074 /*
1075 * 1. Look up python fd record (bail if does not exist)
1076 * 2. Call new_close_with_option()
1077 * 3. Clear the python fd record
1078 * (4. The python script has to close the fd...)
1079 */
1080 if ((callback = get_python_vfd_callback(vfd)))
1081 {
1082 callback->read_callback = NULL;
1083 callback->write_callback = NULL;
1084 callback->except_callback = NULL;
1085 callback->flags = 0;
1086 new_close_with_option(vfd, 1);
1087 }
1088
1089 return PyLong_FromLong(0L);
1090 }
1091
1092 /*
1093 * INTERNAL USE ONLY --
1094 * When you want to register a python module.method as a hardcoded
1095 * builtin ircII command, you need a BUILT_IN_COMMAND() to be registered
1096 * as the callback. Because of how ircII works, the /COMMAND that you
1097 * run ends up in 'command', so this shim just does the glue:
1098 *
1099 * In python:
1100 * epic.builtin_cmd("module.method")
1101 * In ircII:
1102 * /MODULE.METHOD ...args...
1103 *
1104 * XXX - It's not clear if 'subargs' should be passed to the python function.
1105 */
BUILT_IN_COMMAND(pyshim)1106 BUILT_IN_COMMAND(pyshim)
1107 {
1108 char * retval = NULL;
1109
1110 retval = call_python_directly(command, args);
1111 new_free(&retval);
1112 }
1113
1114 /*
1115 * epic.builtin_cmd("module.method") -- Register a python module.method
1116 * as a builtin ircII cmd
1117 * Arguments:
1118 * self - ignored (the "epic" object)
1119 * args - A tuple containing
1120 * 1. A string - the name of "module.method")
1121 * This will become /MODULE.METHOD in ircII.
1122 *
1123 * Return value:
1124 * NULL - PyArg_ParseTuple() didn't like your tuple
1125 * (and threw exception)
1126 * None - The command was registered successfully
1127 */
epic_builtin_cmd(PyObject * self,PyObject * args)1128 static PyObject * epic_builtin_cmd (PyObject *self, PyObject *args)
1129 {
1130 char * symbol;
1131
1132 if (!PyArg_ParseTuple(args, "z", &symbol)) {
1133 return NULL;
1134 }
1135
1136 /* XXX TODO - Test this -- does 'symbol' need to be strdup()d? XXX TODO */
1137 add_builtin_cmd_alias(symbol, pyshim);
1138
1139 /* Success! */
1140 Py_INCREF(Py_None);
1141 return Py_None;
1142 }
1143
1144
1145 static PyMethodDef epicMethods[] = {
1146 /* Higher level facilities - $-expansion supported */
1147 { "echo", epic_echo, METH_VARARGS, "Unconditionally output to screen (yell)" },
1148 { "say", epic_say, METH_VARARGS, "Output to screen unless suppressed (say)" },
1149 { "cmd", epic_cmd, METH_VARARGS, "Run a block statement without expansion (runcmds)" },
1150 { "eval", epic_eval, METH_VARARGS, "Run a block statement with expansion (but $* is empty)" },
1151 { "expr", epic_expr, METH_VARARGS, "Return the result of an expression (parse_inline)" },
1152 { "call", epic_call, METH_VARARGS, "Call a function with expansion (but $* is empty) (call_function)" },
1153 { "expand", epic_expand, METH_VARARGS, "Expand some text with $s" },
1154
1155 /* Lower level facilities - $-expansion NOT supported */
1156 { "run_command", epic_run_command, METH_VARARGS, "Run an alias or builtin command" },
1157 { "call_function", epic_call_function, METH_VARARGS, "Call an alias or builtin function" },
1158 { "get_set", epic_get_set, METH_VARARGS, "Get a /SET value (only)" },
1159 { "get_assign", epic_get_assign, METH_VARARGS, "Get a /ASSIGN value (only)" },
1160 { "get_var", epic_get_assign, METH_VARARGS, "Get a variable (either /ASSIGN or /SET)" },
1161 { "set_set", epic_set_set, METH_VARARGS, "Set a /SET value (only)" },
1162 { "set_assign", epic_set_assign, METH_VARARGS, "Set a /ASSIGN value (only)" },
1163 { "builtin_cmd", epic_builtin_cmd, METH_VARARGS, "Make a Python function an EPIC builtin command" },
1164 /* Lower level IO facilities */
1165 { "callback_when_readable", epic_callback_when_readable, METH_VARARGS, "Register a python function for FD event callbacks" },
1166 { "callback_when_writable", epic_callback_when_writable, METH_VARARGS, "Register a python function for FD event callbacks" },
1167 { "cancel_callback", epic_cancel_callback, METH_VARARGS, "Unregister FD event callbacks" },
1168
1169 { NULL, NULL, 0, NULL }
1170 };
1171
1172 static PyModuleDef epicModule = {
1173 PyModuleDef_HEAD_INIT,
1174 "_epic", NULL, -1, epicMethods,
1175 NULL, NULL, NULL, NULL
1176 };
1177
1178 /*
1179 * This is called via
1180 * PyImport_AppendInittab("_epic", &PyInit_epic);
1181 * before
1182 * PyInitialize();
1183 * in main().
1184 */
PyInit_epic(void)1185 static PyObject * PyInit_epic (void)
1186 {
1187 return PyModule_Create(&epicModule);
1188 }
1189
initialize_python(int start)1190 void initialize_python (int start)
1191 {
1192 if (p_initialized == 0)
1193 {
1194 PyImport_AppendInittab("_epic", &PyInit_epic);
1195 Py_Initialize();
1196 p_initialized = 1;
1197 global_vars = PyModule_GetDict(PyImport_AddModule("__main__"));
1198 init_python_fd_callbacks();
1199 }
1200 }
1201
1202 /***********************************************************/
1203 /*
1204 * python_eval_expression - Call a Python Expression -- the $python() function
1205 *
1206 * Note: This can only be used to call a Python Expression.
1207 * It cannot be used to call a python statement.
1208 *
1209 * See at the top of the file -- Python makes a distinction between
1210 * statements and expressions (like ircII does) and has different
1211 * API calls for each (PyRun_String() and PyRun_SimpleString()).
1212 *
1213 * Arguments:
1214 * input - A string to pass to the Python interpreter.
1215 * It must be a python expression, or python will throw exception.
1216 *
1217 * Return Value:
1218 * The return value of the python expression, as a new_malloc()ed string.
1219 * YOU are responsible for new_free()ing the value later (if you call this
1220 * other than as the $python() function, of course)
1221 */
python_eval_expression(char * input)1222 char * python_eval_expression (char *input)
1223 {
1224 PyObject *retval;
1225 PyObject *retval_repr;
1226 const char *r;
1227 char *retvalstr = NULL;
1228
1229 if (p_initialized == 0)
1230 initialize_python(1);
1231
1232 /*
1233 * https://docs.python.org/3/c-api/veryhigh.html
1234 * says that this returns NULL if an exception is raised.
1235 * So in that case, we try to handle/format the exception.
1236 */
1237 if (!(retval = PyRun_String(input, Py_eval_input, global_vars, global_vars)))
1238 output_traceback();
1239
1240 /* Convert retval to a string */
1241 retval_repr = PyObject_Repr(retval);
1242 r = PyUnicode_AsUTF8(retval_repr);
1243 retvalstr = malloc_strdup(r);
1244
1245 Py_XDECREF(retval);
1246 Py_XDECREF(retval_repr);
1247 RETURN_MSTR(retvalstr);
1248 }
1249
1250 /*
1251 * python_eval_statement -- Call a Python Statement -- The /PYTHON function
1252 *
1253 * Note: This can only be used to call a Python Statement.
1254 * It cannot be used to call a python expression.
1255 *
1256 * See at the top of the file -- Python makes a distinction between
1257 * statements and expressions (like ircII does) and has different
1258 * API calls for each (PyRun_String() and PyRun_SimpleString()).
1259 *
1260 * Arguments:
1261 * input - A string to pass to the Python interpreter.
1262 * It must be a python statement, or python will throw exception
1263 *
1264 * Note: It's not clear if the statement throws an exception whether or not
1265 * we can catch and format it. We'll see!
1266 */
python_eval_statement(char * input)1267 void python_eval_statement (char *input)
1268 {
1269 if (p_initialized == 0)
1270 initialize_python(1);
1271
1272 /*
1273 * https://docs.python.org/3/c-api/veryhigh.html
1274 * says that "returns 0 on success or -1 if an exception is raised.
1275 * If there was an error, there is no way to get the exception
1276 * information;" That's not 100% clear. So I decided to assume
1277 * that if -1 is returned, we should see if there is exception
1278 * information and output it if we can. There is the possibility
1279 * that python has just dumped the exception to stdout and that
1280 * we are out of luck for reformatting it.
1281 */
1282 if (PyRun_SimpleString(input))
1283 output_traceback();
1284 }
1285
1286
1287 /*
1288 * The /PYTHON command: Evalulate the args as a PYTHON block and ignore the
1289 * return value of the statement.
1290 */
BUILT_IN_COMMAND(pythoncmd)1291 BUILT_IN_COMMAND(pythoncmd)
1292 {
1293 char *body;
1294
1295 if (*args == '{')
1296 {
1297 if (!(body = next_expr(&args, '{')))
1298 {
1299 my_error("PYTHON: unbalanced {");
1300 return;
1301 }
1302 }
1303 else
1304 body = args;
1305
1306 python_eval_statement(body);
1307 }
1308
1309 /*
1310 *
1311 * Call a python module.method directly without quoting hell
1312 * The return value (if any) is ignored.
1313 *
1314 * Arguments:
1315 * orig_object - a string containing "module.method", the name of a python method
1316 * args - a string containing the argument that will be passed to "module.method"
1317 *
1318 * Return value:
1319 * A new_malloc()ed string containing the repr()d return value of the method (success)
1320 * A new_malloc()ed zero length string, if something went wrong (failure)
1321 */
call_python_directly(const char * orig_object,char * args)1322 char * call_python_directly (const char *orig_object, char *args)
1323 {
1324 char *object = NULL, *module = NULL, *method = NULL;
1325 PyObject *mod_py = NULL, *meth_py = NULL, *args_py = NULL;
1326 PyObject *pModule = NULL, *pFunc = NULL, *pArgs = NULL, *pRetVal = NULL;
1327 PyObject *retval_repr = NULL;
1328 const char *r = NULL;
1329 char *retvalstr = NULL;
1330
1331 /* BAH! */
1332 if (!orig_object)
1333 RETURN_EMPTY;
1334
1335 object = LOCAL_COPY(orig_object);
1336 module = object;
1337 if (!(method = strchr(module, '.')))
1338 {
1339 my_error("Usage: /PYDIRECT module.method arguments");
1340 RETURN_EMPTY;
1341 }
1342 *method++ = 0;
1343
1344 mod_py = Py_BuildValue("z", module);
1345 pModule = PyImport_Import(mod_py);
1346 Py_XDECREF(mod_py);
1347
1348 if (pModule == NULL)
1349 {
1350 my_error("PYDIRECT: Unable to import module %s", module);
1351 goto c_p_d_error;
1352 }
1353
1354 pFunc = PyObject_GetAttrString(pModule, method);
1355 if (pFunc == NULL)
1356 {
1357 my_error("PYDIRECT: The module %s has nothing named %s", module, method);
1358 goto c_p_d_error;
1359 }
1360
1361 if (!PyCallable_Check(pFunc))
1362 {
1363 my_error("PYDIRECT: The thing named %s.%s is not a function", module, method);
1364 goto c_p_d_error;
1365 }
1366
1367 if (!(pArgs = PyTuple_New(1)))
1368 goto c_p_d_error;
1369
1370 if (!(args_py = Py_BuildValue("z", args)))
1371 goto c_p_d_error;
1372
1373 if ((PyTuple_SetItem(pArgs, 0, args_py)))
1374 goto c_p_d_error;
1375 args_py = NULL; /* args_py now belongs to the tuple! */
1376
1377 if (!(pRetVal = PyObject_CallObject(pFunc, pArgs)))
1378 goto c_p_d_error;
1379
1380 if (!(retval_repr = PyObject_Repr(pRetVal)))
1381 goto c_p_d_error;
1382
1383 if (!(r = PyUnicode_AsUTF8(retval_repr)))
1384 goto c_p_d_error;
1385
1386 retvalstr = malloc_strdup(r);
1387 goto c_p_d_cleanup;
1388
1389 c_p_d_error:
1390 output_traceback();
1391
1392 c_p_d_cleanup:
1393 Py_XDECREF(pArgs);
1394 Py_XDECREF(pFunc);
1395 Py_XDECREF(pModule);
1396 Py_XDECREF(pRetVal);
1397
1398 RETURN_MSTR(retvalstr);
1399 }
1400
1401 /*
1402 * /PYDIRECT -- Call a python module.method directly, without using
1403 * PyRun[Simple]String() [which handles syntax parsing]
1404 *
1405 * Usage:
1406 * /PYDIRECT module.method arguments
1407 *
1408 * You can only call "module.method" python functions that accept exactly
1409 * one string as its input parameters. If you need to call anything more
1410 * sophisticated than that, you need to use /PYTHON or $python() to handle
1411 * the parsing.
1412 */
BUILT_IN_COMMAND(pydirect_cmd)1413 BUILT_IN_COMMAND(pydirect_cmd)
1414 {
1415 char *pyfuncname;
1416 char *x;
1417
1418 if (!args || !*args)
1419 {
1420 say("Usage: /PYDIRECT module.method arguments");
1421 return;
1422 }
1423
1424 pyfuncname = new_next_arg(args, &args);
1425 x = call_python_directly(pyfuncname, args);
1426 new_free(&x);
1427 }
1428
1429
1430 /*
1431 * output_traceback - output a python exception in an epic-friendly way
1432 *
1433 * Certain things may cause Python Exceptions. When we detect that an
1434 * exception has occurred, we call this function to handle it.
1435 *
1436 * Arguments: None
1437 * Return value : None
1438 */
output_traceback(void)1439 void output_traceback (void)
1440 {
1441 PyObject *ptype, *pvalue, *ptraceback;
1442 PyObject *ptype_repr, *pvalue_repr, *ptraceback_repr;
1443 char *ptype_str, *pvalue_str, *ptraceback_str;
1444
1445 say("The python evaluation threw an exception.");
1446 #if 0
1447 PyErr_Print();
1448 PyErr_Fetch(&ptype, &pvalue, &ptraceback);
1449 if (ptype != NULL)
1450 {
1451 ptype_repr = PyObject_Repr(ptype);
1452 ptype_str = PyUnicode_AsUTF8(ptype_repr);
1453 say("Exception Type: %s", ptype_str);
1454 }
1455 if (pvalue != NULL)
1456 {
1457 pvalue_repr = PyObject_Repr(pvalue);
1458 pvalue_str = PyUnicode_AsUTF8(pvalue_repr);
1459 say("Value: %s", pvalue_str);
1460 }
1461 if (ptraceback != NULL)
1462 {
1463 #if 0
1464 ptraceback_repr = PyObject_Repr(ptraceback);
1465 ptraceback_str = PyUnicode_AsUTF8(ptraceback_repr);
1466 say("Traceback: %s", ptraceback_str);
1467 #endif
1468 }
1469 Py_XDECREF(ptype);
1470 Py_XDECREF(pvalue);
1471 Py_XDECREF(ptraceback);
1472 #endif
1473 return;
1474 }
1475
1476