2004-01-14 21:36:10 +00:00
/*
2004-10-07 19:25:40 +00:00
* $ Id $
2004-01-14 21:36:10 +00:00
*
* * * * * * 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 .
*
2004-11-02 05:13:52 +00:00
* Contributor ( s ) : Willian P . Germano , Michael Reimpell
2004-01-14 21:36:10 +00:00
*
* * * * * * END GPL / BL DUAL LICENSE BLOCK * * * * *
*/
2004-10-07 19:25:40 +00:00
/*
* This is the main file responsible for having bpython scripts accessible
2004-01-14 21:36:10 +00:00
* from Blender menus . To know more , please start with its header file .
2004-10-07 19:25:40 +00:00
*/
2004-01-14 21:36:10 +00:00
# ifdef HAVE_CONFIG_H
# include <config.h>
# endif
# include <stdio.h>
# include <stdlib.h>
# include <string.h>
# include <sys/types.h>
# include <sys/stat.h>
2004-01-14 21:48:56 +00:00
# include <Python.h>
2004-01-14 21:36:10 +00:00
# ifndef WIN32
# include <dirent.h>
# else
# include "BLI_winstuff.h"
# include <io.h>
# include <direct.h>
2004-10-07 19:25:40 +00:00
# endif
2004-01-14 21:36:10 +00:00
2004-01-23 19:24:45 +00:00
# include "BKE_global.h"
2004-01-14 21:36:10 +00:00
# include "BKE_utildefines.h"
# include "BLI_blenlib.h"
# include "MEM_guardedalloc.h"
2004-10-07 19:25:40 +00:00
# include <DNA_userdef_types.h> /* for U.pythondir */
2004-01-14 21:36:10 +00:00
# include "BPY_extern.h"
# include "BPY_menus.h"
# include <errno.h>
2004-01-23 02:59:54 +00:00
# define BPYMENU_DATAFILE "Bpymenus"
2004-01-23 19:24:45 +00:00
static int DEBUG ;
2004-01-23 02:59:54 +00:00
/* 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 ] ;
2004-10-07 19:25:40 +00:00
static int bpymenu_group_atoi ( char * str )
2004-01-14 21:36:10 +00:00
{
2004-10-07 19:25:40 +00:00
if ( ! strcmp ( str , " Import " ) )
return PYMENU_IMPORT ;
else if ( ! strcmp ( str , " Export " ) )
return PYMENU_EXPORT ;
else if ( ! strcmp ( str , " Help " ) )
return PYMENU_HELP ;
else if ( ! strcmp ( str , " Websites " ) | | ! strcmp ( str , " HelpWebsites " ) )
2004-07-30 05:18:14 +00:00
return PYMENU_HELPWEBSITES ;
2004-10-07 19:25:40 +00:00
else if ( ! strcmp ( str , " System " ) | | ! strcmp ( str , " HelpSystem " ) )
2004-07-30 05:18:14 +00:00
return PYMENU_HELPSYSTEM ;
2004-10-07 19:25:40 +00:00
else if ( ! strcmp ( str , " Add " ) )
return PYMENU_ADD ;
else if ( ! strcmp ( str , " Mesh " ) )
return PYMENU_MESH ;
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 , " Object " ) )
return PYMENU_OBJECT ;
2004-01-20 04:57:47 +00:00
/* "Misc" or an inexistent group name: use misc */
2004-10-07 19:25:40 +00:00
else
return PYMENU_MISC ;
2004-01-14 21:36:10 +00:00
}
2004-10-07 19:25:40 +00:00
char * BPyMenu_group_itoa ( short menugroup )
2004-01-14 21:36:10 +00:00
{
2004-10-07 19:25:40 +00:00
switch ( menugroup ) {
case PYMENU_IMPORT :
return " Import " ;
break ;
case PYMENU_EXPORT :
return " Export " ;
break ;
case PYMENU_ADD :
return " Add " ;
break ;
case PYMENU_HELP :
return " Help " ;
break ;
case PYMENU_HELPWEBSITES :
return " Websites " ;
break ;
case PYMENU_HELPSYSTEM :
return " System " ;
break ;
case PYMENU_MESH :
return " Mesh " ;
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_OBJECT :
return " Object " ;
break ;
case PYMENU_MISC :
return " Misc " ;
break ;
2004-01-14 21:36:10 +00:00
}
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 .
*/
2004-10-07 19:25:40 +00:00
char * BPyMenu_CreatePupmenuStr ( BPyMenu * pym , short menugroup )
2004-01-14 21:36:10 +00:00
{
BPySubMenu * pysm = pym - > submenus ;
char str [ 1024 ] , str2 [ 100 ] ;
int i = 0 , rlen ;
2004-10-07 19:25:40 +00:00
if ( ! pym | | ! pysm )
return NULL ;
2004-01-14 21:36:10 +00:00
str [ 0 ] = ' \0 ' ;
2004-10-07 19:25:40 +00:00
PyOS_snprintf ( str2 , sizeof ( str2 ) , " %s: %s%%t " ,
BPyMenu_group_itoa ( menugroup ) , pym - > name ) ;
strcat ( str , str2 ) ;
2004-01-14 21:36:10 +00:00
2004-10-07 19:25:40 +00:00
while ( pysm ) {
PyOS_snprintf ( str2 , sizeof ( str2 ) , " |%s%%x%d " , pysm - > name ,
i ) ;
rlen = sizeof ( str ) - strlen ( str ) ;
strncat ( str , str2 , rlen ) ;
2004-01-14 21:36:10 +00:00
i + + ;
pysm = pysm - > next ;
}
2004-10-07 19:25:40 +00:00
return BLI_strdup ( str ) ;
2004-01-14 21:36:10 +00:00
}
2004-10-07 19:25:40 +00:00
static void bpymenu_RemoveAllSubEntries ( BPySubMenu * smenu )
2004-01-14 21:36:10 +00:00
{
BPySubMenu * tmp ;
2004-10-07 19:25:40 +00:00
while ( smenu ) {
2004-01-14 21:36:10 +00:00
tmp = smenu - > next ;
2004-10-07 19:25:40 +00:00
if ( smenu - > name )
MEM_freeN ( smenu - > name ) ;
if ( smenu - > arg )
MEM_freeN ( smenu - > arg ) ;
MEM_freeN ( smenu ) ;
2004-01-14 21:36:10 +00:00
smenu = tmp ;
}
return ;
}
2004-10-07 19:25:40 +00:00
void BPyMenu_RemoveAllEntries ( void )
2004-01-14 21:36:10 +00:00
{
BPyMenu * tmp , * pymenu ;
int i ;
2004-10-07 19:25:40 +00:00
for ( i = 0 ; i < PYMENU_TOTAL ; i + + ) {
2004-01-14 21:36:10 +00:00
pymenu = BPyMenuTable [ i ] ;
2004-10-07 19:25:40 +00:00
while ( pymenu ) {
2004-01-14 21:36:10 +00:00
tmp = pymenu - > next ;
2004-10-07 19:25:40 +00:00
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 ) ;
2004-01-14 21:36:10 +00:00
pymenu = tmp ;
}
BPyMenuTable [ i ] = NULL ;
}
return ;
}
2004-10-07 19:25:40 +00:00
static BPyMenu * bpymenu_FindEntry ( short group , char * name )
2004-01-14 21:36:10 +00:00
{
BPyMenu * pymenu ;
2004-10-07 19:25:40 +00:00
if ( ( group < 0 ) | | ( group > = PYMENU_TOTAL ) )
return NULL ;
2004-01-14 21:36:10 +00:00
pymenu = BPyMenuTable [ group ] ;
2004-10-07 19:25:40 +00:00
while ( pymenu ) {
if ( ! strcmp ( pymenu - > name , name ) )
return pymenu ;
2004-01-14 21:36:10 +00:00
pymenu = pymenu - > next ;
}
return NULL ;
}
2004-01-27 03:34:16 +00:00
/* BPyMenu_GetEntry:
* given a group and a position , return the entry in that position from
* that group .
2004-10-07 19:25:40 +00:00
*/
BPyMenu * BPyMenu_GetEntry ( short group , short pos )
2004-01-27 03:34:16 +00:00
{
BPyMenu * pym = NULL ;
2004-10-07 19:25:40 +00:00
if ( ( group < 0 ) | | ( group > = PYMENU_TOTAL ) )
return NULL ;
2004-01-27 03:34:16 +00:00
pym = BPyMenuTable [ group ] ;
2004-10-07 19:25:40 +00:00
while ( pos - - ) {
if ( pym )
pym = pym - > next ;
else
break ;
2004-01-27 03:34:16 +00:00
}
2004-10-07 19:25:40 +00:00
return pym ; /* found entry or NULL */
2004-01-27 03:34:16 +00:00
}
2004-10-07 19:25:40 +00:00
static void bpymenu_set_tooltip ( BPyMenu * pymenu , char * tip )
2004-01-14 21:36:10 +00:00
{
2004-10-07 19:25:40 +00:00
if ( ! pymenu )
return ;
2004-01-14 21:36:10 +00:00
2004-10-07 19:25:40 +00:00
if ( pymenu - > tooltip )
MEM_freeN ( pymenu - > tooltip ) ;
pymenu - > tooltip = BLI_strdup ( tip ) ;
2004-01-14 21:36:10 +00:00
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 .
*/
2004-10-07 19:25:40 +00:00
static BPyMenu * bpymenu_AddEntry ( short group , short version , char * name ,
char * fname , int whichdir , char * tooltip )
2004-01-14 21:36:10 +00:00
{
2004-01-20 04:57:47 +00:00
BPyMenu * menu , * next = NULL , * * iter ;
int nameclash = 0 ;
2004-01-14 21:36:10 +00:00
2004-10-07 19:25:40 +00:00
if ( ( group < 0 ) | | ( group > = PYMENU_TOTAL ) )
return NULL ;
if ( ! name | | ! fname )
return NULL ;
2004-01-14 21:36:10 +00:00
2004-10-07 19:25:40 +00:00
menu = bpymenu_FindEntry ( group , name ) ; /* already exists? */
2004-01-14 21:36:10 +00:00
2004-01-20 04:57:47 +00:00
/* 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 . */
2004-10-07 19:25:40 +00:00
if ( menu ) {
if ( menu - > dir < whichdir ) { /* new one is in U.pythondir */
2004-01-20 04:57:47 +00:00
nameclash = 1 ;
2004-10-07 19:25:40 +00:00
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 ) ;
2004-01-20 04:57:47 +00:00
next = menu - > next ;
2004-10-07 19:25:40 +00:00
} else { /* they are in the same dir */
if ( DEBUG ) {
printf ( " \n Warning: script %s's menu name is already in use. \n " , fname ) ;
printf ( " Edit the script and change its Name: '%s' field, please. \n " " Note: if you really want two scripts in the same menu with \n " " the same name, keep one in the default dir and the other in \n " " the user defined dir, where it will take precedence. \n " , name ) ;
2004-01-23 19:24:45 +00:00
}
2004-01-20 04:57:47 +00:00
return NULL ;
}
2004-10-07 19:25:40 +00:00
} else
menu = MEM_mallocN ( sizeof ( BPyMenu ) , " pymenu " ) ;
2004-01-14 21:36:10 +00:00
2004-10-07 19:25:40 +00:00
if ( ! menu )
return NULL ;
2004-01-14 21:36:10 +00:00
2004-10-07 19:25:40 +00:00
menu - > name = BLI_strdup ( name ) ;
2004-01-16 23:40:14 +00:00
menu - > version = version ;
2004-10-07 19:25:40 +00:00
menu - > filename = BLI_strdup ( fname ) ;
2004-01-14 21:36:10 +00:00
menu - > tooltip = NULL ;
2004-10-07 19:25:40 +00:00
if ( tooltip )
menu - > tooltip = BLI_strdup ( tooltip ) ;
2004-01-20 04:57:47 +00:00
menu - > dir = whichdir ;
2004-01-14 21:36:10 +00:00
menu - > submenus = NULL ;
2004-10-07 19:25:40 +00:00
menu - > next = next ; /* non-NULL if menu already existed */
2004-01-20 04:57:47 +00:00
2004-10-07 19:25:40 +00:00
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 */
2004-05-22 20:25:22 +00:00
BPyMenu * prev = NULL ;
char * s = NULL ;
iter = & BPyMenuTable [ group ] ;
2004-10-07 19:25:40 +00:00
while ( * iter ) {
s = ( * iter ) - > name ;
if ( s )
if ( strcmp ( menu - > name , s ) < 0 )
break ; /* sort by names */
2004-05-22 20:25:22 +00:00
prev = * iter ;
2004-10-07 19:25:40 +00:00
iter = & ( ( * iter ) - > next ) ;
2004-05-22 20:25:22 +00:00
}
2004-01-14 21:36:10 +00:00
2004-10-07 19:25:40 +00:00
if ( * iter ) { /* prepend */
2004-05-22 20:25:22 +00:00
menu - > next = * iter ;
2004-10-07 19:25:40 +00:00
if ( prev )
prev - > next = menu ;
else
BPyMenuTable [ group ] = menu ; /* is first entry */
} else
* iter = menu ; /* append */
2004-05-22 20:25:22 +00:00
}
2004-01-14 21:36:10 +00:00
return menu ;
}
/* bpymenu_AddSubEntry:
* add a submenu to an existing python menu .
*/
2004-10-07 19:25:40 +00:00
static int bpymenu_AddSubEntry ( BPyMenu * mentry , char * name , char * arg )
2004-01-14 21:36:10 +00:00
{
BPySubMenu * smenu , * * iter ;
2004-10-07 19:25:40 +00:00
smenu = MEM_mallocN ( sizeof ( BPySubMenu ) , " pysubmenu " ) ;
if ( ! smenu )
return - 1 ;
2004-01-14 21:36:10 +00:00
2004-10-07 19:25:40 +00:00
smenu - > name = BLI_strdup ( name ) ;
smenu - > arg = BLI_strdup ( arg ) ;
2004-01-14 21:36:10 +00:00
smenu - > next = NULL ;
2004-10-07 19:25:40 +00:00
if ( ! smenu - > name | | ! smenu - > arg )
return - 1 ;
2004-01-14 21:36:10 +00:00
2004-10-07 19:25:40 +00:00
iter = & ( mentry - > submenus ) ;
while ( * iter )
iter = & ( ( * iter ) - > next ) ;
2004-01-14 21:36:10 +00:00
* 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 .
*/
2004-10-07 19:25:40 +00:00
static int bpymenu_CreateFromFile ( void )
2004-01-14 21:36:10 +00:00
{
FILE * fp ;
char line [ 255 ] , w1 [ 255 ] , w2 [ 255 ] , tooltip [ 255 ] , * tip ;
2004-01-20 04:57:47 +00:00
int parsing , version , whichdir ;
2004-01-14 21:36:10 +00:00
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 . ) */
2004-10-07 19:25:40 +00:00
for ( group = 0 ; group < PYMENU_TOTAL ; group + + )
2004-01-14 21:36:10 +00:00
BPyMenuTable [ group ] = NULL ;
/* let's try to open the file with bpymenu data */
2004-10-07 19:25:40 +00:00
BLI_make_file_string ( " / " , line , bpy_gethome ( ) , BPYMENU_DATAFILE ) ;
2004-01-14 21:36:10 +00:00
2004-10-07 19:25:40 +00:00
fp = fopen ( line , " rb " ) ;
2004-01-14 21:36:10 +00:00
2004-10-07 19:25:40 +00:00
if ( ! fp ) {
if ( DEBUG )
printf ( " BPyMenus error: couldn't open config file %s. \n " , line ) ;
2004-01-20 04:57:47 +00:00
return - 1 ;
}
2004-10-07 19:25:40 +00:00
fgets ( line , 255 , fp ) ; /* header */
2004-01-20 04:57:47 +00:00
/* 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 ' ;
2004-10-07 19:25:40 +00:00
fscanf ( fp , " # User defined scripts dir: %[^ \n ] \n " , w1 ) ;
if ( w1 ) {
if ( strcmp ( w1 , U . pythondir ) ! = 0 )
return - 1 ;
2004-01-20 04:57:47 +00:00
w1 [ 0 ] = ' \0 ' ;
2004-01-14 21:36:10 +00:00
}
2004-10-07 19:25:40 +00:00
while ( fgets ( line , 255 , fp ) ) { /* parsing file lines */
2004-01-14 21:36:10 +00:00
2004-10-07 19:25:40 +00:00
switch ( line [ 0 ] ) { /* check first char */
case ' # ' : /* comment */
continue ;
break ;
case ' \n ' :
continue ;
break ;
default :
parsing = sscanf ( line , " %s { \n " , w1 ) ; /* menu group */
break ;
2004-01-14 21:36:10 +00:00
}
2004-10-07 19:25:40 +00:00
if ( parsing = = 1 ) { /* got menu group string */
group = bpymenu_group_atoi ( w1 ) ;
if ( group < 0 & & DEBUG ) { /* invalid type */
printf ( " BPyMenus error parsing config file: wrong group: %s, " " will use 'Misc'. \n " , w1 ) ;
2004-01-14 21:36:10 +00:00
}
2004-10-07 19:25:40 +00:00
} else
continue ;
2004-01-14 21:36:10 +00:00
2004-10-07 19:25:40 +00:00
while ( 1 ) {
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 , & whichdir ,
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 , whichdir ,
tip ) ;
if ( ! pymenu ) {
puts ( " BPyMenus error: couldn't create bpymenu entry. \n " ) ;
fclose ( fp ) ;
2004-01-20 04:57:47 +00:00
return - 1 ;
2004-01-14 21:36:10 +00:00
}
2004-10-07 19:25:40 +00:00
} 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 ) ;
2004-01-14 21:36:10 +00:00
}
}
}
2004-01-15 03:46:47 +00:00
2004-10-07 19:25:40 +00:00
fclose ( fp ) ;
2004-01-20 04:57:47 +00:00
return 0 ;
2004-01-14 21:36:10 +00:00
}
/* bpymenu_WriteDataFile:
* writes the registered scripts info to the user ' s home dir , for faster
* access when the scripts dir hasn ' t changed .
*/
2004-10-07 19:25:40 +00:00
static void bpymenu_WriteDataFile ( void )
2004-01-14 21:36:10 +00:00
{
BPyMenu * pymenu ;
BPySubMenu * smenu ;
FILE * fp ;
2004-10-07 19:25:40 +00:00
char fname [ FILE_MAXDIR + FILE_MAXFILE ] ;
2004-01-14 21:36:10 +00:00
int i ;
2004-10-07 19:25:40 +00:00
BLI_make_file_string ( " / " , fname , bpy_gethome ( ) , BPYMENU_DATAFILE ) ;
2004-01-14 21:36:10 +00:00
2004-10-07 19:25:40 +00:00
fp = fopen ( fname , " w " ) ;
if ( ! fp ) {
if ( DEBUG )
printf ( " BPyMenus error: couldn't write %s file. " ,
fname ) ;
2004-01-14 21:36:10 +00:00
return ;
}
2004-10-07 19:25:40 +00:00
fprintf ( fp ,
" # Blender: registered menu entries for bpython scripts \n " ) ;
2004-01-14 21:36:10 +00:00
2004-10-07 19:25:40 +00:00
if ( U . pythondir [ 0 ] ! = ' \0 ' )
fprintf ( fp , " # User defined scripts dir: %s \n " , U . pythondir ) ;
2004-01-20 04:57:47 +00:00
2004-10-07 19:25:40 +00:00
for ( i = 0 ; i < PYMENU_TOTAL ; i + + ) {
2004-01-14 21:36:10 +00:00
pymenu = BPyMenuTable [ i ] ;
2004-10-07 19:25:40 +00:00
if ( ! pymenu )
continue ;
fprintf ( fp , " \n %s { \n " , BPyMenu_group_itoa ( 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 " ) ;
2004-01-14 21:36:10 +00:00
smenu = pymenu - > submenus ;
2004-10-07 19:25:40 +00:00
while ( smenu ) {
fprintf ( fp , " |_%s: %s \n " , smenu - > name ,
smenu - > arg ) ;
2004-01-14 21:36:10 +00:00
smenu = smenu - > next ;
}
pymenu = pymenu - > next ;
}
2004-10-07 19:25:40 +00:00
fprintf ( fp , " } \n " ) ;
2004-01-14 21:36:10 +00:00
}
2004-01-15 03:46:47 +00:00
2004-10-07 19:25:40 +00:00
fclose ( fp ) ;
2004-01-15 03:46:47 +00:00
return ;
2004-01-14 21:36:10 +00:00
}
/* BPyMenu_PrintAllEntries:
* useful for debugging .
2004-10-07 19:25:40 +00:00
*/
void BPyMenu_PrintAllEntries ( void )
2004-01-14 21:36:10 +00:00
{
BPyMenu * pymenu ;
BPySubMenu * smenu ;
int i ;
2004-10-07 19:25:40 +00:00
printf ( " # Blender: registered menu entries for bpython scripts \n " ) ;
2004-01-14 21:36:10 +00:00
2004-10-07 19:25:40 +00:00
for ( i = 0 ; i < PYMENU_TOTAL ; i + + ) {
2004-01-14 21:36:10 +00:00
pymenu = BPyMenuTable [ i ] ;
2004-10-07 19:25:40 +00:00
printf ( " \n %s { \n " , BPyMenu_group_itoa ( 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 " ) ;
2004-01-14 21:36:10 +00:00
smenu = pymenu - > submenus ;
2004-10-07 19:25:40 +00:00
while ( smenu ) {
printf ( " |_%s: %s \n " , smenu - > name ,
smenu - > arg ) ;
2004-01-14 21:36:10 +00:00
smenu = smenu - > next ;
}
pymenu = pymenu - > next ;
}
2004-10-07 19:25:40 +00:00
printf ( " } \n " ) ;
2004-01-14 21:36:10 +00:00
}
}
2004-11-02 05:13:52 +00:00
/** Creates BPyMenu entries for scripts from directory.
*
* This function scans the scripts directory looking for . py files with the
2004-01-14 21:36:10 +00:00
* right header and menu info , using that to fill the bpymenu structs .
2004-01-20 04:57:47 +00:00
* whichdir defines if the script is in the default scripts dir or the
* user defined one ( U . pythondir : whichdir = = 1 ) .
2004-01-14 21:36:10 +00:00
* Speed is important .
2004-11-02 05:13:52 +00:00
* < code > whichdir < / code > defines if the script is in the default scripts dir
* or the user defined one ( U . pythondir : < code > whichdir = = 1 < / code > ) .
* < p >
* The first line of the script must be ' < code > # ! BPY < / code > ' .
* The header registration lines must appear between the first pair of
* ' < code > # \ " \" \" </code>' and follow this order (the single-quotes are part of
* the format ) :
* < p >
* < code >
* # \ " \" \" <br>
* # Name : ' script name for the menu ' < br >
* # Blender : < code > short int < / code > ( minimal Blender version ) < br >
* # Group : ' group name ' ( defines menu ) < br >
* # Submenu : ' submenu name ' related_1word_arg < br >
* # Tooltip : ' tooltip for the menu ' < br >
* # \ " \" \" <br>
* < / code >
* < p >
* Notes :
* < ul >
* < li > There may be more than one submenu line , or none :
* Submenus and the tooltip are optional ;
* < li > The Blender version is the same number reported by
* < code > Blender . Get ( ' version ' ) < / code > in BPython or < code > G . version < / code >
* in C ;
* < li > Line length must be less than 99.
* < li > Script headers as python documentation strings without the leading
* hash character ( # ) should no longer be used .
* < / ul >
*
* @ param dirname Directory name to scan .
* @ param whichdir Specifies the directory . 1 if user defined script directory ,
* else default script directory .
* @ return 0 on success .
*/
2004-10-07 19:25:40 +00:00
static int bpymenu_CreateFromDir ( char * dirname , int whichdir )
2004-01-14 21:36:10 +00:00
{
2004-11-02 05:13:52 +00:00
DIR * dir ; /* directory stream object */
FILE * currentFile ; /* file stream object */
struct dirent * dirEntry ; /* directory entry */
struct stat fileStatus ;
char * fileExtension ;
char fileName [ FILE_MAXFILE + FILE_MAXDIR ] ; /* filename including path */
/* parser variables */
char line [ 100 ] ;
char head [ 100 ] ;
char middle [ 100 ] ;
char tail [ 100 ] ;
int nMatches ;
int parserState ;
/* script header variables */
char scriptName [ 100 ] ;
int scriptBlender ;
int scriptGroup ;
BPyMenu * scriptMenu = NULL ;
/* other */
int returnValue = 0 ;
/* open directory stream */
dir = opendir ( dirname ) ;
if ( dir ! = NULL ) {
/* directory stream opened */
2005-01-22 02:48:03 +00:00
while ( ( dirEntry = readdir ( dir ) ) ! = NULL ) {
2004-11-02 05:13:52 +00:00
/* Check if filename does not start with a dot,
* ends with ' . py ' and is a regular file . */
BLI_make_file_string ( " / " , fileName , dirname , dirEntry - > d_name ) ;
fileExtension = strstr ( dirEntry - > d_name , " .py " ) ;
if ( ( strncmp ( dirEntry - > d_name , " . " , 1 ) ! = 0 )
& & ( fileExtension ! = NULL )
& & ( * ( fileExtension + 3 ) = = ' \0 ' )
& & ( stat ( fileName , & fileStatus ) = = 0 )
& & ( S_ISREG ( fileStatus . st_mode ) ) ) {
/* check file header */
currentFile = fopen ( fileName , " rb " ) ;
if ( currentFile ! = NULL ) {
parserState = 1 ; /* state of parser, 0 to terminate */
while ( ( parserState ! = 0 ) & & ( fgets ( line , 100 , currentFile ) ! = NULL ) ) {
switch ( parserState ) {
case 1 : /* #!BPY */
if ( strncmp ( line , " #!BPY " , 5 ) = = 0 ) {
parserState + + ;
} else {
parserState = 0 ;
}
break ;
case 2 : /* # \"\"\" */
if ( ( strstr ( line , " \" \" \" " ) ) ) {
parserState + + ;
}
break ;
case 3 : /* # Name: 'script name for the menu' */
nMatches = sscanf ( line , " %[^']'%[^']'%c " , head , scriptName , tail ) ;
if ( ( nMatches = = 3 ) & & ( strstr ( head , " Name: " ) ! = NULL ) ) {
parserState + + ;
} else {
if ( DEBUG ) {
fprintf ( stderr , " BPyMenus error: Wrong 'Name' line: %s \n " , fileName ) ;
}
parserState = 0 ;
}
break ;
case 4 : /* # Blender: <short int> */
nMatches = sscanf ( line , " %[^1234567890]%i%c " , head , & scriptBlender , tail ) ;
if ( nMatches = = 3 ) {
parserState + + ;
} else {
if ( DEBUG ) {
fprintf ( stderr , " BPyMenus error: Wrong 'Blender' line: %s \n " , fileName ) ;
}
parserState = 0 ;
}
break ;
case 5 : /* # Group: 'group name' */
nMatches = sscanf ( line , " %[^']'%[^']'%c " , head , middle , tail ) ;
if ( ( nMatches = = 3 ) & & ( strstr ( head , " Group: " ) ! = NULL ) ) {
scriptGroup = bpymenu_group_atoi ( middle ) ;
if ( scriptGroup < 0 ) {
if ( DEBUG ) {
fprintf ( stderr , " BPyMenus error: Unknown group \" %s \" : %s \n " , middle , fileName ) ;
}
parserState = 0 ;
} else {
/* register script */
scriptMenu = bpymenu_AddEntry ( scriptGroup , ( short int ) scriptBlender , scriptName ,
dirEntry - > d_name , whichdir , NULL ) ;
if ( scriptMenu = = NULL ) {
if ( DEBUG ) {
fprintf ( stderr , " BPyMenus error: Couldn't create entry for: %s \n " , fileName ) ;
}
parserState = 0 ;
} else {
parserState + + ;
}
}
} else {
if ( DEBUG ) {
fprintf ( stderr , " BPyMenus error: Wrong 'Group' line: %s \n " , fileName ) ;
}
parserState = 0 ;
}
break ;
case 6 : /* optional elements */
/* # Submenu: 'submenu name' related_1word_arg */
nMatches = sscanf ( line , " %[^']'%[^']'%s \n " , head , middle , tail ) ;
if ( ( nMatches = = 3 ) & & ( strstr ( head , " Submenu: " ) ! = NULL ) ) {
bpymenu_AddSubEntry ( scriptMenu , middle , tail ) ;
} else {
/* # Tooltip: 'tooltip for the menu */
nMatches = sscanf ( line , " %[^']'%[^']'%c " , head , middle , tail ) ;
if ( ( nMatches = = 3 )
& & ( ( strstr ( head , " Tooltip: " ) ! = NULL ) | | ( strstr ( head , " Tip: " ) ! = NULL ) ) ) {
bpymenu_set_tooltip ( scriptMenu , middle ) ;
}
parserState = 0 ;
}
break ;
default :
parserState = 0 ;
break ;
}
}
/* close file stream */
fclose ( currentFile ) ;
} else {
/* open file failed */
if ( DEBUG ) {
fprintf ( stderr , " BPyMenus error: Couldn't open %s. \n " , dirEntry - > d_name ) ;
}
}
2004-01-14 21:36:10 +00:00
}
}
2004-11-02 05:13:52 +00:00
/* close directory stream */
closedir ( dir ) ;
} else {
/* open directory stream failed */
fprintf ( stderr , " opendir %s failed: %s \n " , dirname , strerror ( errno ) ) ;
returnValue = - 1 ;
2004-01-14 21:36:10 +00:00
}
2004-11-02 05:13:52 +00:00
return returnValue ;
2004-01-20 04:57:47 +00:00
}
2004-10-07 19:25:40 +00:00
static int bpymenu_GetStatMTime ( char * name , int is_file , time_t * mtime )
2004-01-20 04:57:47 +00:00
{
struct stat st ;
int result ;
2004-10-07 19:25:40 +00:00
result = stat ( name , & st ) ;
2004-01-20 04:57:47 +00:00
2004-10-07 19:25:40 +00:00
if ( result = = - 1 )
return - 1 ;
2004-01-20 04:57:47 +00:00
2004-10-07 19:25:40 +00:00
if ( is_file ) {
if ( ! S_ISREG ( st . st_mode ) )
return - 2 ;
} else if ( ! S_ISDIR ( st . st_mode ) )
return - 2 ;
2004-01-20 04:57:47 +00:00
* mtime = st . st_mtime ;
return 0 ;
2004-01-14 21:36:10 +00:00
}
/* BPyMenu_Init:
* import the bpython menus data to Blender , either from :
2004-01-23 19:24:45 +00:00
* - the BPYMENU_DATAFILE file ( ? / . blender / Bpymenus ) or
2004-01-20 04:57:47 +00:00
* - the scripts dir ( s ) , case newer than the datafile ( then update the file ) .
2004-01-14 21:36:10 +00:00
* then fill the bpymenu table with this data .
2004-01-20 04:57:47 +00:00
* if param usedir ! = 0 , then the data is recreated from the dir ( s ) anyway .
2004-01-14 21:36:10 +00:00
*/
2004-10-07 19:25:40 +00:00
int BPyMenu_Init ( int usedir )
2004-01-14 21:36:10 +00:00
{
2004-10-07 19:25:40 +00:00
char fname [ FILE_MAXDIR + FILE_MAXFILE ] ;
2004-01-20 04:57:47 +00:00
char dirname [ FILE_MAXDIR ] ;
char * upydir = U . pythondir ;
2004-04-19 10:19:41 +00:00
time_t tdir1 = 0 , tdir2 = 0 , tfile = 0 ;
int res1 = 0 , res2 = 0 , resf = 0 ;
2004-01-20 04:57:47 +00:00
2004-10-07 19:25:40 +00:00
DEBUG = G . f & G_DEBUG ; /* is Blender in debug mode (started with -d) ? */
2004-01-23 19:24:45 +00:00
2004-01-20 04:57:47 +00:00
/* init global bpymenu table (it is a list of pointers to struct BPyMenus
* for each available group : import , export , etc . ) */
2004-10-07 19:25:40 +00:00
for ( res1 = 0 ; res1 < PYMENU_TOTAL ; res1 + + )
2004-01-20 04:57:47 +00:00
BPyMenuTable [ res1 ] = NULL ;
2004-01-14 21:36:10 +00:00
2004-10-07 19:25:40 +00:00
if ( U . pythondir [ 0 ] = = ' \0 ' )
upydir = NULL ;
2004-01-14 21:36:10 +00:00
2004-10-07 19:25:40 +00:00
BLI_make_file_string ( " / " , dirname , bpy_gethome ( ) , " scripts " ) ;
2004-01-20 04:57:47 +00:00
2004-10-07 19:25:40 +00:00
res1 = bpymenu_GetStatMTime ( dirname , 0 , & tdir1 ) ;
2004-01-20 04:57:47 +00:00
2004-10-07 19:25:40 +00:00
if ( res1 < 0 ) {
2004-01-20 04:57:47 +00:00
tdir1 = 0 ;
2004-10-07 19:25:40 +00:00
if ( DEBUG ) {
printf ( " \n Default scripts dir: %s: \n %s \n " , dirname ,
strerror ( errno ) ) ;
if ( upydir )
printf ( " Getting scripts menu data from user defined dir: %s. \n " , upydir ) ;
2004-01-23 19:24:45 +00:00
}
2004-10-07 19:25:40 +00:00
} else {
syspath_append ( dirname ) ;
2004-01-14 21:36:10 +00:00
}
2004-10-07 19:25:40 +00:00
if ( upydir ) {
res2 = bpymenu_GetStatMTime ( U . pythondir , 0 , & tdir2 ) ;
2004-01-20 04:57:47 +00:00
2004-10-07 19:25:40 +00:00
if ( res2 < 0 ) {
2004-01-20 04:57:47 +00:00
tdir2 = 0 ;
2004-10-07 19:25:40 +00:00
if ( DEBUG )
printf ( " \n User defined scripts dir: %s: \n %s. \n " , upydir , strerror ( errno ) ) ;
if ( res1 < 0 ) {
if ( DEBUG )
printf ( " To have scripts in menus, please add them to the " " default scripts dir: %s \n " " and/or go to 'Info window -> File Paths tab' and set a valid \n " " path for the user defined scripts dir. \n " , dirname ) ;
return - 1 ;
2004-01-20 04:57:47 +00:00
}
}
2004-10-07 19:25:40 +00:00
} else
res2 = - 1 ;
2004-01-14 21:36:10 +00:00
2004-10-07 19:25:40 +00:00
if ( ( res1 < 0 ) & & ( res2 < 0 ) ) {
if ( DEBUG ) {
printf ( " \n Cannot register scripts in menus, no scripts dir " " available. \n Expected default dir in %s . \n " , dirname ) ;
2004-01-23 19:24:45 +00:00
}
2004-01-20 04:57:47 +00:00
return - 1 ;
}
2004-01-14 21:36:10 +00:00
2004-10-07 19:25:40 +00:00
if ( DEBUG )
printf ( " \n Registering scripts in Blender menus ... \n \n " ) ;
2004-01-14 21:36:10 +00:00
2004-10-07 19:25:40 +00:00
if ( ! usedir ) { /* if we're not forced to use the dir */
BLI_make_file_string ( " / " , fname , bpy_gethome ( ) ,
BPYMENU_DATAFILE ) ;
resf = bpymenu_GetStatMTime ( fname , 1 , & tfile ) ;
if ( resf < 0 )
tfile = 0 ;
2004-01-16 23:40:14 +00:00
}
2004-01-14 21:36:10 +00:00
/* comparing dates */
2004-10-07 19:25:40 +00:00
if ( ( tfile > tdir1 ) & & ( tfile > tdir2 ) & & ! resf ) { /* file is newer */
resf = bpymenu_CreateFromFile ( ) ; /* -1 if an error occurred */
if ( ! resf & & DEBUG )
printf ( " Getting menu data for scripts from file: %s \n \n " , fname ) ;
} else
resf = - 1 ; /* -1 to use dirs: didn't use file or it was corrupted */
if ( resf = = - 1 ) { /* use dirs */
if ( DEBUG ) {
printf ( " Getting menu data for scripts from dir(s): \n %s \n " , dirname ) ;
if ( upydir )
printf ( " %s \n " , upydir ) ;
2004-01-23 19:24:45 +00:00
}
2004-10-07 19:25:40 +00:00
if ( res1 = = 0 )
bpymenu_CreateFromDir ( dirname , 0 ) ;
if ( res2 = = 0 )
bpymenu_CreateFromDir ( U . pythondir , 1 ) ;
2004-01-16 23:40:14 +00:00
/* check if we got any data */
2004-10-07 19:25:40 +00:00
for ( res1 = 0 ; res1 < PYMENU_TOTAL ; res1 + + )
if ( BPyMenuTable [ res1 ] )
break ;
2004-01-20 04:57:47 +00:00
2004-01-16 23:40:14 +00:00
/* if we got, recreate the file */
2004-10-07 19:25:40 +00:00
if ( res1 < PYMENU_TOTAL )
bpymenu_WriteDataFile ( ) ;
else if ( DEBUG ) {
printf ( " \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: %s \n " , dirname ) ;
if ( upydir )
printf ( " User defined scripts dir is: %s \n " ,
upydir ) ;
2004-01-20 04:57:47 +00:00
}
2004-01-16 23:40:14 +00:00
return 0 ;
2004-01-14 21:36:10 +00:00
}
2004-01-16 23:40:14 +00:00
return 0 ;
2004-01-14 21:36:10 +00:00
}