Index: tools/Blender.py =================================================================== --- tools/Blender.py (revision 15538) +++ tools/Blender.py (working copy) @@ -9,6 +9,9 @@ * custom printout * wrapper functions +Contributor(s): +- Dietrich Bollmann - added command port build code. + TODO: clean up and sanitise code - crosscheck with btools and SConstruct to kill any code duplication @@ -163,6 +166,8 @@ syslibs += Split(lenv['BF_OPENGL_LIB']) if lenv['OURPLATFORM'] in ('win32-vc', 'win32-mingw','linuxcross'): syslibs += Split(lenv['BF_PTHREADS_LIB']) + if lenv['WITH_COMMAND_PORT'] or lenv['WITH_BLASH']: # (dietrich) + syslibs += Split(lenv['READLINE_LIB']) syslibs += Split(lenv['LLIBS']) @@ -417,6 +422,8 @@ print bc.WARNING+'Not building '+bc.ENDC+bc.OKGREEN+libname+bc.ENDC+' for '+bc.OKBLUE+'BF_QUICK'+bc.ENDC # note: libs is a global add_lib_to_dict(self, libs, libtype, libname, priority) + if lenv['WITH_COMMAND_PORT']: # (dietrich) + lenv.Append(CPPDEFINES=['WITH_COMMAND_PORT']) def BlenderProg(self=None, builddir=None, progname=None, sources=None, includes=None, libs=None, libpath=None, binarykind=''): print bc.HEADER+'Configuring program '+bc.ENDC+bc.OKGREEN+progname+bc.ENDC Index: tools/btools.py =================================================================== --- tools/btools.py (revision 15538) +++ tools/btools.py (working copy) @@ -59,6 +59,7 @@ 'BF_PROFILE_FLAGS', 'LCGDIR', 'WITH_BF_VERSE', 'BF_VERSE_INCLUDE', 'VERSE_BUILD_BINARY', 'VERSE_BUILD_DIR', 'VERSE_REGEN_PROTO', + 'WITH_COMMAND_PORT', 'WITH_BLASH', 'READLINE_LIB', 'BF_TWEAK_MODE', 'BF_SPLIT_SRC', 'WITHOUT_BF_INSTALL', 'WITH_BF_OPENMP', @@ -96,7 +97,8 @@ def validate_targets(targs, bc): valid_list = ['.', 'blender', 'blenderstatic', 'blenderplayer', 'webplugin', 'blendernogame', 'blenderstaticnogame', 'release', - 'everything', 'clean', 'install-bin', 'install', 'nsis'] + 'everything', 'clean', 'install-bin', 'install', 'nsis', + 'blash'] # (dietrich) oklist = [] for t in targs: if t in valid_list: @@ -323,6 +325,10 @@ (BoolOption('BF_BUILDINFO', 'Buildtime in splash if true', 'true')), + (BoolOption('WITH_COMMAND_PORT', 'Build Blender with command port if true', 'false')), + (BoolOption('WITH_BLASH', 'Build blash - the blender python shell - if true', 'false')), + ('READLINE_LIB', 'readline libraries', ''), + (BoolOption('BF_TWEAK_MODE', 'Enable tweak mode if true', 'false')), (BoolOption('BF_SPLIT_SRC', 'Split src lib into several chunks if true', 'false')), (BoolOption('WITHOUT_BF_INSTALL', 'dont install if true', 'false')), Index: source/creator/creator.c =================================================================== --- source/creator/creator.c (revision 15538) +++ source/creator/creator.c (working copy) @@ -22,7 +22,7 @@ * * The Original Code is: all of this file. * - * Contributor(s): none yet. + * Contributor(s): Dietrich Bollmann. * * ***** END GPL LICENSE BLOCK ***** */ @@ -83,6 +83,10 @@ #include "nla.h" #include "datatoc.h" +#ifdef WITH_COMMAND_PORT +#include "commandport.h" /* Blender command port (dietrich) */ +#endif + /* for passing information between creator and gameengine */ #include "SYS_System.h" @@ -108,6 +112,9 @@ /* Local Function prototypes */ static void print_help(); +#ifdef WITH_COMMAND_PORT +static void print_debug_command_port_help(); /* (dietrich) */ +#endif static void print_version(); @@ -224,6 +231,13 @@ #ifdef WIN32 printf (" -R\t\tRegister .blend extension\n"); #endif +#ifdef WITH_COMMAND_PORT + printf (" -c | --command-port \n" /* (dietrich) */ + " \t\tStart the Command Port using port \n"); + printf (" --debug-command-port \tTurn debug mode on for the command port.\n"); /* (dietrich) */ + printf (" \t\tFour different debug levels are defined: 1, 2, 3 and 4.\n"); + printf (" \t\tFor more information try --debug-command-port help.\n"); +#endif printf (" -v\t\tPrint Blender version and exit\n"); printf (" --\t\tEnds option processing. Following arguments are \n"); printf (" \t\t passed unchanged. Access via Python's sys.argv\n"); @@ -252,7 +266,37 @@ printf (" \"blender -b test.blend -o /tmp -f 1\" works as expected.\n\n"); } +#ifdef WITH_COMMAND_PORT +/** + help message for the command port debug mode + (dietrich) +*/ +static void print_debug_command_port_help() +{ + printf("\n" + "* Command Port Debug Mode\n" + "\n" + "Usage:\n" + "\n" + " blender --command-port --debug-command-port [more options]\n" + "\n" + "Print messages for debugging the command port functionality.\n" + "This mode is very useful when developing new command port client applications.\n" + "\n" + "Four different debug levels are defined:\n" + "\n" + " 1 - Print general command port debug messages.\n" + " 2 - Print more detailed information about the evaluation of received commands,\n" + " the command packages received from a Blender client and the result packages\n" + " sent back to the client after evaluating the commands.\n" + " 3 - Hexdump the received packages before processing them.\n" + " 4 - Hexdump the received packages without processing them.\n" + "\n" + ); +} +#endif + double PIL_check_seconds_timer(void); extern void winlay_get_screensize(int *width_r, int *height_r); @@ -269,6 +313,10 @@ { int a, i, stax=0, stay=0, sizx, sizy, scr_init = 0; SYS_SystemHandle syshandle; +#ifdef WITH_COMMAND_PORT + unsigned short port; /* command port */ + int command_port_debug_level; /* command port debug level */ +#endif #if defined(WIN32) || defined (__linux__) int audio = 1; @@ -554,6 +602,61 @@ for(a=1; apy_globaldict = py_dict; - if( !setup_armature_weakrefs()){ + if( !BPY_setup_armature_weakrefs()){ printf("Oops - weakref dict\n"); free_libblock( &G.main->script, script ); ReleaseGlobalDictionary( py_dict ); @@ -1539,7 +1539,7 @@ PyList_SET_ITEM(tarmats, index, tarmat); } - if (!setup_armature_weakrefs()) { + if (!BPY_setup_armature_weakrefs()) { fprintf(stderr, "Oops - weakref dict setup\n"); PyGILState_Release(gilstate); @@ -1707,7 +1707,7 @@ tarmat = newMatrixObject((float *)ct->matrix, 4, 4, Py_NEW); idprop = BPy_Wrap_IDProperty( NULL, con->prop, NULL); - if (!setup_armature_weakrefs()) { + if (!BPY_setup_armature_weakrefs()) { fprintf(stderr, "Oops - weakref dict setup\n"); PyGILState_Release(gilstate); return; @@ -2021,7 +2021,7 @@ setitem_retval = EXPP_dict_set_item_str(bpy_pydriver_Dict, "self", bpy_ob); - if( !setup_armature_weakrefs()){ + if( !BPY_setup_armature_weakrefs()){ fprintf( stderr, "Oops - weakref dict setup\n"); PyGILState_Release(gilstate); return result; @@ -2108,7 +2108,7 @@ } - if( !setup_armature_weakrefs()){ + if( !BPY_setup_armature_weakrefs()){ fprintf(stderr, "Oops - weakref dict\n"); PyGILState_Release(gilstate); return -1; @@ -2262,7 +2262,7 @@ gilstate = PyGILState_Ensure(); - if( !setup_armature_weakrefs()){ + if( !BPY_setup_armature_weakrefs()){ printf("Oops - weakref dict, this is a bug\n"); PyGILState_Release(gilstate); return; @@ -2504,7 +2504,7 @@ gilstate = PyGILState_Ensure(); - if( !setup_armature_weakrefs()){ + if( !BPY_setup_armature_weakrefs()){ printf("Oops - weakref dict, this is a bug\n"); PyGILState_Release(gilstate); return 0; Index: source/blender/commandport/include/commandport.h =================================================================== --- source/blender/commandport/include/commandport.h (revision 0) +++ source/blender/commandport/include/commandport.h (revision 0) @@ -0,0 +1,103 @@ +/* + * $Id: commandport.h, v 1.0 2007/05/02, dietrich, tokyo $ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2007 by the Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Author: Dietrich Bollmann + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + * + * Main Blender Command Port header file. + * + * All command port functionality in files outside of the + * directory `source/blender/commandport/' is implemented + * by calling the functions imported from this file: + * + * - `commandport_init()' initializes the command port and + * is called from function `main()' + * in file `source/creator/creator.c' + * when Blender is started with the `-c' / `--bcp' option; + * + * - `commandport_start()' starts the command port and + * is called from function `screenmain()' + * in file `source/blender/src/editscreen.c' + * when Blender is started with the `-c' / `--bcp' option; + * + * - When the command port thread receives a command sequence from + * a client, a `COMMAND_PORT_INPUT' event token is appended + * to the end of the Blender main event loop queue. + * When the Blender main event handler finds such a token, + * the function `commandport_handle_input_allocate()' is + * called to handle the event. + * See the Blender main event loop in function `screenmain()', + * file `source/blender/src/editscreen.c'. + * + * - When Blender was started with the `-c' / `--bcp' option + * the function `commandport_destroy()' cleans up the command port code + * when Blender exists. + * It is called from function `exit_usiblender()' + * in file `source/blender/src/usiblender.c'. + * + * source file: ../blender/src/commandport.c + * + */ + +#ifndef COMMANDPORT_H +#define COMMANDPORT_H + +/** + Called from function `main()' + in file `source/creator/creator.c' +*/ +void commandport_init(unsigned short port); + +/** + Called from function `main()' + in file `source/creator/creator.c' + + Activate the printing of debug messages for the command port + and set their verbosity level. +*/ +void commandport_set_debug_level(int debug_level); + +/** + Called from function `screenmain()' + in file `source/blender/src/editscreen.c' +*/ +void commandport_start(); + +/** + Called from function `screenmain()' + in file `source/blender/src/editscreen.c' +*/ +void commandport_handle_input_allocate(void* args); + +/** + Called from function `exit_usiblender()' + in file `source/blender/src/usiblender.c' +*/ +void commandport_destroy(); + +#endif /* COMMANDPORT_H */ + +/* fin */ Index: source/blender/commandport/SConscript =================================================================== --- source/blender/commandport/SConscript (revision 0) +++ source/blender/commandport/SConscript (revision 0) @@ -0,0 +1,49 @@ +# -*- mode: python -*- +# +# $Id: SConscript, v 1.0 2007/05/01, dietrich, tokyo $ +# +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# The Original Code is Copyright (C) 2007 by the Blender Foundation. +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Author: Dietrich Bollmann +# Contributor(s): none yet. +# +# ***** END GPL LICENSE BLOCK ***** +# +# Command port main build file. +# + +Import('env') + +sconscripts = [] + +if env['WITH_COMMAND_PORT'] == 1: + sconscripts.append('blender/SConscript') + +if env['WITH_BLASH'] == 1: + sconscripts.append('blash/SConscript') + +if env['WITH_COMMAND_PORT'] == 1 or env['WITH_BLASH'] == 1: + sconscripts.append('utilities/SConscript') + +SConscript(sconscripts) + +# fin. Index: source/blender/commandport/blash/include/blash_usage.h =================================================================== --- source/blender/commandport/blash/include/blash_usage.h (revision 0) +++ source/blender/commandport/blash/include/blash_usage.h (revision 0) @@ -0,0 +1,51 @@ +/* + * $Id: blash_usage.h, v 1.0 2007/07/09, dietrich, tokyo $ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2007 by the Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Author: Dietrich Bollmann + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + * + * blash usage and help functions. + * + * source file: ../src/blash_usage.c + * + */ + +#ifndef BLASH_USAGE_H + +/** + Print `blash' usage information / help text. +*/ +void print_blash_usage(); + +/** + Print `blash' shell command usage help text. + */ +void print_blash_help(); + +#define BLASH_USAGE_H +#endif /* BLASH_USAGE_H */ + +/* fin */ Index: source/blender/commandport/blash/SConscript =================================================================== --- source/blender/commandport/blash/SConscript (revision 0) +++ source/blender/commandport/blash/SConscript (revision 0) @@ -0,0 +1,38 @@ +# -*- mode: python -*- +# +# $Id: SConscript, v 1.0 2007/05/01, dietrich, tokyo $ +# +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# The Original Code is Copyright (C) 2007 by the Blender Foundation. +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Author: Dietrich Bollmann +# Contributor(s): none yet. +# +# ***** END GPL LICENSE BLOCK ***** +# +# blash main build file. +# + +SConscript([ + 'src/SConscript', + ]) + +# fin. Index: source/blender/commandport/blash/src/SConscript =================================================================== --- source/blender/commandport/blash/src/SConscript (revision 0) +++ source/blender/commandport/blash/src/SConscript (revision 0) @@ -0,0 +1,44 @@ +# -*- mode: python -*- +# +# $Id: SConscript, v 1.0 2007/05/01, dietrich, tokyo $ +# +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# The Original Code is Copyright (C) 2007 by the Blender Foundation. +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Author: Dietrich Bollmann +# Contributor(s): none yet. +# +# ***** END GPL LICENSE BLOCK ***** +# +# blash source build file. + +Import ('env') + +incs = ''' + ../include + ../../utilities/include +''' + +sources = env.Glob('*.c') + +env.BlenderLib ('blash', sources, Split(incs), [], libtype=['blash'], priority=[0]) + +# fin. Index: source/blender/commandport/blash/src/blash.c =================================================================== --- source/blender/commandport/blash/src/blash.c (revision 0) +++ source/blender/commandport/blash/src/blash.c (revision 0) @@ -0,0 +1,142 @@ +/* + * $Id: blash.c, v 1.0 2007/05/01, dietrich, tokyo $ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2007 by the Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Author: Dietrich Bollmann + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + * + * blash main file. + * + */ + +#include /* for printf() and fprintf() */ +#include /* for atoi() and exit() */ +#include /* for getopt() */ + +#include "bcp_debug.h" /* for bcp_debug() */ +#include "blash_usage.h" /* for print_blash_usage() */ +#include "bcp_shell.h" /* for bcp_shell() */ +#include "bcp_defaults.h" /* default values: default IP address, default port, ... */ +#include "message_client.h" /* message client to read and send messages */ +#include "string_buffer.h" /* string buffer */ + +/** + Parameters: + Using 'getopt' to parse the parameters. +*/ +extern char* optarg; /* needed to access option arguments */ + +/* Parameter definitions */ +static struct option longopts[] = { + { "debug", optional_argument, NULL, 'd' }, + { "help", no_argument, NULL, 'h' }, + { "IP-address", required_argument, NULL, 'i' }, + { "port", required_argument, NULL, 'p' }, + { "shell-mode", no_argument, NULL, 's' }, + { "eval-mode", no_argument, NULL, 'e' }, + { "file-mode", no_argument, NULL, 'f' }, + { "retries", required_argument, NULL, 'r' }, + { "retry-sleeptime", required_argument, NULL, 't' }, + { "init", required_argument, NULL, 'I' }, + { NULL, 0, NULL, 0 } +}; + +/** + blash main function. + */ +int main(int argc, char *argv[]) +{ + char* server_IP_address; /* server IP address (dotted quad) */ + unsigned short server_port; /* server port */ + int mode; /* shell-mode / text-mode */ + int retries; /* number of times to try to connect to server */ + double retry_sleeptime; /* time to sleep before retrying to connect to server + * in seconds used only if `retries' is not 0 */ + char* init_command; /* if not NULL the `init_command' command is send + * to Blender immediately after (re)connecting */ + + int c; + + init_command = NULL; /* NULL - no init command */ + + /* defaults */ + server_IP_address = BCP_DEFAULT_IP; + server_port = BCP_DEFAULT_PORT; + mode = BCP_SINGLE_MODE; + retries = 0; + retry_sleeptime = 0.5; + + /* parsing the command line parameters */ + while ((c = getopt_long(argc, argv, "hd::i:p:sefr:t:", longopts, NULL)) != -1) { + + switch(c) { + + /* help */ + case 'h': print_blash_usage(); exit(0); break; + + /* set debug message level */ + case 'd': bcp_set_debug_level((optarg == NULL) ? 1 : atoi(optarg)); break; + + /* server address and port */ + case 'i': server_IP_address = optarg; break; + case 'p': server_port = atoi(optarg); break; + + /* shell modes */ + case 's': mode = BCP_SINGLE_MODE; break; + case 'e': mode = BCP_EVAL_MODE; break; + case 'f': mode = BCP_FILE_MODE; break; + + /* retries to connect to Blender server */ + case 'r': retries = atoi(optarg); break; + case 't': retry_sleeptime = atof(optarg); break; + + /* command send to Blender for evaluation + immediately after (re)connecting */ + case 'I': init_command = optarg; break; + + default: + printf("ERROR: Unrecognized option `-%c'\n", c); + printf("\n"); + print_blash_usage(); + exit(1); + } + } + + /* start the shell */ + printf("This is Blash - the GNU BLender-Again SHell :)\n"); + if (bcp_debug()) printf("Connecting to Blender server at IP-address %s, port %d...\n", + server_IP_address, server_port); + + /* starting the shell */ + bcp_shell_wait(server_IP_address, server_port, mode, retries, retry_sleeptime, init_command); + + /* done */ + printf("\n"); + printf("bye...\n"); + printf("\n"); + exit(0); +} + +/* fin */ Index: source/blender/commandport/blash/src/blash_usage.c =================================================================== --- source/blender/commandport/blash/src/blash_usage.c (revision 0) +++ source/blender/commandport/blash/src/blash_usage.c (revision 0) @@ -0,0 +1,121 @@ +/* + * $Id: blash_usage.c, v 1.0 2007/07/09, dietrich, tokyo $ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2007 by the Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Author: Dietrich Bollmann + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + * + * blash usage and help functions. + * + */ + +/* fin */ +/* shell_client.c - Dietrich Bollmann */ + +#include /* for printf() and fprintf() */ + +#include "bcp_defaults.h" /* default values: default IP address, default port, ... */ + +#include "blash_usage.h" + +/** + Print `blash' usage information / help text. + */ +void print_blash_usage() +{ + /* "01234567890123456789012345678901234567890123456789012345678901234567890123456789\n" */ + printf(" \n" + " This is Blash - the GNU BLender-Again SHell.\n" + " \n" + " Blash is used to connect to a running Blender instance\n" + " started in server mode and to \"remote control\" it\n" + " via the Blender Python scripting API.\n" + " \n" + " Usage: blash [OPTION]*...\n" + " \n" + " Options:\n" + " \n" + " -h, --help Print this help message.\n" + " -d[], --debug[=] Print debug messages. The higher the \n" + " verbosity level, the more detailed are \n" + " the debug messages. Currently 3 levels \n" + " are implemented (level 0, 1, 2).\n" + " Default: debug level 0; --debug / -d has\n" + " the same effect as --debug=1 / -d1. \n" + " -i, --IP-address IP address of Blender server.\n" + " default: %s\n" + " -p, --port Port of Blender server.\n" + " Default: %d\n" + " -s, --shell-mode start in shell (single) mode (default).\n" + " -e, --eval-mode start in eval mode.\n" + " -f, --file-mode start in file mode.\n" + " -r, --retries Number of times blash should retry to \n" + " connect to the Blender server.\n" + " -t, --retry-sleeptime Time to sleep before next try to connect.\n" + " Te be used together with `--retries'.\n" + " -I, --init Initialization code for the Blender server.\n" + " is evaluated immediately\n" + " after (re)connecting to the Blender server.\n" + " \n" + " Examples:\n" + " \n" + " blash\n" + " blash --IP-address %s --port %d --shell-mode\n" + " blash --retries 20 --retry-sleeptime 0.1\n" + " \n" + " Copyright (c) published under the GNU General Public License.\n" + " Written by Dietrich Bollmann.\n", + BCP_DEFAULT_IP, + BCP_DEFAULT_PORT, + BCP_DEFAULT_IP, BCP_DEFAULT_PORT /* example 2 */ + ); +} + +/** + Print `blash' shell command usage help text. + */ +void print_blash_help() +{ + /* "01234567890123456789012345678901234567890123456789012345678901234567890123456789\n" */ + printf(" \n" + " * Blash Commands:\n" + " \n" + " help - Print the current help text.\n" + " \n" + " . - Switch temporarily to text input mode. Text input\n" + " mode has to be terminated with another dot.\n" + " .shell, .single, .s - Switch to shell/single input mode.\n" + " .eval, .e - Switch to eval input mode.\n" + " .file, .f - Switch to file input mode.\n" + " \n" + " reconnect [] - Reconnect to the Blender server; use if given.\n" + " bye, quit, exit - Exit Blash.\n" + " \n" + " ...all other inputs are interpreted as Blender python commands.\n" + " \n" + ); +} + +/* fin */ Index: source/blender/commandport/blash/README =================================================================== --- source/blender/commandport/blash/README (revision 0) +++ source/blender/commandport/blash/README (revision 0) @@ -0,0 +1,72 @@ +# +# $Id: README, v 1.0 2007/05/01, dietrich, tokyo $ +# +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# The Original Code is Copyright (C) 2007 by the Blender Foundation. +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Author: Dietrich Bollmann +# Contributor(s): none yet. +# +# ***** END GPL LICENSE BLOCK ***** +# +# blash readme file. + + +* blash - the BLender-Again SHell + +Blash is a Blender-Python shell which can be used together +with Blender when started in server mode. + +See also the BCP (Blender Command Port) README (../README). + +Example: + + # starting the Blender server: + + $ blender -w -p 10 10 800 600 --command-port 6789 & + + # using blash to send Python commands to the Blender server: + + $ blash --port 6789 + + This is Blash - the GNU BLender-Again SHell :) + Connection to Blender Server established. (IP address: 127.0.0.1, port: 6789) + + >>> from Blender import * + >>> + >>> vertices = [[1, 1, 0], [-1, 1, 0], [-1, -1, 0], [1, -1, 0], [0, 0, 1.27]] + >>> faces = [[3, 2, 1, 0], [0, 1, 4], [1, 2, 4], [2, 3, 4], [3, 0, 4]] + >>> + >>> mesh = Mesh.New('mesh') + >>> mesh.verts.extend(vertices) + >>> mesh.faces.extend(faces) + >>> + >>> scene = Scene.GetCurrent() + >>> object = scene.objects.new(mesh, 'object') + >>> Redraw() + >>> + >>> bye + + bye... + +For more information see http://formgames.org/blender/command-port + +# fin. Index: source/blender/commandport/blender/include/bcp_server.h =================================================================== --- source/blender/commandport/blender/include/bcp_server.h (revision 0) +++ source/blender/commandport/blender/include/bcp_server.h (revision 0) @@ -0,0 +1,43 @@ +/* + * $Id: bcp_server.h, v 1.0 2007/05/02, dietrich, tokyo $ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2007 by the Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Author: Dietrich Bollmann + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + * + * Blender command port server. + * + * source file: ../src/bcp_server.c]] + * + */ + +#ifndef BCP_SERVER_H +#define BCP_SERVER_H + +void bcp_server(unsigned short port); + +#endif /* BCP_SERVER_H */ + +/* fin */ Index: source/blender/commandport/blender/include/bcp_thread.h =================================================================== --- source/blender/commandport/blender/include/bcp_thread.h (revision 0) +++ source/blender/commandport/blender/include/bcp_thread.h (revision 0) @@ -0,0 +1,48 @@ +/* + * $Id: bcp_thread.h, v 1.0 2007/05/02, dietrich, tokyo $ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2007 by the Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Author: Dietrich Bollmann + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + * + * the command port server is running in its own thread. + * The communication with the main Blender thread is done + * via the Blender queue. + * + * source file: ../src/bcp_thread.c + * + */ + +#ifndef BCP_THREAD_H +#define BCP_THREAD_H + +/** + Start the command port server thread. +*/ +void bcp_thread_start(unsigned short port); + +#endif /* BCP_THREAD_H */ + +/* fin */ Index: source/blender/commandport/blender/include/py_stdouterr_buffer.h =================================================================== --- source/blender/commandport/blender/include/py_stdouterr_buffer.h (revision 0) +++ source/blender/commandport/blender/include/py_stdouterr_buffer.h (revision 0) @@ -0,0 +1,121 @@ +/* + * $Id: py_stdouterr_buffer.h, v 1.0 2007/05/01, dietrich, tokyo $ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2007 by the Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Author: Dietrich Bollmann + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + * + * A buffer for saving Pythons stdout / stderr + * and accessing it after in form of a c string buffer. + * + * source file: ../src/py_stdouterr_buffer.c + * + */ + +#ifndef PY_STDOUTERR_BUFFER_H +#define PY_STDOUTERR_BUFFER_H + +typedef struct py_stdouterr_buffer_struct *py_stdouterr_buffer; + +/** + Make a new text buffer. +*/ +py_stdouterr_buffer py_stdouterr_buffer_new(); + +/** + Delete a text buffer. +*/ +void py_stdouterr_buffer_delete(py_stdouterr_buffer buffer); + +/** + Redirect stdout to the string buffer. +*/ +void py_stdouterr_buffer_redirect_stdout(py_stdouterr_buffer buffer); + +/** + Redirect stderr to the string buffer. +*/ +void py_stdouterr_buffer_redirect_stderr(py_stdouterr_buffer buffer); + +/** + Redirect stdout/stderr to the string buffer. +*/ +void py_stdouterr_buffer_redirect(py_stdouterr_buffer buffer); + +/** + Restore stdout. +*/ +void py_stdouterr_buffer_restore_stdout(py_stdouterr_buffer buffer); + +/** + Restore stdout/stderr. +*/ +void py_stdouterr_buffer_restore_stderr(py_stdouterr_buffer buffer); + +/** + Restore stdout/stderr. +*/ +void py_stdouterr_buffer_restore(py_stdouterr_buffer buffer); + +/** + Retrive the content of the stdout string buffer. + + NOTE: + The retrived string is allocated starage and has to be freed! +*/ +char* py_stdouterr_buffer_get_stdout_allocate(py_stdouterr_buffer buffer); + +/** + Retrive the content of the stderr string buffer. + + NOTE: + The retrived string is allocated starage and has to be freed! +*/ +char* py_stdouterr_buffer_get_stderr_allocate(py_stdouterr_buffer buffer); + +/** + Print the stdout buffer to STDOUT. +*/ +void py_stdouterr_buffer_print_stdout(py_stdouterr_buffer buffer); + +/** + Print the stderr buffer to STDERR. +*/ +void py_stdouterr_buffer_print_stderr(py_stdouterr_buffer buffer); + +/** + Print first the stdout buffer to STDOUT + and after the stderr buffer to STDERR. +*/ +void py_stdouterr_buffer_print(py_stdouterr_buffer buffer); + +/** + Clear stdout/stderr buffers. +*/ +void py_stdouterr_buffer_clear_buffers(py_stdouterr_buffer buffer); + +#endif /* PY_STDOUTERR_BUFFER_H */ + +/* fin */ Index: source/blender/commandport/blender/include/bcp_handle_client.h =================================================================== --- source/blender/commandport/blender/include/bcp_handle_client.h (revision 0) +++ source/blender/commandport/blender/include/bcp_handle_client.h (revision 0) @@ -0,0 +1,43 @@ +/* + * $Id: bcp_handle_client.h, v 1.0 2007/05/02, dietrich, tokyo $ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2007 by the Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Author: Dietrich Bollmann + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + * + * Handle command port client + * + * source file: ../src/bcp_handle_client.c + * + */ + +#ifndef BCP_HANDLE_CLIENT_H +#define BCP_HANDLE_CLIENT_H + +void bcp_handle_client(int client_socket); /* TCP client handling function */ + +#endif /* BCP_HANDLE_CLIENT_H */ + +/* fin */ Index: source/blender/commandport/blender/include/bcp_blender.h =================================================================== --- source/blender/commandport/blender/include/bcp_blender.h (revision 0) +++ source/blender/commandport/blender/include/bcp_blender.h (revision 0) @@ -0,0 +1,71 @@ +/* + * $Id: bcp_blender.h, v 1.0 2007/05/18, dietrich, tokyo $ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2007 by the Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Author: Dietrich Bollmann + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + * + * Blender command port handler functionality. + * + * source file: ../src/bcp_blender.c + * + */ + +#ifndef BCP_BLENDER_H +#define BCP_BLENDER_H + +typedef struct bcp_blender_handler_struct* bcp_blender_handler; + +/** + Make a new BCP Blender handler to execute the command port input. +*/ +bcp_blender_handler bcp_blender_handler_new(); + +/** + Delete the BCP Blender handler. +*/ +void bcp_blender_handler_delete(bcp_blender_handler handler); + +/** + Make a Blender command port event, + add it to the blender main queue, + wait for the result and return it. + + Note: + The result is returned as newly allocated character array + and has to be freed by the caller! +*/ +char* bcp_blender_handle_input_allocate(bcp_blender_handler handler, char* command); + +/* + Handler used internal by the Blender main event queue event handler. + Note: This function is wrapped into `commandport_handle_input_allocate()' + in order to use `commandport.h' as only interface between Blender and the command port. +*/ +void bcp_blender_queue_handle_input_allocate(void* args); + +#endif /* BCP_BLENDER_H */ + +/* fin */ Index: source/blender/commandport/blender/include/bcp_python_utilities.h =================================================================== --- source/blender/commandport/blender/include/bcp_python_utilities.h (revision 0) +++ source/blender/commandport/blender/include/bcp_python_utilities.h (revision 0) @@ -0,0 +1,165 @@ +/* + * $Id: bcp_python_utilities.h, v 1.0 2007/05/18, dietrich, tokyo $ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2007 by the Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Author: Dietrich Bollmann + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + * + * todo: Short description of this file + * + * source file: ../src/bcp_python_utilities.c + * + */ + +#ifndef BCP_PYTHON_UTILITIES_H +#define BCP_PYTHON_UTILITIES_H + +#define PYTHON_SUCCESS 0 +#define PYTHON_INCOMPLETE_INPUT 1 +#define PYTHON_ERROR 2 + +/* + BCP Input Mode + + The variable 'handler->input_mode' holds the current + input mode of the command port. + + Different types of input can be treated: + + - 'EVAL_INPUT_MODE' - for isolated Python expressions. + This mode corresponds to the 'Py_eval_input' Python grammar symbol. + Compare the documentation to the 'Py_eval_input' token + in http://docs.python.org/api/veryhigh.html#l2h-76 + + - 'FILE_INPUT_MODE' - for sequences of Python statements as read from a file or other source. + This is the symbol to use when compiling arbitrarily long Python source code. + This mode corresponds to the 'Py_file_input' Python grammar symbol. + Compare the documentation to the 'Py_file_input' token + in http://docs.python.org/api/veryhigh.html#l2h-77 + + - 'SINGLE_INPUT_MODE' - for single Python statements. + This is the symbol used for the interactive interpreter loop. + This mode corresponds to the 'Py_single_input' Python grammar symbol. + Compare the documentation to the 'Py_single_input' token + in http://docs.python.org/api/veryhigh.html#l2h-78 + + The input mode can be one of + 'SINGLE_INPUT_MODE', 'EVAL_INPUT_MODE' and 'FILE_INPUT_MODE' + and describes the input type expected. + + The default input mode is 'FILE_INPUT_MODE' + but can be changed at every time with a BCP Meta Command. +*/ +#define SINGLE_INPUT_MODE 0 /* shell / single command input modus */ +#define EVAL_INPUT_MODE 1 /* eval command input modus */ +#define FILE_INPUT_MODE 2 /* file command input modus (default) */ + +/* + BCP Result Print Mode + + The Result Print Mode determines the method used to + convert the result of a python run into a string representation. + + - 'BCP_REPR_PRINT_MODE' - for isolated Python expressions. + todo: add the Phython doc description + todo: add examples: + Strings for example are printed differently depending on the print mode: + RESULT (STR): THE MEANING OF PYTHON... + RESULT (REPR): 'THE MEANING OF PYTHON...' + +Compare the documentation ... + in http://docs.python.org/api/??? + + - 'BCP_STR_PRINT_MODE' - + + The default input mode is 'todo' + but can be changed at every time with a BCP Meta Command. +*/ +#define BCP_REPR_PRINT_MODE 0 +#define BCP_STR_PRINT_MODE 1 + +struct py_stdouterr_buffer_struct; + +/** + Run a c string in single input mode. + Note: For eval or file mode use 'py_input_run_allocate()'! + + This is the mode used for the interactive interpreter loop. + It corresponds to the 'Py_single_input' Python grammar symbol. + Compare the documentation to the 'Py_single_input' token + in http://docs.python.org/api/veryhigh.html#l2h-78 + */ +int py_single_input_run(const char* code, PyObject* namespace, + struct py_stdouterr_buffer_struct* stdouterr_buffer); + +/** + Run a c string in eval or file mode. + Note: For single input mode use 'py_single_input_run()'! + + Eval mode should be used for isolated Python expressions. + This mode corresponds to the 'Py_eval_input' Python grammar symbol. + Compare the documentation to the 'Py_eval_input' token + in http://docs.python.org/api/veryhigh.html#l2h-76 + + File mode should be used for sequences of Python statements + as read from a file or other source. This is the symbol to use when + compiling arbitrarily long Python source code. + This mode corresponds to the 'Py_file_input' Python grammar symbol. + Compare the documentation to the 'Py_file_input' token + in http://docs.python.org/api/veryhigh.html#l2h-77 + */ +int py_input_run_allocate(const char* code, + const int input_mode, + const int result_print_mode, + char** result, + PyObject* namespace, + struct py_stdouterr_buffer_struct* stdouterr_buffer); + +/** + Test if 'code' can be parsed and compiled with the + python grammar using 'start' as start token. + + Returns a python object with the compiled code if + the parsing and compilation was successful + and NULL if not. + + Possible start token are: + Py_eval_input, Py_file_input, or Py_single_input. + + Compare python API documentation ( http://docs.python.org/api ) for + 'Py_CompileStringFlags()' ( http://docs.python.org/api/veryhigh.html#l2h-74 ), + 'Py_eval_input' ( http://docs.python.org/api/veryhigh.html#l2h-76 ), + 'Py_file_input' ( http://docs.python.org/api/veryhigh.html#l2h-77 ) and + 'Py_single_input' ( http://docs.python.org/api/veryhigh.html#l2h-78 ). + + This code was written using an example from the "Extending/Embedding FAQ" - see: + http://www.python.org/doc/faq/extending/#how-do-i-tell-incomplete-input-from-invalid-input + which in turn was inspired by code from Alex Farber :) +*/ +/* int python_compile(const char *code, int start_token, PyObject** compiled_code); */ + +#endif /* BCP_PYTHON_UTILITIES_H */ + +/* fin */ Index: source/blender/commandport/blender/include/py_codeop.h =================================================================== --- source/blender/commandport/blender/include/py_codeop.h (revision 0) +++ source/blender/commandport/blender/include/py_codeop.h (revision 0) @@ -0,0 +1,89 @@ +/* + * $Id: py_codeop.h, v 1.0 2008/04/24, dietrich, tokyo $ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2007 by the Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Author: Dietrich Bollmann + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + * + * A C wrapper for the function 'compile_command()' + * from the Python 'codeop' module. + * + * The documentation for the Python 'codeop' module can be found + * here: http://docs.python.org/lib/module-codeop.html + * + * The function 'compile_command()' is used rather than + * 'Py_CompileString()' to implement the interactive read-eval-print + * loop as it is able to make the difference between incomplete input + * and erroneous input. + * + * source file: ../src/py_codeop.c + * + */ + +#ifndef PY_CODEOP_H +#define PY_CODEOP_H + +/** + A C wrapper for the Python command 'compile_command()' + from the Python modules 'code' and 'codeop'. + + The function 'compile_command()' is used rather than + 'Py_CompileString()' to implement the interactive read-eval-print + loop as 'compile_command()' contrary to 'Py_CompileString()' + is able to make the difference between incomplete input + and erroneous input. + + The function returns + + - a code object if the command is complete and valid; + - NULL (and not 'None' as the wrapped Python function) + if the command is incomplete; + - raises a SyntaxError if the command is complete and contains a + syntax error, or raises an OverflowError or ValueError if the + command contains an invalid literal. + + Excerpt from the documentation of 'compile_command()' + of the 'code' module: + + This function is useful for programs that want to emulate + Python's interpreter main loop (a.k.a. the read-eval-print loop). + The tricky part is to determine when the user has entered an + incomplete command that can be completed by entering more text + (as opposed to a complete command or a syntax error). + This function almost always makes the same decision as the real + interpreter main loop. + + The original documentation of 'compile_command()' can be found here: + + - 27.1 code -- Interpreter base classes + http://docs.python.org/lib/module-code.html + - 27.2 codeop -- Compile Python code + http://docs.python.org/lib/module-codeop.html : +*/ +PyObject *compile_command(const char *source); + +#endif /* PY_CODEOP_H */ + +/* fin */ Index: source/blender/commandport/blender/include/bcp_python.h =================================================================== --- source/blender/commandport/blender/include/bcp_python.h (revision 0) +++ source/blender/commandport/blender/include/bcp_python.h (revision 0) @@ -0,0 +1,52 @@ +/* + * $Id: bcp_python.h, v 1.0 2007/05/18, dietrich, tokyo $ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2007 by the Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Author: Dietrich Bollmann + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + * + * Functionality to run a python script in the Blender server. + * + * source file: ../src/bcp_python.c + * + */ + +#ifndef BCP_PYTHON_H +#define BCP_PYTHON_H + +struct py_stdouterr_buffer_struct; + +char* bcp_run_python_script_allocate(int* input_mode, + int* result_print_mode, + struct py_stdouterr_buffer_struct* stdouterr_buffer, + PyObject** namespace, + char* script, + char** shell_input_buffer, + int* shell_input_buffer_length, + int* shell_input_line_count); + +#endif /* BCP_PYTHON_H */ + +/* fin */ Index: source/blender/commandport/blender/SConscript =================================================================== --- source/blender/commandport/blender/SConscript (revision 0) +++ source/blender/commandport/blender/SConscript (revision 0) @@ -0,0 +1,37 @@ +# -*- mode: python -*- +# +# $Id: SConscript, v 1.0 2007/05/18, dietrich, tokyo $ +# +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# The Original Code is Copyright (C) 2007 by the Blender Foundation. +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Author: Dietrich Bollmann +# Contributor(s): none yet. +# +# ***** END GPL LICENSE BLOCK ***** +# +# SCons build file for ..../commandport/blender/SConscript/src + +SConscript([ + 'src/SConscript', + ]) + +# fin. Index: source/blender/commandport/blender/src/bcp_blender.c =================================================================== --- source/blender/commandport/blender/src/bcp_blender.c (revision 0) +++ source/blender/commandport/blender/src/bcp_blender.c (revision 0) @@ -0,0 +1,300 @@ +/* + * $Id: bcp_blender.c, v 1.0 2007/05/18, dietrich, tokyo $ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2007 by the Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Author: Dietrich Bollmann + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + * + * Blender command port handler functionality. + * + * header file: ../include/bcp_blender.h + * + */ + +#include +#include +#include + +#include + +#include "BIF_mainqueue.h" +#include "BPY_extern.h" + +#include "mydevice.h" /* for COMMAND_PORT_INPUT */ + +#include "error_codes.h" +#include "bcp_python_utilities.h" +#include "bcp_python.h" +#include "py_stdouterr_buffer.h" +#include "bcp_defaults.h" + +#include "bcp_blender.h" + +/* a structure to pass arguments between + command port and blender thread + and to synchronize them. +*/ +typedef struct bcp_blender_handler_struct { + + /* BCP input mode - see bcp_python.h. + The input mode can be one of + 'SINGLE_INPUT_MODE', 'EVAL_INPUT_MODE' and 'FILE_INPUT_MODE' + The default is 'FILE_INPUT_MODE'. + */ + int input_mode; + + /* Print mode: + The result can be formated using two different print functions: + - BCP_REPR_PRINT_MODE, uses 'PyObject_Repr()' to print the result, + Example: Stings are printed with "'": 'THE MEANING OF PYTHON...' + - BCP_STR_PRINT_MODE, uses 'PyObject_Str()' to print the result, + Example: Stings are printed without "'": THE MEANING OF PYTHON... + The default is BCP_REPR_PRINT_MODE + */ + int result_print_mode; + + /* a buffer to store pythons stdout/stderr + and send it to the client */ + py_stdouterr_buffer stdouterr_buffer; + + /* Python name space of the command port instance */ + PyObject* namespace; + + /* the command to be run by the Blender thread */ + char* command; + + /* shell mode: buffer holding the (possibly incomplete) + code entered until the current moment */ + char* shell_input_buffer; + + /* shell mode: length of the 'shell_input_buffer' */ + int shell_input_buffer_length; + + /* shell mode: line index of the current shell input */ + int shell_input_line_count; + + /* the result delivered by the Blender thread */ + char* result; + + /* mutex to protect struct against + simultaneous access by BCP and Blender threads */ + pthread_mutex_t mutex; + + /* thread condition variable to implement a master/servant model: + - The BCP thread waits on the condition for the result of his request + - The Blender thread fills in the result slot + and signals the BCP that his run request has been finished + and the result can be read. + */ + pthread_cond_t condition; + +} bcp_blender_handler_struct; + +/**/ +bcp_blender_handler bcp_blender_handler_new() +{ + /* allocate memory for the handler data struct */ + bcp_blender_handler handler; + handler = (bcp_blender_handler) malloc(sizeof(bcp_blender_handler_struct)); + + if (handler == NULL) { + fprintf(stderr, "Couldn't allocate memory for new bcp_blender_handler!\n"); + exit(ERROR_MEMORY); + } + + /* init the handler data slots */ + handler->input_mode = FILE_INPUT_MODE; + handler->result_print_mode = BCP_REPR_PRINT_MODE; + handler->stdouterr_buffer = py_stdouterr_buffer_new(); + handler->namespace = NULL; + handler->command = NULL; + handler->shell_input_buffer = NULL; + handler->shell_input_buffer_length = 0; + handler->shell_input_line_count = 0; + handler->result = NULL; + pthread_mutex_init( &handler->mutex, NULL ); + pthread_cond_init( &handler->condition, NULL ); + + return handler; +} + +/**/ +void bcp_blender_handler_delete(bcp_blender_handler handler) +{ + PyGILState_STATE gstate; + + /* free the members */ + py_stdouterr_buffer_delete(handler->stdouterr_buffer); + + /* aquire python thread */ + gstate = PyGILState_Ensure(); + + if (handler->namespace != NULL ) { Py_XDECREF(handler->namespace); } + + /* release python thread */ + PyGILState_Release(gstate); + + /* Note: handler->command + is initialized from a parameter of the function + 'bcp_blender_handle_input_allocate(blender_handler, command)' + and should be freed in the calling context of this function and not here! + */ + if (handler->shell_input_buffer != NULL ) { free(handler->shell_input_buffer); } + if (handler->result != NULL ) { free(handler->result); } + + pthread_mutex_destroy( &handler->mutex ); + pthread_cond_destroy( &handler->condition ); + + /* free the bcp_blender_handler_struct */ + free(handler); +} + +/**/ +char* bcp_blender_handle_input_allocate(bcp_blender_handler handler, char* command) +{ + /* pack arguments and + initialize result mutex + bcp_queue_handler_args args; + args.command = script; + args.result = NULL; + args.result_mutex = PTHREAD_MUTEX_INITIALIZER; + */ + + /* get the condition variable and the mutex + to synchronize command port and blender thread + */ + pthread_mutex_t* mutex = &handler->mutex; + pthread_cond_t* condition = &handler->condition; + + /* the command to be run by the Blender thread */ + handler->command = command; + + /* initialize the result */ + handler->result = NULL; + + /* enter the command request into the blender main queue */ + void* args = (void*) handler; + mainqenter_args(COMMAND_PORT_INPUT, 1, 0, args); /* dtodo: why 1 ?? */ + + /* wait on the condition variable for the command being executed and + the result being returned + */ + if (pthread_mutex_lock(mutex)) { + fprintf(stderr, "[BCP] ERROR: BCP thread couldn't lock the result mutex!\n"); + exit(ERROR_SYNCHRONIZATION); + } + + if (pthread_cond_wait(condition, mutex)) { + fprintf(stderr, "[BCP] ERROR: BCP thread couldn't wait on the result condition!\n"); + exit(ERROR_SYNCHRONIZATION); + } + + /* get the result */ + char* result = handler->result; + + if (pthread_mutex_unlock(mutex)) { + fprintf(stderr, "[BCP] ERROR: BCP thread couldn't unlock the result mutex!\n"); + exit(ERROR_SYNCHRONIZATION); + } + + /* when the condition variable is signalled, the result should be available */ + if (handler->result == NULL) { + fprintf(stderr, "[BCP] ERROR: No result returned from blender thread!\n"); + exit(ERROR_SYNCHRONIZATION); + } + + /* after returning, the caller is responsible to free the result memory. + => resetting handlers result buffer slot. + if this is not done and the handler is deleted, + bcp_blender_handler_delete() will try to free the memory again... + */ + handler->result = NULL; + + /* return the result :) */ + return result; +} + +void bcp_blender_queue_handle_input_allocate(void* args) +{ + /* extract the arguments */ + bcp_blender_handler handler_args = (bcp_blender_handler) args; + int* input_mode = &handler_args->input_mode; + int* result_print_mode = &handler_args->result_print_mode; + py_stdouterr_buffer stdouterr_buffer = handler_args->stdouterr_buffer; + PyObject** namespace = &handler_args->namespace; + char* command = handler_args->command; + char** shell_input_buffer = &handler_args->shell_input_buffer; + int* shell_input_buffer_length = &handler_args->shell_input_buffer_length; + int* shell_input_line_count = &handler_args->shell_input_line_count; + + pthread_mutex_t* mutex = &handler_args->mutex; + pthread_cond_t* condition = &handler_args->condition; + + /* + todo - compiler complains about: + + bcp_blender.c: In function ‘bcp_blender_queue_handle_input_allocate’: + bcp_blender.c:115: warning: unused variable ‘condition’ + bcp_blender.c:114: warning: unused variable ‘mutex’ + */ + + /* execute command and get the result */ + char* result; + + /* todo todo todo todo : result = ??? */ + result = bcp_run_python_script_allocate(input_mode, + result_print_mode, + stdouterr_buffer, + namespace, + command, + shell_input_buffer, + shell_input_buffer_length, + shell_input_line_count); + + /* signal the BCP thread that the result is available */ + if (pthread_mutex_lock(mutex)) { + fprintf(stderr, "[BCP] ERROR: Blender thread couldn't lock the result mutex!\n"); + exit(ERROR_SYNCHRONIZATION); + } + + /* set the result pointer */ + handler_args->result = result; + + /* the result has been calculated - awake the BCP thread to continue */ + if (pthread_cond_signal(condition)) { + fprintf(stderr, "[BCP] ERROR: Blender thread couldn't signal the result condition!\n"); + exit(ERROR_SYNCHRONIZATION); + } + + if (pthread_mutex_unlock(mutex)) { + fprintf(stderr, "[BCP] ERROR: Blender thread couldn't unlock the result mutex!\n"); + exit(ERROR_SYNCHRONIZATION); + } +} + +// ========================================================= +// ========================================================= + +/* fin */ Index: source/blender/commandport/blender/src/test.c =================================================================== --- source/blender/commandport/blender/src/test.c (revision 0) +++ source/blender/commandport/blender/src/test.c (revision 0) @@ -0,0 +1,57 @@ +/* + * $Id: test.c, v 1.0 2007/05/18, dietrich, tokyo $ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2007 by the Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Author: Dietrich Bollmann + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + * + * Main file for testing the string buffer. + * + * no header file. + * + */ + +#include /* for printf() and fprintf() */ +#include /* for socket(), connect(), send(), and recv() */ +#include /* for sockaddr_in and inet_addr() */ +#include /* for atoi() and exit() */ +#include /* for memset() */ +#include /* for close() */ + +#include "string_buffer.h" +#include "string_buffer_test.h" + +int main(int argc, char *argv[]) +{ + /* test (some of) my code */ + + /* testing the string_buffer */ + string_buffer_test(); + + printf("bye...\n"); + exit(0); +} + +/* fin */ Index: source/blender/commandport/blender/src/bcp_python_utilities.c =================================================================== --- source/blender/commandport/blender/src/bcp_python_utilities.c (revision 0) +++ source/blender/commandport/blender/src/bcp_python_utilities.c (revision 0) @@ -0,0 +1,388 @@ +/* + * $Id: bcp_python_utilities.c, v 1.0 2007/05/18, dietrich, tokyo $ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2007 by the Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Author: Dietrich Bollmann + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + * + * Functions to execute python code in the blender server. + * + * header file: ../include/bcp_python_utilities.h + * + */ + +#include + +#include "bcp_python_utilities.h" + +#include "py_stdouterr_buffer.h" +#include "py_codeop.h" + +/* function declarations */ +int get_start_symbol(int input_mode); +char* result_to_string_allocate(PyObject* result_obj, int result_print_mode); +char* empty_string_allocate(); + +/** + Run a c string in single input mode. + Note: For eval or file mode use 'py_input_run_allocate()'! + + This is the mode used for the interactive interpreter loop. + It corresponds to the 'Py_single_input' Python grammar symbol. + Compare the documentation to the 'Py_single_input' token + in http://docs.python.org/api/veryhigh.html#l2h-78 + */ +int py_single_input_run(const char* code, PyObject* namespace, + py_stdouterr_buffer stdouterr_buffer) +{ + PyGILState_STATE gstate; + int ret; /* the return code */ + PyObject *compiled_code_obj, *result_obj, *exception, *error, *traceback; + + /* aquire python thread */ + gstate = PyGILState_Ensure(); + + /* redirect stdout/stderr to buffer */ + py_stdouterr_buffer_redirect(stdouterr_buffer); + + /* compile + + Using 'compile_command()' rather than 'Py_CompileString()' as: + + - 'compile_command()' contrary to 'Py_CompileString()' is able + to determine the difference between incomplete code and + erroneous code: In the first case NULL is returned; in the + second one an error is thrown. When the code is complete and + correct, the compiled code is returned in a Python object. + + - the code is part of an official Python module - and hopefully + doesn't break with every new Python release :) + */ + compiled_code_obj = compile_command(code); + + /* check result of comilation */ + if (compiled_code_obj == NULL) { + + /* the code couldn't be compiled - + or it is incomplete, or there are syntax errors */ + + /* check for errors */ + if (PyErr_Occurred()) { + + /* some error occurred - print error message */ + + /* retrive error */ + PyErr_Fetch(&exception, &error, &traceback); + + /* restore the error for printing + Note: not owning exception, error, traceback anymore! + see documentation of PyErr_Restore(). */ + PyErr_Restore(exception, error, traceback); + + /* print it and set the corresponding return code */ + PyErr_Print(); + ret = PYTHON_ERROR; + + } else { + + /* the 'code' input is incomplete */ + + /* set the corresponding return code */ + ret = PYTHON_INCOMPLETE_INPUT; + } + + } else { + + /* compilation was successfull */ + + /* evaluate code */ + result_obj = PyEval_EvalCode((PyCodeObject*) compiled_code_obj, + namespace, namespace); + + /* the result object is not needed: + the result is printed to the stdout buffer */ + Py_XDECREF(result_obj); + Py_XDECREF(compiled_code_obj); + + /* check result of evaluation for errors */ + if (PyErr_Occurred()) { + + /* an error occurred - + print it and set the corresponding return code */ + PyErr_Print(); + ret = PYTHON_ERROR; + + } else { + + /* the code was executed successfully */ + ret = PYTHON_SUCCESS; + } + } + + /* restore the original stdout/stderr */ + py_stdouterr_buffer_restore(stdouterr_buffer); + + /* release python thread */ + PyGILState_Release(gstate); + + /* return the result code */ + return ret; +} + +/** + Run a c string in eval or file mode. + Note: For single input mode use 'py_single_input_run()'! + + Eval mode should be used for isolated Python expressions. + This mode corresponds to the 'Py_eval_input' Python grammar symbol. + Compare the documentation to the 'Py_eval_input' token + in http://docs.python.org/api/veryhigh.html#l2h-76 + + File mode should be used for sequences of Python statements + as read from a file or other source. This is the symbol to use when + compiling arbitrarily long Python source code. + This mode corresponds to the 'Py_file_input' Python grammar symbol. + Compare the documentation to the 'Py_file_input' token + in http://docs.python.org/api/veryhigh.html#l2h-77 + */ +int py_input_run_allocate(const char* code, + const int input_mode, + const int result_print_mode, + char** result, + PyObject* namespace, + struct py_stdouterr_buffer_struct* stdouterr_buffer) +{ + int ret; /* the return code */ + PyObject *compiled_code_obj, *result_obj; + PyGILState_STATE gstate; + + /* aquire python thread */ + gstate = PyGILState_Ensure(); + + /* redirect stdout/stderr to buffer */ + py_stdouterr_buffer_redirect(stdouterr_buffer); + + /* compile */ + compiled_code_obj = Py_CompileString(code, "", get_start_symbol(input_mode)); + + if (compiled_code_obj != NULL) { + + /* compilation was successfull */ + + /* evaluate code */ + result_obj = PyEval_EvalCode((PyCodeObject*) compiled_code_obj, + namespace, namespace); + + if (PyErr_Occurred()) { + + /* an error occurred - + print it and set the corresponding return code */ + PyErr_Print(); + ret = PYTHON_ERROR; + + /* return a newly allocated emtpy string */ + *result = empty_string_allocate(); + + } else { + + /* the code was executed successfully */ + ret = PYTHON_SUCCESS; + + /* convert the result in a newly allocated string to return */ + *result = result_to_string_allocate(result_obj, result_print_mode); + + } + + /* garbage collect the result object */ + Py_XDECREF(result_obj); + Py_XDECREF(compiled_code_obj); + + } else { + + /* some non-syntax error + print it and set the corresponding return code */ + PyErr_Print(); + ret = PYTHON_ERROR; + + /* return a newly allocated emtpy string */ + *result = empty_string_allocate(); + + } + + /* restore the original stdout/stderr */ + py_stdouterr_buffer_restore(stdouterr_buffer); + + /* release python thread */ + PyGILState_Release(gstate); + + /* return the result code */ + return ret; +} + +/** + Get the start symbol of the Python grammar corresponding to the + input mode given as parameter. +*/ +int get_start_symbol(int input_mode) +{ + switch (input_mode) { + case SINGLE_INPUT_MODE : return Py_single_input; break; + case EVAL_INPUT_MODE : return Py_eval_input; break; + case FILE_INPUT_MODE : return Py_file_input; break; + default : return Py_file_input; break; + } +} + +/** + Convert the Python result object returned by 'ObjectPyEval_EvalCode()' + to a string. + + Depending on the parameter 'result_print_mode', + two different conversion functions can be used: + + - BCP_REPR_PRINT_MODE 'PyObject_Repr()' is used to convert the result. + + Example: + + Strings are printed with "'": + 'THE MEANING OF PYTHON...' + + - BCP_STR_PRINT_MODE 'PyObject_Str()' is used to convert the result. + + Example: + + Strings are printed without "'": + THE MEANING OF PYTHON... + +*/ +char* result_to_string_allocate(PyObject* result_obj, int result_print_mode) +{ + PyObject* result_str_obj; + PyGILState_STATE gstate; + char *result_str, *result_buffer; + int result_length; + + /* check if a result object was given */ + if (result_obj == NULL) { + fprintf(stderr, "[BCP] ERROR: Python didn't return any result!\n"); + exit(1); + // todo: clean up + } + + /* aquire python thread */ + gstate = PyGILState_Ensure(); + + /* convert the result object to a string object */ + if (result_print_mode == BCP_REPR_PRINT_MODE) { + + /* compute a string representation of the result object + using 'PyObject_Repr()' + + PyObject* PyObject_Repr(PyObject *o) + Return value: New reference. + Compute a string representation of object o. + Returns the string representation on success, NULL on failure. + This is the equivalent of the Python expression "repr(o)". + Called by the repr() built-in function and by reverse quotes. + + (see http://docs.python.org/api/object.html) + */ + result_str_obj = PyObject_Repr(result_obj); + + } else if (result_print_mode == BCP_STR_PRINT_MODE) { + + /* compute a string representation of the result object + using 'PyObject_Str();' + + PyObject* PyObject_Str(PyObject *o) + Return value: New reference. + Compute a string representation of object o. + Returns the string representation on success, NULL on failure. + This is the equivalent of the Python expression "str(o)". + Called by the str() built-in function and by the print statement. + + (see http://docs.python.org/api/object.html) + */ + result_str_obj = PyObject_Str(result_obj); + + } else { + + /* this should never be the case - but... */ + fprintf(stderr, "[BCP] ERROR: todo: unknown print result mode!\n" ); + + } + + if (result_str_obj == NULL) { + fprintf(stderr, "[BCP] ERROR: Couldn't compute a string representation from the result object!\n"); + fprintf(stderr, "todo: catch error and print / return error message!"); + exit(1); + // todo: clean up + } + + /* convert the python string object to a c string */ + if (!PyArg_Parse(result_str_obj, "s", &result_str)) { + fprintf(stderr, "[BCP] ERROR: Couldn't convert the python result to a c string!\n"); + exit(1); /* todo: catch error and print / return error message */ + // todo: clean up + } + + /* allocate a c string buffer to return the result */ + result_length = strlen(result_str); + result_buffer = (char*) malloc((result_length + 1) * sizeof(char)); + + /* copy the result string into the buffer */ + memcpy(result_buffer, result_str, result_length); + result_buffer[result_length]= '\0'; + + /* clean up */ + Py_DECREF(result_str_obj); + // todo: there are other object references to count down!!! + + /* release python thread */ + PyGILState_Release(gstate); + + /* return the allocated result buffer */ + return result_buffer; +} + + +/** + return a newly allocated empty string. +*/ +char* empty_string_allocate() +{ + /* allocate a c string buffer to return the result */ + char* empty_string; + empty_string = (char*) malloc(1 * sizeof(char)); + + /* copy the result string into the buffer */ + empty_string[0]= '\0'; + + /* return the allocated empty string */ + return empty_string; +} + +/* fin */ + Index: source/blender/commandport/blender/src/py_codeop.c =================================================================== --- source/blender/commandport/blender/src/py_codeop.c (revision 0) +++ source/blender/commandport/blender/src/py_codeop.c (revision 0) @@ -0,0 +1,85 @@ +/* + * $Id: py_stdouterr_buffer.c, v 1.0 2008/04/24, dietrich, tokyo $ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2007 by the Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Author: Dietrich Bollmann + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + * + * A C wrapper for the function 'compile_command()' + * from the Python 'codeop' module. + * + * The documentation for the Python 'codeop' module can be found + * here: http://docs.python.org/lib/module-codeop.html + * + * The function 'compile_command()' is used rather than + * 'Py_CompileString()' to implement the interactive read-eval-print + * loop as it is able to make the difference between incomplete input + * and erroneous input. + * + * header file: ../include/py_codeop.h + * + */ + +#include + +#include "py_codeop.h" + +PyObject *compile_command(const char *source) +{ + PyGILState_STATE gstate; + PyObject *mod_codeop; + PyObject *func_compile_command, *obj_args, *obj_res; + + /* aquire python thread */ + gstate = PyGILState_Ensure(); + + /* get the 'compile_command()' function */ + mod_codeop = PyImport_ImportModule("codeop"); + func_compile_command = PyObject_GetAttrString(mod_codeop, "compile_command"); + Py_DECREF(mod_codeop); + + /* call it with the code from parameter 'source' */ + obj_args = Py_BuildValue("(s)", source); + obj_res = PyEval_CallObject(func_compile_command, obj_args); + Py_DECREF(func_compile_command); + Py_DECREF(obj_args); + + /* - Return a code object if the command is complete and valid + - Return NULL if the command is incomplete + */ + if (obj_res == Py_None) { + + Py_DECREF(obj_res); + obj_res = NULL; + } + + /* release python thread */ + PyGILState_Release(gstate); + + /* return the code object or NULL for an incomplete python input */ + return obj_res; +} + +/* fin */ Index: source/blender/commandport/blender/src/commandport.c =================================================================== --- source/blender/commandport/blender/src/commandport.c (revision 0) +++ source/blender/commandport/blender/src/commandport.c (revision 0) @@ -0,0 +1,121 @@ +/* + * $Id: commandport.c, v 1.0 2007/05/02, dietrich, tokyo $ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2007 by the Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Author: Dietrich Bollmann + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + * + * Main Blender Command Port source file. + * + * All command port functionality in files outside of the + * directory `source/blender/commandport/' is implemented + * by calling the functions imported from this file: + * + * - `commandport_init()' initializes the command port and + * is called from function `main()' + * in file `source/creator/creator.c' + * when Blender is started with the `-c' / `--bcp' option; + * + * - `commandport_start()' starts the command port and + * is called from function `screenmain()' + * in file `source/blender/src/editscreen.c' + * when Blender is started with the `-c' / `--bcp' option; + * + * - When the command port thread receives a command sequence from + * a client, a `COMMAND_PORT_INPUT' event token is appended + * to the end of the Blender main event loop queue. + * When the Blender main event handler finds such a token, + * the function `commandport_handle_input_allocate()' is + * called to handle the event. + * See the Blender main event loop in function `screenmain()', + * file `source/blender/src/editscreen.c'. + * + * - When Blender was started with the `-c' / `--bcp' option + * the function `commandport_destroy()' cleans up the command port code + * when Blender exists. + * It is called from function `exit_usiblender()' + * in file `source/blender/src/usiblender.c'. + * + * header file: ../../include/commandport.h + * + */ + +#include + +#include "bcp_thread.h" +#include "bcp_blender.h" +#include "bcp_debug.h" + +#include "commandport.h" + +/* command port data */ +unsigned short g_bcp_port = 0; + +/** +*/ +void commandport_init(unsigned short port) +{ + /* init the commandport data */ + g_bcp_port = port; +} + +/** +*/ +void commandport_set_debug_level(int debug_level) +{ + /* init the BCP debug message level */ + bcp_set_debug_level(debug_level); +} + +/** +*/ +void commandport_start() +{ + /* check if the command port was initialized */ + if (g_bcp_port == 0) return; + + /* if the command port was initialized, start it */ + printf("Starting the Blender command port - listening on port %d.\n", g_bcp_port); + bcp_thread_start(g_bcp_port); +} + +/** +*/ +void commandport_handle_input_allocate(void* args) +{ + /* this is just a wrapper for the function defined in bcp_blender.h + in order ot be able to import everything from only one header: commandport.h + */ + bcp_blender_queue_handle_input_allocate(args); +} + +/** +*/ +void commandport_destroy() +{ + /* nothing to do */ +} + +/* fin */ Index: source/blender/commandport/blender/src/bcp_python.c =================================================================== --- source/blender/commandport/blender/src/bcp_python.c (revision 0) +++ source/blender/commandport/blender/src/bcp_python.c (revision 0) @@ -0,0 +1,912 @@ +/* + * $Id: bcp_python.c, v 1.0 2007/05/18, dietrich, tokyo $ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2007 by the Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Author: Dietrich Bollmann + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + * + * Functionality ro run a BCP package in Blender. + * + * header file: ../include/bcp_python.h + * + */ + +#include + +#include /* for the PyCodeObject needed by eval.h */ +#include /* for PyEval_EvalCode */ + +#include "BPY_extern.h" /* for BPY_setup_armature_weakrefs() */ + +#include "bcp_debug.h" /* bcp_debug() */ +#include "bcp_defaults.h" +#include "bcp_meta_commands.h" +#include "bcp_package.h" +#include "bcp_python.h" +#include "bcp_python_utilities.h" +#include "error_codes.h" +#include "py_stdouterr_buffer.h" + +void process_bcp_meta_command(char meta_command, int* input_mode, int* result_print_mode); +PyObject* new_python_namespace(); +void delete_python_namespace(PyObject* namespace); +void reinitialize_python_namespace(PyObject** namespace); +char* compile_and_evaluate_allocate(int input_mode, + int result_print_mode, + py_stdouterr_buffer stdouterr_buffer, + PyObject** namespace, + char* script, + char** shell_input_buffer, + int* shell_input_buffer_length, + int* shell_input_line_count); +char* process_python_single_input_allocate(py_stdouterr_buffer stdouterr_buffer, + PyObject** namespace, + char* line, + char** shell_input_buffer, + int* shell_input_buffer_length, + int* shell_input_line_count); + +char* process_python_input_allocate(int input_mode, + int result_print_mode, + py_stdouterr_buffer stdouterr_buffer, + PyObject** namespace, + char* code); +/* tools */ +void print_input_mode(int input_mode); +void dump_string(char* string); + +/** + Runs a python script + packed together with zero or more BCP meta commands + into a bcp package. + + BCP Protocol: + - The package might start with zero or more BCP meta commands. + - There should be exacly ONE command string in every package. + - The command string should be the last element in the package. +*/ +char* bcp_run_python_script_allocate(int* input_mode, + int* result_print_mode, + py_stdouterr_buffer stdouterr_buffer, + PyObject** namespace, + char* script, + char** shell_input_buffer, + int* shell_input_buffer_length, + int* shell_input_line_count) +{ + /* get debug level */ + int debug = bcp_debug(); + /* unused: int debug1 = (debug == 1); */ + int debug2 = (debug >= 2); + + bcp_package command_package; + bcp_package_enumerator enumerator; + void* elem; + char type; + char meta_command; + char* command = NULL; + char* result = NULL; + + /* DEBUG */ + if (debug2) { + + /* print packed package */ + printf(">>> the packed command package:\n"); + printf(">>>%s<<<\n", script); + printf("\n"); + } + + /* unpack the client command package */ + command_package = bcp_package_unpack(script); + + /* DEBUG - short + + printf("[DEBUG] dumping the client command package:\n"); + dump_package(command_package); + printf("\n"); + */ + + /* DEBUG - more detailed + + dump_packed_package(package); + printf("\n"); + */ + + /* make new package enumerator */ + enumerator = bcp_package_enumerator_new(command_package); + + /* print element */ + while (1) { + + /* get next element */ + elem = bcp_package_enumerator_get_next_element(enumerator, &type); + + /* if there are no more elements - exit */ + if (type == BCP_PACKAGE_TYPE_EMPTY) break; + + /* print value */ + switch (type) { + + case BCP_PACKAGE_TYPE_UNDEFINED: + + /* ERROR - undefined package type */ + fprintf(stderr, "ERROR in BCP protocol: Client send a bcp_package element with an unknown type!\n"); + exit(ERROR_IN_BCP_PROTOCOL); + break; + + case BCP_PACKAGE_TYPE_INT: + + /* ERROR - client should only send + - command type elements and + - string type element + */ + fprintf(stderr, "ERROR in BCP protocol: " + "Client send a bcp_package int element which is not defined by the BCP protocol!\n"); + exit(ERROR_IN_BCP_PROTOCOL); + break; + + case BCP_PACKAGE_TYPE_STRING: + + /* every string send by the client is interpreted as command string */ + command = (char*) elem; + + /* DEBUG + printf("python command string: \"%s\"\n", command); + */ + + /* init the BCP Python namespace if not already done */ + if (*namespace == NULL) { + *namespace = new_python_namespace(); + } + + /* execute the script and return the result + - in the current state of the BCP namespace (see 'handler->namespace') + - using the currently active BCP Input Mode (see 'handler->input_mode') + */ + result = compile_and_evaluate_allocate(*input_mode, + *result_print_mode, + stdouterr_buffer, + namespace, + command, + shell_input_buffer, + shell_input_buffer_length, + shell_input_line_count); + + /* never reached */ + break; + + case BCP_PACKAGE_TYPE_COMMAND: + + /* the element is a BCP Meta Command */ + meta_command = *((char*) elem); + + /* DEBUG + printf("BCP meta command: %c\n", meta_command); + */ + + /* process the BCP Meta Command */ + process_bcp_meta_command(meta_command, input_mode, result_print_mode); + + break; + + default: + + /* ERROR - element with unknown type */ + fprintf(stderr, "ERROR in BCP protocol: " + "Client send a bcp_package element with an unknown type!\n"); + exit(ERROR_IN_BCP_PROTOCOL); + } + } + + /* delete the package enumerator */ + bcp_package_enumerator_delete(enumerator); + + /* delete package */ + bcp_package_delete(command_package); + + /* return result */ + return result; +} + +/** + Process a BCP Meta Command. +*/ +void process_bcp_meta_command(char meta_command, int* input_mode, int* result_print_mode) +{ + /* get debug level */ + int debug = bcp_debug(); + + switch (meta_command) { + + case BCP_SINGLE_MODE_COMMAND: + + if (debug) printf("[BCP] Setting Input Mode to 'Single Input Mode'.\n"); + *input_mode = SINGLE_INPUT_MODE; + break; + + case BCP_EVAL_MODE_COMMAND: + + if (debug) printf("[BCP] Setting Input Mode to 'Eval Input Mode'.\n"); + *input_mode = EVAL_INPUT_MODE; + break; + + case BCP_FILE_MODE_COMMAND: + + if (debug) printf("[BCP] Setting Input Mode to 'File Input Mode'.\n"); + *input_mode = FILE_INPUT_MODE; + break; + + case BCP_REPR_PRINT_MODE_COMMAND: + + if (debug) printf("[BCP] Setting Result Print Mode: Printing Result Representation.\n"); + *result_print_mode = BCP_REPR_PRINT_MODE; + break; + + case BCP_STR_PRINT_MODE_COMMAND: + + if (debug) printf("[BCP] Setting Result Print Mode: Printing Result String.\n"); + *result_print_mode = BCP_STR_PRINT_MODE; + break; + + case BCP_RESET_COMMAND: + + /* if (debug) */ + printf("[BCP] Resetting the Command Port.\n"); + printf("... todo ...\n"); + break; + + default: + + /* the given meta command is not defined - + print a warning message and ignore the command + */ + printf("[BCP] WARNING: '" + "' is not a valid BCP Meta Command and will be ignored!\n"); + break; + + } /* end of switch */ +} + +/** + Create a new Python namespace to evaluate Python scripts in. +*/ +PyObject* new_python_namespace() +{ + PyObject* main_string_obj; + PyObject *namespace; + PyGILState_STATE gstate; + + /* aquire python thread */ + gstate = PyGILState_Ensure(); + + /* make new namespace dictionary */ + namespace = PyDict_New(); + if (namespace == NULL) { + printf( "[BCP] ERROR: Problems while trying to create a new python dictonary!\n" ); + exit(1); /* todo: catch error and print / return error message */ + } + + /* initialize the namespace with the Python buildins */ + if (PyDict_SetItemString(namespace, "__builtins__", PyEval_GetBuiltins())) { + printf( "[BCP] ERROR: Couldn't get the Python buildins!\n" ); + exit(1); /* todo: catch error and print / return error message */ + } + + /* name the BCP namespace __main__ - like top-level Python program */ + main_string_obj = PyString_FromString("__main__"); + if (PyDict_SetItemString(namespace, "__name__", main_string_obj)) { + printf( "[BCP] ERROR: Couldn't name the BCP namespase as '__main__'!\n" ); + exit(1); /* todo: catch error and print / return error message */ + } + /* delete added string object: + When some object is just created to be added to the dictionary, + its reference count needs to be decremented so it can be reclaimed. + (Compare `EXPP_dict_set_item_str(dict, key, value)' + in blender/source/blender/python/api2_2x/gen_utils.c) + */ + Py_DECREF(main_string_obj); + + /* Without setting up the armature weakrefs the error + "RuntimeError: internal error - update_armature_weakrefs" + is thrown when executing the python function + `Blender.Window.EditMode(1)' via the command port. + */ + if (!BPY_setup_armature_weakrefs()) { + fprintf(stderr, "[command port error] couldn't setup weakref dictionary!\n"); + PyGILState_Release(gstate); + return NULL; + } + + /* release python thread */ + PyGILState_Release(gstate); + + /* return the new namespace */ + return namespace; +} + +/** + Delete a new Python namespace created with 'new_python_namespace()'. +*/ +void delete_python_namespace(PyObject* namespace) +{ + PyGILState_STATE gstate; + + /* count down the reference counter of the namespace + to allow the Python garbage collector to + garbage collect the namespace object. + + Note: + This works only if there is only one reference to the namespace object! + */ + if (namespace != NULL ) { + + /* aquire python thread */ + gstate = PyGILState_Ensure(); + + Py_XDECREF(namespace); + + /* release python thread */ + PyGILState_Release(gstate); + } +} + +/** + Sustitute the given namespace with a newly created one. +*/ +void reinitialize_python_namespace(PyObject** namespace) +{ + /* delete the current namespace object */ + delete_python_namespace(*namespace); + + /* ...and substitute it with a new one */ + *namespace = new_python_namespace(); +} + +/** + Compile and evaluate a Python script given as a c string. + The result is returned as a newly allocated c string + and has to be freed after usage. + + The second parameter start specifies the start token that should be used + to parse the source code and should be one of + 'Py_eval_input', 'Py_file_input' and 'Py_single_input'. + + Compare the documentation for + 'PyRun_StringFlags()' ( http://docs.python.org/api/veryhigh.html#l2h-69 ) and + 'Py_CompileStringFlags()' ( http://docs.python.org/api/veryhigh.html#l2h-74 ). + + + * Shell Evaluation Modes + + Three different modes can be used from the interactive bash shell. + Each "shell evaluation mode" corresponds to a Python grammar start symbol which will be used to parse + the entered string and to a strategy which determines the usage of the parsed information. + + The following macros specify the shell evaluation mode: + + ------------------------------------------------------------ + macro - corresponding Python grammar start symbol + ------------------------------------------------------------ + BCP_SINGLE_MODE - Py_single_input + BCP_EVAL_MODE - Py_eval_input + BCP_FILE_MODE - Py_file_input + ------------------------------------------------------------ + + Description: + + - Py_single_input + + The start symbol from the Python grammar for a single statement; for use with Py_CompileString(). This is the symbol used for the interactive interpreter loop. + + See Python documentation: http://docs.python.org/api/veryhigh.html#l2h-78 + + - Py_eval_input + + The start symbol from the Python grammar for isolated expressions; for use with Py_CompileString(). + + See Python documentation: http://docs.python.org/api/veryhigh.html#l2h-76 + + + - Py_file_input + + The start symbol from the Python grammar for sequences of statements as read from a file or other source; for use with Py_CompileString(). This is the symbol to use when compiling arbitrarily long Python source code. + + See Python documentation: http://docs.python.org/api/veryhigh.html#l2h-77 + + +*/ + +char* compile_and_evaluate_allocate(int input_mode, + int result_print_mode, + py_stdouterr_buffer stdouterr_buffer, + PyObject** namespace, + char* script, + char** shell_input_buffer, + int* shell_input_buffer_length, + int* shell_input_line_count) +{ + switch (input_mode) { + + case SINGLE_INPUT_MODE : + + return process_python_single_input_allocate(stdouterr_buffer, + namespace, + script, + shell_input_buffer, + shell_input_buffer_length, + shell_input_line_count); + + case EVAL_INPUT_MODE : + case FILE_INPUT_MODE : + + return process_python_input_allocate(input_mode, + result_print_mode, + stdouterr_buffer, + namespace, + script); + + + + default : + fprintf(stderr, "[BCP] ERROR: Unknown input mode: %d\n", input_mode); + exit(1); + } +} + +/** + Note: The following function was written using code from the + Extending/Embedding FAQ - see: + http://www.python.org/doc/faq/extending/#how-do-i-tell-incomplete-input-from-invalid-input + which in turn was inspired by code from Alex Farber :) + + Returns NULL if the imput is still incomplete or + an error occurred. +*/ +char* process_python_single_input_allocate(py_stdouterr_buffer stdouterr_buffer, + PyObject** namespace, + char* line, + char** shell_input_buffer, + int* shell_input_buffer_length, + int* shell_input_line_count) +{ + /* get debug level */ + int debug, debug1, debug2; + int ret, result_code; + char *stdout_string, *stderr_string, *packed_result, **code; + int *clen, *lcount, llen; + bcp_package result_package; + + /* making aliases for readability */ + code = shell_input_buffer; + clen = shell_input_buffer_length; + lcount = shell_input_line_count; + llen = 0; /* lengths of line, code */ + + /* get debug level */ + debug = bcp_debug(); + debug1 = (debug == 1); + debug2 = (debug >= 2); + + /* make a package for sending back the result of the current python execution */ + result_package = bcp_package_new(); + + llen = strlen(line); /* newly entered line */ + + if (*code == NULL) { /* nothing in the code buffer yet */ + *clen = 0; + *lcount = 0; /* line counter is 0 */ + } else { + *clen = strlen(*code); /* there are already some code lines + in the code buffer and the current + newly entered line will be added + to them + */ + } + + *code = realloc(*code, *clen + llen + 2); + if (NULL == *code) { /* out of memory */ + + /* ERROR: out of memory */ + fprintf(stderr, "[BCP] ERROR: Out of memory!"); + exit (1); + } + + if (0 == *clen) { /* the code buffer was empty */ + (*code)[0] = '\0'; /* to keep strncat happy */ + } + + strncat(*code, line, llen); /* append line to the code buffer + Note: the line (command) is freed by the + `bcp_handle_client()' loop! */ + (*code)[*clen + llen ] = '\n'; /* append '\n' to the code buffer */ + (*code)[*clen + llen + 1] = '\0'; /* terminate code buffer with NULL caracter */ + (*lcount)++; /* increment line counter */ + + /* DEBUG */ + /* print the content of stdout/stderr buffer */ + if (debug1) { + + /* short: */ + printf(">>> ========================================================\n"); + printf(">>> - new input line: '%s'\n", line); + printf(">>> - current input: '%s'\n", *code); + + } else if (debug2) { + + /* longer: */ + printf(">>> ========================================================\n"); + printf(">>> - debug message level: %d\n", debug); + printf(">>> \n"); + printf(">>> - new input line:\n"); + printf(">>> \n"); + printf(">>> - length: %d\n", llen); + printf(">>> - content: '%s'\n", line); + printf(">>> - dump: "); dump_string(line); printf("\n"); + printf(">>> \n"); + printf(">>> - current input:\n"); + printf(">>> \n"); + printf(">>> - length: %d\n", *clen); + printf(">>> - lines: %d\n", *lcount); + printf(">>> - content: '%s'\n", *code); + printf(">>> - dump: "); dump_string(*code); printf("\n"); + printf(">>> \n"); + } + + /* try to execute the code + received until now from the shell */ + ret = py_single_input_run(*code, *namespace, stdouterr_buffer); + + result_code = BCP_RESULT_CODE_UNDEFINED; + if (ret == PYTHON_SUCCESS) { + + /* compiled - + + As in the python shell + an input is accepted as complete and executed if + - it can be interpreted / parsed as a complete input + and it is one line long + - it can be interpreted / parsed as a complete input + and it is more than one line long + and it is terminated with an empty line + */ + if (*lcount == 1 || /* first input line, prompt '>>> ' */ + (*lcount > 1 && (llen == 0)) /* not first input line and + input line is empty, prompt '... ' */ + ) { + + /* The python evaluation was successful */ + result_code = BCP_RESULT_CODE_SUCCESS; + + free(*code); + *code = NULL; /* nothing in the code buffer yet */ + *clen = 0; + *lcount = 0; /* line counter is 0 */ + + } else { + + + /* The entered python code is incomplete + + The code could be successfully executed + but the input is not complete as + - it is more than one line long + (the current line is not the first line) and + - it was NOT terminated with an empty line + (as the current line is not empty). + + Send a message back to the client indicating + that the blender server waits for the next line: + */ + result_code = BCP_RESULT_CODE_INCOMPLETE_INPUT; + + } + + } else if (ret == PYTHON_INCOMPLETE_INPUT) { + + /* The entered python code is incomplete + and the blender server waits for more + input lines to complete the input */ + result_code = BCP_RESULT_CODE_INCOMPLETE_INPUT; + + /* don't do anything + - the code in (*code) will be prepended to the next input */ + + } else if (ret == PYTHON_ERROR) { + + /* An error occured during the + evaluation ot the python code */ + result_code = BCP_RESULT_CODE_ERROR; + + /* free the memory of the newly entered current line */ + free(*code); + *code = NULL; + + } else { + + /* + ERROR - This line should never be reached + as the last cases should deal with all possible results + */ + result_code = BCP_RESULT_CODE_UNDEFINED; + + /* free the memory of the newly entered current line */ + free(*code); + *code = NULL; + + } + + /* DEBUG */ + if (debug) { + + /* print result code (see bcp_meta_commands.h) */ + printf(">>> - result code: %d (", result_code); + switch (result_code) { + case BCP_RESULT_CODE_SUCCESS : printf("BCP_RESULT_CODE_SUCCESS"); break; + case BCP_RESULT_CODE_INCOMPLETE_INPUT : printf("BCP_RESULT_CODE_INCOMPLETE_INPUT"); break; + case BCP_RESULT_CODE_ERROR : printf("BCP_RESULT_CODE_ERROR"); break; + case BCP_RESULT_CODE_UNDEFINED : printf("BCP_RESULT_CODE_UNDEFINED"); break; + case BCP_RESULT_CODE_EMPTY_INPUT : printf("BCP_RESULT_CODE_EMPTY_INPUT"); break; + default : printf("ERROR: unknown result code!"); break; + } + printf(")\n"); + + /* short: */ + /* print the contenet of stdout/stderr buffer */ + fprintf(stderr, ">>> - stderr: '"); + py_stdouterr_buffer_print_stderr(stdouterr_buffer); + fprintf(stderr, "'\n"); + fflush(stderr); + fprintf(stdout, ">>> - stdout: '"); + py_stdouterr_buffer_print_stdout(stdouterr_buffer); + fprintf(stdout, "'\n"); + fflush(stdout); + } + + /* add the result code */ + bcp_package_add_int(result_package, result_code); + + /* in python single input mode the result is directly printed to stdout + and there is no other result returned. + But as the BCP protocol in order to be simple always sends a + result string as second element, an empty dummy result string is added. + */ + bcp_package_add_string(result_package, ""); + + /* add the blender/python stdout string */ + stdout_string = NULL; + stdout_string = py_stdouterr_buffer_get_stdout_allocate(stdouterr_buffer); + bcp_package_add_string(result_package, stdout_string); + + /* add the blender/python stderr string */ + stderr_string = py_stdouterr_buffer_get_stderr_allocate(stdouterr_buffer); + bcp_package_add_string(result_package, stderr_string); + + /* pack the buffer into a newly allocated string */ + packed_result = bcp_package_pack_allocate(result_package); + + /* free the strout / stderr buffers */ + free(stdout_string); + stdout_string = NULL; + free(stderr_string); + stderr_string = NULL; + + /* DEBUG */ + if (debug2) { + + /* print packed package */ + printf(">>> - the packed package: `\n"); + printf("%s'\n", packed_result); + } + + if (debug) printf(">>> ========================================================\n"); + + /* delete package */ + bcp_package_delete(result_package); + + /* + clear stdout/stderr buffers + + Note: + The buffer can be cleared only after the result package + was packed into a newly allocated packed buffer string representation + becausee the unpacked package just holds the pointers to the added strings + and not a copy of the string itself. + */ + py_stdouterr_buffer_clear_buffers(stdouterr_buffer); + + /* return the allocated result buffer */ + return packed_result; +} + +/** + todo................. + +Process a complete python input (eval or file input but not single input) + + + Note: The following function was written using code from the + Extending/Embedding FAQ - see: + http://www.python.org/doc/faq/extending/#how-do-i-tell-incomplete-input-from-invalid-input + which in turn was inspired by code from Alex Farber :) + + Returns NULL if the imput is still incomplete or + an error occurred. +*/ +char* process_python_input_allocate(int input_mode, + int result_print_mode, + py_stdouterr_buffer stdouterr_buffer, + PyObject** namespace, + char* code) +{ + int debug, debug2; + bcp_package result_package; + int ret, result_code; + char *result, *stdout_string, *stderr_string, *packed_result; + + /* get debug level */ + debug = bcp_debug(); + debug2 = (debug >= 2); + + /* make a package for sending back the result of the current python execution */ + result_package = bcp_package_new(); + + /* DEBUG */ + if (debug) { + + /* print the content of stdout/stderr buffer */ + + /* short: */ + printf(">>> ========================================================\n"); + printf(">>> debug: %d\n", debug); + printf(">>> - input mode: "); print_input_mode(input_mode); printf("\n"); + printf(">>> - input: '%s'\n", code); + } + + /* try to execute the code + received until now from the shell */ + result = NULL; + ret = py_input_run_allocate(code, input_mode, result_print_mode, &result, + *namespace, stdouterr_buffer); + + /* convert the result into the BCP result code */ + result_code = BCP_RESULT_CODE_UNDEFINED; + switch (ret) { + case PYTHON_SUCCESS : result_code = BCP_RESULT_CODE_SUCCESS; break; + case PYTHON_ERROR : result_code = BCP_RESULT_CODE_ERROR; break; + default : result_code = BCP_RESULT_CODE_UNDEFINED; break; + } + + /* DEBUG */ + if (debug) { + + /* print result code (see bcp_meta_commands.h) */ + printf(">>> - result code: %d (", result_code); + + switch (result_code) { + case BCP_RESULT_CODE_SUCCESS : printf("BCP_RESULT_CODE_SUCCESS"); break; + case BCP_RESULT_CODE_ERROR : printf("BCP_RESULT_CODE_ERROR"); break; + case BCP_RESULT_CODE_UNDEFINED : printf("BCP_RESULT_CODE_UNDEFINED"); break; + default : printf("ERROR: unknown result code!"); break; + } + printf(")\n"); + + /* print the result */ + printf(">>> - result: '%s'\n", result); + + /* print the contenet of stdout/stderr buffer */ + fprintf(stderr, ">>> - stderr: '"); + py_stdouterr_buffer_print_stderr(stdouterr_buffer); + fprintf(stderr, "'\n"); + fflush(stderr); + fprintf(stdout, ">>> - stdout: '"); + py_stdouterr_buffer_print_stdout(stdouterr_buffer); + fprintf(stdout, "'\n"); + fflush(stdout); + printf(">>> ========================================================\n"); + } + + /* add the result code */ + bcp_package_add_int(result_package, result_code); + + /* add the result coded as string */ + bcp_package_add_string(result_package, result); + + /* add the blender/python stdout string */ + stdout_string = py_stdouterr_buffer_get_stdout_allocate(stdouterr_buffer); + bcp_package_add_string(result_package, stdout_string); + + /* add the blender/python stderr string */ + stderr_string = py_stdouterr_buffer_get_stderr_allocate(stdouterr_buffer); + bcp_package_add_string(result_package, stderr_string); + + /* pack the buffer into a newly allocated string */ + packed_result = bcp_package_pack_allocate(result_package); + + /* free the result / strout / stderr buffers */ + free(result); + result = NULL; + free(stdout_string); + stdout_string = NULL; + free(stderr_string); + stderr_string = NULL; + + /* DEBUG */ + if (debug2) { + + /* print packed package */ + printf(">>> the packed package:\n"); + printf(">>>%s<<<\n", packed_result); + printf("\n"); + } + + /* delete package */ + bcp_package_delete(result_package); + + /* + clear stdout/stderr buffers + + Note: + The buffer can be cleared only after the result package + was packed into a newly allocated packed buffer string representation + becausee the unpacked package just holds the pointers to the added strings + and not a copy of the string itself. + */ + py_stdouterr_buffer_clear_buffers(stdouterr_buffer); + + /* return the allocated result buffer */ + return packed_result; +} + +/* tools */ + +/** + Print given input mode. +*/ +void print_input_mode(int input_mode) +{ + switch (input_mode) { + case SINGLE_INPUT_MODE : printf("SINGLE_INPUT_MODE"); break; + case EVAL_INPUT_MODE : printf("EVAL_INPUT_MODE"); break; + case FILE_INPUT_MODE : printf("FILE_INPUT_MODE"); break; + default : printf("ERROR: Undefined input mode!"); break; + } +} + +/** + DEBUG - Dump a string to stdout. +*/ +void dump_string(char* string) +{ + for( ; *string != '\0'; string++) { + printf("%X ", *string); + } + printf("%X", *string); +} + +// ========================================================= +// ========================================================= + +/* fin */ + Index: source/blender/commandport/blender/src/SConscript =================================================================== --- source/blender/commandport/blender/src/SConscript (revision 0) +++ source/blender/commandport/blender/src/SConscript (revision 0) @@ -0,0 +1,54 @@ +# -*- mode: python -*- +# +# $Id: SConscript, v 1.0 2007/05/02, dietrich, tokyo $ +# +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# The Original Code is Copyright (C) 2007 by the Blender Foundation. +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Author: Dietrich Bollmann +# Contributor(s): none yet. +# +# ***** END GPL LICENSE BLOCK ***** +# +# blender command port source build file +# + +Import ('env') + +sources = env.Glob('*.c') + +incs = ''' + ../include + ../../include + ../../utilities/include + #/intern/guardedalloc + #/source/blender/blenkernel + #/source/blender/blenlib + #/source/blender/include + #/source/blender/makesdna + #/source/blender/python +''' + +incs += ' ' + env['BF_PYTHON_INC'] + +env.BlenderLib ( 'blender_commandport', sources, Split(incs), [], libtype=['blender'], priority=[0] ) + +# fin. Index: source/blender/commandport/blender/src/bcp_server.c =================================================================== --- source/blender/commandport/blender/src/bcp_server.c (revision 0) +++ source/blender/commandport/blender/src/bcp_server.c (revision 0) @@ -0,0 +1,170 @@ +/* + * $Id: bcp_server.c, v 1.0 2007/05/02, dietrich, tokyo $ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2007 by the Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Author: Dietrich Bollmann + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + * + * Blender command port server. + * + * header file: ../include/bcp_server.h]] + * + */ + +#include /* printf(), fprintf() */ +#include /* socket(), bind(), connect() */ +#include /* sockaddr_in, inet_ntoa() */ +#include /* pthread */ +#include /* atoi(), exit() */ +#include /* memset() */ +#include /* close() */ + +#include "error_codes.h" /* error codes */ +#include "bcp_handle_client.h" /* bcp_handle_client() */ +#include "bcp_debug.h" /* bcp_debug() */ + +#define MAXPENDING 5 /* Maximum outstanding connection requests */ + +/** Structure with arguments to pass to client thread */ +struct bcp_client_thread_args +{ + int client_socket; +}; + +void bcp_client_thread_start(int client_socket); +void* bcp_client_thread(void* args); + +/** + `port' is the BCP server port +*/ +void bcp_server(unsigned short port) +{ + int server_socket; /* Socket descriptor for server */ + int client_socket; /* Socket descriptor for client */ + struct sockaddr_in server_address; /* Local address */ + struct sockaddr_in client_address; /* Client address */ + unsigned int length; /* Length of client address data structure */ + + /* Create socket for incoming connections */ + if ((server_socket = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) { + fprintf(stderr, "Couldn't create socket!\n"); + exit(ERROR_SOCKET); + } + + /* Construct local address structure */ + memset(&server_address, 0, sizeof(server_address)); /* Zero out structure */ + server_address.sin_family = AF_INET; /* Internet address family */ + server_address.sin_addr.s_addr = htonl(INADDR_ANY); /* Any incoming interface */ + server_address.sin_port = htons(port); /* Local port */ + + /* Bind to the local address */ + if (bind(server_socket, (struct sockaddr *) &server_address, sizeof(server_address)) < 0) { + fprintf(stderr, "Couldn't bind socket!\n"); + exit(ERROR_SOCKET); + } + + /* Mark the socket so it will listen for incoming connections */ + if (listen(server_socket, MAXPENDING) < 0) { + fprintf(stderr, "Couldn't listen on socket!\n"); + exit(ERROR_SOCKET); + } + + while (1) /* Run forever */ + { + /* Set the size of the in-out parameter */ + length = sizeof(client_address); + + /* Wait for a client to connect */ + if ((client_socket = accept(server_socket, + (struct sockaddr *) &client_address, + &length)) < 0) { + fprintf(stderr, "Couldn't accept client!\n"); + exit(ERROR_SOCKET); + } + + /* client_socket is connected to a client! */ + printf("Handling client %s\n", inet_ntoa(client_address.sin_addr)); + + /* start a thread to handle the client */ + bcp_client_thread_start(client_socket); + } + /* NOT REACHED */ +} + +/** + Start a Blender Command Port client thread. + */ +void bcp_client_thread_start(int client_socket) +{ + int ret; + pthread_t client_thread; + + /* allocate memory for the client thread args */ + struct bcp_client_thread_args* args; + args = (struct bcp_client_thread_args *) malloc(sizeof(struct bcp_client_thread_args)); + + args->client_socket = client_socket; + ret = pthread_create(&client_thread, NULL, bcp_client_thread, (void*) args); + + /* did the thread creation succeed? */ + if (ret != 0) { + printf("ERROR: Couldn't create a Blender Command Port client thread!\n"); + } else if (bcp_debug()) { + printf("Blender Command Port client thread %x started!\n", + (int) client_thread); + } +} + +/** + Client thread. +*/ +void* bcp_client_thread(void* args) +{ + struct bcp_client_thread_args *targs; + int client_socket; + pthread_t client_thread; + + /* extract arguments */ + targs = (struct bcp_client_thread_args *) args; + client_socket = targs->client_socket; + free(targs); + args = targs = NULL; + + /* get my thread handle */ + client_thread = pthread_self(); + if (bcp_debug()) + printf("Blender Command Port client thread %x running!\n", (int) client_thread); + + /* Detache the Blender Command Port thread */ + pthread_detach(client_thread); + + /* handle client */ + bcp_handle_client(client_socket); + + /* exit */ + pthread_exit( NULL ); +} + +/* fin */ Index: source/blender/commandport/blender/src/bcp_thread.c =================================================================== --- source/blender/commandport/blender/src/bcp_thread.c (revision 0) +++ source/blender/commandport/blender/src/bcp_thread.c (revision 0) @@ -0,0 +1,124 @@ +/* + * $Id: bcp_thread.c, v 1.0 2007/05/02, dietrich, tokyo $ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2007 by the Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Author: Dietrich Bollmann + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + * + * the command port server is running in its own thread. + * The communication with the main Blender thread is done + * via the Blender queue. + * + * header file: ../include/bcp_thread.h + * + */ + +#include +#include /* memset() */ +#include +#include +#include /* socket(), bind(), and connect() */ +#include /* sockaddr_in and inet_ntoa() */ +#include /* atoi() and exit() */ + +#include "bcp_debug.h" /* bcp_debug() */ +#include "bcp_server.h" + +#include "bcp_thread.h" + +/** Structure with arguments to pass to server thread */ +struct bcp_server_thread_args +{ + unsigned short server_port; /* BCP port */ +}; + +void *blender_command_port_server_thread(void *args); + +/** + BCP Error handling function +*/ +void bcp_error(char *err_msg) +{ + perror( err_msg ); + exit( 1 ); +} + +/** + Start the Blender Command Port thread. + */ +void bcp_thread_start(unsigned short port) +{ + int ret; + pthread_t bcpthread; + + /* allocate memory for command port thread args */ + struct bcp_server_thread_args* args; + args = (struct bcp_server_thread_args *) malloc(sizeof(struct bcp_server_thread_args)); + + args->server_port = port; + ret = pthread_create(&bcpthread, NULL, + blender_command_port_server_thread, + (void*) args); + + /* did the thread creation succeed? */ + if (ret != 0) { + bcp_error("Can't create Blender Command Port server thread!\n"); + } else if (bcp_debug()) { + printf("Blender Command Port server thread %x started " + "(port: %hu)!\n", + (int) bcpthread, port); + } +} + +/** + */ +void *blender_command_port_server_thread(void* args) +{ + struct bcp_server_thread_args *targs; + unsigned short server_port; + pthread_t server_thread; + + /* extract arguments */ + targs = (struct bcp_server_thread_args *) args; + server_port = targs->server_port; + free(targs); + args = targs = NULL; + + /* get my thread handle */ + server_thread = pthread_self(); + if (bcp_debug()) + printf("Blender Command Port server thread %x running!\n", (int) server_thread); + + /* Detache the Blender Command Port thread */ + pthread_detach(server_thread); + + /* starting the bcp_server */ + bcp_server(server_port); + + /* exit */ + pthread_exit( NULL ); +} + +/* fin */ Index: source/blender/commandport/blender/src/py_stdouterr_buffer_test.c =================================================================== --- source/blender/commandport/blender/src/py_stdouterr_buffer_test.c (revision 0) +++ source/blender/commandport/blender/src/py_stdouterr_buffer_test.c (revision 0) @@ -0,0 +1,139 @@ +/* + * $Id: py_stdouterr_buffer_test.c, v 1.0 2007/05/18, dietrich, tokyo $ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2007 by the Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Author: Dietrich Bollmann + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + * + * Main test file for testing the + * functions to redirect the stdout / stderr into a string buffer. + * + * no header file. + * + */ + +/* fetch and call objects in modules */ + +#include + +#include "py_stdouterr_buffer.h" + +char buffer[100]; + +void message_stdout(int i, int j) { + sprintf(buffer, "\n", i, j); + PySys_WriteStdout(buffer); +} + +void message_stderr(int i, int j) { + sprintf(buffer, "\n", i, j); + PySys_WriteStderr(buffer); +} + +main() { + /* initialize python */ + Py_Initialize(); + + printf("\n"); + printf(">>> ========================================================\n"); + printf(">>> redirect stdin / stdout to write into a string :)\n"); + printf(">>> --------------------------------------------------------\n"); + printf("\n"); + + /* make a stdout/stderr string buffer */ + py_stdouterr_buffer buffer; + buffer = py_stdouterr_buffer_new(); + + int i, j; + for (i = 0, j = 0; i < 3; i++, j = 0) { + + printf(">>> ========================================================\n"); + printf(">>> experiment %d\n", i); + printf(">>> --------------------------------------------------------\n"); + printf("\n"); + + /* print something - this should go to stdout/stderr of the terminal :) */ + message_stdout(i, j); + message_stderr(i, j); + j++; + + /* redirect stdout/stderr to buffer */ + py_stdouterr_buffer_redirect(buffer); + + /* print something - this should go to the buffer :) */ + message_stdout(i, j); + message_stderr(i, j); + j++; + message_stdout(i, j); + message_stderr(i, j); + j++; + + /* restore the original stdout/stderr */ + py_stdouterr_buffer_restore(buffer); + + /* print something - this should go to stdout again :) */ + message_stdout(i, j); + message_stderr(i, j); + j++; + + /* retrive buffered stdout */ + char* stdout_str; + stdout_str = py_stdouterr_buffer_get_stdout_allocate(buffer); + printf("\n"); + printf("# here comes the buffered stdout:\n"); + printf("\n"); + printf(">>>%s<<<\n", stdout_str); + printf("\n"); + free(stdout_str); + stdout_str = NULL; + + /* retrive buffered stderr */ + char* stderr_str; + stderr_str = py_stdouterr_buffer_get_stderr_allocate(buffer); + printf("# here comes the buffered stderr:\n"); + printf("\n"); + printf(">>>%s<<<\n", stderr_str); + printf("\n"); + free(stderr_str); + stderr_str = NULL; + + /* the buffers have to be cleared! */ + py_stdouterr_buffer_clear_buffers(buffer); + } + + printf(">>> ========================================================\n"); + printf(">>> ========================================================\n"); + printf("\n"); + + /* free the buffer */ + py_stdouterr_buffer_delete(buffer); + buffer = NULL; + + /* done :) */ + printf("bye... :)\n"); + printf("\n"); +} + +/* fin */ Index: source/blender/commandport/blender/src/py_stdouterr_buffer.c =================================================================== --- source/blender/commandport/blender/src/py_stdouterr_buffer.c (revision 0) +++ source/blender/commandport/blender/src/py_stdouterr_buffer.c (revision 0) @@ -0,0 +1,354 @@ +/* + * $Id: py_stdouterr_buffer.c, v 1.0 2007/05/01, dietrich, tokyo $ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2007 by the Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Author: Dietrich Bollmann + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + * + * A buffer for saving Pythons stdout / stderr + * and accessing it after in form of a c string buffer. + * + * header file: ../include/py_stdouterr_buffer.h + * + */ + +#include + +#include "error_codes.h" + +#include "py_stdouterr_buffer.h" + + +typedef struct py_stdouterr_buffer_struct { + + /* the needed modules */ + PyObject *mod_sys; + PyObject *mod_cStringIO; + + /* the initial stdout/stderr are stored here */ + PyObject *stdout_obj; + PyObject *stderr_obj; + + /* string buffer to store stdout/stderr */ + PyObject *outbuf_obj; + PyObject *errbuf_obj; + +} py_stdouterr_buffer_struct; + +char* py_buffer_get_content_allocate(PyObject *buffer); + +/** + Make a new python io buffer. +*/ +py_stdouterr_buffer py_stdouterr_buffer_new() +{ + py_stdouterr_buffer buffer; + PyGILState_STATE gstate; + + buffer = (py_stdouterr_buffer) malloc(sizeof(py_stdouterr_buffer_struct)); + + if (buffer == NULL) { + fprintf(stderr, "Couldn't allocate memory for new py_stdouterr_buffer!\n"); + exit(ERROR_MEMORY); + } + + /* aquire python thread */ + gstate = PyGILState_Ensure(); + + buffer->mod_sys = PyImport_ImportModule("sys"); + buffer->mod_cStringIO = PyImport_ImportModule("cStringIO"); + + /* store stdout and stderr */ + buffer->stdout_obj = PyObject_GetAttrString(buffer->mod_sys, "stdout"); + buffer->stderr_obj = PyObject_GetAttrString(buffer->mod_sys, "stderr"); + + /* make new string buffer for stdout and stderr */ + PyObject *func_StringIO, *args_StringIO; + func_StringIO = PyObject_GetAttrString(buffer->mod_cStringIO, "StringIO"); + args_StringIO = Py_BuildValue("()"); + buffer->outbuf_obj = PyEval_CallObject(func_StringIO, args_StringIO); + buffer->errbuf_obj = PyEval_CallObject(func_StringIO, args_StringIO); + Py_DECREF(args_StringIO); + Py_DECREF(func_StringIO); + + /* release python thread */ + PyGILState_Release(gstate); + + return buffer; +} + + +/** + Delete a i/o buffer. +*/ +void py_stdouterr_buffer_delete(py_stdouterr_buffer buffer) +{ + PyGILState_STATE gstate; + + /* aquire python thread */ + gstate = PyGILState_Ensure(); + + /* free the stdout/stderr buffer */ + Py_DECREF(buffer->errbuf_obj); + Py_DECREF(buffer->outbuf_obj); + + /* free the stdout/stderr objects */ + Py_DECREF(buffer->stdout_obj); + Py_DECREF(buffer->stderr_obj); + + /* free the imported modules */ + Py_DECREF(buffer->mod_cStringIO); + Py_DECREF(buffer->mod_sys); + + /* release python thread */ + PyGILState_Release(gstate); + + /* free string buffer structure */ + free(buffer); +} + + +/** + Redirect stdout to the string buffer. +*/ +void py_stdouterr_buffer_redirect_stdout(py_stdouterr_buffer buffer) +{ + PyGILState_STATE gstate; + + /* aquire python thread */ + gstate = PyGILState_Ensure(); + + PyObject_SetAttrString(buffer->mod_sys, "stdout", buffer->outbuf_obj); + + /* release python thread */ + PyGILState_Release(gstate); +} + + +/** + Redirect stderr to the string buffer. +*/ +void py_stdouterr_buffer_redirect_stderr(py_stdouterr_buffer buffer) +{ + PyGILState_STATE gstate; + + /* aquire python thread */ + gstate = PyGILState_Ensure(); + + PyObject_SetAttrString(buffer->mod_sys, "stderr", buffer->errbuf_obj); + + /* release python thread */ + PyGILState_Release(gstate); +} + + +/** + Redirect stdout/stderr to the string buffer. +*/ +void py_stdouterr_buffer_redirect(py_stdouterr_buffer buffer) +{ + py_stdouterr_buffer_redirect_stdout(buffer); + py_stdouterr_buffer_redirect_stderr(buffer); +} + + +/** + Restore stdout. +*/ +void py_stdouterr_buffer_restore_stdout(py_stdouterr_buffer buffer) +{ + PyGILState_STATE gstate; + + /* aquire python thread */ + gstate = PyGILState_Ensure(); + + PyObject_SetAttrString(buffer->mod_sys, "stdout", buffer->stdout_obj); + + /* release python thread */ + PyGILState_Release(gstate); +} + + +/** + Restore stdout/stderr. +*/ +void py_stdouterr_buffer_restore_stderr(py_stdouterr_buffer buffer) +{ + PyGILState_STATE gstate; + + /* aquire python thread */ + gstate = PyGILState_Ensure(); + + PyObject_SetAttrString(buffer->mod_sys, "stderr", buffer->stderr_obj); + + /* release python thread */ + PyGILState_Release(gstate); +} + + +/** + Restore stdout/stderr. +*/ +void py_stdouterr_buffer_restore(py_stdouterr_buffer buffer) +{ + py_stdouterr_buffer_restore_stdout(buffer); + py_stdouterr_buffer_restore_stderr(buffer); +} + + +/** + Retrive the content of the stderr string buffer. + + NOTE: + The retrived string is allocated storage and has to be freed! +*/ +char* py_buffer_get_content_allocate(PyObject *buffer) +{ + PyGILState_STATE gstate; + + /* aquire python thread */ + gstate = PyGILState_Ensure(); + + /* access the stored stderr string buffer content as c string */ + PyObject *func_getvalue, *args_getvalue, *buffer_obj; + func_getvalue = PyObject_GetAttrString(buffer, "getvalue"); + args_getvalue = Py_BuildValue("()"); + buffer_obj = PyEval_CallObject(func_getvalue, args_getvalue); + char* buf_pointer; + PyArg_Parse(buffer_obj, "s", &buf_pointer); + + /* allocate a c string buffer to return the string */ + int content_length = strlen(buf_pointer); + char* content; + content = (char*) malloc((content_length + 1) * sizeof(char)); + + /* copy the content string into the new buffer */ + memcpy(content, buf_pointer, content_length); + content[content_length]= '\0'; + + /* give objects free for garbage collection */ + Py_DECREF(buffer_obj); + Py_DECREF(args_getvalue); + Py_DECREF(func_getvalue); + + /* release python thread */ + PyGILState_Release(gstate); + + return content; +} + + +/** + Retrive the content of the stdout string buffer. + + NOTE: + The retrived string is allocated storage and has to be freed! +*/ +char* py_stdouterr_buffer_get_stdout_allocate(py_stdouterr_buffer buffer) +{ + return py_buffer_get_content_allocate(buffer->outbuf_obj); +} + + +/** + Retrive the content of the stderr string buffer. + + NOTE: + The retrived string is allocated storage and has to be freed! +*/ +char* py_stdouterr_buffer_get_stderr_allocate(py_stdouterr_buffer buffer) +{ + return py_buffer_get_content_allocate(buffer->errbuf_obj); +} + + +/** + Print the stdout buffer to STDOUT. +*/ +void py_stdouterr_buffer_print_stdout(py_stdouterr_buffer buffer) +{ + /* retrive buffered stdout */ + char* stdout_str; + stdout_str = py_stdouterr_buffer_get_stdout_allocate(buffer); + fprintf(stdout, "%s", stdout_str); + free(stdout_str); + stdout_str = NULL; +} + + +/** + Print the stderr buffer to STDERR. +*/ +void py_stdouterr_buffer_print_stderr(py_stdouterr_buffer buffer) +{ + /* retrive buffered stderr */ + char* stderr_str; + stderr_str = py_stdouterr_buffer_get_stderr_allocate(buffer); + fprintf(stderr, "%s", stderr_str); + free(stderr_str); + stderr_str = NULL; +} + + +/** + Print first the stdout buffer to STDOUT + and after the stderr buffer to STDERR. +*/ +void py_stdouterr_buffer_print(py_stdouterr_buffer buffer) +{ + py_stdouterr_buffer_print_stdout(buffer); + py_stdouterr_buffer_print_stderr(buffer); +} + + +/** + Clear stdout/stderr buffers. +*/ +void py_stdouterr_buffer_clear_buffers(py_stdouterr_buffer buffer) +{ + PyGILState_STATE gstate; + + /* aquire python thread */ + gstate = PyGILState_Ensure(); + + /* free the stdout/stderr buffer */ + Py_DECREF(buffer->errbuf_obj); + Py_DECREF(buffer->outbuf_obj); + + /* make new string buffer for stdout and stderr */ + PyObject *func_StringIO, *args_StringIO; + func_StringIO = PyObject_GetAttrString(buffer->mod_cStringIO, "StringIO"); + args_StringIO = Py_BuildValue("()"); + buffer->outbuf_obj = PyEval_CallObject(func_StringIO, args_StringIO); + buffer->errbuf_obj = PyEval_CallObject(func_StringIO, args_StringIO); + Py_DECREF(args_StringIO); + Py_DECREF(func_StringIO); + + /* release python thread */ + PyGILState_Release(gstate); +} + + +/* fin */ Index: source/blender/commandport/blender/src/bcp_handle_client.c =================================================================== --- source/blender/commandport/blender/src/bcp_handle_client.c (revision 0) +++ source/blender/commandport/blender/src/bcp_handle_client.c (revision 0) @@ -0,0 +1,149 @@ +/* + * $Id: bcp_handle_client.c, v 1.0 2007/05/02, dietrich, tokyo $ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2007 by the Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Author: Dietrich Bollmann + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + * + * Handle command port client + * + * header file: ../include/bcp_handle_client.h + * + */ + +#include /* for printf() */ +#include /* for free() */ +#include /* strlen(), memcpy() */ +#include + +#include "message_handler.h" +#include "string_buffer.h" + +#include "bcp_debug.h" /* bcp_debug() */ +#include "bcp_blender.h" +#include "bcp_handle_client.h" +#include "hexdump_string.h" /* hexdump_string() */ + +// void mainqenter_command_port_input_event(char* script); +char* make_no_result_package_allocate(); + +#define BCP_NO_RESULT "#i0\n#s4\nNone\n#s0\n\n#s0\n\n" /* a packed Blender `None' result - + used in DEBUG mode */ + +void bcp_handle_client(int client_socket) +{ + int debug, debug3, debug4; + message_handler message_handler; + bcp_blender_handler blender_handler; + char *command, *result; + int package_number; + + /* get debug level */ + debug = bcp_debug(); + debug3 = (debug >= 3); /* if debug >= 3 hexdump the received packages before processing them */ + debug4 = (debug >= 4); /* if debug >= 4 only hexdump the received packages + without sending them to blender for processing. */ + + /* message handler */ + message_handler = message_handler_new(client_socket); + + /* Blender handler to handle the client command run requests */ + blender_handler = bcp_blender_handler_new(); + + /* client socket loop */ + package_number = 0; /* the number of the current package */ + while ((command = message_handler_receive_message_allocate(message_handler)) != (char*) NULL) { + + /* increment package counter */ + package_number++; + + /* DEBUG - dump command */ + if (debug3) { + /* DEBUG > 3 mode - + print and dump received packages */ + printf("[DEBUG] >>> Received package #%d:\n", package_number); + printf(" >>>%s<<<\n", command); /* print package */ + hexdump_string(" ", command); /* dump package */ + } + + /* process the command */ + if (debug4) { + /* DEBUG > 4 mode - + don't process package, just return `None' result package */ + result = make_no_result_package_allocate(); + } else { + /* put a package process request in blender queue + and wait for result */ + result = bcp_blender_handle_input_allocate(blender_handler, command); + } + + /* send the result back */ + message_handler_send_message(message_handler, result); + + /* free the result buffer */ + if (debug) printf("[DEBUG] bcp_handle_client: free(result), result: %p\n", result); + free(result); + result = NULL; + + /* free the command buffer */ + if (debug) printf("[DEBUG] bcp_handle_client: free(command), command: %p\n", command); + free(command); + command = NULL; + } + + printf("bye...\n"); + + /* cleanup */ + bcp_blender_handler_delete(blender_handler); + if (debug) printf("[DEBUG] bcp_handle_client: bcp_blender_handler_delete(blender_handler);\n"); + message_handler_delete(message_handler); + if (debug) printf("[DEBUG] bcp_handle_client: message_handler_delete(message_handler);\n"); + close(client_socket); + if (debug) printf("[DEBUG] bcp_handle_client: close(client_socket);\n"); +} + +/** + For DEBUG mode only - + make a `None' result package and return it. +*/ +char* make_no_result_package_allocate() +{ + char *none_result_package, *package; + int length; + + /* allocate memory for message client structure */ + none_result_package = BCP_NO_RESULT; + + /* allocating memory for the package */ + length = strlen(none_result_package); + package = (char*) malloc((length + 1) * sizeof(char)); + memcpy(package, none_result_package, length); + package[length]= '\0'; + + /* return the newly allocated copy */ + return package; +} + +/* fin */ Index: source/blender/commandport/utilities/test/bcp_package_test.c =================================================================== --- source/blender/commandport/utilities/test/bcp_package_test.c (revision 0) +++ source/blender/commandport/utilities/test/bcp_package_test.c (revision 0) @@ -0,0 +1,52 @@ +/* + * $Id: bcp_package_test.c, v 1.0 2007/06/13, dietrich, tokyo $ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2007 by the Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Author: Dietrich Bollmann + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + * + * Main function for testing the + * Blender Commandport Package functionality + * using the tests defined in ../src/bcp_package.c + * + * usage: + * + * cd /blender/source/blender/commandport/utilities/test/ + * scons -f SConstruct.bcp_package.test + * ./test + * + */ + +#include + +#include "bcp_package.h" + +int main(int argc, char *argv[]) +{ + /* test */ + bcp_package_test(); +} + +/* fin */ Index: source/blender/commandport/utilities/test/SConstruct.bcp_package.test =================================================================== --- source/blender/commandport/utilities/test/SConstruct.bcp_package.test (revision 0) +++ source/blender/commandport/utilities/test/SConstruct.bcp_package.test (revision 0) @@ -0,0 +1,52 @@ +# -*- mode: python -*- +# +# $Id: SConstruct.bcp_package.test, v 1.0 2007/06/13, dietrich, tokyo $ +# +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# The Original Code is Copyright (C) 2007 by the Blender Foundation. +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Author: Dietrich Bollmann +# Contributor(s): none yet. +# +# ***** END GPL LICENSE BLOCK ***** +# +# A simple build file for testing the +# Blender Commandport Package functionality +# using the tests defined in bcp_package_test.c and ../src/bcp_package.c +# +# usage: +# +# cd /blender/source/blender/commandport/utilities/test/ +# scons -f SConstruct.bcp_package.test +# ./test + +env = Environment() + +env.Append(CPPPATH = ['../include']) + +test = env.Program('test', [ + '../src/bcp_package.c', + 'bcp_package_test.c' + ]) + +Default(test) + +# fin. Index: source/blender/commandport/utilities/include/bcp_debug.h =================================================================== --- source/blender/commandport/utilities/include/bcp_debug.h (revision 0) +++ source/blender/commandport/utilities/include/bcp_debug.h (revision 0) @@ -0,0 +1,72 @@ +/* + * $Id: bcp_debug.h, v 1.0 2007/05/30, dietrich, tokyo $ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2007 by the Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Author: Dietrich Bollmann + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + * + * Module for initializing, storing and querying + * the Blender command port debug level. + * + * The command port can be made to print debug messages in different + * verbosity levels via the command line option `--debug bcp:'. + * `' can be one of 1, 2, 3, 4. + * + * For more information see the debug help text defined in function + * `print_help_debug()' in file `../../blender/src/bcp_handle_client.c' + * or call Blender with the option `-hd' / `--help=debug'. + * + * For the command port debug code search sources for `debug("bcp")' + * and `bcp_debug()'. + * + * source file: ../src/bcp_debug.c + * + */ + +#ifndef BCP_DEBUG_H +#define BCP_DEBUG_H + +/** + Set BCP debug level. + + This option currently is used in + - blender/source/blender/commandport/blender/src/commandport.c and + - blender/source/blender/commandport/blash/src/blash.c + to init the debug level for the Blender command port server / client + respectively. +*/ +void bcp_set_debug_level(int level); + +/** + Returns the debug level for the Blender command port. + + Used in all functions printing debug messages + which depend on the debug level. +*/ +int bcp_debug(); + +#endif /* BCP_DEBUG_H */ + +/* fin */ Index: source/blender/commandport/utilities/include/bcp_meta_commands.h =================================================================== --- source/blender/commandport/utilities/include/bcp_meta_commands.h (revision 0) +++ source/blender/commandport/utilities/include/bcp_meta_commands.h (revision 0) @@ -0,0 +1,85 @@ +/* + * $Id: bcp_meta_commands.h, v 1.0 2007/06/13, dietrich, tokyo $ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2007 by the Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Author: Dietrich Bollmann + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + * + * The Meta Commands class defines codes used by the command port. + * + * Different classes of codes / meta commands exist: + * + * - codes to tell the Blender Python interpreter how to evaluate the + * messages send by a client + * + * - codes to change the Python print mode + * + * - codes to reset the command port + * + * - codes expressing the result of the evaluation of Python command string + * + * - codes to tell the client if the send command string is a complete or + * incomplete Python command sequence + * + * included by the following files: + * + * - ../../blender/src/bcp_python.c + * - ../src/bcp_shell.c + * + */ + +#ifndef BCP_META_COMMANDS_H +#define BCP_META_COMMANDS_H + +/* BCP input modes */ +#define BCP_SINGLE_MODE_COMMAND 'S' /* single command input mode */ +#define BCP_EVAL_MODE_COMMAND 'E' /* eval command input mode */ +#define BCP_FILE_MODE_COMMAND 'F' /* file command input mode (default) */ + +/* result print modes */ +#define BCP_REPR_PRINT_MODE_COMMAND 'r' /* reset the command port (default) */ +#define BCP_STR_PRINT_MODE_COMMAND 's' /* reset the command port */ + +/* reset the BCP namespace */ +#define BCP_RESET_COMMAND 'R' /* reset the command port */ + +/** + Result codes - +*/ +#define BCP_RESULT_CODE_SUCCESS 0 /* The python evaluation was successful */ +#define BCP_RESULT_CODE_INCOMPLETE_INPUT 1 /* The entered python code is incomplete + and the blender server waits for more + input lines to complete the input */ +#define BCP_RESULT_CODE_ERROR 2 /* An error occured during the + evaluation ot the python code */ +#define BCP_RESULT_CODE_UNDEFINED 3 /* This code should never be returned + and indicates that an unexpecte result + was returned by the Python interpreter */ +#define BCP_RESULT_CODE_EMPTY_INPUT 4 /* Returned if the shell input was emtpy */ + +#endif /* BCP_META_COMMANDS_H */ + +/* fin */ + Index: source/blender/commandport/utilities/include/bcp_shell.h =================================================================== --- source/blender/commandport/utilities/include/bcp_shell.h (revision 0) +++ source/blender/commandport/utilities/include/bcp_shell.h (revision 0) @@ -0,0 +1,90 @@ +/* + * $Id: bcp_shell.h, v 1.0 2007/05/31, dietrich, tokyo $ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2007 by the Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Author: Dietrich Bollmann + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + * + * Defines the interactive shell called by blash's `main()' function. + * + * source file: ../src/bcp_shell.c + * + */ + +#ifndef BCP_SHELL_H + +/** + Shell Evaluation Modes + + Three different modes can be used from the interactive bash shell: + + * BCP_SINGLE_MODE + + This is the normal shell mode: + Python commands are entered line by line. + If a single line can be interpreted as complete python command, + it is evaluated and the result is printed; + if the first line doesn't correspond to a complete python command, + all lines following this first line are stored until an empty line + is entered. At this point all lines together are evaluated and the + result is printed to the shell. + + * BCP_EVAL_MODE + + The entered string is interpreted as a complete, isolated Python expression and + evaluated by the python interpreter. The result is printed to the shell. + + * BCP_FILE_MODE + + A sequences of Python statements can be entered and executed by the Python interpreter. No result is printed. + This mode is usefull when a full program is entered at once. It is also useful for + executing definitions which contain blank lines. + + For more informatin concerning the shell evaluation modes compare the + documentation in `bcp_python.h' and `bcp_python.c'. + +*/ +#define BCP_SINGLE_MODE 0 +#define BCP_EVAL_MODE 1 +#define BCP_FILE_MODE 2 + +/** + Open a new Blender command port shell. +*/ +void bcp_shell(char* server_IP_address, unsigned short server_port, int mode); + +/** + Open a new Blender command port shell. + + If the connection to the Blender server could not been established immediately, + retry up to `retries' times. Sleep `retry_sleeptime' seconds before trying again. +*/ +void bcp_shell_wait(char* server_IP_address, unsigned short server_port, int mode, + int retries, float retry_sleeptime, char* init_command); + +#define BCP_SHELL_H +#endif /* BCP_SHELL_H */ + +/* fin */ Index: source/blender/commandport/utilities/include/bcp_defaults.h =================================================================== --- source/blender/commandport/utilities/include/bcp_defaults.h (revision 0) +++ source/blender/commandport/utilities/include/bcp_defaults.h (revision 0) @@ -0,0 +1,47 @@ +/* + * $Id: bcp_defaults.h, v 1.0 2007/06/13, dietrich, tokyo $ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2007 by the Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Author: Dietrich Bollmann + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + * + * Default definitions for the Blender Command Port. + * + */ + +#ifndef BCP_DEFAULTS_H +#define BCP_DEFAULTS_H + +/** + Defaults +*/ + +/* IP and port */ +#define BCP_DEFAULT_IP "127.0.0.1" +#define BCP_DEFAULT_PORT 5555 + +#endif /* BCP_DEFAULTS_H */ + +/* fin */ Index: source/blender/commandport/utilities/include/string_buffer_test.h =================================================================== --- source/blender/commandport/utilities/include/string_buffer_test.h (revision 0) +++ source/blender/commandport/utilities/include/string_buffer_test.h (revision 0) @@ -0,0 +1,48 @@ +/* + * $Id: string_buffer_test.h, v 1.0 2007/05/30, dietrich, tokyo $ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2007 by the Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Author: Dietrich Bollmann + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + * + * Some functions to test the `string_buffer' functions. + * + * see: `../include/string_buffer.h' and `../src/string_buffer.c' + * + * source file: ../src/string_buffer_test.c + * + */ + +#ifndef STRING_BUFFER_TEST_H +#define STRING_BUFFER_TEST_H + +/** + main string_buffer testing function... +*/ +void string_buffer_test(); + +#endif /* STRING_BUFFER_TEST_H */ + +/* fin */ Index: source/blender/commandport/utilities/include/fsleep.h =================================================================== --- source/blender/commandport/utilities/include/fsleep.h (revision 0) +++ source/blender/commandport/utilities/include/fsleep.h (revision 0) @@ -0,0 +1,50 @@ +/* + * $Id: fsleep.h, v 1.0 2007/05/19, dietrich, tokyo $ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2007 by the Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Author: Dietrich Bollmann + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + * + * sleep for an amount of time - the time might be any fraction of seconds given as float. + * + * source file: ../src/fsleep.c + * + */ + +#ifndef FSLEEP_H +#define FSLEEP_H + +/** + sleep for an amount of time - + + the time might be any fraction of seconds given as float. +*/ +int fsleep(float seconds); + +#endif /* FSLEEP_H */ + +/* fin */ + + Index: source/blender/commandport/utilities/include/bcp_package.h =================================================================== --- source/blender/commandport/utilities/include/bcp_package.h (revision 0) +++ source/blender/commandport/utilities/include/bcp_package.h (revision 0) @@ -0,0 +1,162 @@ +/* + * $Id: bcp_package.h, v 1.0 2007/05/31, dietrich, tokyo $ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2007 by the Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Author: Dietrich Bollmann + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + * + * Functions to pack and unpack integers, strings and commands into a + * single string for sending them over the command port socket. + * + * source file: ../src/bcp_package.c + * + */ + +#ifndef BCP_PACKAGE_H +#define BCP_PACKAGE_H + +/* types */ +#define BCP_PACKAGE_TYPE_EMPTY 'e' +#define BCP_PACKAGE_TYPE_UNDEFINED 'u' +#define BCP_PACKAGE_TYPE_INT 'i' +#define BCP_PACKAGE_TYPE_STRING 's' +#define BCP_PACKAGE_TYPE_COMMAND 'c' + +/** + bcp_package type definition +*/ +typedef struct bcp_package_struct *bcp_package; + +/** + Make a new package. +*/ +bcp_package bcp_package_new(); + +/** + Delete a package. +*/ +void bcp_package_delete(bcp_package package); + +/** + Empty a package. +*/ +void bcp_package_make_empty(bcp_package package); + +/** + Add integer. +*/ +void bcp_package_add_int(bcp_package package, int i); + +/** + Add string. +*/ +void bcp_package_add_string(bcp_package package, char* s); + +/** + Add command. +*/ +void bcp_package_add_command(bcp_package package, char command); + +/** + Convert the package to a string representation + which can be stored / send via the internet .... + + Note: + The memory for the string returned by this function + has to be freed by the caller! +*/ +char* bcp_package_pack_allocate(bcp_package package); + +/** + Unpack the elements in the string `packed' + and return the result package. + + Note: + The string `is manipulated' and not printable as + one string after calling this function. + Note also that no new memory is allocated + for unpacked string elements. + `packed' therefore only can be freed after + the processing of the unpacked elements is finished. +*/ +bcp_package bcp_package_unpack(char* packed); + + +/* ========================================================= + * BCP package enumerator functions + * --------------------------------------------------------- + */ + +/** + bcp_package enumerator type definition +*/ +typedef struct bcp_package_enumerator_struct *bcp_package_enumerator; + +/** + Make a new package enumerator. +*/ +bcp_package_enumerator bcp_package_enumerator_new(bcp_package p); + +/** + Delete a package enumerator. +*/ +void bcp_package_enumerator_delete(bcp_package_enumerator enumerator); + +/** + Reset enumerator. +*/ +void bcp_package_enumerator_reset(bcp_package_enumerator e); + +/** + Get next element in package. +*/ +void* bcp_package_enumerator_get_next_element(bcp_package_enumerator e, char* type); + +/** + Debugging function: + Dump an unpacked package +*/ +void dump_package(bcp_package p); + +/* ========================================================= + * Test functions + * --------------------------------------------------------- + */ + +/* to build the test functions, uncomment the following define: */ +#define BCP_PACKAGE_TEST + +#ifdef BCP_PACKAGE_TEST + +/** + test +*/ +void bcp_package_test(); + +#endif /* BCP_PACKAGE_TEST */ + +#endif /* BCP_PACKAGE_H */ + +/* fin */ Index: source/blender/commandport/utilities/include/string_buffer.h =================================================================== --- source/blender/commandport/utilities/include/string_buffer.h (revision 0) +++ source/blender/commandport/utilities/include/string_buffer.h (revision 0) @@ -0,0 +1,187 @@ +/* + * $Id: string_buffer.h, v 1.0 2007/05/30, dietrich, tokyo $ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2007 by the Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Author: Dietrich Bollmann + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + * + * A buffer to save c strings in chunks. + * + * Every string chunk (or slice) appended (or prepended) to the + * buffer is copied into newly allocated memory which is appended (or + * prepended) to a queue. Only when the whole string is needed (or + * some other operation is performed for which the whole string is + * needed), the slices are copied into a single newly allocated c + * buffer. + * + * source file: ../src/string_buffer.c + * + */ + +#ifndef STRING_BUFFER_H +#define STRING_BUFFER_H + +typedef struct string_buffer_struct *string_buffer; + +/** + Make a new text buffer. +*/ +string_buffer string_buffer_new(); + +/** + Delete a text buffer. +*/ +void string_buffer_delete(string_buffer buffer); + +/** + Return true if the string buffer is empty and false if not. +*/ +int string_buffer_is_empty(string_buffer buffer); + +/** + Empty a text buffer. +*/ +void string_buffer_make_empty(string_buffer buffer); + +/** + Prepend a string to a string buffer. +*/ +void string_buffer_prepend(string_buffer buffer, char* str); + +/** + Append a newline caracter to 'str' and + prepend the result to a string buffer. +*/ +void string_buffer_prepend_newline(string_buffer buffer, char* str); + +/** + Append a line to a text buffer. +*/ +void string_buffer_append(string_buffer buffer, char* str); + +/** + Append a string and a newline caracter to a string buffer. +*/ +void string_buffer_append_newline(string_buffer buffer, char* str); + +/** + Get the length of a string buffer. +*/ +int string_buffer_get_length(string_buffer buffer); + +/** + Cleanup a string buffer. + Returns the length of the string buffer. + + Append the string slices constituting a string buffer + into one single string slice. +*/ +int string_buffer_cleanup(string_buffer buffer); + +/** + Like strcmp - but for string buffers :) +*/ +int string_buffer_compare_to_string(string_buffer buffer, char* str); + +/** + Check if the string buffer starts with the given prefix. + Return 1 if this is the case and 0 otherwise. +*/ +int string_buffer_starts_with_prefix(string_buffer buffer, char* prefix); + +/** + Check if the string buffer is empty + or only contains white space. +*/ +int string_buffer_is_empty_or_white_space_string(string_buffer buffer); + +/** + Transform a string buffer into a newly allocated character array. + A pointer to the allocated char array is returned. + The length of the string is returned as second parameter. +*/ +char* string_buffer_to_char_array_allocate(string_buffer buffer, int* length); + +/** + Read a single line from stdin. + The function returns the accumulated length of lines in 'buffer'. +*/ +int string_buffer_read_line_from_stdin(string_buffer buffer); + +/** + Get the line prompt. + The returned string is a copy of the original prompt in newly allocated memory. +*/ +char* string_buffer_get_line_prompt_allocate(string_buffer buffer); + +/** + Get the text prompt. + The returned string is a copy of the original prompt in newly allocated memory. +*/ +char* string_buffer_get_text_prompt_allocate(string_buffer buffer); + +/** + Get the text coninue prompt. + The returned string is a copy of the original prompt in newly allocated memory. +*/ +char* string_buffer_get_text_coninue_prompt_allocate(string_buffer buffer); + +/** + Set the read line prompt. +*/ +void string_buffer_set_line_prompt(string_buffer buffer, char *prompt); + +/** + Read a text (a sequence of lines) from stdin. + The input is terminated by a line containing only a dot character '.'. + + The function returns the accumulated length of all read lines. +*/ +int string_buffer_read_text_from_stdin(string_buffer buffer); + +/** + Set the read text prompt. +*/ +void string_buffer_set_text_prompt(string_buffer buffer, char *prompt); + +/** + Set the read text continue prompt. +*/ +void string_buffer_set_text_coninue_prompt(string_buffer buffer, char *prompt); + +/** + Print a text buffer. +*/ +void string_buffer_print(string_buffer buffer); + +/** + Dump the inner structure of a string buffer to stdout. + Note: This function is only for use during development. +*/ +void string_buffer_dump(string_buffer buffer); + +#endif /* STRING_BUFFER_H */ + +/* fin */ Index: source/blender/commandport/utilities/include/hexdump_string.h =================================================================== --- source/blender/commandport/utilities/include/hexdump_string.h (revision 0) +++ source/blender/commandport/utilities/include/hexdump_string.h (revision 0) @@ -0,0 +1,128 @@ +/* + * $Id: hexdump_string.h, v 1.0 2007/05/30, dietrich, tokyo $ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2007 by the Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Author: Dietrich Bollmann + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + * + * Hexdump functions to debug the Blender Command Port... + * + * source file: ../src/hexdump_string.c + * + */ + +#ifndef HEXDUMP_STRING_H +#define HEXDUMP_STRING_H + +/** + Print ascii code table. + + +---+----------------------------------------------------------------+ + | \ | 0 1 2 3 4 5 6 7 8 9 A B C D E F | + +---+----------------------------------------------------------------+ + | 0 | NUL SOH STX ETX EOT ENQ ACK BEL BS HT LF VT FF CR SO SI | + | 1 | DLE DC1 DC2 DC3 DC4 NAK SYN ETB CAN EM SUB ESC FS GS RS US | + | 2 | SP ! " # $ % & ' ( ) * + , - . / | + | 3 | 0 1 2 3 4 5 6 7 8 9 : ; < = > ? | + | 4 | @ A B C D E F G H I J K L M N O | + | 5 | P Q R S T U V W X Y Z [ \ ] ^ _ | + | 6 | ` a b c d e f g h i j k l m n o | + | 7 | p q r s t u v w x y z { | } ~ DEL | + +---+----------------------------------------------------------------+ +*/ +void print_ascii_code_table(); + +/** + Print the code table used in last column by `hexdump_string()'. + + The character codes are represented by the following characters: + + - the character represented by the code itself - if printable + - '>' for tab (0x09 - ascii: HT = Horizontal Tab) + - '^' for newline (0x0a - ascii: LF = Line Feed) + - '0' for the null character (0x00 - ascii: NUL = Null char.) + - '?' for things which might cause problems - and ? itself :) + + +---+----------------------------------------------------------------+ + | \ | 0 1 2 3 4 5 6 7 8 9 A B C D E F | + +---+----------------------------------------------------------------+ + | 0 | 0 ? ? ? ? ? ? ? ? > ^ ? ? ? ? ? | + | 1 | ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? | + | 2 | SP ! " # $ % & ' ( ) * + , - . / | + | 3 | 0 1 2 3 4 5 6 7 8 9 : ; < = > ? | + | 4 | @ A B C D E F G H I J K L M N O | + | 5 | P Q R S T U V W X Y Z [ \ ] ^ _ | + | 6 | ` a b c d e f g h i j k l m n o | + | 7 | p q r s t u v w x y z { | } ~ ? | + +---+----------------------------------------------------------------+ +*/ +void print_printable_dump_code_table(); + +/** + Dump the hex codes a string is made of. + + Example: + + The string + "eins zwei drei vier fuenf sechs sieben, tab: '\t', newline: '\n' and - to terminate the string - the nullchar: " + is dumped as: + + ============================================================================== + addr 0 1 2 3 4 5 6 7 8 9 A B C D E F | printable repr.| + ------------------------------------------------------------+----------------+ + 00000000 65 69 6e 73 20 7a 77 65 69 20 64 72 65 69 20 76 |eins zwei drei v| + 00000010 69 65 72 20 66 75 65 6e 66 20 73 65 63 68 73 20 |ier fuenf sechs | + 00000020 73 69 65 62 65 6e 2c 20 74 61 62 3a 20 27 09 27 |sieben, tab: '>'| + 00000030 2c 20 6e 65 77 6c 69 6e 65 3a 20 27 0a 27 20 61 |, newline: '^' a| + 00000040 6e 64 20 2d 20 74 6f 20 74 65 72 6d 69 6e 61 74 |nd - to terminat| + 00000050 65 20 74 68 65 20 73 74 72 69 6e 67 20 2d 20 74 |e the string - t| + 00000060 68 65 20 6e 75 6c 6c 63 68 61 72 3a 20 00 |he nullchar: 0| + ============================================================================== +*/ +void hexdump_string(char* prefix, char* string); + +/** + Dump the hex codes a string is made of. + + Simple formatting - example: + + The string "eins zwei drei vier fuenf sechs sieben." + is dumped as: + + 65 69 6e 73 20 7a 77 65 69 20 64 72 65 69 20 76 + 69 65 72 20 66 75 65 6e 66 20 73 65 63 68 73 20 + 73 69 65 62 65 6e 2e 00 +*/ +void simple_hexdump_string(char* string); + +/** + Test the hexdump functions. +*/ +void hexdump_string_test(); + +#endif /* HEXDUMP_STRING_H */ + +/* fin */ + Index: source/blender/commandport/utilities/include/message_handler.h =================================================================== --- source/blender/commandport/utilities/include/message_handler.h (revision 0) +++ source/blender/commandport/utilities/include/message_handler.h (revision 0) @@ -0,0 +1,69 @@ +/* + * $Id: message_handler.h, v 1.0 2007/06/13, dietrich, tokyo $ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2007 by the Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Author: Dietrich Bollmann + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + * + * The message handler class implements the protocol used by the + * commandport for exchanging text messages via a socket connection. + * A message is defined as a string of an arbitrary length terminated + * with a '\0' character. + * + * source file: ../src/message_handler.c + * + */ + +#ifndef MESSAGE_HANDLER_H +#define MESSAGE_HANDLER_H + +typedef struct message_handler_data* message_handler; + +#include "error_codes.h" + +/** + Make a new message socket handler. +*/ +message_handler message_handler_new(int socket); + +/** + Delete a message socket handler. +*/ +void message_handler_delete(message_handler handler); + +/** + Send a message. + */ +void message_handler_send_message(message_handler handler, char* message); + +/** + Receive a message. + The return value NULL signals the end of the client connection. +*/ +char* message_handler_receive_message_allocate(message_handler handler); + +#endif /* MESSAGE_HANDLER_H */ + +/* fin */ Index: source/blender/commandport/utilities/include/message_client.h =================================================================== --- source/blender/commandport/utilities/include/message_client.h (revision 0) +++ source/blender/commandport/utilities/include/message_client.h (revision 0) @@ -0,0 +1,84 @@ +/* + * $Id: message_client.h, v 1.0 2007/06/13, dietrich, tokyo $ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2007 by the Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Author: Dietrich Bollmann + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + * + * The message client class is the central part of a Blender Command + * Port client written in c. It implements the functionality for + * connecting and disconnecting to / from a Blender Server and for + * sending and receiving text messages. + * + * source file: ../src/message_client.c + * + */ + +#ifndef MESSAGE_CLIENT_H +#define MESSAGE_CLIENT_H + +#include "error_codes.h" + +typedef struct message_client_struct *message_client; + +/** + Make a new message client. +*/ +message_client message_client_new(char *server_IP_address, unsigned short server_port); + +/** + Make a new message client. + + If the connection could not been established immediately, retry up to `retries' times. + Sleep `retry_sleeptime' seconds before trying again. +*/ +message_client message_client_new_wait(char *server_IP_address, unsigned short server_port, + int retries, float retry_sleeptime); + +/** + Delete a message client. +*/ +void message_client_delete(message_client client); + +/** + Send a message. + */ +void message_client_send(message_client client, char* message); + +/** + Receive a message. + The return value NULL signals the end of the client connection. + */ +char* message_client_receive_allocate(message_client client); + +/** + Send a message and return the answer. + */ +char* message_client_send_receive_allocate(message_client client, char* message); + +#endif /* MESSAGE_CLIENT_H */ + +/* fin */ + Index: source/blender/commandport/utilities/include/error_codes.h =================================================================== --- source/blender/commandport/utilities/include/error_codes.h (revision 0) +++ source/blender/commandport/utilities/include/error_codes.h (revision 0) @@ -0,0 +1,52 @@ +/* + * $Id: error_codes.h, v 1.0 2007/06/13, dietrich, tokyo $ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2007 by the Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Author: Dietrich Bollmann + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + * + * Blender Command Port error codes. + * + */ + +#ifndef ERROR_CODES_H +#define ERROR_CODES_H + +#define ERROR_TEXTBUFFER 2 +#define ERROR_MEMORY 3 +#define ERROR_RECEIVE 4 +#define ERROR_SEND 5 +#define ERROR_SOCKET 6 +#define ERROR_CONNECTION 7 +#define ERROR_SYNCHRONIZATION 8 +#define ERROR_UNKNOWN_TYPE 9 +#define ERROR_PARSER 10 +#define ERROR_IN_BCP_PROTOCOL 11 +#define ERROR_BCP_PYTHON 12 + +#endif /* ERROR_CODES_H */ + +/* fin */ + Index: source/blender/commandport/utilities/SConscript =================================================================== --- source/blender/commandport/utilities/SConscript (revision 0) +++ source/blender/commandport/utilities/SConscript (revision 0) @@ -0,0 +1,37 @@ +# -*- mode: python -*- +# +# $Id: SConscript, v 1.0 2007/06/13, dietrich, tokyo $ +# +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# The Original Code is Copyright (C) 2007 by the Blender Foundation. +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Author: Dietrich Bollmann +# Contributor(s): none yet. +# +# ***** END GPL LICENSE BLOCK ***** +# +# Build file for the Blender Commandport Utilities. + +SConscript([ + 'src/SConscript', + ]) + +# fin. Index: source/blender/commandport/utilities/src/string_buffer_test.c =================================================================== --- source/blender/commandport/utilities/src/string_buffer_test.c (revision 0) +++ source/blender/commandport/utilities/src/string_buffer_test.c (revision 0) @@ -0,0 +1,123 @@ +/* + * $Id: string_buffer_test.c, v 1.0 2007/05/30, dietrich, tokyo $ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2007 by the Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Author: Dietrich Bollmann + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + * + * Some functions to test the `string_buffer' functions. + * + * see: `../include/string_buffer.h' and `../src/string_buffer.c' + * + * header file: ../include/string_buffer_test.h + * + */ + +#include +#include +#include + +#include "string_buffer.h" + +void string_buffer_test_append() +{ + string_buffer text = string_buffer_new(); + + string_buffer_append(text, "hi die :)\n"); + string_buffer_append(text, " was"); + string_buffer_append(text, " "); + string_buffer_append(text, "macht\n"); + string_buffer_append(text, " das Leben?\n"); + + string_buffer_print(text); + + string_buffer_delete(text); +} + +void string_buffer_cleanup_test() +{ + /* init buffer */ + string_buffer buffer = string_buffer_new(); + + string_buffer_append(buffer, "hi die :)\n"); + string_buffer_append(buffer, " was"); + string_buffer_append(buffer, " "); + string_buffer_append(buffer, "macht\n"); + string_buffer_append(buffer, " das Leben?\n"); + + /* clean up the buffer buffer */ + /* DEBUG */ + printf("===\n"); + printf("Buffer before cleanup (length: %d):\n", string_buffer_get_length(buffer)); + printf("===\n"); + string_buffer_print(buffer); + string_buffer_dump(buffer); + + int length = string_buffer_cleanup(buffer); + + /* DEBUG */ + printf("Buffer after cleanup (length: %d):\n", string_buffer_get_length(buffer)); + printf("===\n"); + string_buffer_print(buffer); + string_buffer_dump(buffer); + + string_buffer_delete(buffer); +} + +/** + Reading a sequende of non-empty lines from stdin + The input is terminated by entering an empty line. + */ +void test_string_buffer_read_text_from_stdin() +{ + /* allocate a string buffer for the lines to read */ + string_buffer paragraph = string_buffer_new(); + + /* read a paragraph from stdin */ + int length = string_buffer_read_text_from_stdin(paragraph); + printf("\n"); + + /* print the paragraph */ + printf("The paragraph is %d characters long...\n", length); + printf("---\n"); + string_buffer_dump(paragraph); + string_buffer_print(paragraph); + printf("---\n"); + printf("\n"); +} + +/** + main string_buffer testing function... +*/ +void string_buffer_test() +{ + string_buffer_test_append(); + string_buffer_cleanup_test(); + test_string_buffer_read_text_from_stdin(); + + printf("\nend of string_buffer tests...\n\n"); +} + +/* fin */ Index: source/blender/commandport/utilities/src/fsleep.c =================================================================== --- source/blender/commandport/utilities/src/fsleep.c (revision 0) +++ source/blender/commandport/utilities/src/fsleep.c (revision 0) @@ -0,0 +1,58 @@ +/* + * $Id: fsleep.c, v 1.0 2007/05/19, dietrich, tokyo $ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2007 by the Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Author: Dietrich Bollmann + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + * + * sleep for an amount of time - the time might be any fraction of seconds given as float. + * + * header file: ../include/fsleep.h + * + */ + +#include + +/** + sleep for an amount of time - + + the time might be any fraction of seconds given as float. +*/ +int fsleep(float seconds) +{ + /* separate in seconds and nanoseconds */ + int sec = (int) seconds; + int nsec = (int) ((seconds - (float) sec) * 1.0e9); + + /* fill timespec to pass to nanosleep() */ + struct timespec requested_time, remaining; + requested_time.tv_sec = sec; + requested_time.tv_nsec = nsec; + + /* sleep */ + nanosleep(&requested_time, &remaining); +} + +/* fin */ Index: source/blender/commandport/utilities/src/bcp_package.c =================================================================== --- source/blender/commandport/utilities/src/bcp_package.c (revision 0) +++ source/blender/commandport/utilities/src/bcp_package.c (revision 0) @@ -0,0 +1,1139 @@ +/* + * $Id: bcp_package.c, v 1.0 2007/05/31, dietrich, tokyo $ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2007 by the Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Author: Dietrich Bollmann + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + * + * Functions to pack and unpack integers, strings and commands into a + * single string for sending them over the command port socket. + * + * header file: ../include/bcp_package.h + * + */ + +/* fin */ +/* bcp_package.c */ + +#include +#include +#include + +#include "bcp_package.h" +#include "error_codes.h" + +/** + element type +*/ +typedef struct element_struct *element; +typedef struct element_struct { + char type; + union { + int vint; + char* vstr; + char vcmd; + } element; + element next; +} element_struct; + +/** + package type struct +*/ +typedef struct bcp_package_struct { + element first; + element last; +} bcp_package_struct; + + +/* Declaration of utility functions */ +element new_element_allocate(); +void add_element(bcp_package p, element e); +void delete_element(element e); +element new_int_element(int i); +element new_string_element(char* s); +int intlen(int e); +int length_packed_element(element e); +int length_packed(bcp_package p); + +char* pack_element(char* buffer, element e); +char unpack_element(bcp_package p, char** packed); + +int parse_int(char** s); +char parse_char(char** s); +char parse_type(char** s); +void parse_newline(char** s); +int parse_int_element(char** s); +char* parse_string(char** s); +char* parse_string_element(char** s); +char parse_command_element(char** s); + +/* test functions */ +#ifdef BCP_PACKAGE_TEST +#define BUFFER_SIZE 80 +void print_element(element e); +void dump_packed_package(bcp_package p); +void dump_packed_element(element e); +void dump_element_header(char* header); +#endif /* BCP_PACKAGE_TEST */ + + +/** + Make a new package. +*/ +bcp_package bcp_package_new() +{ + bcp_package package; + package = (bcp_package) malloc(sizeof(bcp_package_struct)); + + if (package == NULL) { + fprintf(stderr, "Couldn't allocate memory for new bcp_package!\n"); + exit(ERROR_MEMORY); + } + + package->first = (element) NULL; + package->last = (element) NULL; + + return package; +} + + +/** + Delete a package. +*/ +void bcp_package_delete(bcp_package package) +{ + /* empty the package */ + bcp_package_make_empty(package); + + /* free package structure */ + free(package); +} + + +/** + Empty a package. +*/ +void bcp_package_make_empty(bcp_package package) +{ + /* delete all elements */ + element e = package->first; + for( ; e != NULL; e = e->next) { + delete_element(e); + } + + /* set pointers to NULL + to indicate that the package is empty */ + package->first = (element) NULL; + package->last = (element) NULL; +} + + +/** + Allocate memory for a new package element. +*/ +element new_element_allocate() +{ + element e; + e = (element) malloc(sizeof(element_struct)); + + if (e == NULL) { + fprintf(stderr, "Couldn't allocate memory for new bcp_package element!\n"); + exit(ERROR_MEMORY); + } + + e->type = BCP_PACKAGE_TYPE_UNDEFINED; + e->next = NULL; + + return e; +} + + +/** + Add an element to a package. +*/ +void add_element(bcp_package p, element e) +{ + /* set the 'next' member to NULL + to indicate that it is the last element */ + e->next = (element) NULL; + + /* append the new element to the element list of the package */ + if (p->first == NULL) { + p->first = e; + } else { + p->last->next = e; + } + p->last = e; +} + + +/** + Delete a package element. +*/ +void delete_element(element e) +{ + free(e); +} + +/** + Make a new integer element. +*/ +element new_int_element(int i) +{ + element e; + e = new_element_allocate(); + + e->type = BCP_PACKAGE_TYPE_INT; + e->element.vint = i; + + return e; +} + +/** + Make a new string element. +*/ +element new_string_element(char* s) +{ + element e; + e = new_element_allocate(); + + e->type = BCP_PACKAGE_TYPE_STRING; + e->element.vstr = s; + + return e; +} + +/** + Make a new command element. +*/ +element new_command_element(char command) +{ + element e; + e = new_element_allocate(); + + e->type = BCP_PACKAGE_TYPE_COMMAND; + e->element.vcmd = command; + + return e; +} + +/** + Add integer. +*/ +void bcp_package_add_int(bcp_package package, int i) +{ + /* make a new integer element */ + element e; + e = new_int_element(i); + add_element(package, e); +} + +/** + Add string. +*/ +void bcp_package_add_string(bcp_package package, char* s) +{ + /* make a new string element */ + element e; + e = new_string_element(s); + add_element(package, e); +} + +/** + Add command. +*/ +void bcp_package_add_command(bcp_package package, char command) +{ + /* make a new command element */ + element e; + e = new_command_element(command); + add_element(package, e); +} + +/** + Calculate the length of an integers string representation. +*/ +int intlen(int i) +{ + /* 0 has the length 1 */ + if (i == 0) return 1; + + /* calculate length for i > 0 */ + int length; + for (length = 0; i > 0; i /= 10, length++); + + /* done */ + return length; +} + +/** + Calculate the length of a packed element. +*/ +int length_packed_element(element e) +{ + /* an undefined element will not be packed + - return 0 */ + if (e->type == BCP_PACKAGE_TYPE_UNDEFINED) return 0; + + /* length accumulator */ + int length = 0; + + /* add length of prefix '#' */ + length += 1; + + /* add length of the element type code + - the type is represented by a caracter of length 1 */ + length += 1; + + /* the header is terminated by '\n' - add 1 */ + length += 1; + + /* the rest of the header depends on the element type */ + int vlen; + switch (e->type) { + + case BCP_PACKAGE_TYPE_INT: + + /* integer are coded as part of the header + example: 123 is coded as "#i123\n" */ + + /* add the length of the integer value */ + length += intlen(e->element.vint); + + /* done */ + break; + + case BCP_PACKAGE_TYPE_STRING: + + /* the header of a string element + contains the lenght of the string. + The string value itself followes the header. + example: "hallo" is coded as "#s5\nhallo\n" + */ + + /* calculate the length of the string value */ + vlen = strlen(e->element.vstr); + + /* the length of the string value is written into the header + - add the necessary length */ + length += intlen(vlen); + + /* add the length of the string value */ + length += vlen; + + /* to faciliate the readability of the packed representation + a newline is added after the value - add its length */ + length += 1; + + /* done */ + break; + + case BCP_PACKAGE_TYPE_COMMAND: + + /* commands are characters coded as part of the header + example: 'c' is coded as "#cc\n" */ + + /* add 1 for the command caracter */ + length += 1; + + /* done */ + break; + + default: + fprintf(stderr, "Found a bcp_package element with an unknown type!\n"); + exit(ERROR_UNKNOWN_TYPE); + } + + /* done */ + return length; +} + +/** + Calculate the length of the packed + representation of a package. +*/ +int length_packed(bcp_package p) +{ + /* add the length of all elements */ + int length = 0; + element e = p->first; + for( ; e != NULL; e = e->next) { + length += length_packed_element(e); + } + + /* done */ + return length; +} + +/** + Code the package + as a human readable string. +*/ +char* bcp_package_pack_allocate(bcp_package package) +{ + /* calculate length */ + int length = length_packed(package); + + /* allocate memory for the packed string representation */ + char* packed = (char*) malloc((length + 1) * sizeof(char)); + if (packed == NULL) { + fprintf(stderr, "Couldn't allocate memory to pack a bcp_package!\n"); + exit(ERROR_MEMORY); + } + + /* write all elements to the buffer */ + char* p = packed; + element e = package->first; + for( ; e != NULL; e = e->next) { + p = pack_element(p, e); + } + + /* terminate the packed string representation + with the null character */ + *p = '\0'; + + /* return the packed representation */ + return packed; +} + +/** + Pack an element. +*/ +char* pack_element(char* buffer, element e) +{ + /* an undefined element will not be packed + - return the buffer as it is */ + if (e->type == BCP_PACKAGE_TYPE_UNDEFINED) return buffer; + + /* the rest of the header depends on the element type */ + switch (e->type) { + + case BCP_PACKAGE_TYPE_INT: + + /* integer are coded as part of the header + example: 123 is coded as "#i123\n" */ + + /* add the integer element */ + buffer += sprintf(buffer, "#i%d\n", e->element.vint); + + /* done */ + break; + + case BCP_PACKAGE_TYPE_STRING: + + /* the header of a string element + contains the lenght of the string. + The string value itself followes the header. + example: "hallo" is coded as "#s5\nhallo\n" + */ + + /* write the string header */ + buffer += sprintf(buffer, "#s%d\n", strlen(e->element.vstr)); + + /* write the string itself */ + buffer += sprintf(buffer, "%s\n", e->element.vstr); + + /* done */ + break; + + case BCP_PACKAGE_TYPE_COMMAND: + + /* commands are characters coded as part of the header + example: 'c' is coded as "#cc\n" */ + + /* write the command element */ + buffer += sprintf(buffer, "#c%c\n", e->element.vcmd); + + /* done */ + break; + + default: + fprintf(stderr, "Found a bcp_package element with an unknown type!\n"); + exit(ERROR_UNKNOWN_TYPE); + } + + /* return a pointer to the next unwritten caracter */ + return buffer; +} + +/** + Unpack the elements in the string `packed' + and return the result package. +*/ +bcp_package bcp_package_unpack(char* packed) +{ + /* make a new empty package */ + bcp_package package; + package = bcp_package_new(); + + /* unpack all elements */ + char** p = &packed; + char type; + + do { + type = unpack_element(package, p); + } while (*p != NULL); + + /* return the new package */ + return package; +} + +/** + Unpack the first element in `packed'. + A pointer to the next element + - or NULL if the current element was the last one - + is returned. +*/ +char unpack_element(bcp_package p, char** packed) +{ + /* set return *packed to NULL and + return BCP_PACKAGE_TYPE_EMPTY + if there are no more elements to parse */ + if (**packed == '\0') { + *packed = NULL; /* NULL to signal that there are no more elements */ + return BCP_PACKAGE_TYPE_EMPTY; /* return BCP_PACKAGE_TYPE_EMPTY + to signal that there are no more elements */ + } + + /* unpack element type */ + char type; + type = parse_type(packed); + /* DEBUG: printf("type: %c, rest: \"%s\"\n", type, *packed); */ + + /* print value */ + int integer; + char* str; + char command; + switch (type) { + + case BCP_PACKAGE_TYPE_UNDEFINED: + /* do nothing */ + break; + + case BCP_PACKAGE_TYPE_INT: + + /* unpack integer */ + integer = parse_int_element(packed); + + /* add the integer */ + bcp_package_add_int(p, integer); + + break; + + case BCP_PACKAGE_TYPE_STRING: + + /* unpack string */ + str = parse_string_element(packed); + + /* add string */ + bcp_package_add_string(p, str); + + break; + + case BCP_PACKAGE_TYPE_COMMAND: + + /* unpack command */ + command = parse_command_element(packed); + + /* add a command */ + bcp_package_add_command(p, command); + + break; + + default: + fprintf(stderr, "Found a bcp_package element with an unknown type!\n"); + exit(ERROR_UNKNOWN_TYPE); + } + + /* return type of parsed element */ + return type; +} + +/** + Parse a caracter from the beginning of string `*s' + and return it. +*/ +char parse_char(char** s) +{ + /* parse character */ + char c; + int parsed; + parsed = sscanf(*s, "%c", &c); + + /* check if the item could be parsed */ + if (parsed != 1) { + fprintf(stderr, "ERROR: Couldn't parse caracter: %s\n", *s); + exit(ERROR_PARSER); + } + + /* advance to the next caracters */ + (*s)++; + + /* return parsed char */ + return c; +} + +/** + Parse an integer from the beginning of string `s' + and return it. +*/ +int parse_int(char** s) +{ + /* parse character */ + int i; + int parsed; + parsed = sscanf(*s, "%d", &i); + + /* check if the item could be parsed */ + if (parsed != 1) { + fprintf(stderr, "ERROR: Couldn't parse integer: %s\n", *s); + exit(ERROR_PARSER); + } + + /* calculate length of parsed integer string */ + int length; + length = intlen(i); + + /* advance to the next caracters */ + *s += length; + + /* return the parsed integer */ + return i; +} + +/** + Parse a type from the beginning of string `*s' + and return the it. +*/ +char parse_type(char** s) +{ + /* parse number sign (#) */ + char number_sign; + number_sign = parse_char(s); + + /* check if the item could be parsed */ + if (number_sign != '#') { + fprintf(stderr, "ERROR: Couldn't parse type: %s\n", *s); + exit(ERROR_PARSER); + } + + /* parse the type caracter */ + char type; + type = parse_char(s); + + /* return parsed type */ + return type; +} + +/** + Parse a newline caracter from the beginning of string `*s'. +*/ +void parse_newline(char** s) +{ + /* parse character */ + char newline; + newline = parse_char(s); + + /* check if the item could be parsed */ + if (newline != '\n') { + fprintf(stderr, "ERROR: Couldn't parse newline: %s\n", *s); + exit(ERROR_PARSER); + } +} + +/** + Parse an integer element + and return it. +*/ +int parse_int_element(char** s) +{ + /* extract the integer */ + int i; + i = parse_int(s); + + /* parse the newline terminating the header */ + parse_newline(s); + + /* return parsed integer */ + return i; +} + +/** + Parse a string + and return a pointer to it. +*/ +char* parse_string(char** s) +{ + /* extract the length of the string */ + int length; + length = parse_int(s); + + /* parse the newline terminating the header */ + parse_newline(s); + + /* store pointer to found string */ + char* str; + str = *s; + + /* calculate the position of the newline caracter + which terminates the string */ + *s = *s + length; + + /* overwrite the newline character at the end of the string + with a string terminator / null caracter */ + **s = '\0'; + + /* calculate the position of the next packed element */ + (*s)++; + + /* return pointer to the found string */ + return str; +} + +/** + Parse a string element + and return a pointer to it. +*/ +char* parse_string_element(char** s) +{ + /* extract the integer */ + char* str; + str = parse_string(s); + + /* return pointer to parsed string */ + return str; +} + +/** + Parse a command element + and return a pointer to it. +*/ +char parse_command_element(char** s) +{ + /* parse character */ + char command; + command = parse_char(s); + + /* calculate the position of the next packed element */ + (*s)++; + + /* return the parsed command */ + return command; +} + +/* ========================================================= + * BCP package enumerator functions + * --------------------------------------------------------- + */ + +/** + package enumerator type struct +*/ +typedef struct bcp_package_enumerator_struct { + bcp_package package; + element next; +} bcp_package_enumerator_struct; + +/** + Make a new enumerator. +*/ +bcp_package_enumerator bcp_package_enumerator_new(bcp_package p) +{ + bcp_package_enumerator enumerator; + enumerator = (bcp_package_enumerator) malloc(sizeof(bcp_package_enumerator_struct)); + + if (enumerator == NULL) { + fprintf(stderr, "Couldn't allocate memory for new bcp_package_enumerator!\n"); + exit(ERROR_MEMORY); + } + + enumerator->package = p; + enumerator->next = p->first; + + return enumerator; +} + +/** + Delete a package enumerator. +*/ +void bcp_package_enumerator_delete(bcp_package_enumerator enumerator) +{ + /* free enumerator structure */ + free(enumerator); +} + +/** + Reset enumerator. +*/ +void bcp_package_enumerator_reset(bcp_package_enumerator e) +{ + e->next = e->package->first; +} + +/** + Get next element in package. +*/ +void* bcp_package_enumerator_get_next_element(bcp_package_enumerator e, char* type) +{ + /* get next element */ + element elem = e->next; + + /* if there is no next element + set type to BCP_PACKAGE_TYPE_EMPTY to indicate that there is no further element + and return NULL + */ + if (elem == NULL) { + *type = BCP_PACKAGE_TYPE_EMPTY; + return NULL; + } + + /* set enumerators `next' pointer to `elem's next element */ + e->next = elem->next; + + /* get type of found element */ + *type = elem->type; + + /* return pointer to value */ + switch (*type) { + + case BCP_PACKAGE_TYPE_UNDEFINED: + return (void*) NULL; + break; + + case BCP_PACKAGE_TYPE_INT: + return (void*) &(elem->element.vint); + break; + + case BCP_PACKAGE_TYPE_STRING: + return (void*) elem->element.vstr; + break; + + case BCP_PACKAGE_TYPE_COMMAND: + return (void*) &(elem->element.vcmd); + break; + + default: + fprintf(stderr, "Found a bcp_package element with an unknown type!\n"); + exit(ERROR_UNKNOWN_TYPE); + } +} + +/* ========================================================= + * Test functions + * --------------------------------------------------------- + */ + +#ifdef BCP_PACKAGE_TEST + +void bcp_package_test() +{ + /* stuff needed for the tests */ + char buffers[BUFFER_SIZE][BUFFER_SIZE]; + + /* test */ + printf("[test] Make a package, add elements, delete package:\n"); + printf("\n"); + + /* make a new package */ + bcp_package package; + package = bcp_package_new(); + + /* add some elements */ + int i; + int j = 1; + for (i = 0; i < 3; i++) { + + /* add an integer */ + bcp_package_add_int(package, j); + + /* add a string */ + sprintf(buffers[i], "Hi, number %d :)", j); + bcp_package_add_string(package, buffers[i]); + + /* add a command */ + char command = 'a' + i; + bcp_package_add_command(package, command); + + /* calculate a new example integer */ + j *= j * 100; + } + + /* dump */ + printf(">>> dumping the original package:\n"); + dump_package(package); + printf("\n"); + + /* DEBUG - for a more detailed dump uncomment the following: */ + /* + dump_packed_package(package); + printf("\n"); + */ + + /* pack */ + char* packed; + packed = bcp_package_pack_allocate(package); + + /* print packed package */ + printf(">>> the packed package:\n"); + printf(">>>%s<<<\n", packed); + printf("\n"); + + /* delete package */ + bcp_package_delete(package); + + /* unpack the string `packed' */ + bcp_package package2; + package2 = bcp_package_unpack(packed); + + /* dump */ + printf(">>> dumping the unpacked package:\n"); + dump_package(package2); + printf("\n"); + + /* DEBUG - for a more detailed dump uncomment the following: */ + /* + dump_packed_package(package); + printf("\n"); + */ + + /* test the enumerator functions */ + printf(">>> testing enumerator functions:\n"); + printf("\n"); + + /* make new package enumerator */ + bcp_package_enumerator enumerator; + enumerator = bcp_package_enumerator_new(package2); + + /* header */ + printf(" listing elements:\n"); + + /* print element */ + i = 0; + void* elem; + char type; + while (1) { + + /* get next element */ + elem = bcp_package_enumerator_get_next_element(enumerator, &type); + + /* if there are no more elements - exit */ + if (type == BCP_PACKAGE_TYPE_EMPTY) break; + + /* print index and type of element */ + printf(" %3d. (%c): ", i, type); + + /* print value */ + switch (type) { + + case BCP_PACKAGE_TYPE_UNDEFINED: + printf(""); + break; + + case BCP_PACKAGE_TYPE_INT: + printf("%d", *((int*) elem)); + break; + + case BCP_PACKAGE_TYPE_STRING: + printf("\"%s\"", (char*) elem); + break; + + case BCP_PACKAGE_TYPE_COMMAND: + printf("%c", *((char*) elem)); + break; + + default: + fprintf(stderr, "Found a bcp_package element with an unknown type!\n"); + exit(ERROR_UNKNOWN_TYPE); + } + + printf("\n"); + + /* increment element index */ + i++; + } + + /* all elements have been printed */ + printf(" done.\n"); + + /* delete the package enumerator */ + bcp_package_enumerator_delete(enumerator); + + printf("\n"); + + /* delete package */ + bcp_package_delete(package2); + + /* free the packed string representation */ + free(packed); + packed = NULL; + + /* done :) */ + printf("bye :)\n"); + printf("\n"); +} + +/** + Dump all elements in a package. + + example: + + (package): { + 0. (c): 'a' + 1. (i): 124, + 2. (s): "laber", + } + +*/ +void dump_package(bcp_package p) +{ + /* print first line: type and length of the package */ + printf(" (package,%d): {\n", length_packed(p)); + + /* print elements */ + int i = 0; + element e = p->first; + for( ; e != NULL; i++, e = e->next) { + + /* print number, type and value of the ith element */ + printf(" %3d. (%c): ", i, e->type); + print_element(e); + printf(",\n"); + } + + /* print last line */ + printf(" }\n"); +} + +/** + Dump an element. +*/ +void print_element(element e) +{ + /* print value */ + switch (e->type) { + + case BCP_PACKAGE_TYPE_UNDEFINED: + printf(""); + break; + + case BCP_PACKAGE_TYPE_INT: + printf("%d", e->element.vint); + break; + + case BCP_PACKAGE_TYPE_STRING: + printf("\"%s\"", e->element.vstr); + break; + + case BCP_PACKAGE_TYPE_COMMAND: + printf("%c", e->element.vcmd); + break; + + default: + fprintf(stderr, "Found a bcp_package element with an unknown type!\n"); + exit(ERROR_UNKNOWN_TYPE); + } +} + +/** + Dump all elements in a package + together with their packed representation. +*/ +void dump_packed_package(bcp_package p) +{ + /* print first line: type and length of the package */ + printf(" package:\n"); + printf("\n"); + printf(" - length: %d\n", length_packed(p)); + printf(" - elements:\n"); + printf("\n"); + + /* print elements */ + int i = 0; + element e = p->first; + for( ; e != NULL; i++, e = e->next) { + + /* print ith element */ + printf(" - element %d:\n", i); + dump_packed_element(e); + printf("\n"); + } + + /* print last line */ + printf("\n"); +} + +/** + Dump an element + together with its packed representation. +*/ +void dump_packed_element(element e) +{ + /* calculate length */ + int length = length_packed_element(e); + + /* allocate memory for the packed string representation */ + char* packed = (char*) malloc((length + 1) * sizeof(char)); + if (packed == NULL) { + fprintf(stderr, "Couldn't allocate memory to pack an element!\n"); + exit(ERROR_MEMORY); + } + + /* write the element to the buffer */ + pack_element(packed, e); + + /* terminate the packed string representation + with the null character */ + packed[length] = '\0'; + + /* print element type, value, + length of packed representation + and the packed representation itself */ + printf(" - type: %c\n", e->type); + printf(" - value: "); print_element(e); printf("\n"); + printf(" - packed representation:\n"); + printf(" - calculated length: %d\n", length); + printf(" - packed: \"%s\"\n", packed); + printf(" - length: %d\n", strlen(packed)); + + /* free the allocated memory */ + free (packed); +} + +/** + Dump an element header. +*/ +void dump_element_header(char* header) +{ + /* dump header */ + char* p = header; + for( ; *p != '\0'; p++) { + printf("%X ", *p); + } + printf("%X", *p); +} + +#endif /* BCP_PACKAGE_TEST */ + +/* fin */ Index: source/blender/commandport/utilities/src/string_buffer.c =================================================================== --- source/blender/commandport/utilities/src/string_buffer.c (revision 0) +++ source/blender/commandport/utilities/src/string_buffer.c (revision 0) @@ -0,0 +1,690 @@ +/* + * $Id: string_buffer.c, v 1.0 2007/05/30, dietrich, tokyo $ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2007 by the Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Author: Dietrich Bollmann + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + * + * A buffer to save c strings in chunks. + * + * Every string chunk (or slice) appended (or prepended) to the + * buffer is copied into newly allocated memory which is appended (or + * prepended) to a queue. Only when the whole string is needed (or + * some other operation is performed for which the whole string is + * needed), the slices are copied into a single newly allocated c + * buffer. + * + * header file: ../include/string_buffer.h + * + */ + +/* string_buffer.c - Dietrich Bollmann */ + +#include +#include +#include /* isspace(c) */ +#include +#include +#include + +#include "error_codes.h" + +#include "string_buffer.h" + +typedef struct string_slice_struct *string_slice; +typedef struct string_slice_struct { + char* str; + string_slice next; +} string_slice_struct; + +typedef struct string_buffer_struct { + string_slice first; + string_slice last; + char* line_prompt; + char* text_prompt; + char* text_coninue_prompt; +} string_buffer_struct; + +#define LINE_PROMPT ">>> " +#define TEXT_PROMPT ">>> " +#define TEXT_CONTINUE_PROMPT "... " + +/* Declaration of utility functions */ +void set_prompt(char** target, char* prompt); +string_slice new_string_slice(char* str, int append_newline_flag); +char* copy_string_allocate(char* string); + +/** + Make a new string buffer. +*/ +string_buffer string_buffer_new() +{ + string_buffer buffer; + buffer = (string_buffer) malloc(sizeof(string_buffer_struct)); + + if (buffer == NULL) { + fprintf(stderr, "Couldn't allocate memory for new string_buffer!\n"); + exit(ERROR_MEMORY); + } + + buffer->first = (string_slice) NULL; + buffer->last = (string_slice) NULL; + + /* prompts used by the input functions */ + /* initializing them with NULL - + required by the 'string_buffer_set_*_prompt' function + */ + buffer->line_prompt = NULL; + buffer->text_prompt = NULL; + buffer->text_coninue_prompt = NULL; + /* init with defaults */ + string_buffer_set_line_prompt( buffer, LINE_PROMPT ); + string_buffer_set_text_prompt( buffer, TEXT_PROMPT ); + string_buffer_set_text_coninue_prompt( buffer, TEXT_CONTINUE_PROMPT ); + + return buffer; +} + +/** + Delete a string buffer. +*/ +void string_buffer_delete(string_buffer buffer) +{ + /* empty the buffer - free all slices */ + string_buffer_make_empty(buffer); + + /* free the momory for the prompts */ + free(buffer->line_prompt); + free(buffer->text_prompt); + free(buffer->text_coninue_prompt); + + /* free string buffer structure */ + free(buffer); +} + +/** + Get the line prompt. + The returned string is a copy of the original prompt in newly allocated memory. +*/ +char* string_buffer_get_line_prompt_allocate(string_buffer buffer) +{ + return copy_string_allocate(buffer->line_prompt); +} + +/** + Get the text prompt. + The returned string is a copy of the original prompt in newly allocated memory. +*/ +char* string_buffer_get_text_prompt_allocate(string_buffer buffer) +{ + return copy_string_allocate(buffer->text_prompt); +} + +/** + Get the text coninue prompt. + The returned string is a copy of the original prompt in newly allocated memory. +*/ +char* string_buffer_get_text_coninue_prompt_allocate(string_buffer buffer) +{ + return copy_string_allocate(buffer->text_coninue_prompt); +} + +/** + Set a prompt. +*/ +void set_prompt(char** target, char* prompt) +{ + /* if defined, free memory of former prompt */ + if (*target != NULL) { free(*target); } + + /* copy the prompt */ + char* newprompt = copy_string_allocate(prompt); + + /* setting new prompt */ + *target = newprompt; +} + +/** + Set the read line prompt. +*/ +void string_buffer_set_line_prompt(string_buffer buffer, char *prompt) +{ + set_prompt(&buffer->line_prompt, prompt); +} + +/** + Set the read text prompt. +*/ +void string_buffer_set_text_prompt(string_buffer buffer, char *prompt) +{ + set_prompt(&buffer->text_prompt, prompt); +} + +/** + Set the read text continue prompt. +*/ +void string_buffer_set_text_coninue_prompt(string_buffer buffer, char *prompt) +{ + set_prompt(&buffer->text_coninue_prompt, prompt); +} + +/** + Return 1 if the string buffer is empty and 0 if not. +*/ +int string_buffer_is_empty(string_buffer buffer) +{ + return ((buffer->first == (string_slice) NULL) && + (buffer->last == (string_slice) NULL)); +} + +/** + Empty a string buffer. +*/ +void string_buffer_make_empty(string_buffer buffer) +{ + /* free the slice buffers */ + string_slice next; + string_slice slice = buffer->first; + while(slice != NULL) { + /* save pointer to the next slice buffer */ + next = slice->next; + + /* free the string holding the slice */ + free(slice->str); + + /* free the slice struct itself */ + free(slice); + + /* get the next slice */ + slice = next; + } + + /* finally set the string slice pointers to NULL + (signifying a string buffer to be empty) + */ + buffer->first = (string_slice) NULL; + buffer->last = (string_slice) NULL; +} + +/** + Append a string_slice to a string_buffer. + + Note: + Only for internal use: No new memory is allocated for the string_slice! +*/ +void string_buffer_append_string_slice(string_buffer buffer, string_slice sliceBuffer) +{ + /* Ensure that the next pointer of the appended slice is NULL */ + sliceBuffer->next = (string_slice) NULL; /* The new slice is the last one */ + + /* Append the new string_slice buffer to 'buffer' */ + if (buffer->first == NULL) { + buffer->first = sliceBuffer; + } else { + buffer->last->next = sliceBuffer; + } + buffer->last = sliceBuffer; +} + +/** + Prepend a string_slice to a string_buffer. + + Note: + Only for internal use: No new memory is allocated for the string_slice! +*/ +void string_buffer_prepend_string_slice(string_buffer buffer, string_slice sliceBuffer) +{ + /* The former first slice now is the second one + works also for an empty buffer (buffer->first == NULL) */ + sliceBuffer->next = buffer->first; + + /* The new slice is the new first one */ + buffer->first = sliceBuffer; + + /* If the string buffer is empty (buffer->last == NULL), + the new slice is also the last one */ + if (buffer->last == NULL) { + buffer->last = sliceBuffer; + } +} + + +/** + Allocate a new string slice for the string parameter. + If the 'append_newline_flag' is set, append a newline to 'string'. +*/ +string_slice new_string_slice(char* str, int append_newline_flag) +{ + /* Make a new string_slice for the string */ + string_slice sliceBuffer; + sliceBuffer = (string_slice) malloc(sizeof(string_slice_struct)); + + if (sliceBuffer == NULL) { + fprintf(stderr, "Couldn't allocate memory for new slice in string_buffer!\n"); + exit(ERROR_MEMORY); + } + + /* Copy the string into the new slice struct */ + + /* allocate memory and copy the string */ + int length = strlen(str); + if (append_newline_flag) { + length++; /* add 1 for the newline */ + } + char* newstr = (char*) malloc((length + 1) * sizeof(char)); + memcpy(newstr, str, length); + if (append_newline_flag) { + newstr[length - 1]= '\n'; /* append the newline */ + } + newstr[length]= '\0'; + + /* hang the string into the new slice buffer */ + sliceBuffer->str = newstr; + + /* No next slice for the moment - + initializing the pointer to the next slice with NULL */ + sliceBuffer->next = (string_slice) NULL; + + /* return the new string slice */ + return sliceBuffer; +} + + +/** + Append a string to a string buffer. +*/ +void string_buffer_append(string_buffer buffer, char* str) +{ + /* Make a new string_slice for the string */ + string_slice sliceBuffer = new_string_slice(str, 0); + + /* append the new string_slice to 'buffer' */ + string_buffer_append_string_slice(buffer, sliceBuffer); +} + + +/** + Append a string and a newline caracter to a string buffer. +*/ +void string_buffer_append_newline(string_buffer buffer, char* str) +{ + /* Make a new string_slice for the string */ + string_slice sliceBuffer = new_string_slice(str, 1); + + /* append the new string_slice to 'buffer' */ + string_buffer_append_string_slice(buffer, sliceBuffer); +} + + +/** + Prepend a string to a string buffer. +*/ +void string_buffer_prepend(string_buffer buffer, char* str) +{ + /* Make a new string_slice for the string */ + string_slice sliceBuffer = new_string_slice(str, 0); + + /* prepend the new string_slice to 'buffer' */ + string_buffer_prepend_string_slice(buffer, sliceBuffer); +} + + +/** + Append a newline to 'str' and + prepend the result to a string buffer. +*/ +void string_buffer_prepend_newline(string_buffer buffer, char* str) +{ + /* Make a new string_slice for the string */ + string_slice sliceBuffer = new_string_slice(str, 1); + + /* prepend the new string_slice to 'buffer' */ + string_buffer_prepend_string_slice(buffer, sliceBuffer); +} + + +/** + Get the length of a string buffer. +*/ +int string_buffer_get_length(string_buffer buffer) +{ + + /* sum up the length of all string slices */ + int length = 0; + string_slice slice; + for (slice = buffer->first; slice != NULL; slice = slice->next) { + int slice_length = strlen(slice->str); + length += slice_length; + } + + /* return the lenth of the buffer */ + return length; +} + +/** + Cleanup a string buffer. + Returns the length of the string buffer. + + Append the string slices constituting a string buffer + into one single string slice. +*/ +int string_buffer_cleanup(string_buffer buffer) +{ + /* no cleanup necessary if the buffer is empty + ('buffer->first' and 'buffer->last->next' are both NULL) + or there is only one string slice in the string buffer + (the first string slice is also the last ) + - both can be tested with + (buffer->first == buffer->last) + */ + if (buffer->first == buffer->last) { + /* no cleanup necessary */ + return string_buffer_get_length(buffer); + } + + /* copy the content of the string_buffer into a newly allocated char array */ + int length; + char* content = string_buffer_to_char_array_allocate(buffer, &length); + + /* free the old slices */ + string_buffer_make_empty(buffer); + + /* Make a new string_slice for the content */ + string_slice sliceBuffer; + sliceBuffer = (string_slice) malloc(sizeof(string_slice_struct)); + + if (sliceBuffer == NULL) { + fprintf(stderr, "Couldn't allocate memory for new slice in string_buffer!\n"); + exit(ERROR_MEMORY); + } + + /* link the new buffer into 'sliceBuffer' */ + sliceBuffer->str = content; + + /* the pointer 'sliceBuffer->next' + is set to NULL by 'string_buffer_append_string_slice()', + signalling that the new slice is the last one. + */ + + /* append the new and only string_slice to 'buffer' */ + string_buffer_append_string_slice(buffer, sliceBuffer); + + /* return the length */ + return length; +} + +/** + Like strcmp - but for string buffers :) +*/ +int string_buffer_compare_to_string(string_buffer buffer, char* str) +{ + /* simlify the buffer by copying all slices into a single one */ + string_buffer_cleanup(buffer); + + /* the string of the remaining slice now can be combined with strcmp */ + return strcmp(buffer->first->str, str); +} + +/** + Check if the string buffer starts with the given prefix. + Return 1 if this is the case and 0 otherwise. +*/ +int string_buffer_starts_with_prefix(string_buffer buffer, char* prefix) +{ + /* simlify the buffer by copying all slices into a single one */ + string_buffer_cleanup(buffer); + + /* get the length of the prefix */ + int length = strlen(prefix); + + /* compare the first 'length' caracters of the string buffer + to the prefix and return the result of the comparison */ + if (strncmp(buffer->first->str, prefix, length) == 0) { + /* the buffer starts with the prefix */ + return 1; + } else { + /* the buffer does not start with the prefix */ + return 0; + } +} + +/** + Check if the string buffer is empty + or only contains white space. +*/ +int string_buffer_is_empty_or_white_space_string(string_buffer buffer) +{ + /* if string buffer is empty return true */ + if (string_buffer_is_empty(buffer)) return 1; + + /* simlify the buffer by copying all slices into a single one */ + string_buffer_cleanup(buffer); + + /* get the length of the buffer content */ + int length; + length = string_buffer_get_length(buffer); + + /* get pointer to first char in the buffer */ + char* c = buffer->first->str; + char* limit = c + length; + + /* if one of the characters in the buffer is not a white space character, return false */ + for ( ; c < limit; c++) { + /* isspace(c) <=> c is one of: space, formfeed, newline, + carriage return, tab, vertical tab (defined in ) + */ + if (!isspace(*c)) return 0; + } + + /* all characters are white space characters */ + return 1; +} + +/** + Transform a string buffer into a newly allocated character array. + A pointer to the allocated char array is returned. + The length of the string is returned as second parameter. + If NULL is supplied as second parameter, it is ignored. +*/ +char* string_buffer_to_char_array_allocate(string_buffer buffer, int* length) +{ + /* allocate a new buffer 'content' + to hold the whole content of the current string buffer */ + int buffer_length; + buffer_length = string_buffer_get_length(buffer); + char* content = (char*) malloc( (buffer_length + 1) * sizeof(char) ); + + /* copy the content of the slices into the newly allocated buffer */ + string_slice slice; + char* p = content; /* init pointer to position in new string buffer */ + for (slice = buffer->first; slice != NULL; slice = slice->next) { + int slice_length = strlen(slice->str); /* get length of the current string slice */ + memcpy(p, slice->str, slice_length); + p += slice_length; /* set pointer to the end in new string buffer */ + } + *p = '\0'; /* mark the end of the buffer with the character '\0' */ + + /* return the result */ + if (length != (int*) NULL) *length = buffer_length; + return content; +} + +/** + Read a single line from stdin. + The function returns the accumulated length of lines in 'buffer'. +*/ +int string_buffer_read_line_from_stdin(string_buffer buffer) +{ + /* print prompt and + get the next line using GNU readline() */ + char* line = NULL; + line = readline(buffer->line_prompt); + + /* checking the result */ + if (line == NULL) { + + /* - either there was a problem while trying to read a line from stdin - + - or blash received an EOT (End-Of-Transmission character) + for example because CTRL-D was pressed... + */ + + return -1; + } + + /* save non-empty lines in readline() history */ + if (strlen(line) > 0) { + add_history(line); + } + + /* append read line to buffer */ + string_buffer_append(buffer, line); + + /* free the string buffer allocated by readline() */ + free(line); + + /* clean up the buffer buffer */ + int length = string_buffer_cleanup(buffer); + + /* return the length of the read buffer */ + return length; +} + +/** + Read a text (a sequence of lines) from stdin. + The input is terminated by a line containing only a dot character '.'. + + The function returns the accumulated length of all read lines. + + If the there was a problem while trying to read an input + - for example because CTRL-D was hit - -1 is returned. +*/ +int string_buffer_read_text_from_stdin(string_buffer buffer) +{ + /* set prompt for first line */ + char* prompt = NULL; + prompt = buffer->text_prompt; + + /* loop to read a sequence of lines from stdin */ + char* line = NULL; + while (1) { + + /* print prompt and get the next line */ + line = readline(prompt); + + /* checking the result */ + if (line == NULL) { + + /* - either there was a problem while trying to read a line from stdin - + - or blash received an EOT (End-Of-Transmission character) + for example because CTRL-D was pressed... + */ + + return -1; + } + + /* save non-empty lines in readline() history */ + if (strlen(line) > 0) { + add_history(line); + } + + /* a line containing only a '.' signals the end of the sequence of input lines */ + if (strcmp(line, ".") == 0) { + + /* if the buffer is still empty an empty text was entered: + Set the buffer to an empty text */ + if (string_buffer_is_empty(buffer)) { + string_buffer_append(buffer, ""); + } + + free(line); /* free the string buffer allocated by readline() */ + break; /* exit the readline loop */ + } + + /* append read line to buffer */ + string_buffer_append_newline(buffer, line); + + /* free the string buffer allocated by readline() */ + free(line); + + /* use "continue prompt" for all following lines... + signalling that the loop is in the process to read a buffer */ + prompt = buffer->text_coninue_prompt; + } + + /* clean up the buffer buffer */ + int length = string_buffer_cleanup(buffer); + + /* return the length of the read buffer */ + return length; +} + +/** + Print a string buffer. +*/ +void string_buffer_print(string_buffer buffer) +{ + string_slice slice; + for (slice = buffer->first; slice != NULL; slice = slice->next) { + printf(slice->str); + } +} + +/** + Dump the inner structure of a string buffer to stdout. + Note: This function is only for use during development. +*/ +void string_buffer_dump(string_buffer buffer) +{ + printf("===\n"); + + string_slice slice; + int i; + for (slice = buffer->first, i = 0; slice != NULL; slice = slice->next, i++) { + if (i > 0) printf("---\n"); + printf(">>> Slice #%d, length %d:\n", i, strlen(slice->str)); + printf("---\n"); + printf(slice->str); + } + + printf("===\n"); +} + +/** + Copy string. + Return a copy of a string in newly allocated memory. +*/ +char* copy_string_allocate(char* string) +{ + /* allocating memory for the copy */ + int length = strlen(string); + char* newstr = (char*) malloc((length + 1) * sizeof(char)); + memcpy(newstr, string, length); + newstr[length]= '\0'; + + /* return the newly allocated copy */ + return newstr; +} + +/* fin */ Index: source/blender/commandport/utilities/src/hexdump_string.c =================================================================== --- source/blender/commandport/utilities/src/hexdump_string.c (revision 0) +++ source/blender/commandport/utilities/src/hexdump_string.c (revision 0) @@ -0,0 +1,360 @@ +/* + * $Id: hexdump_string.c, v 1.0 2007/05/30, dietrich, tokyo $ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2007 by the Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Author: Dietrich Bollmann + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + * + * Hexdump functions to debug the Blender Command Port... + * + * header file: ../include/hexdump_string.h + * + */ + +#include + +#include "hexdump_string.h" + +/* declaration of locally used functions */ +char* to_hex(char* buffer, char code); +char to_printable(char c); + +/** + Print ascii code table. +*/ +void print_ascii_code_table() +{ + printf(" +---+----------------------------------------------------------------+\n" + " | \\ | 0 1 2 3 4 5 6 7 8 9 A B C D E F |\n" + " +---+----------------------------------------------------------------+\n" + " | 0 | NUL SOH STX ETX EOT ENQ ACK BEL BS HT LF VT FF CR SO SI |\n" + " | 1 | DLE DC1 DC2 DC3 DC4 NAK SYN ETB CAN EM SUB ESC FS GS RS US |\n" + " | 2 | SP ! \" # $ %% & ' ( ) * + , - . / |\n" + " | 3 | 0 1 2 3 4 5 6 7 8 9 : ; < = > ? |\n" + " | 4 | @ A B C D E F G H I J K L M N O |\n" + " | 5 | P Q R S T U V W X Y Z [ \\ ] ^ _ |\n" + " | 6 | ` a b c d e f g h i j k l m n o |\n" + " | 7 | p q r s t u v w x y z { | } ~ DEL |\n" + " +---+----------------------------------------------------------------+\n" + ); +} + + +/** + Print the printable code table + used in the `| printable repr.|' column of `hexdump_string()'. +*/ +void print_printable_dump_code_table() +{ + printf(" +---+----------------------------------------------------------------+\n" + " | \\ | 0 1 2 3 4 5 6 7 8 9 A B C D E F |\n" + " +---+----------------------------------------------------------------+\n" + " | 0 | 0 ? ? ? ? ? ? ? ? > ^ ? ? ? ? ? |\n" + " | 1 | ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? |\n" + " | 2 | SP ! \" # $ %% & ' ( ) * + , - . / |\n" + " | 3 | 0 1 2 3 4 5 6 7 8 9 : ; < = > ? |\n" + " | 4 | @ A B C D E F G H I J K L M N O |\n" + " | 5 | P Q R S T U V W X Y Z [ \\ ] ^ _ |\n" + " | 6 | ` a b c d e f g h i j k l m n o |\n" + " | 7 | p q r s t u v w x y z { | } ~ ? |\n" + " +---+----------------------------------------------------------------+\n" + ); +} + + +/** + Dump the hex codes a string is made of. + + Nicer formatting than the `simple' one - example: +*/ +void hexdump_string(char* prefix, char* string) +{ + char* c; /* pointer to current char in string */ + c = string; + + /* print a header */ + printf("%s==============================================================================\n", prefix); + printf("%saddr 0 1 2 3 4 5 6 7 8 9 A B C D E F | printable repr.|\n", prefix); + printf("%s------------------------------------------------------------+----------------+\n", prefix); + + /* string buffer to print the hex values into */ + char hexbuf[50]; /* ex: */ + hexbuf[0] = '\0'; /* "65 69 6e 73 20 7a 77 65 69 20 64 72 65 69 20 76 " */ + char* ihex; /* >1234567890123456789012345678901234567890123456789< + \0 */ + ihex = hexbuf; + + /* string buffer to print the printable chars into */ + char charbuf[17]; /* ex: */ + charbuf[0] = '\0'; /* "eins zwei drei v" */ + char* ichar; /* >1234567890123456< + \0 */ + ichar = charbuf; + + int ifirst = 0; + int iline = 0; + int hex_per_line = 16; + + while (1) { + + /* hex column separator between 8th and 9th hex column */ + if (iline == (hex_per_line / 2) ) { /* an extra space between the 8th and 9th column */ + sprintf(ihex, " "); /* to make the grouping easier to grap for the eyes */ + ihex++; + } + + /* every dump line dumps 16 bytes */ + if (iline == hex_per_line) { /* every 16 characters ... */ + + // printf("%s%0.8x %-50s|%s|\n", prefix, ifirst, hexbuf, charbuf); /* ...print line */ + printf("%s%.8x %-50s|%s|\n", prefix, ifirst, hexbuf, charbuf); /* ...print line */ + /* and start a new line */ + + ihex = hexbuf; /* reset ihex, ichar and iline */ + ichar = charbuf; + hexbuf[0] = '\0'; + charbuf[0] = '\0'; + iline = 0; + + ifirst += hex_per_line; /* set the string index */ + /* to the first character of the new line */ + } + + /* hex code */ + to_hex(ihex, *c); /* print hex code of char */ + ihex += 3; + + /* character representation */ + sprintf(ichar, "%c", to_printable(*c)); /* print character representation of char */ + ichar += 1; + + if (*c == '\0') break; + + /* increment char index and counter */ + c++; + iline++; + } + + /* print remaining bytes */ + // printf("%s%0.8x %-50s|%s|\n", prefix, ifirst, hexbuf, charbuf); /* print everything not printed yet */ + printf("%s%.8x %-50s|%s|\n", prefix, ifirst, hexbuf, charbuf); /* print everything not printed yet */ + + /* ... and a footer */ + printf("%s==============================================================================\n", prefix); +} + +/** + The char code `code' is formatted + - as "00" and "7f" if between 00 and 127 - and + - as "?!" if outside of this range... + + Returns the pointer `buffer' to the buffer it is given. +*/ +char* to_hex(char* buffer, char code) +{ + if ((0x00 <= code) && (code <= 0x7f)) { /* redundand predicates - */ + /* they are always true due to the range of char... */ + // sprintf(buffer, "%0.2x ", code); + sprintf(buffer, "%.2x ", code); + } else { + sprintf(buffer, "?!"); + } + + return buffer; +} + + +/** + Return a simple printable representation of ascii codes. + Return a simple printable representation of ascii codes. + + - printables - as they are + - '>' for tab (0x09 - ascii: HT = Horizontal Tab) + - '^' for newline (0x0a - ascii: LF = Line Feed) + - '0' for the null character (0x00 - ascii: NUL = Null char.) + - '?' for things which might cause problems - and ? itself :) + + In form of a table: + +---+----------------------------------------------------------------+ + | \ | 0 1 2 3 4 5 6 7 8 9 A B C D E F | + +---+----------------------------------------------------------------+ + | 0 | 0 ? ? ? ? ? ? ? ? > ^ ? ? ? ? ? | + | 1 | ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? | + | 2 | SP ! " # $ % & ' ( ) * + , - . / | + | 3 | 0 1 2 3 4 5 6 7 8 9 : ; < = > ? | + | 4 | @ A B C D E F G H I J K L M N O | + | 5 | P Q R S T U V W X Y Z [ \ ] ^ _ | + | 6 | ` a b c d e f g h i j k l m n o | + | 7 | p q r s t u v w x y z { | } ~ ? | + +---+-----------------------------------------------------------------+ + + ascii table: + +---+----------------------------------------------------------------+ + | \ | 0 1 2 3 4 5 6 7 8 9 A B C D E F | + +---+----------------------------------------------------------------+ + | 0 | NUL SOH STX ETX EOT ENQ ACK BEL BS HT LF VT FF CR SO SI | + | 1 | DLE DC1 DC2 DC3 DC4 NAK SYN ETB CAN EM SUB ESC FS GS RS US | + | 2 | SP ! " # $ % & ' ( ) * + , - . / | + | 3 | 0 1 2 3 4 5 6 7 8 9 : ; < = > ? | + | 4 | @ A B C D E F G H I J K L M N O | + | 5 | P Q R S T U V W X Y Z [ \ ] ^ _ | + | 6 | ` a b c d e f g h i j k l m n o | + | 7 | p q r s t u v w x y z { | } ~ DEL | + +---+----------------------------------------------------------------+ +*/ +char to_printable(char c) +{ + /* print: + + - tab as '>' + - newline as '^' + - nullchar as '0' + - all printables as they are + - all others as '?'... + */ + char* special_chars = "\t\n"; + char tab = special_chars[0]; + char newline = special_chars[1]; + char nullchar = special_chars[2]; + + if (c == tab) { + return '>'; + } else if (c == newline) { + return '^'; + } else if (c == nullchar) { + return '0'; + } else if ((0x20 <= c) && (c <= 0x7e)) { + return c; + } else { + return '?'; + } +} + + +/** + Dump the hex codes a string is made of. +*/ +void simple_hexdump_string(char* string) +{ + char* c; + c = string; + + int i = 0; + while (1) { + + if ((i > 0) && (i % 8) == 0) printf(" "); + if ((i > 0) && (i % 16) == 0) printf("\n"); + + // printf("%0.2x ", *c); + printf("%.2x ", *c); + + if (*c == '\0') break; + + c++; + i++; + } + + printf("\n"); +} + + +/** + Test the hexdump functions. +*/ +void hexdump_string_test() +{ + /* print a header */ + printf("# ==========================================================\n"); + printf("# Test: Hexdump String Functions:\n"); + printf("# ----------------------------------------------------------\n"); + printf("\n"); + + /* print the ascii code table */ + printf(" ASCII Code Table:\n"); + print_ascii_code_table(); + printf("\n"); + + /* print the printable codes used in `hexdump_string()' */ + printf(" Printabel Code Table -\n"); + printf(" as used in the last column by `hexdump_string()':\n"); + print_printable_dump_code_table(); + printf("\n"); + + /* example string */ + /* simple example: char* example_str = "eins zwei drei vier fuenf sechs sieben."; */ + /* slightly more complicated: */ + char* example_str = + "eins zwei drei vier fuenf sechs sieben, " + "tab: '\t', newline: '\n' and - to terminate the string - the nullchar: "; + + /* prefix to indent the dumps */ + char* prefix = " "; + + /* print example text */ + printf(" Dumping the following string:\n"); + printf(" \"\%s\"\n", example_str); + printf("\n"); + + /* test the dump function */ + printf(" String hex-dump using `hexdump_string()':\n"); + hexdump_string(prefix, example_str); + printf("\n"); + + /* test the simple dump function */ + printf("Simple string hex-dump using `simple_hexdump_string()':\n"); + simple_hexdump_string(example_str); + printf("\n"); + + /* dumping all ASCII between 0 and 127 */ + printf(" A dump of all ASCII between 01 and 7F - and the 00-char at the end:\n"); + + /* making a code buffer with all ASCII between 0 and 127 */ + char hexbuf[0x7f + 1]; + char* c = hexbuf; + char code; + *c++ = ' '; /* The first char is a blank... */ + for (code = 1; 1 /* 0 <= code <= 0x7f */; code++, c++) { + /* fill the buffer with ASCII char codes */ + /* Note: (code <= 0x7f) is always true */ + /* as `code' is of type char... */ + *c = code; + if (code == 0x7f) break; /* !!! code is a char and will turn negetive */ + /* !!! if bigger incremented beyond 0x7e */ + } + code = 0; + c++; + *c = code; /* 0x00 terminates the string */ + + /* dumping the code buffer */ + hexdump_string(prefix, hexbuf); + printf("\n"); + + /* ... and a footer */ + printf("# ==========================================================\n"); + printf("# ==========================================================\n"); + printf("\n"); + printf("# fin :)\n"); + printf("\n"); +} + +/* fin */ Index: source/blender/commandport/utilities/src/message_handler.c =================================================================== --- source/blender/commandport/utilities/src/message_handler.c (revision 0) +++ source/blender/commandport/utilities/src/message_handler.c (revision 0) @@ -0,0 +1,275 @@ +/* + * $Id: message_handler.c, v 1.0 2007/06/13, dietrich, tokyo $ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2007 by the Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Author: Dietrich Bollmann + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + * + * The message handler class implements the protocol used by the + * commandport for exchanging text messages via a socket connection. + * A message is defined as a string of an arbitrary length terminated + * with a '\0' character. + * + * header file: ../include/message_handler.h + * + */ + +/* fin */ + +/* Note: + for debugging the message handler, uncomment `#define DEBUG'. +*/ + +#include /* for printf() and fprintf() */ +#include /* for strlen() */ +#include +#include /* for recv() and send() */ +#include /* for close() */ + +#include "error_codes.h" /* error codes */ +#include "string_buffer.h" + +#include "message_handler.h" + +/* #define DEBUG */ + +#ifdef DEBUG + +#define RCVBUFSIZE 5 /* DEBUG: make receive buffer small */ +#define IF_DEBUG(x) x + +#else + +#define RCVBUFSIZE 1024 /* Size of receive buffer */ +#define IF_DEBUG(x) + +#endif + +/* data structures */ + +typedef struct message_handler_data { + int socket; /* socket id */ + char* socket_buffer; /* internal receive buffer */ + string_buffer message_buffer; /* a message might be send in different chunks - + this buffer is used to store the message chunks. + If more than one message is received in one chunk, + the remaining messages are also stored in this buffer. */ + int chars_remaining; /* number of chars remaining in the internal receive buffer. + if `chars_remaining' is 0, the process will wait on + the socket for the next message; + if `chars_remaining' is bigger than 0, some bytes of + the next message already have been received */ +} message_handler_data; + +/* declarations */ + +int scan_for_0_char(char* buffer, int length); +void dump_message_chunk(char* buffer, int length); + +/* definitions */ + +/** + */ +message_handler message_handler_new(int socket) +{ + /* allocate message handler data struct */ + message_handler handler; + handler = (message_handler) malloc( sizeof(message_handler_data) ); + + /* init message handler data struct */ + handler->socket = socket; /* socket id */ + handler->socket_buffer = (char*) malloc( (RCVBUFSIZE + 1) * sizeof(char) ); + /* internal receive buffer */ + handler->socket_buffer[RCVBUFSIZE] = '\0'; /* the receive buffer always has to end on '\0' + to work with the string functions */ + handler->message_buffer = string_buffer_new(); /* buffer to store the received message chunks */ + handler->chars_remaining = 0; /* the internal message receive buffer is empty */ + + /* return the message handler data struct */ + return handler; +} + +/** + */ +void message_handler_delete(message_handler handler) +{ + /* free the members of the message handler data struct */ + free(handler->socket_buffer); + string_buffer_delete(handler->message_buffer); + + /* finally free the message handler data struct itself */ + free(handler); +} + +/** + Send a message. +*/ +void message_handler_send_message(message_handler handler, char* message) +{ + int length; + length = strlen(message); /* length of message */ + message[length] = '\0'; /* make sure that message ends on '\0' */ + + /* Send message */ + length++; /* include the end-of-string / end-of-message marker '\0' */ + if (send(handler->socket, message, length, 0) != length) { + fprintf(stderr, "Couldn't send message \"%s\"!\n", message); + exit(ERROR_SEND); + } +} + +/** + */ +char* message_handler_receive_message_allocate(message_handler handler) +{ + /* empty the message buffer */ + string_buffer_make_empty(handler->message_buffer); + + /* get first chunk of message */ + int received_chars; /* Size of chunk */ + if (handler->chars_remaining) { /* first message chunk is still / already + in internal receive buffer - start with it */ + received_chars = handler->chars_remaining; + + } else { + + /* receive first message chunk from socket */ + if ((received_chars = recv(handler->socket, handler->socket_buffer, RCVBUFSIZE, 0)) < 0) { + fprintf(stderr, "Couldn't receive message!\n"); + exit(ERROR_RECEIVE); + } + } + + /* get rest of message */ + while (1) { + + /* a chunk size of 0 signals the end of the client connection */ + if (received_chars == 0) return NULL; + + /* printf(">>> %s", handler->socket_buffer); */ + string_buffer_append(handler->message_buffer, handler->socket_buffer); + + /* scan received buffer for the end-of-message character '\0' + `scan_for_0_char(handler->socket_buffer, RCVBUFSIZE)' returns + - received_chars if no '\0' was found and + - the position of '\0' in `buffer' if '\0' was found. + */ + int length = scan_for_0_char(handler->socket_buffer, received_chars); + + /* If '\0' was found (length != received_chars) + this is the last chunk of the current message + => set the `last_chunk_flag' */ + int last_chunk_flag = (length != received_chars); + + /* If the chunk size is one longer than the number of receive chars + (bytes + '\0') no bytes from the next message are received. + => If the number of received chars is bigger + set the `chars_remaining_flag' */ + int chars_remaining_flag = ((length+1) < received_chars); + + /* DEBUG: dump the received message chunk */ + IF_DEBUG(dump_message_chunk(handler->socket_buffer, length); + printf("length: %d, received_chars: %d, " + "last_flag: %d, chars_remaining_flag: %d\n", + length, received_chars, + last_chunk_flag, chars_remaining_flag); + ); + + if (last_chunk_flag) { /* last chunk of message */ + + /* store the beginning of the next message (if existing) */ + if (chars_remaining_flag) { /* more chars received than + number of chars still part of current message + +1 for the end-of-message marker '\n' + => these chars are part of the next message. + */ + + /* store the received chars in the message buffer */ + + /* calculate start of next message */ + char* nextMessage = (handler->socket_buffer + (length+1 * sizeof(char))); + + /* calculate number of chars remaining */ + handler->chars_remaining = received_chars - (length+1); + + /* move the remaining chars to begin of buffer */ + memcpy(handler->socket_buffer, nextMessage, handler->chars_remaining); + /* terminate with '\0' for the `string_buffer' functions */ + handler->socket_buffer[handler->chars_remaining] = '\0'; + + IF_DEBUG(printf("DEBUG: %d chars remaining in internal receive buffer: \"%s\"\n", + handler->chars_remaining, handler->socket_buffer); + ); + } else { + + handler->chars_remaining = 0; /* no chars remaining */ + IF_DEBUG( printf("DEBUG: no chars remaining in internal receive buffer.\n"); ); + } + + /* get the message: + allocate a char array in the length of the received message + and store the message in the array + */ + int length; /* length of the message */ + char* message = string_buffer_to_char_array_allocate(handler->message_buffer, &length); + + /* empty the message buffer */ + string_buffer_make_empty(handler->message_buffer); + return message; + } + + /* See if there is more data to receive */ + if ((received_chars = recv(handler->socket, handler->socket_buffer, RCVBUFSIZE, 0)) < 0) { + fprintf(stderr, "Couldn't receive message!\n"); + exit(ERROR_RECEIVE); + } + } +} + +/** + */ +int scan_for_0_char(char* buffer, int length) +{ + int i; + for(i = 0; i < length; i++) if (buffer[i] == '\0') return i; + return i; +} + +/** + Internal function only used for debugging: + Dump the first 'length' bytes of 'buffer'. +*/ +void dump_message_chunk(char* buffer, int length) +{ + printf("DEBUG: received %d bytes: [ ", length); + int i; + for(i = 0; i < length; i++) { + if (i > 0) printf(", "); + printf("`%c' (%u)", buffer[i], buffer[i]); + } + printf(" ]\n"); +} + +/* fin */ Index: source/blender/commandport/utilities/src/message_client.c =================================================================== --- source/blender/commandport/utilities/src/message_client.c (revision 0) +++ source/blender/commandport/utilities/src/message_client.c (revision 0) @@ -0,0 +1,277 @@ +/* + * $Id: message_client.c, v 1.0 2007/06/13, dietrich, tokyo $ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2007 by the Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Author: Dietrich Bollmann + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + * + * The message client class is the central part of a Blender Command + * Port client written in c. It implements the functionality for + * connecting and disconnecting to / from a Blender Server and for + * sending and receiving text messages. + * + * header file: ../include/message_client.h + * + */ + +#include /* for printf() and fprintf() */ +#include /* for sockaddr_in and inet_addr() */ +#include /* for atoi() and exit() */ +#include /* for memset() */ +#include /* for close() */ + +#include "message_handler.h" /* message handler to send and receive messages */ + +#include "message_client.h" +#include "fsleep.h" + +typedef struct message_client_struct { + char* server_IP_address; /* The IP address of the server to connect to */ + unsigned short server_port; /* Port of the server */ + struct sockaddr_in* server_address; /* server address structure */ + int socket; /* socket descriptor */ + message_handler handler; /* message handler to send and receive messages */ +} message_client_struct; + +/* utility function declarations */ + +char* string_copy_allocate(char* str); +struct sockaddr_in* make_server_address_structure_allocate(char* IP_address, + unsigned short server_port); +void free_server_address_structure(struct sockaddr_in* server_address); +int server_connect(message_client client); +int server_connect_wait(message_client client, int retries, float retry_sleeptime); +void server_disconnect(int socket_descriptor); + +/* function definitions */ + +/** + */ +message_client message_client_new(char *server_IP_address, unsigned short server_port) +{ + /* try only once to connect */ + int retries = 0; + float retry_sleeptime = 0.0; + return message_client_new_wait(server_IP_address, server_port, retries, retry_sleeptime); +} + +/** + */ +message_client message_client_new_wait(char *server_IP_address, unsigned short server_port, + int retries, float retry_sleeptime) +{ + /* allocate memory for message client structure */ + message_client client; + client = (message_client) malloc( sizeof(message_client_struct) ); + + /* check for errors */ + if (client == NULL) { + fprintf(stderr, "Couldn't allocate memory for new message_client!\n"); + exit(ERROR_MEMORY); + } + + /* init members */ + client->server_IP_address + = string_copy_allocate(server_IP_address); /* server_IP_address */ + client->server_port = server_port; /* server_port */ + client->server_address + = make_server_address_structure_allocate(server_IP_address, server_port); + /* server address structure */ + + /* connect to the server */ + client->socket = server_connect_wait(client, retries, retry_sleeptime); + + /* message handler */ + client->handler = message_handler_new(client->socket); + + /* return message client structure */ + return client; +} + +/** + Delete a message client. +*/ +void message_client_delete(message_client client) +{ + /* disconnect from server */ + server_disconnect(client->socket); + + /* free members */ + free(client->server_IP_address); + free_server_address_structure(client->server_address); + message_handler_delete(client->handler); + + /* free message client structure */ + free(client); +} + +/** + Send a message. +*/ +void message_client_send(message_client client, char* message) +{ + /* send message via the message handler */ + message_handler_send_message(client->handler, message); +} + +/** + Receive a message. + The return value NULL signals the end of the client connection. +*/ +char* message_client_receive_allocate(message_client client) +{ + /* receive message via the message handler */ + return message_handler_receive_message_allocate(client->handler); +} + +/** + Send a message and return the answer. +*/ +char* message_client_send_receive_allocate(message_client client, char* message) +{ + /* send the message */ + message_client_send(client, message); + + /* return the reply */ + return message_client_receive_allocate(client); +} + +/* utility functions */ + +char* string_copy_allocate(char* str) +{ + int length = strlen(str); + char* copy = (char*) malloc( (length + 1) * sizeof(char) ); + memcpy(copy, str, length); + copy[length]= '\0'; + return copy; +} + +/** + Allocates the memory for a server address structure + and initializes its members with the given parameters. +*/ +struct sockaddr_in* make_server_address_structure_allocate(char* IP_address, + unsigned short server_port) +{ + /* allocate memory for server address structure */ + struct sockaddr_in* server_address; + server_address = (struct sockaddr_in*) malloc( sizeof(struct sockaddr_in) ); + + /* Construct the server address structure */ + memset(server_address, 0, sizeof(struct sockaddr_in)); /* zero out structure */ + server_address->sin_family = AF_INET; /* internet address family */ + server_address->sin_addr.s_addr = inet_addr(IP_address); /* server IP address */ + server_address->sin_port = htons(server_port); /* server port */ + + /* return the socket address structure */ + return server_address; +} + +/** + Frees a server address structure. +*/ +void free_server_address_structure(struct sockaddr_in* server_address) +{ + free(server_address); +} + +/** + Connect to server. + Returns the socket descriptor. +*/ +int server_connect(message_client client) +{ + /* try only once to connect */ + int retries = 0; + float retry_sleeptime = 0.0; + return server_connect_wait(client, retries, retry_sleeptime); +} + +/** + Connect to server. + Returns the socket descriptor. +*/ +int server_connect_wait(message_client client, int retries, float retry_sleeptime) +{ + /* socket descriptor */ + int socket_descriptor; + + /* Create reliable stream socket using TCP */ + if ((socket_descriptor = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) { + fprintf(stderr, "Couldn't create socket!\n"); + exit(ERROR_SOCKET); + } + + /* Try to establish a connection to the echo server - + retry `retries' times and sleep `retry_sleeptime' seconds in between. + */ + int connected = -1; /* when a connection could be established, this should be 0 and -1 otherwise */ + int i; + for (i = 0; i <= retries; i++) { + + /* sleep `retry_sleeptime' seconds between attempts to connect to the server */ + if (i > 0) fsleep(retry_sleeptime); + + /* try to connect */ + connected = connect(socket_descriptor, + (struct sockaddr*) client->server_address, + sizeof(*client->server_address)); + + /* if connection could be established, break */ + if (connected == 0) break; + + /* print a dot to signal that something is done */ + if (i > 0) printf("."); + fflush(stdout); + } + + /* check if connection could be established */ + if (connected == 0) { + fprintf(stdout, "Connection to Blender Server established. (IP address: %s, port: %d)\n", + client->server_IP_address, + (int) client->server_port); + } else { + fprintf(stderr, "Couldn't connect to Blender Server (IP address: %s, port: %d)!\n", + client->server_IP_address, + (int) client->server_port); + exit(ERROR_CONNECTION); + } + + /* return the socket descriptor */ + return socket_descriptor; +} + +/** + Disonnect from a server + by sending an empty message. +*/ +void server_disconnect(int socket_descriptor) +{ + /* close the socket */ + close(socket_descriptor); +} + +/* fin */ Index: source/blender/commandport/utilities/src/SConscript =================================================================== --- source/blender/commandport/utilities/src/SConscript (revision 0) +++ source/blender/commandport/utilities/src/SConscript (revision 0) @@ -0,0 +1,45 @@ +# -*- mode: python -*- +# +# $Id: SConscript, v 1.0 2007/05/30, dietrich, tokyo $ +# +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# The Original Code is Copyright (C) 2007 by the Blender Foundation. +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Author: Dietrich Bollmann +# Contributor(s): none yet. +# +# ***** END GPL LICENSE BLOCK ***** +# +# Build file for directory: blender/source/blender/commandport/utilities/src/ + +Import ('env') + +sources = env.Glob('*.c') + +incs = ''' + ../include + ../../blash/include +''' + +env.BlenderLib ( 'blender_commandport_utilities', sources, Split(incs), [], + libtype=['blender', 'blash'], priority=[0,0] ) + +# fin. Index: source/blender/commandport/utilities/src/bcp_debug.c =================================================================== --- source/blender/commandport/utilities/src/bcp_debug.c (revision 0) +++ source/blender/commandport/utilities/src/bcp_debug.c (revision 0) @@ -0,0 +1,72 @@ +/* + * $Id: bcp_debug.c, v 1.0 2007/05/30, dietrich, tokyo $ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2007 by the Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Author: Dietrich Bollmann + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + * + * Module for initializing, storing and querying + * the Blender command port debug level. + * + * The command port can be made to print debug messages in different + * verbosity levels via the command line option `--debug bcp:'. + * `' can be one of 1, 2, 3, 4. + * + * For more information see the debug help text defined in function + * `print_help_debug()' in file `../../blender/src/bcp_handle_client.c' + * or call Blender with the option `-hd' / `--help=debug'. + * + * For the command port debug code search sources for `debug("bcp")' + * and `bcp_debug()'. + * + * header file: ../../../blenkernel/intern/debug.c + * + */ + +#include +#include "bcp_debug.h" + +/* global BCP debug flag */ +int g_bcp_debug_flag = 0; + +/** + Set BCP debug level. +*/ +void bcp_set_debug_level(int level) +{ + extern int g_bcp_debug_flag; + g_bcp_debug_flag = level; +} + +/** + Returns the debug level for the Blender command port. +*/ +int bcp_debug() +{ + extern int g_bcp_debug_flag; + return g_bcp_debug_flag; +} + +/* fin */ Index: source/blender/commandport/utilities/src/bcp_shell.c =================================================================== --- source/blender/commandport/utilities/src/bcp_shell.c (revision 0) +++ source/blender/commandport/utilities/src/bcp_shell.c (revision 0) @@ -0,0 +1,823 @@ +/* + * $Id: bcp_shell.c, v 1.0 2007/05/31, dietrich, tokyo $ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2007 by the Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Author: Dietrich Bollmann + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + * + * Defines the interactive shell called by blash's `main()' function. + * + * header file: ../include/bcp_shell.h + * + */ + +#include +#include /* for exit() */ +#include + +#include "blash_usage.h" /* for print_blash_help() */ +#include "string_buffer.h" +#include "message_client.h" +#include "bcp_debug.h" +#include "bcp_meta_commands.h" +#include "bcp_package.h" + +#include "bcp_shell.h" + +#define MAXLINE 1024 +#define SHELL_SINGLE_FILE_INPUT_PROMPT "SF> " +#define EVAL_MODE_PROMPT "EM> " +#define FILE_MODE_PROMPT "FM> " +#define SINGLE_MODE_PROMPT ">>> " +#define INPUT_CONTINUE_PROMPT "... " + +/* function declarations */ +int process_shell_meta_command(message_client client, string_buffer command, int *mode); +int read_command(string_buffer buffer, int mode); +void process_python_single_input_loop(message_client client, string_buffer command, int mode); +int blender_process_python_input(message_client client, string_buffer command, int mode); +int print_blender_result(char* result); +char mode_to_bcp_meta_command(int mode); + +/** + Open a new Blender command port shell. +*/ +void bcp_shell(char* server_IP_address, unsigned short server_port, int mode) +{ + /* try only once to connect */ + int retries = 0; + float retry_sleeptime = 0.0; + bcp_shell_wait(server_IP_address, server_port, mode, retries, retry_sleeptime, NULL); +} + +/** + Open a new Blender command port shell. + + If the connection to the Blender server could not been established immediately, + retry up to `retries' times. Sleep `retry_sleeptime' seconds before trying again. +*/ +void bcp_shell_wait(char* server_IP_address, unsigned short server_port, int mode, + int retries, float retry_sleeptime, char* init_command) +{ + /* get debug message level */ + int debug = bcp_debug(); + + string_buffer command = NULL; + message_client client = NULL; + int length, ok, reconnect, exit_shell, num, port; + + /* + connect to client, start shell, deconnect... + + `reconnect' can be set via the shell to 1 + for making the shell reconnect to the server. + */ + reconnect = 0; + do { + + /* make a new message client + to handle the communication with the server + */ + client = message_client_new_wait(server_IP_address, server_port, + retries, retry_sleeptime); + + /* error checking */ + if (client == NULL) { + fprintf(stderr, "ERROR - Couldn't connect to the Blender server!"); + exit(1); + } + + /* a string buffer to read the commands from stdin */ + command = string_buffer_new(); + + /* error checking */ + if (command == NULL) { + fprintf(stderr, "ERROR - Couldn't allocate command text buffer!"); + exit(1); + } + + /* init the prompts to use */ + string_buffer_set_line_prompt( command, SINGLE_MODE_PROMPT ); + string_buffer_set_text_prompt( command, FILE_MODE_PROMPT ); + string_buffer_set_text_coninue_prompt( command, INPUT_CONTINUE_PROMPT ); + + /* if an init command was specified, send it to Blender */ + if (init_command) { + if (debug) printf("[DEBUG] initializing shell with command: %s\n", init_command); + string_buffer_append(command, init_command); + process_python_single_input_loop(client, command, BCP_FILE_MODE); + string_buffer_make_empty(command); + } + + /* the shell loop */ + exit_shell = 0; + do { + + /* read input from shell + - if in line mode read a line; + - if in text mode read a text. + + if length < 0 there was a problem while reading the input + - probably because CTRL-D was hit. => exit... + */ + length = read_command(command, mode); + + /* process the command: + - check for shell meta commands and process them + - if no shell meta command was found, process the + command in the currently active shell mode + */ + + /* process shell command */ + if (length < 0 || + !string_buffer_compare_to_string(command, "bye") || + !string_buffer_compare_to_string(command, "quit") || + !string_buffer_compare_to_string(command, "exit") || + !string_buffer_compare_to_string(command, "bye\n") || + !string_buffer_compare_to_string(command, "quit\n") || + !string_buffer_compare_to_string(command, "exit\n") + ) { + + /* exit the shell loop without reconnecting */ + reconnect = 0; + exit_shell = 1; + + } else if (!string_buffer_compare_to_string(command, "help") || + !string_buffer_compare_to_string(command, "help\n") + ) { + + /* print help text */ + print_blash_help(); + + } else if (string_buffer_starts_with_prefix(command, "reconnect")) { + + /* + reconnect to blender server. + if a port number is specified, use it to reconnect. + */ + + /* get command line */ + char *command_line; + command_line = string_buffer_to_char_array_allocate(command, NULL); + + /* parse command line */ + num = sscanf(command_line, "reconnect %i", &port); + + /* free command line */ + free(command_line); + + /* check if a new port was given */ + if (num == 1) { /* a new port was given on the blash command line - use it */ + server_port = port; + } + + /* print a message */ + printf("reconnecting...\n"); + + /* exit the shell loop and reconnect */ + reconnect = 1; + exit_shell = 1; + + } else if (string_buffer_starts_with_prefix(command, ".")) { + + /* the command starts with a dot ('.') + and is interpreted as shell meta command. + Process the shell meta command + */ + ok = process_shell_meta_command(client, command, &mode); + + /* if !ok, + process_shell_meta_command() probably tried to read from the shell + without result - probably because CTRL-D was hit. + exit + */ + if (!ok) { + /* exit the shell loop */ + exit_shell = 1; + } + + + } else if (string_buffer_is_empty_or_white_space_string(command)) { + + /* the command is an empty line + or a line made only from white space + */ + /* ignore the input line... */ + + } else { + + /* A Blender Python command: + Send command to blender for evaluation in the given evaluation mode + and print the result. + */ + process_python_single_input_loop(client, command, mode); + } + + /* empty the command buffer */ + string_buffer_make_empty(command); + + } while (!exit_shell); + + /* shell exited - cleanup */ + + + /* delete the command buffer */ + if (debug) printf("[DEBUG] bcp_shell: string_buffer_delete(command);\n"); + string_buffer_delete(command); + + /* delete the message client */ + if (debug) printf("[DEBUG] bcp_shell: message_client_delete(client);\n"); + message_client_delete(client); + + } while (reconnect); +} + +/** + Process a shell meta command. + Shell meta commands are commands starting with a dot caracter ('.'). + + The following meta commands are defined: + + - . The next input is interpreted as a multi line command, + terminated with another dot. + Multi line command are evaluated in file mode. + - .shell / .single Switch to shell/single input mode. + - .eval Switch to eval input mode. + - .file Switch to file input mode. +*/ +int process_shell_meta_command(message_client client, string_buffer command, int *mode) +{ + char* prompt = NULL; + char* command_string = NULL; + int length, bcp_return_code; + + /* process the shell meta command */ + if (!string_buffer_compare_to_string(command, ".")) { + + /* read a single multi line command from stdin, + process it in file mode and + continue with the shell mode in the same mode as before + */ + printf("...single text\n"); + string_buffer_make_empty(command); /* empty command buffer */ + + /* read a single multi line command (text) from stdin + using the appropriate prompt + */ + + /* store current prompt */ + prompt = NULL; + prompt = string_buffer_get_text_prompt_allocate(command); + if (prompt == NULL) { + fprintf(stderr, "ERROR while trying to copy a string buffer line input prompt!\n"); + exit(1); + } + + /* (temporarily) set text prompt */ + string_buffer_set_text_prompt(command, SHELL_SINGLE_FILE_INPUT_PROMPT); + + /* read a multi line command (text) from stdin */ + length = string_buffer_read_text_from_stdin(command); + + /* if -1 was returned, exit: there was either an input problem or CTRL-D was hit */ + if (length < 0) { + /* return -1 without doing anything */ + string_buffer_make_empty(command); /* empty command buffer */ + return 0; + } + + /* restore prompt */ + string_buffer_set_text_prompt(command, prompt); + free(prompt); + + /* Send command to blender for evaluation in BCP_FILE_MODE + and print the result. + */ + + bcp_return_code = blender_process_python_input(client, command, BCP_FILE_MODE); + + } else if (!string_buffer_compare_to_string(command, ".shell") || + !string_buffer_compare_to_string(command, ".single") || + !string_buffer_compare_to_string(command, ".s") || + !string_buffer_compare_to_string(command, ".shell\n") || + !string_buffer_compare_to_string(command, ".single\n") || + !string_buffer_compare_to_string(command, ".s\n") + ) { + + printf("...shell/single mode\n"); + + /* switch to single mode */ + string_buffer_set_text_prompt(command, SINGLE_MODE_PROMPT); /* set prompt */ + *mode = BCP_SINGLE_MODE; + + } else if (!string_buffer_compare_to_string(command, ".eval") || + !string_buffer_compare_to_string(command, ".e") || + !string_buffer_compare_to_string(command, ".eval\n") || + !string_buffer_compare_to_string(command, ".e\n") + ) { + + printf("...eval mode\n"); + + /* switch to eval mode */ + string_buffer_set_text_prompt(command, EVAL_MODE_PROMPT); /* set prompt */ + *mode = BCP_EVAL_MODE; + + } else if (!string_buffer_compare_to_string(command, ".file") || + !string_buffer_compare_to_string(command, ".f") || + !string_buffer_compare_to_string(command, ".file\n") || + !string_buffer_compare_to_string(command, ".f\n") + ) { + + printf("...file mode\n"); + + /* switch to file mode */ + string_buffer_set_text_prompt(command, FILE_MODE_PROMPT); /* set prompt */ + *mode = BCP_FILE_MODE; + + } else { + + /* Unknown shell meta command */ + + /* make it a string */ + command_string = NULL; + command_string = string_buffer_to_char_array_allocate(command, NULL); + if (command_string == NULL) { + fprintf(stderr, "ERROR: Couldn't convert a string buffer to a string!"); + exit(1); + } + + /* print warning */ + printf("WARNING: Ignoring unknown shell meta command: %s...\n", command_string); + free(command_string); + + /* do nothing - ignore command */ + } + + /* empty command buffer */ + string_buffer_make_empty(command); + + /* success */ + return 1; +} + +/** + Read command from shell + - if in line mode read a line; + - if in text mode read a text. +*/ +int read_command(string_buffer command, int mode) +{ + int length; /* return the length of the read input */ + + switch (mode) { + + case BCP_SINGLE_MODE: + + /* read a single line from stdin */ + length = string_buffer_read_line_from_stdin(command); + break; + + case BCP_EVAL_MODE: + case BCP_FILE_MODE: + + /* read a multi line command (text) from stdin */ + length = string_buffer_read_text_from_stdin(command); + break; + + default : + /* ERROR: undefined mode: */ + fprintf(stderr, "ERROR: Undefined shell input mode!"); + exit(1); + break; + } + + /* return length */ + return length; +} + +/** + Process a shell meta command. + Shell meta commands are commands starting with a dot caracter ('.'). + + The following meta commands are defined: + + - . The next input is interpreted as a multi line command, + terminated with another dot. + Multi line command are evaluated in file mode. + - .shell / .single Switch to shell/single input mode. + - .eval Switch to eval input mode. + - .file Switch to file input mode. +*/ +void process_python_single_input_loop(message_client client, string_buffer command, int mode) +{ + int debug; + int bcp_return_code; + + /* get debug message level */ + debug = bcp_debug(); + + /* read input lines + until command is entered completely + or an input error is detected + */ + while (1) { + + /* send next command line to blender */ + bcp_return_code = blender_process_python_input(client, command, mode); + + /* react corresponding to the return code */ + switch (bcp_return_code) { + + case BCP_RESULT_CODE_SUCCESS: + + /* a complete python command was entered + and executed successfully + + continue with the shell loop + */ + + /* DEBUG */ + if (debug) printf("[DEBUG] return code: BCP_RESULT_CODE_SUCCESS\n"); + + /* continue with the shell loop */ + break; + + case BCP_RESULT_CODE_INCOMPLETE_INPUT: + + /* the entered command is still incomplete + + set the "input continue prompt" ('... ') + read next line + and continue with the loop + */ + + /* DEBUG */ + if (debug) printf("[DEBUG] return code: BCP_RESULT_CODE_INCOMPLETE_INPUT\n"); + + /* empty the command buffer */ + string_buffer_make_empty(command); + + /* set the line prompt to "... " + to indicate an uncomplete python input + */ + string_buffer_set_line_prompt(command, INPUT_CONTINUE_PROMPT); + + /* read next input line from shell */ + read_command(command, mode); + + /* continue with loop */ + continue; + + /* never reached */ + break; + + case BCP_RESULT_CODE_ERROR: + + /* there was an error + while reading or executing the input already entered + + a python error should have been printed already by `blender_process_python_input()' + continue with the shell loop + */ + + /* DEBUG */ + if (debug) printf("[DEBUG] return code: BCP_RESULT_CODE_ERROR\n"); + + break; + + case BCP_RESULT_CODE_UNDEFINED: + + /* the evaluatino of the input resulted in an unexpected result + ...this should never happen... + + print an error + and exit the shell + */ + + /* DEBUG */ + if (debug) printf("[DEBUG] return code: BCP_RESULT_CODE_UNDEFINED\n"); + + /* print error message */ + fprintf(stderr, "ERROR in BCP protocol: Blender reported an unexpected result!\n"); + exit(ERROR_BCP_PYTHON); + + break; + + case BCP_RESULT_CODE_EMPTY_INPUT: + + /* the input was empty + this should never happen + as empty input lines are handled by the shell + + print an error + and exit + */ + + /* DEBUG */ + if (debug) printf("[DEBUG] return code: BCP_RESULT_CODE_EMPTY_INPUT\n"); + + /* print error message */ + fprintf(stderr, "ERROR in BCP protocol: Blender complained about an empty input!\n"); + exit(ERROR_IN_BCP_PROTOCOL); + + break; + + default: + + /* an unknown return code was returned + this should never happen + and results an error in the BCP protocol... + + print an error and exit + */ + + /* DEBUG */ + if (debug) printf("[DEBUG] return code: ERROR - unknown result code!\n"); + + /* print error message */ + fprintf(stderr, "ERROR in BCP protocol: Blender returned an unknown return code!\n"); + exit(ERROR_IN_BCP_PROTOCOL); + + /* never reached */ + break; + } + + /* a complete command was entered and executed + or an error occurred + + continue with the shell loop + */ + break; + + } + + /* restore the normal python line prompt ('>>> ') + to indicate that a complete python command was read in + */ + string_buffer_set_line_prompt(command, SINGLE_MODE_PROMPT); +} + +/** + Send command to blender for evaluation in the given evaluation mode + and print the result. +*/ +int blender_process_python_input(message_client client, string_buffer command, int mode) +{ + /* pack + - the mode code and + - the command + into a bcp_package + */ + int debug, debug2; + int bcp_return_code; + bcp_package command_package; + char *command_string, *packed_command, *result; + char mode_command; + + /* get debug message level */ + debug = bcp_debug(); + debug2 = (debug >= 2); + + /* make a package */ + command_package = bcp_package_new(); + + /* add the code for the mode */ + mode_command = mode_to_bcp_meta_command(mode); + bcp_package_add_command(command_package, mode_command); + + /* add the command string */ + command_string = string_buffer_to_char_array_allocate(command, NULL); + bcp_package_add_string(command_package, command_string); + + /* pack the buffer into a newly allocated string */ + packed_command = bcp_package_pack_allocate(command_package); + + /* debug: print the packed package */ + if (debug2) { + printf(">>> the packed command package:\n>>>"); + printf("%s", packed_command); + printf("<<<\n"); + } + + /* delete package */ + bcp_package_delete(command_package); + + /* free the command string */ + free(command_string); + command_string = NULL; + + /* ================= */ + /* process the input */ + /* ----------------- */ + + /* send the command to the server and wait for the reply */ + result = message_client_send_receive_allocate(client, packed_command); + + /* free the packed command */ + free(packed_command); + packed_command = NULL; + + /* error checking */ + if (result == NULL) { + fprintf(stderr, "ERROR - Couldn't get a result from the Blender server!\n"); + fflush(stderr); + exit(1); + } + + /* print the result */ + bcp_return_code = print_blender_result(result); + + /* free the packed string representation */ + free(result); + result = NULL; + + /* return BCP return code */ + return bcp_return_code; +} + +/** + Extract the return code, stdout string and stderr string from the + packed result string returned by + `message_client_send_receive_allocate(client, command_string)', + from blender, print + - the stdout string to stdout and + - the stderr string to stderr + and return the result code. +*/ +int print_blender_result(char* result) +{ + /* get debug message level */ + int debug = bcp_debug(); + int debug2 = (debug >= 2); + + bcp_package result_package; + bcp_package_enumerator enumerator; + int return_code; + void* elem; + char type; + char* result_str; + + /* + Unpack the `result' string returned by blender. + + Blender packs three components into the `result' string: + - the Python return code + - the Python stdout output as string + - the Python stderr output as string + + These components are unpacked and: + - the Python return code is returned + - the Python stdout output is printed to the stdout of the shell + - the Python stderr output is printed to the stdout of the shell + */ + result_package = bcp_package_unpack(result); + + /* make new package enumerator */ + enumerator = bcp_package_enumerator_new(result_package); + + /* =================== */ + /* (1) get return code */ + /* ------------------- */ + + /* get next element */ + elem = bcp_package_enumerator_get_next_element(enumerator, &type); + + /* check if it has the right type (int) */ + if (type != BCP_PACKAGE_TYPE_INT) { + fprintf(stderr, + "Error in BCP protocol: expected an integer (BCP return code) " + "but found an element of type %d!\n", type); + exit(ERROR_IN_BCP_PROTOCOL); + } + + /* get return code */ + return_code = *((int*) elem); + + /* ======================= */ + /* (2) get the eval result */ + /* ----------------------- */ + + /* get next element */ + elem = bcp_package_enumerator_get_next_element(enumerator, &type); + + /* check if it has the right type (string) */ + if (type != BCP_PACKAGE_TYPE_STRING) { + fprintf(stderr, + "Error in BCP protocol: expected a string (BCP stdout) " + "but found an element of type %d!\n", type); + exit(ERROR_IN_BCP_PROTOCOL); + } + + /* get and - if there is a result - print to stdout */ + result_str = (char*) elem; + if (strlen(result_str)) fprintf(stdout, "%s\n", result_str); + + /* ======================== */ + /* (3) get and print stdout */ + /* ------------------------ */ + + /* get next element */ + elem = bcp_package_enumerator_get_next_element(enumerator, &type); + + /* check if it has the right type (string) */ + if (type != BCP_PACKAGE_TYPE_STRING) { + fprintf(stderr, + "Error in BCP protocol: expected a string (BCP stdout) " + "but found an element of type %d!\n", type); + exit(ERROR_IN_BCP_PROTOCOL); + } + + /* get and print stdout */ + if (debug2) fprintf(stdout, "[STDOUT]>>"); + fprintf(stdout, "%s", (char*) elem); + if (debug2) fprintf(stdout, "<<\n"); + + /* ======================== */ + /* (4) get and print stderr */ + /* ------------------------ */ + + /* get next element */ + elem = bcp_package_enumerator_get_next_element(enumerator, &type); + + /* check if it has the right type (string) */ + if (type != BCP_PACKAGE_TYPE_STRING) { + fprintf(stderr, + "Error in BCP protocol: expected a string (BCP stderr) " + "but found an element of type %d!\n", type); + exit(ERROR_IN_BCP_PROTOCOL); + } + + /* get and print stderr */ + if (debug2) fprintf(stderr, "[STDERR]>>"); + fprintf(stderr, "%s", (char*) elem); + if (debug2) fprintf(stderr, "<<\n"); + + /* ========================================= */ + /* (5) check that there are no more elements */ + /* ----------------------------------------- */ + + /* get next element */ + elem = bcp_package_enumerator_get_next_element(enumerator, &type); + + /* there should be no more elements: */ + if (type != BCP_PACKAGE_TYPE_EMPTY) { + fprintf(stderr, + "Error in BCP protocol: expected no more returned elements " + "but found an element of type %d!\n", type); + exit(ERROR_IN_BCP_PROTOCOL); + } + + /* delete the package enumerator */ + bcp_package_enumerator_delete(enumerator); + enumerator = NULL; + + /* delete package */ + bcp_package_delete(result_package); + result_package = NULL; + + /* return BCP return code */ + return return_code; +} + +/** + Translate a shell mode into the corresponding BCP meta command. +*/ +char mode_to_bcp_meta_command(int mode) +{ + switch (mode) { + + case BCP_SINGLE_MODE: return BCP_SINGLE_MODE_COMMAND; break; + case BCP_EVAL_MODE: return BCP_EVAL_MODE_COMMAND; break; + case BCP_FILE_MODE: return BCP_FILE_MODE_COMMAND; break; + + default : + /* ERROR: undefined mode: */ + fprintf(stderr, "ERROR: Undefined shell input mode!"); + exit(1); + break; + } +} + +/* fin */ Index: source/blender/commandport/README =================================================================== --- source/blender/commandport/README (revision 0) +++ source/blender/commandport/README (revision 0) @@ -0,0 +1,76 @@ +# +# $Id: README, v 1.0 2007/05/01, dietrich, tokyo $ +# +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# The Original Code is Copyright (C) 2007 by the Blender Foundation. +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Author: Dietrich Bollmann +# Contributor(s): none yet. +# +# ***** END GPL LICENSE BLOCK ***** +# +# Blender Command Port readme file. + + +* The Blender Command Port (BCP) + +BCP implements a Python command socket for Blender. + +When started with the '--command-port ' option, Blender starts +in server mode. Clients can connect and send Python commands via the +socket for evaluation by the Blender server. + +See also the blash README (./blash/README) - blash, the BLender Again SHell, +is a Blender shell client similar to a Python command shell. + +Example: + + # starting the Blender server: + + $ blender -w -p 10 10 800 600 --command-port 6789 & + + # using blash to send Python commands to the Blender server: + + $ blash --port 6789 + + This is Blash - the GNU BLender-Again SHell :) + Connection to Blender Server established. (IP address: 127.0.0.1, port: 6789) + + >>> from Blender import * + >>> + >>> vertices = [[1, 1, 0], [-1, 1, 0], [-1, -1, 0], [1, -1, 0], [0, 0, 1.27]] + >>> faces = [[3, 2, 1, 0], [0, 1, 4], [1, 2, 4], [2, 3, 4], [3, 0, 4]] + >>> + >>> mesh = Mesh.New('mesh') + >>> mesh.verts.extend(vertices) + >>> mesh.faces.extend(faces) + >>> + >>> scene = Scene.GetCurrent() + >>> object = scene.objects.new(mesh, 'object') + >>> Redraw() + >>> + >>> bye + + bye... + +For more information see http://formgames.org/blender/command-port + +# fin. Index: source/blender/commandport/examples/example.txt =================================================================== --- source/blender/commandport/examples/example.txt (revision 0) +++ source/blender/commandport/examples/example.txt (revision 0) @@ -0,0 +1,67 @@ +# ========================================================== +# +# $Id: example.txt, v 1.0 2007/05/01, dietrich, tokyo $ +# +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# The Original Code is Copyright (C) 2007 by the Blender Foundation. +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Author: Dietrich Bollmann +# Contributor(s): none yet. +# +# ***** END GPL LICENSE BLOCK ***** +# +# A simple example to be used with blash. +# +# ---------------------------------------------------------- + +# start the Blender server + +blender -w -p 10 10 800 600 --command-port 6789 & + +# erase the default cube + +# start blash + +blash --port 6789 + +# enter the following commands via blash + +from Blender import * + +vertices = [[1, 1, 0], [-1, 1, 0], [-1, -1, 0], [1, -1, 0], [0, 0, 1.27]] +faces = [[3, 2, 1, 0], [0, 1, 4], [1, 2, 4], [2, 3, 4], [3, 0, 4]] + +mesh = Mesh.New('mesh') +mesh.verts.extend(vertices) +mesh.faces.extend(faces) + +scene = Scene.GetCurrent() +object = scene.objects.new(mesh, 'object') +Redraw() + +bye + +# ...you should now see a simple pyramid in the 3D-view :) + +# ========================================================== +# ========================================================== + +# fin. Index: source/blender/include/mydevice.h =================================================================== --- source/blender/include/mydevice.h (revision 15538) +++ source/blender/include/mydevice.h (working copy) @@ -32,8 +32,9 @@ * * The Original Code is: all of this file. * - * Contributor(s): none yet. - * + * Contributor(s): + * - Dietrich Bollmann - added command port queue event definition (COMMAND_PORT_INPUT) + * * ***** END GPL LICENSE BLOCK ***** */ @@ -208,6 +209,9 @@ #define UI_BUT_EVENT 0x4008 #define AUTOSAVE_FILE 0x4009 #define UNDOPUSH 0x400A +#ifdef WITH_COMMAND_PORT +#define COMMAND_PORT_INPUT 0x400B /* (dietrich) */ +#endif /* REDRAWVIEW3D has to be the first one (lowest number) for buttons! */ #define REDRAWVIEW3D 0x4010 Index: source/blender/include/BIF_mainqueue.h =================================================================== --- source/blender/include/BIF_mainqueue.h (revision 15538) +++ source/blender/include/BIF_mainqueue.h (working copy) @@ -24,7 +24,10 @@ * * The Original Code is: all of this file. * - * Contributor(s): none yet. + * Contributor(s): + * - Dietrich Bollmann + * - added thread protection (mainqueue_mutex) for main queue. + * - added the new parameter 'args' to pass an argument struct pointer * * ***** END GPL LICENSE BLOCK ***** */ @@ -34,11 +37,26 @@ #define MAXQUEUE 4096 -unsigned short mainqtest (void); -unsigned short mainqread (short *val, char *ascii); -void mainqenter (unsigned short event, short val); -void mainqenter_ext (unsigned short event, short val, char ascii); -void mainqpushback (unsigned short event, short val, char ascii); +unsigned short mainqtest (void); +unsigned short mainqread (short *val, char *ascii); +unsigned short mainqread_args (short *val, char *ascii +#ifdef WITH_COMMAND_PORT + , void** args +#endif + ); +void mainqenter (unsigned short event, short val); +void mainqenter_ext (unsigned short event, short val, char ascii); +void mainqenter_args (unsigned short event, short val, char ascii +#ifdef WITH_COMMAND_PORT + , void* args +#endif + ); +void mainqpushback (unsigned short event, short val, char ascii); +void mainqpushback_args (unsigned short event, short val, char ascii +#ifdef WITH_COMMAND_PORT + , void* args +#endif + ); #endif /* BIF_MAINQUEUE_H */ Index: source/blender/src/mainqueue.c =================================================================== --- source/blender/src/mainqueue.c (revision 15538) +++ source/blender/src/mainqueue.c (working copy) @@ -22,7 +22,10 @@ * * The Original Code is: all of this file. * - * Contributor(s): none yet. + * Contributor(s): + * - Dietrich Bollmann + * - added thread protection (mainqueue_mutex) for main queue. + * - added the new parameter 'args' to pass an argument struct pointer * * ***** END GPL LICENSE BLOCK ***** * @@ -32,16 +35,58 @@ #include #include + +#ifdef WITH_MULTI_THREADING_SUPPORT +#include +#endif +#include + #include "BIF_mainqueue.h" #ifdef HAVE_CONFIG_H #include #endif + +#ifdef WITH_MULTI_THREADING_SUPPORT +/** + Using a mutex to protect the mainqueue against simultaneous access + by different threads: +*/ +pthread_mutex_t mainqueue_mutex = PTHREAD_MUTEX_INITIALIZER; + +/** + Locking the mutex + protecting the mainqueue against access by multiple threads. +*/ +void lock_mainqueue_mutex() +{ + if ( pthread_mutex_lock( &mainqueue_mutex ) ) { + perror( "Error: couldn't lock the mainqueue mutex!" ); + exit( 1 ); + } +} + +/** + Unlocking the mutex + protecting the mainqueue against access by multiple threads. +*/ +void unlock_mainqueue_mutex() +{ + if ( pthread_mutex_unlock( &mainqueue_mutex ) ) { + perror( "Error: couldn't unlock the mainqueue mutex!" ); + exit( 1 ); + } +} +#endif + typedef struct { - unsigned short event; - short val; - char ascii; + unsigned short event; + short val; + char ascii; +#ifdef WITH_COMMAND_PORT + void* args; +#endif } QEvent; static QEvent mainqueue[MAXQUEUE]; @@ -49,51 +94,154 @@ unsigned short mainqread(short *val, char *ascii) { + void* dummy; + return mainqread_args(val, ascii +#ifdef WITH_COMMAND_PORT + , &dummy +#endif + ); +} + +unsigned short mainqread_args(short *val, char *ascii +#ifdef WITH_COMMAND_PORT + , void** args +#endif + ) +{ + unsigned short event = 0; + + +#ifdef WITH_MULTI_THREADING_SUPPORT + lock_mainqueue_mutex(); + /* begin of critical section */ +#endif + if (nevents) { nevents--; - *val= mainqueue[nevents].val; - *ascii= mainqueue[nevents].ascii; + *val = mainqueue[nevents].val; + *ascii = mainqueue[nevents].ascii; +#ifdef WITH_COMMAND_PORT + *args = mainqueue[nevents].args; +#endif if((*ascii<32)||(*ascii==127)) *ascii=0; - return mainqueue[nevents].event; - } else - return 0; + event = mainqueue[nevents].event; + } + + +#ifdef WITH_MULTI_THREADING_SUPPORT + /* end of critical section */ + unlock_mainqueue_mutex(); +#endif + + return event; } void mainqenter(unsigned short event, short val) { - mainqenter_ext(event, val, 0); + mainqenter_args(event, val, 0 +#ifdef WITH_COMMAND_PORT + , NULL +#endif + ); } void mainqenter_ext(unsigned short event, short val, char ascii) { + mainqenter_args(event, val, ascii +#ifdef WITH_COMMAND_PORT + , NULL +#endif + ); +} + +void mainqenter_args(unsigned short event, short val, char ascii +#ifdef WITH_COMMAND_PORT + , void* args +#endif + ) +{ if (!event) return; +#ifdef WITH_MULTI_THREADING_SUPPORT + lock_mainqueue_mutex(); + /* begin of critical section */ +#endif + if (nevents or --bcp + was specified on the command line. + + (dietrich) + */ + commandport_start(); +#endif + window_make_active(mainwin); while (1) { unsigned short event; short val, towin; char ascii; +#ifdef WITH_COMMAND_PORT + void* args; +#endif flush_extqd_events(); if (nafterqitems && !qtest()) { append_afterqueue(); event= val= ascii= 0; } else { - event= screen_qread(&val, &ascii); + event= screen_qread_args(&val, &ascii +#ifdef WITH_COMMAND_PORT + , &args +#endif + ); } // window_make_active(mainwin); // (only for inputchange, removed, (ton)) @@ -1375,6 +1458,12 @@ BIF_read_file(ext_load_str); sound_initialize_sounds(); } +#ifdef WITH_COMMAND_PORT + else if (event == COMMAND_PORT_INPUT) { + /* handle Blender command port input (dietrich) */ + commandport_handle_input_allocate(args); + } +#endif else if ((event==ONLOAD_SCRIPT) && BPY_has_onload_script()) { /* event queued in setup_app_data() in blender.c, where G.f is checked */ onload_script = 1; @@ -2124,10 +2213,10 @@ void BIF_wait_for_statechange(void) { if (!statechanged) { - /* Safety, don't wait more than 0.1 seconds */ + /* Safety, don't wait more than 0.1 seconds */ double stime= PIL_check_seconds_timer(); while (!statechanged) { - winlay_process_events(1); + wait_for_event(); if ((PIL_check_seconds_timer()-stime)>0.1) break; } statechanged= 0; Index: source/blender/src/usiblender.c =================================================================== --- source/blender/src/usiblender.c (revision 15538) +++ source/blender/src/usiblender.c (working copy) @@ -22,7 +22,7 @@ * * The Original Code is: all of this file. * - * Contributor(s): none yet. + * Contributor(s): Dietrich Bollmann. * * ***** END GPL LICENSE BLOCK ***** */ @@ -143,6 +143,10 @@ #include "radio.h" #include "datatoc.h" +#ifdef WITH_COMMAND_PORT +#include "commandport.h" /* Blender command port (dietrich) */ +#endif + #include "SYS_System.h" #include "PIL_time.h" @@ -1054,6 +1058,11 @@ { struct TmpFont *tf; +#ifdef WITH_COMMAND_PORT + /* cleanup the command port (dietrich) */ + commandport_destroy(); +#endif + BIF_clear_tempfiles(); tf= G.ttfdata.first; Index: source/blender/src/eventdebug.c =================================================================== --- source/blender/src/eventdebug.c (revision 15538) +++ source/blender/src/eventdebug.c (working copy) @@ -187,6 +187,9 @@ smap(ENDKEY); smap(REDRAWNLA); smap(ONLOAD_SCRIPT); +#ifdef WITH_COMMAND_PORT + smap(COMMAND_PORT_INPUT); /* (dietrich) */ +#endif } #undef smap } Index: source/blender/SConscript =================================================================== --- source/blender/SConscript (revision 15538) +++ source/blender/SConscript (working copy) @@ -31,3 +31,8 @@ if env['WITH_BF_QUICKTIME'] == 1: SConscript (['quicktime/SConscript']) + +# command port (dietrich) +if env['WITH_COMMAND_PORT'] == 1: + SConscript (['commandport/SConscript']) + Index: config/win32-vc-config.py =================================================================== --- config/win32-vc-config.py (revision 15538) +++ config/win32-vc-config.py (working copy) @@ -174,3 +174,15 @@ BF_BUILDDIR = '..\\build\\win32-vc' BF_INSTALLDIR='..\\install\\win32-vc' + +# command port (dietrich) +WITH_COMMAND_PORT = 'false' + +# blash - the blender python shell (relies on the command port) (dietrich) +WITH_BLASH = 'false' + +# libraries needed by 'readline' (dietrich) +# which libraries are necessary for 'readline'? - in the case of linux: +# todo: READLINE_LIB = 'readline curses' + +# fin. Index: config/linuxcross-config.py =================================================================== --- config/linuxcross-config.py (revision 15538) +++ config/linuxcross-config.py (working copy) @@ -137,3 +137,14 @@ BF_BUILDDIR = '../build/linuxcross' BF_INSTALLDIR='../install/linuxcross' + +# command port (dietrich) +WITH_COMMAND_PORT = 'false' + +# blash - the blender python shell (relies on the command port) (dietrich) +WITH_BLASH = 'false' + +# libraries needed by 'readline' (dietrich) +READLINE_LIB = 'readline curses' + +# fin. Index: config/sunos5-config.py =================================================================== --- config/sunos5-config.py (revision 15538) +++ config/sunos5-config.py (working copy) @@ -169,3 +169,15 @@ PLATFORM_LINKFLAGS = [''] + +# command port (dietrich) +WITH_COMMAND_PORT = 'false' + +# blash - the blender python shell (relies on the command port) (dietrich) +WITH_BLASH = 'false' + +# libraries needed by 'readline' (dietrich) +# which libraries are necessary for 'readline'? - in the case of linux: +READLINE_LIB = 'readline curses' + +# fin. Index: config/openbsd3-config.py =================================================================== --- config/openbsd3-config.py (revision 15538) +++ config/openbsd3-config.py (working copy) @@ -158,3 +158,15 @@ BF_BUILDDIR='../build/openbsd3' BF_INSTALLDIR='../install/openbsd3' + +# command port (dietrich) +WITH_COMMAND_PORT = 'false' + +# blash - the blender python shell (relies on the command port) (dietrich) +WITH_BLASH = 'false' + +# libraries needed by 'readline' (dietrich) +# which libraries are necessary for 'readline'? - in the case of linux: +READLINE_LIB = 'readline curses' + +# fin. Index: config/linux2-config.py =================================================================== --- config/linux2-config.py (revision 15538) +++ config/linux2-config.py (working copy) @@ -197,3 +197,12 @@ #Link against pthread PLATFORM_LINKFLAGS = ['-pthread'] +# command port (dietrich) +WITH_COMMAND_PORT = 'false' + +# blash - the blender python shell (relies on the command port) (dietrich) +WITH_BLASH = 'false' + +# libraries needed by 'readline' (dietrich) +READLINE_LIB = 'readline curses' + Index: config/win32-mingw-config.py =================================================================== --- config/win32-mingw-config.py (revision 15538) +++ config/win32-mingw-config.py (working copy) @@ -161,3 +161,15 @@ BF_BUILDDIR = '..\\build\\win32-mingw' BF_INSTALLDIR='..\\install\\win32-mingw' + +# command port (dietrich) +WITH_COMMAND_PORT = 'false' + +# blash - the blender python shell (relies on the command port) (dietrich) +WITH_BLASH = 'false' + +# libraries needed by 'readline' (dietrich) +# which libraries are necessary for 'readline'? - in the case of linux: +# todo: READLINE_LIB = 'readline curses' + +# fin. Index: config/darwin-config.py =================================================================== --- config/darwin-config.py (revision 15538) +++ config/darwin-config.py (working copy) @@ -258,3 +258,15 @@ BF_BUILDDIR='../build/darwin' BF_INSTALLDIR='../install/darwin' + +# command port (dietrich) +WITH_COMMAND_PORT = 'false' + +# blash - the blender python shell (relies on the command port) (dietrich) +WITH_BLASH = 'false' + +# libraries needed by 'readline' (dietrich) +# which libraries are necessary for 'readline'? - in the case of linux: +READLINE_LIB = 'readline curses' + +# fin. Index: SConstruct =================================================================== --- SConstruct (revision 15538) +++ SConstruct (working copy) @@ -21,7 +21,10 @@ # # The Original Code is: all of this file. # -# Contributor(s): Nathan Letwory. +# Contributor(s): +# +# - Nathan Letwory. +# - Dietrich Bollmann : added building instructions for the command port and blash (2007/05/01). # # ***** END GPL LICENSE BLOCK ***** # @@ -56,9 +59,12 @@ B.possible_types = ['core', 'common', 'blender', 'intern', 'international', 'game', 'game2', - 'player', 'player2', 'system'] + 'player', 'player2', 'system', + 'blash'] -B.binarykind = ['blender' , 'blenderplayer'] +B.binarykind = ['blender' , 'blenderplayer', + 'blash'] # (dietrich) + ################################## # target and argument validation # ################################## @@ -247,6 +253,10 @@ if 'blendernogame' in B.targets: env['WITH_BF_GAMEENGINE'] = False +# blash - the blender python shell (dietrich) +if env['WITH_COMMAND_PORT'] and 'blash' in B.targets: + env['WITH_BLASH'] = True + # lastly we check for root_build_dir ( we should not do before, otherwise we might do wrong builddir #B.root_build_dir = B.arguments.get('BF_BUILDDIR', '..'+os.sep+'build'+os.sep+platform+os.sep) B.root_build_dir = env['BF_BUILDDIR'] @@ -335,6 +345,11 @@ playerlist = B.create_blender_liblist(env, 'player') env.BlenderProg(B.root_build_dir, "blenderplayer", dobj + playerlist + thestatlibs, [], thesyslibs, [B.root_build_dir+'/lib'] + thelibincs, 'blenderplayer') +# blash - the blender python shell (dietrich) +if env['WITH_COMMAND_PORT'] and env['WITH_BLASH']: + blashlist = B.create_blender_liblist(env, 'blash') + env.BlenderProg(B.root_build_dir, "blash", dobj + blashlist + thestatlibs, [], thesyslibs, [B.root_build_dir+'/lib'] + thelibincs, 'blash') + ##### Now define some targets @@ -487,6 +502,10 @@ blendernogame = env.Alias('blendernogame', B.program_list) Depends(blendernogame,installtarget) +if env['WITH_COMMAND_PORT'] and env['WITH_BLASH']: # (dietrich) + blenderplayer = env.Alias('blash', B.program_list) + Depends(blenderplayer,installtarget) + Depends(nsiscmd, allinstall) Default(B.program_list)