diff options
Diffstat (limited to 'source/blender/python/BPY_menus.c')
-rw-r--r-- | source/blender/python/BPY_menus.c | 1118 |
1 files changed, 0 insertions, 1118 deletions
diff --git a/source/blender/python/BPY_menus.c b/source/blender/python/BPY_menus.c deleted file mode 100644 index b67f1e717da..00000000000 --- a/source/blender/python/BPY_menus.c +++ /dev/null @@ -1,1118 +0,0 @@ -/* - * $Id: BPY_menus.c 12932 2007-12-17 20:21:06Z theeth $ - * - * ***** BEGIN GPL/BL DUAL 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. The Blender - * Foundation also sells licenses for use in proprietary software under - * the Blender License. See http://www.blender.org/BL/ for information - * about this. - * - * 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) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * This is a new part of Blender. - * - * Contributor(s): Willian P. Germano, Michael Reimpell - * - * ***** END GPL/BL DUAL LICENSE BLOCK ***** -*/ - -/* - *This is the main file responsible for having bpython scripts accessible - * from Blender menus. To know more, please start with its header file. - */ - -#include "BPY_menus.h" - -#include <Python.h> -#ifndef WIN32 - #include <dirent.h> -#else - #include "BLI_winstuff.h" -#endif -#include "BKE_global.h" -#include "BKE_utildefines.h" -#include "BLI_blenlib.h" -#include "MEM_guardedalloc.h" -#include "DNA_userdef_types.h" /* for U.pythondir */ -#include "api2_2x/EXPP_interface.h" /* for bpy_gethome() */ - -#define BPYMENU_DATAFILE "Bpymenus" -#define MAX_DIR_DEPTH 4 /* max depth for traversing scripts dirs */ -#define MAX_DIR_NUMBER 30 /* max number of dirs in scripts dirs trees */ - -static int DEBUG; -static int Dir_Depth; -static int Dirs_Number; - -/* BPyMenuTable holds all registered pymenus, as linked lists for each menu - * where they can appear (see PYMENUHOOKS enum in BPY_menus.h). -*/ -BPyMenu *BPyMenuTable[PYMENU_TOTAL]; - -static int bpymenu_group_atoi( char *str ) -{ - if( !strcmp( str, "Export" ) ) - return PYMENU_EXPORT; - else if( !strcmp( str, "Import" ) ) - return PYMENU_IMPORT; - else if( !strcmp( str, "Help" ) ) - return PYMENU_HELP; - else if( !strcmp( str, "HelpWebsites" ) ) - return PYMENU_HELPWEBSITES; - else if( !strcmp( str, "HelpSystem" ) ) - return PYMENU_HELPSYSTEM; - else if( !strcmp( str, "Render" ) ) - return PYMENU_RENDER; - else if( !strcmp( str, "System" ) ) - return PYMENU_SYSTEM; - else if( !strcmp( str, "Object" ) ) - return PYMENU_OBJECT; - else if( !strcmp( str, "Mesh" ) ) - return PYMENU_MESH; - else if( !strncmp( str, "Theme", 5 ) ) - return PYMENU_THEMES; - else if( !strcmp( str, "Add" ) ) - return PYMENU_ADD; - else if( !strcmp( str, "Wizards" ) ) - return PYMENU_WIZARDS; - else if( !strcmp( str, "Animation" ) ) - return PYMENU_ANIMATION; - else if( !strcmp( str, "Materials" ) ) - return PYMENU_MATERIALS; - else if( !strcmp( str, "UV" ) ) - return PYMENU_UV; - else if( !strcmp( str, "Image" ) ) - return PYMENU_IMAGE; - else if( !strcmp( str, "FaceSelect" ) ) - return PYMENU_FACESELECT; - else if( !strcmp( str, "WeightPaint" ) ) - return PYMENU_WEIGHTPAINT; - else if( !strcmp( str, "VertexPaint" ) ) - return PYMENU_VERTEXPAINT; - else if( !strcmp( str, "UVCalculation" ) ) - return PYMENU_UVCALCULATION; - else if( !strcmp( str, "Armature" ) ) - return PYMENU_ARMATURE; - else if( !strcmp( str, "ScriptTemplate" ) ) - return PYMENU_SCRIPTTEMPLATE; - else if( !strcmp( str, "MeshFaceKey" ) ) - return PYMENU_MESHFACEKEY; - else if( !strcmp( str, "AddMesh" ) ) - return PYMENU_ADDMESH; - /* "Misc" or an inexistent group name: use misc */ - else - return PYMENU_MISC; -} - -char *BPyMenu_group_itoa( short menugroup ) -{ - switch ( menugroup ) { - case PYMENU_EXPORT: - return "Export"; - break; - case PYMENU_IMPORT: - return "Import"; - break; - case PYMENU_ADD: - return "Add"; - break; - case PYMENU_HELP: - return "Help"; - break; - case PYMENU_HELPWEBSITES: - return "HelpWebsites"; - break; - case PYMENU_HELPSYSTEM: - return "HelpSystem"; - break; - case PYMENU_RENDER: - return "Render"; - break; - case PYMENU_SYSTEM: - return "System"; - break; - case PYMENU_OBJECT: - return "Object"; - break; - case PYMENU_MESH: - return "Mesh"; - break; - case PYMENU_THEMES: - return "Themes"; - break; - case PYMENU_WIZARDS: - return "Wizards"; - break; - case PYMENU_ANIMATION: - return "Animation"; - break; - case PYMENU_MATERIALS: - return "Materials"; - break; - case PYMENU_UV: - return "UV"; - break; - case PYMENU_IMAGE: - return "Image"; - break; - case PYMENU_FACESELECT: - return "FaceSelect"; - break; - case PYMENU_WEIGHTPAINT: - return "WeightPaint"; - break; - case PYMENU_VERTEXPAINT: - return "VertexPaint"; - break; - case PYMENU_UVCALCULATION: - return "UVCalculation"; - break; - case PYMENU_ARMATURE: - return "Armature"; - break; - case PYMENU_SCRIPTTEMPLATE: - return "ScriptTemplate"; - break; - case PYMENU_MESHFACEKEY: - return "MeshFaceKey"; - break; - case PYMENU_ADDMESH: - return "AddMesh"; - break; - case PYMENU_MISC: - return "Misc"; - break; - } - return NULL; -} - -/* BPyMenu_CreatePupmenuStr: - * build and return a meaninful string to be used by pupmenu(). The - * string is made of a bpymenu name as title and its submenus as possible - * choices for the user. -*/ -char *BPyMenu_CreatePupmenuStr( BPyMenu * pym, short menugroup ) -{ - BPySubMenu *pysm = pym->submenus; - char str[1024], str2[100]; - int i = 0, rlen; - - if( !pym || !pysm ) - return NULL; - - str[0] = '\0'; - - PyOS_snprintf( str2, sizeof( str2 ), "%s: %s%%t", - BPyMenu_group_itoa( menugroup ), pym->name ); - strcat( str, str2 ); - - while( pysm ) { - PyOS_snprintf( str2, sizeof( str2 ), "|%s%%x%d", pysm->name, - i ); - rlen = sizeof( str ) - strlen( str ); - strncat( str, str2, rlen ); - i++; - pysm = pysm->next; - } - - return BLI_strdup( str ); -} - -static void bpymenu_RemoveAllSubEntries( BPySubMenu * smenu ) -{ - BPySubMenu *tmp; - - while( smenu ) { - tmp = smenu->next; - if( smenu->name ) - MEM_freeN( smenu->name ); - if( smenu->arg ) - MEM_freeN( smenu->arg ); - MEM_freeN( smenu ); - smenu = tmp; - } - return; -} - -void BPyMenu_RemoveAllEntries( void ) -{ - BPyMenu *tmp, *pymenu; - int i; - - for( i = 0; i < PYMENU_TOTAL; i++ ) { - pymenu = BPyMenuTable[i]; - while( pymenu ) { - tmp = pymenu->next; - if( pymenu->name ) - MEM_freeN( pymenu->name ); - if( pymenu->filename ) - MEM_freeN( pymenu->filename ); - if( pymenu->tooltip ) - MEM_freeN( pymenu->tooltip ); - if( pymenu->submenus ) - bpymenu_RemoveAllSubEntries( pymenu-> - submenus ); - MEM_freeN( pymenu ); - pymenu = tmp; - } - BPyMenuTable[i] = NULL; - } - - Dirs_Number = 0; - Dir_Depth = 0; - - return; -} - -static BPyMenu *bpymenu_FindEntry( short group, char *name ) -{ - BPyMenu *pymenu; - - if( ( group < 0 ) || ( group >= PYMENU_TOTAL ) ) - return NULL; - - pymenu = BPyMenuTable[group]; - - while( pymenu ) { - if( !strcmp( pymenu->name, name ) ) - return pymenu; - pymenu = pymenu->next; - } - - return NULL; -} - -/* BPyMenu_GetEntry: - * given a group and a position, return the entry in that position from - * that group. -*/ -BPyMenu *BPyMenu_GetEntry( short group, short pos ) -{ - BPyMenu *pym = NULL; - - if( ( group < 0 ) || ( group >= PYMENU_TOTAL ) ) - return NULL; - - pym = BPyMenuTable[group]; - - while( pos-- ) { - if( pym ) - pym = pym->next; - else - break; - } - - return pym; /* found entry or NULL */ -} - -static void bpymenu_set_tooltip( BPyMenu * pymenu, char *tip ) -{ - if( !pymenu ) - return; - - if( pymenu->tooltip ) - MEM_freeN( pymenu->tooltip ); - pymenu->tooltip = BLI_strdup( tip ); - - return; -} - -/* bpymenu_AddEntry: - * try to find an existing pymenu entry with the given type and name; - * if found, update it with new info, otherwise create a new one and fill it. - */ -static BPyMenu *bpymenu_AddEntry( short group, short version, char *name, - char *fname, int is_userdir, char *tooltip ) -{ - BPyMenu *menu, *next = NULL, **iter; - int nameclash = 0; - - if( ( group < 0 ) || ( group >= PYMENU_TOTAL ) ) - return NULL; - if( !name || !fname ) - return NULL; - - menu = bpymenu_FindEntry( group, name ); /* already exists? */ - - /* if a menu with this name already exists in the same group: - * - if one script is in the default dir and the other in U.pythondir, - * accept and let the new one override the other. - * - otherwise, report the error and return NULL. */ - if( menu ) { - if( menu->dir < is_userdir ) { /* new one is in U.pythondir */ - nameclash = 1; - if( menu->name ) - MEM_freeN( menu->name ); - if( menu->filename ) - MEM_freeN( menu->filename ); - if( menu->tooltip ) - MEM_freeN( menu->tooltip ); - if( menu->submenus ) - bpymenu_RemoveAllSubEntries( menu->submenus ); - next = menu->next; - } else { /* they are in the same dir */ - if (DEBUG) { - fprintf(stderr, "\n\ -Warning: script %s's menu name is already in use.\n\ -Edit the script and change its \n\ -Name: '%s'\n\ -field, please.\n\ -Note: if you really want to have two scripts for the same menu with\n\ -the same name, keep one in the default dir and the other in\n\ -the user defined dir (only the later will be registered).\n", fname, name); - } - return NULL; - } - } else - menu = MEM_mallocN( sizeof( BPyMenu ), "pymenu" ); - - if( !menu ) - return NULL; - - menu->name = BLI_strdup( name ); - menu->version = version; - menu->filename = BLI_strdup( fname ); - menu->tooltip = NULL; - if( tooltip ) - menu->tooltip = BLI_strdup( tooltip ); - menu->dir = is_userdir; - menu->submenus = NULL; - menu->next = next; /* non-NULL if menu already existed */ - - if( nameclash ) - return menu; /* no need to place it, it's already at the list */ - else { /* insert the new entry in its correct position at the table */ - BPyMenu *prev = NULL; - char *s = NULL; - - iter = &BPyMenuTable[group]; - while( *iter ) { - s = ( *iter )->name; - if( s ) - if( strcmp( menu->name, s ) < 0 ) - break; /* sort by names */ - prev = *iter; - iter = &( ( *iter )->next ); - } - - if( *iter ) { /* prepend */ - menu->next = *iter; - if( prev ) - prev->next = menu; - else - BPyMenuTable[group] = menu; /* is first entry */ - } else - *iter = menu; /* append */ - } - - return menu; -} - -/* bpymenu_AddSubEntry: - * add a submenu to an existing python menu. - */ -static int bpymenu_AddSubEntry( BPyMenu * mentry, char *name, char *arg ) -{ - BPySubMenu *smenu, **iter; - - smenu = MEM_mallocN( sizeof( BPySubMenu ), "pysubmenu" ); - if( !smenu ) - return -1; - - smenu->name = BLI_strdup( name ); - smenu->arg = BLI_strdup( arg ); - smenu->next = NULL; - - if( !smenu->name || !smenu->arg ) - return -1; - - iter = &( mentry->submenus ); - while( *iter ) - iter = &( ( *iter )->next ); - - *iter = smenu; - - return 0; -} - -/* bpymenu_CreateFromFile: - * parse the bpymenus data file where Python menu data is stored; - * based on this data, create and fill the pymenu structs. - */ -static int bpymenu_CreateFromFile( void ) -{ - FILE *fp; - char line[255], w1[255], w2[255], tooltip[255], *tip; - char *homedir = NULL; - int parsing, version, is_userdir; - short group; - BPyMenu *pymenu = NULL; - - /* init global bpymenu table (it is a list of pointers to struct BPyMenus - * for each available cathegory: import, export, etc.) */ - for( group = 0; group < PYMENU_TOTAL; group++ ) - BPyMenuTable[group] = NULL; - - /* let's try to open the file with bpymenu data */ - homedir = bpy_gethome(0); - if (!homedir) { - if( DEBUG ) - fprintf(stderr, - "BPyMenus error: couldn't open config file Bpymenus: no home dir.\n"); - return -1; - } - - BLI_make_file_string( "/", line, homedir, BPYMENU_DATAFILE ); - - fp = fopen( line, "rb" ); - - if( !fp ) { - if( DEBUG ) - fprintf(stderr, "BPyMenus error: couldn't open config file %s.\n", line ); - return -1; - } - - fgets( line, 255, fp ); /* header */ - - /* check if the U.pythondir we saved at the file is different from the - * current one. If so, return to force updating from dirs */ - w1[0] = '\0'; - fscanf( fp, "# User defined scripts dir: %[^\n]\n", w1 ); - if( w1 ) { - char upythondir[FILE_MAXDIR]; - - BLI_strncpy(upythondir, U.pythondir, FILE_MAXDIR); - BLI_convertstringcode(upythondir, G.sce, 0); - if( strcmp( w1, upythondir ) != 0 ) - return -1; - w1[0] = '\0'; - } - - while( fgets( line, 255, fp ) ) { /* parsing file lines */ - - switch ( line[0] ) { /* check first char */ - case '#': /* comment */ - continue; - break; - case '\n': - continue; - break; - default: - parsing = sscanf( line, "%s {\n", w1 ); /* menu group */ - break; - } - - if( parsing == 1 ) { /* got menu group string */ - group = (short)bpymenu_group_atoi( w1 ); - if( group < 0 && DEBUG ) { /* invalid type */ - fprintf(stderr, - "BPyMenus error parsing config file: wrong group: %s,\n\ -will use 'Misc'.\n", w1 ); - } - } else - continue; - - for(;;) { - tip = NULL; /* optional tooltip */ - fgets( line, 255, fp ); - if( line[0] == '}' ) - break; - else if( line[0] == '\n' ) - continue; - else if( line[0] == '\'' ) { /* menu entry */ - parsing = - sscanf( line, - "'%[^']' %d %s %d '%[^']'\n", - w1, &version, w2, &is_userdir, - tooltip ); - - if( parsing <= 0 ) { /* invalid line, get rid of it */ - fgets( line, 255, fp ); - } else if( parsing == 5 ) - tip = tooltip; /* has tooltip */ - - pymenu = bpymenu_AddEntry( group, - ( short ) version, - w1, w2, is_userdir, - tip ); - if( !pymenu ) { - puts( "BPyMenus error: couldn't create bpymenu entry.\n" ); - fclose( fp ); - return -1; - } - } else if( line[0] == '|' && line[1] == '_' ) { /* menu sub-entry */ - if( !pymenu ) - continue; /* no menu yet, skip this line */ - sscanf( line, "|_%[^:]: %s\n", w1, w2 ); - bpymenu_AddSubEntry( pymenu, w1, w2 ); - } - } - } - - fclose( fp ); - return 0; -} - -/* bpymenu_WriteDataFile: - * writes the registered scripts info to the user's home dir, for faster - * access when the scripts dir hasn't changed. -*/ -static void bpymenu_WriteDataFile( void ) -{ - BPyMenu *pymenu; - BPySubMenu *smenu; - FILE *fp; - char fname[FILE_MAXDIR], *homedir; - int i; - - homedir = bpy_gethome(0); - - if (!homedir) { - if( DEBUG ) - fprintf(stderr, - "BPyMenus error: couldn't write Bpymenus file: no home dir.\n\n"); - return; - } - - BLI_make_file_string( "/", fname, homedir, BPYMENU_DATAFILE ); - - fp = fopen( fname, "w" ); - if( !fp ) { - if( DEBUG ) - fprintf(stderr, "BPyMenus error: couldn't write %s file.\n\n", - fname ); - return; - } - - fprintf( fp, - "# Blender: registered menu entries for bpython scripts\n" ); - - if (U.pythondir[0] != '\0' && - strcmp(U.pythondir, "/") != 0 && strcmp(U.pythondir, "//") != 0) - { - char upythondir[FILE_MAXDIR]; - - BLI_strncpy(upythondir, U.pythondir, FILE_MAXDIR); - BLI_convertstringcode(upythondir, G.sce, 0); - fprintf( fp, "# User defined scripts dir: %s\n", upythondir ); - } - - for( i = 0; i < PYMENU_TOTAL; i++ ) { - pymenu = BPyMenuTable[i]; - if( !pymenu ) - continue; - fprintf( fp, "\n%s {\n", BPyMenu_group_itoa( (short)i ) ); - while( pymenu ) { - fprintf( fp, "'%s' %d %s %d", pymenu->name, - pymenu->version, pymenu->filename, - pymenu->dir ); - if( pymenu->tooltip ) - fprintf( fp, " '%s'\n", pymenu->tooltip ); - else - fprintf( fp, "\n" ); - smenu = pymenu->submenus; - while( smenu ) { - fprintf( fp, "|_%s: %s\n", smenu->name, - smenu->arg ); - smenu = smenu->next; - } - pymenu = pymenu->next; - } - fprintf( fp, "}\n" ); - } - - fclose( fp ); - return; -} - -/* BPyMenu_PrintAllEntries: - * useful for debugging. - */ -void BPyMenu_PrintAllEntries( void ) -{ - BPyMenu *pymenu; - BPySubMenu *smenu; - int i; - - printf( "# Blender: registered menu entries for bpython scripts\n" ); - - for( i = 0; i < PYMENU_TOTAL; i++ ) { - pymenu = BPyMenuTable[i]; - printf( "\n%s {\n", BPyMenu_group_itoa( (short)i ) ); - while( pymenu ) { - printf( "'%s' %d %s %d", pymenu->name, pymenu->version, - pymenu->filename, pymenu->dir ); - if( pymenu->tooltip ) - printf( " '%s'\n", pymenu->tooltip ); - else - printf( "\n" ); - smenu = pymenu->submenus; - while( smenu ) { - printf( "|_%s: %s\n", smenu->name, - smenu->arg ); - smenu = smenu->next; - } - pymenu = pymenu->next; - } - printf( "}\n" ); - } -} - -/* bpymenu_ParseFile: - * recursively scans folders looking for scripts to register. - * - * This function scans the scripts directory looking for .py files with the - * right header and menu info, using that to fill the bpymenu structs. - * is_userdir defines if the script is in the default scripts dir or the - * user defined one (U.pythondir: is_userdir == 1). - * Speed is important. - * - * The first line of the script must be '#!BPY'. - * The header registration lines must appear between the first pair of - * '\"\"\"' and follow this order (the single-quotes are part of - * the format): - * - * # \"\"\"<br> - * # Name: 'script name for the menu' - * # Blender: <code>short int</code> (minimal Blender version) - * # Group: 'group name' (defines menu) - * # Submenu: 'submenu name' related_1word_arg - * # Tooltip: 'tooltip for the menu' - * # \"\"\" - * - * Notes: - * - * - Commenting out header lines with "#" is optional, but recommended. - * - There may be more than one submenu line, or none: - * submenus and the tooltip are optional; - * - The Blender version is the same number reported by - * Blender.Get('version') in BPython or G.version in C; - * - Line length must be less than 99. - */ -static int bpymenu_ParseFile(FILE *file, char *fname, int is_userdir) -{ - char line[100]; - char head[100]; - char middle[100]; - char tail[100]; - int matches; - int parser_state; - - char script_name[100]; - int script_version = 1; - int script_group; - - BPyMenu *scriptMenu = NULL; - - if (file != NULL) { - parser_state = 1; /* state of parser, 0 to terminate */ - - while ((parser_state != 0) && (fgets(line, 100, file) != NULL)) { - - switch (parser_state) { - - case 1: /* !BPY */ - if (strncmp(line, "#!BPY", 5) == 0) { - parser_state++; - } else { - parser_state = 0; - } - break; - - case 2: /* \"\"\" */ - if ((strstr(line, "\"\"\""))) { - parser_state++; - } - break; - - case 3: /* Name: 'script name for the menu' */ - matches = sscanf(line, "%[^']'%[^']'%c", head, script_name, tail); - if ((matches == 3) && (strstr(head, "Name:") != NULL)) { - parser_state++; - } else { - if (DEBUG) - fprintf(stderr, "BPyMenus error: Wrong 'Name' line: %s\n", fname); - parser_state = 0; - } - break; - - case 4: /* Blender: <short int> */ - matches = sscanf(line, "%[^1234567890]%i%c", head, &script_version, - tail); - if (matches == 3) { - parser_state++; - } else { - if (DEBUG) - fprintf(stderr,"BPyMenus error: Wrong 'Blender' line: %s\n",fname); - parser_state = 0; - } - break; - - case 5: /* Group: 'group name' */ - matches = sscanf(line, "%[^']'%[^']'%c", head, middle, tail); - if ((matches == 3) && (strstr(head, "Group:") != NULL)) { - script_group = bpymenu_group_atoi(middle); - if (script_group < 0) { - if (DEBUG) - fprintf(stderr, "BPyMenus error: Unknown group \"%s\": %s\n", - middle, fname); - parser_state = 0; - } - - else { /* register script */ - scriptMenu = bpymenu_AddEntry((short)script_group, - (short int)script_version, script_name, fname, is_userdir,NULL); - if (scriptMenu == NULL) { - if (DEBUG) - fprintf(stderr, - "BPyMenus error: Couldn't create entry for: %s\n", fname); - parser_state = 0; - } else { - parser_state++; - } - } - - } else { - if (DEBUG) - fprintf(stderr, "BPyMenus error: Wrong 'Group' line: %s\n",fname); - parser_state = 0; - } - break; - - case 6: /* optional elements */ - /* Submenu: 'submenu name' related_1word_arg */ - matches = sscanf(line, "%[^']'%[^']'%s\n", head, middle, tail); - if ((matches == 3) && (strstr(head, "Submenu:") != NULL)) { - bpymenu_AddSubEntry(scriptMenu, middle, tail); - } else { - /* Tooltip: 'tooltip for the menu */ - matches = sscanf(line, "%[^']'%[^']'%c", head, middle, tail); - if ((matches == 3) && ((strstr(head, "Tooltip:") != NULL) || - (strstr(head, "Tip:") != NULL))) { - bpymenu_set_tooltip(scriptMenu, middle); - } - parser_state = 0; - } - break; - - default: - parser_state = 0; - break; - } - } - } - - else { /* shouldn't happen, it's checked in bpymenus_ParseDir */ - if (DEBUG) - fprintf(stderr, "BPyMenus error: Couldn't open %s.\n", fname); - return -1; - } - - return 0; -} - -/* bpymenu_ParseDir: - * recursively scans folders looking for scripts to register. - * - * This function scans the scripts directory looking for .py files with the - * right header and menu info. - * - is_userdir defines if the script is in the default scripts dir or the - * user defined one (U.pythondir: is_userdir == 1); - * - parentdir is the parent dir name to store as part of the script filename, - * if we're down a subdir. - * Speed is important. - */ -static int bpymenu_ParseDir(char *dirname, char *parentdir, int is_userdir ) -{ - DIR *dir; - FILE *file = NULL; - struct dirent *de; - struct stat status; - char *file_extension; - char path[FILE_MAX]; - char subdir[FILE_MAX]; - char *s = NULL; - - dir = opendir(dirname); - - if (dir != NULL) { - while ((de = readdir(dir)) != NULL) { - - /* skip files and dirs starting with '.' or 'bpy' */ - if ((de->d_name[0] == '.') || !strncmp(de->d_name, "bpy", 3)) { - continue; - } - - BLI_make_file_string("/", path, dirname, de->d_name); - - if (stat(path, &status) != 0) { - if (DEBUG) - fprintf(stderr, "stat %s failed: %s\n", path, strerror(errno)); - } - - if (S_ISREG(status.st_mode)) { /* is file */ - - file_extension = strstr(de->d_name, ".py"); - - if (file_extension && *(file_extension + 3) == '\0') { - file = fopen(path, "rb"); - - if (file) { - s = de->d_name; - if (parentdir) { - /* Join parentdir and de->d_name */ - BLI_join_dirfile(subdir, parentdir, de->d_name); - - s = subdir; - } - bpymenu_ParseFile(file, s, is_userdir); - fclose(file); - } - - else { - if (DEBUG) - fprintf(stderr, "BPyMenus error: Couldn't open %s.\n", path); - } - } - } - - else if (S_ISDIR(status.st_mode)) { /* is subdir */ - Dirs_Number++; - Dir_Depth++; - if (Dirs_Number > MAX_DIR_NUMBER) { - if (DEBUG) { - fprintf(stderr, "BPyMenus error: too many subdirs.\n"); - } - closedir(dir); - return -1; - } - else if (Dir_Depth > MAX_DIR_DEPTH) { - if (DEBUG) - fprintf(stderr, - "BPyMenus error: max depth reached traversing dir tree.\n"); - closedir(dir); - return -1; - } - s = de->d_name; - if (parentdir) { - /* Join parentdir and de->d_name */ - BLI_join_dirfile(subdir, parentdir, de->d_name); - s = subdir; - } - if (bpymenu_ParseDir(path, s, is_userdir) == -1) { - closedir(dir); - return -1; - } - Dir_Depth--; - } - - } - closedir(dir); - } - - else { /* open directory stream failed */ - if (DEBUG) - fprintf(stderr, "opendir %s failed: %s\n", dirname, strerror(errno)); - return -1; - } - - return 0; -} - -static int bpymenu_GetStatMTime( char *name, int is_file, time_t * mtime ) -{ - struct stat st; - int result; - - result = stat( name, &st ); - - if( result == -1 ) - return -1; - - if( is_file ) { - if( !S_ISREG( st.st_mode ) ) - return -2; - } else if( !S_ISDIR( st.st_mode ) ) - return -2; - - *mtime = st.st_mtime; - - return 0; -} - -/* BPyMenu_Init: - * import the bpython menus data to Blender, either from: - * - the BPYMENU_DATAFILE file (?/.blender/Bpymenus) or - * - the scripts dir(s), case newer than the datafile (then update the file). - * then fill the bpymenu table with this data. - * if param usedir != 0, then the data is recreated from the dir(s) anyway. -*/ -int BPyMenu_Init( int usedir ) -{ - char fname[FILE_MAXDIR]; - char dirname[FILE_MAXDIR]; - char upythondir[FILE_MAXDIR]; - char *upydir = U.pythondir, *sdir = NULL; - time_t time_dir1 = 0, time_dir2 = 0, time_file = 0; - int stat_dir1 = 0, stat_dir2 = 0, stat_file = 0; - int i; - - DEBUG = G.f & G_DEBUG; /* is Blender in debug mode (started with -d) ? */ - - /* init global bpymenu table (it is a list of pointers to struct BPyMenus - * for each available group: import, export, etc.) */ - for( i = 0; i < PYMENU_TOTAL; i++ ) - BPyMenuTable[i] = NULL; - - if( DEBUG ) - fprintf(stdout, "\nRegistering scripts in Blender menus ...\n\n" ); - - if( U.pythondir[0] == '\0') { - upydir = NULL; - } - else if (strcmp(U.pythondir, "/") == 0 || strcmp(U.pythondir, "//") == 0) { - /* these are not accepted to prevent possible slight slowdowns on startup; - * they should not be used as user defined scripts dir, anyway, also from - * speed considerations, since they'd not be dedicated scripts dirs */ - if (DEBUG) fprintf(stderr, - "BPyMenus: invalid user defined Python scripts dir: \"/\" or \"//\".\n"); - upydir = NULL; - } - else { - BLI_strncpy(upythondir, upydir, FILE_MAXDIR); - BLI_convertstringcode(upythondir, G.sce, 0); - } - - sdir = bpy_gethome(1); - - if (sdir) { - BLI_strncpy(dirname, sdir, FILE_MAXDIR); - stat_dir1 = bpymenu_GetStatMTime( dirname, 0, &time_dir1 ); - - if( stat_dir1 < 0 ) { - time_dir1 = 0; - if( DEBUG ) { - fprintf(stderr, - "\nDefault scripts dir: %s:\n%s\n", dirname, strerror(errno)); - if( upydir ) - fprintf(stdout, - "Getting scripts menu data from user defined dir: %s.\n", - upythondir ); - } - } - } - else stat_dir1 = -1; - - if( upydir ) { - stat_dir2 = bpymenu_GetStatMTime( upythondir, 0, &time_dir2 ); - - if( stat_dir2 < 0 ) { - time_dir2 = 0; - upydir = NULL; - if( DEBUG ) - fprintf(stderr, "\nUser defined scripts dir: %s:\n%s.\n", - upythondir, strerror( errno ) ); - if( stat_dir1 < 0 ) { - if( DEBUG ) - fprintf(stderr, "\ -To have scripts in menus, please add them to the default scripts dir:\n\ -%s\n\ -and / or go to 'Info window -> File Paths tab' and set a valid path for\n\ -the user defined Python scripts dir.\n", dirname ); - return -1; - } - } - } - else stat_dir2 = -1; - - if( ( stat_dir1 < 0 ) && ( stat_dir2 < 0 ) ) { - if( DEBUG ) { - fprintf(stderr, "\nCannot register scripts in menus, no scripts dir" - " available.\nExpected default dir at: %s \n", dirname ); - } - return -1; - } - - if (usedir) stat_file = -1; - else { /* if we're not forced to use the dir */ - char *homedir = bpy_gethome(0); - - if (homedir) { - BLI_make_file_string( "/", fname, homedir, BPYMENU_DATAFILE ); - stat_file = bpymenu_GetStatMTime( fname, 1, &time_file ); - if( stat_file < 0 ) - time_file = 0; - - /* comparing dates */ - - if((stat_file == 0) - && (time_file > time_dir1) && (time_file > time_dir2)) - { /* file is newer */ - stat_file = bpymenu_CreateFromFile( ); /* -1 if an error occurred */ - if( !stat_file && DEBUG ) - fprintf(stdout, - "Getting menu data for scripts from file:\n%s\n\n", fname ); - } - else stat_file = -1; - } - else stat_file = -1; /* -1 to use dirs: didn't use file or it was corrupted */ - } - - if( stat_file == -1 ) { /* use dirs */ - if( DEBUG ) { - fprintf(stdout, - "Getting menu data for scripts from dir(s):\ndefault: %s\n", dirname ); - if( upydir ) - fprintf(stdout, "user defined: %s\n", upythondir ); - fprintf(stdout, "\n"); - } - if( stat_dir1 == 0 ) { - i = bpymenu_ParseDir( dirname, NULL, 0 ); - if (i == -1 && DEBUG) - fprintf(stderr, "Default scripts dir does not seem valid.\n\n"); - } - if( stat_dir2 == 0 ) { - BLI_strncpy(dirname, U.pythondir, FILE_MAXDIR); - BLI_convertstringcode(dirname, G.sce, 0); - i = bpymenu_ParseDir( dirname, NULL, 1 ); - if (i == -1 && DEBUG) - fprintf(stderr, "User defined scripts dir does not seem valid.\n\n"); - } - - /* check if we got any data */ - for( i = 0; i < PYMENU_TOTAL; i++ ) - if( BPyMenuTable[i] ) - break; - - /* if we got, recreate the file */ - if( i < PYMENU_TOTAL ) - bpymenu_WriteDataFile( ); - else if( DEBUG ) { - fprintf(stderr, "\n\ -Warning: Registering scripts in menus -- no info found.\n\ -Either your scripts dirs have no .py scripts or the scripts\n\ -don't have a header with registration data.\n\ -Default scripts dir is:\n\ -%s\n", dirname ); - if( upydir ) - fprintf(stderr, "User defined scripts dir is: %s\n", - upythondir ); - } - } - - return 0; -} |