BPython:
[blender-staging.git] / source / blender / python / BPY_menus.c
1 /* 
2  *
3  * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License
7  * as published by the Free Software Foundation; either version 2
8  * of the License, or (at your option) any later version. The Blender
9  * Foundation also sells licenses for use in proprietary software under
10  * the Blender License.  See http://www.blender.org/BL/ for information
11  * about this.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software Foundation,
20  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
21  *
22  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
23  * All rights reserved.
24  *
25  * This is a new part of Blender.
26  *
27  * Contributor(s): Willian P. Germano
28  *
29  * ***** END GPL/BL DUAL LICENSE BLOCK *****
30 */
31
32 /* This is the main file responsible for having bpython scripts accessible
33  * from Blender menus.  To know more, please start with its header file.
34 */
35
36 #ifdef HAVE_CONFIG_H
37 #include <config.h>
38 #endif
39
40 #include <stdio.h>
41 #include <stdlib.h>
42 #include <string.h>
43 #include <sys/types.h>
44 #include <sys/stat.h>
45 #include <Python.h>
46
47 #ifndef WIN32
48 #include <dirent.h>
49 #else
50 #include "BLI_winstuff.h"
51 #include <io.h>
52 #include <direct.h>
53 #endif 
54
55 #include "BKE_global.h"
56 #include "BKE_utildefines.h"
57 #include "BLI_blenlib.h"
58 #include "MEM_guardedalloc.h"
59
60 #include <DNA_userdef_types.h> /* for U.pythondir */
61
62 #include "BPY_extern.h"
63 #include "BPY_menus.h"
64
65 #include <errno.h>
66
67 #define BPYMENU_DATAFILE "Bpymenus"
68
69 static int DEBUG;
70
71 /* BPyMenuTable holds all registered pymenus, as linked lists for each menu
72  * where they can appear (see PYMENUHOOKS enum in BPY_menus.h).
73 */
74 BPyMenu *BPyMenuTable[PYMENU_TOTAL];
75
76 /* we can't be sure if BLI_gethome() returned a path
77  * with '.blender' appended or not.  Besides, this function now
78  * either returns userhome/.blender (if it exists) or
79  * blenderInstallDir/.blender/ otherwise */
80 char *bpymenu_gethome()
81 {
82         static char homedir[FILE_MAXDIR];
83         char bprogdir[FILE_MAXDIR];
84         char *s;
85         int i;
86
87         if (homedir[0] != '\0') return homedir; /* no need to search twice */
88
89         s = BLI_gethome();
90
91         if (strstr(s, ".blender")) PyOS_snprintf(homedir, FILE_MAXDIR, s);
92         else BLI_make_file_string ("/", homedir, s, ".blender/");
93
94         /* if userhome/.blender/ exists, return it */
95         if (BLI_exists(homedir)) return homedir;
96
97         /* otherwise, use argv[0] (bprogname) to get .blender/ in
98          * Blender's installation dir */
99         s = BLI_last_slash(bprogname);
100
101         i = s - bprogname + 1;
102
103         PyOS_snprintf(bprogdir, i, bprogname);
104         BLI_make_file_string ("/", homedir, bprogdir, ".blender/");
105
106         return homedir;
107 }
108
109 static int bpymenu_group_atoi (char *str)
110 {
111         if (!strcmp(str, "Import")) return PYMENU_IMPORT;
112         else if (!strcmp(str, "Export")) return PYMENU_EXPORT;
113         /* "Misc" or an inexistent group name: use misc */
114         else return PYMENU_MISC;
115 }
116
117 char *BPyMenu_group_itoa (short menugroup)
118 {
119         switch (menugroup) {
120                 case PYMENU_IMPORT:
121                         return "Import";
122                         break;
123                 case PYMENU_EXPORT:
124                         return "Export";
125                         break;
126                 case PYMENU_MISC:
127                         return "Misc";
128                         break;
129         }
130         return NULL;
131 }
132
133 /* BPyMenu_CreatePupmenuStr:
134  * build and return a meaninful string to be used by pupmenu().  The
135  * string is made of a bpymenu name as title and its submenus as possible
136  * choices for the user.
137 */
138 char *BPyMenu_CreatePupmenuStr(BPyMenu *pym, short menugroup)
139 {
140         BPySubMenu *pysm = pym->submenus;
141         char str[1024], str2[100];
142         int i = 0, rlen;
143
144         if (!pym || !pysm) return NULL;
145
146         str[0] = '\0';
147
148         PyOS_snprintf(str2, sizeof(str2), "%s: %s%%t",
149                 BPyMenu_group_itoa(menugroup), pym->name);
150         strcat(str, str2);
151
152         while (pysm) {
153                 PyOS_snprintf(str2, sizeof(str2), "|%s%%x%d", pysm->name, i);
154                 rlen = sizeof(str) - strlen(str);
155                 strncat(str, str2, rlen);
156                 i++;
157                 pysm = pysm->next;
158         }
159
160         return BLI_strdup(str);
161 }
162
163 static void bpymenu_RemoveAllSubEntries (BPySubMenu *smenu)
164 {
165         BPySubMenu *tmp;
166
167         while (smenu) {
168                 tmp = smenu->next;
169                 if (smenu->name) MEM_freeN(smenu->name);
170                 if (smenu->arg)  MEM_freeN(smenu->arg);
171                 MEM_freeN(smenu);
172                 smenu = tmp;
173         }
174         return;
175 }
176
177 void BPyMenu_RemoveAllEntries (void)
178 {
179         BPyMenu *tmp, *pymenu;
180         int i;
181
182         for (i = 0; i < PYMENU_TOTAL; i++) {
183                 pymenu = BPyMenuTable[i];
184                 while (pymenu) {
185                         tmp = pymenu->next;
186                         if (pymenu->name) MEM_freeN(pymenu->name);
187                         if (pymenu->filename) MEM_freeN(pymenu->filename);
188                         if (pymenu->tooltip) MEM_freeN(pymenu->tooltip);
189                         if (pymenu->submenus) bpymenu_RemoveAllSubEntries(pymenu->submenus);
190                         MEM_freeN(pymenu);
191                         pymenu = tmp;
192                 }
193                 BPyMenuTable[i] = NULL;
194         }
195         return;
196 }
197
198 static BPyMenu *bpymenu_FindEntry (short group, char *name)
199 {
200         BPyMenu *pymenu;
201
202         if ((group <0) || (group >= PYMENU_TOTAL)) return NULL;
203
204         pymenu = BPyMenuTable[group];
205
206         while (pymenu) {
207                 if (!strcmp(pymenu->name, name)) return pymenu;
208                 pymenu = pymenu->next;
209         }
210
211         return NULL;
212 }
213
214 /* BPyMenu_GetEntry:
215  * given a group and a position, return the entry in that position from
216  * that group.
217 */ 
218 BPyMenu *BPyMenu_GetEntry (short group, short pos)
219 {
220         BPyMenu *pym = NULL;
221
222         if ((group < 0) || (group >= PYMENU_TOTAL)) return NULL;
223
224         pym = BPyMenuTable[group];
225
226         while (pos--) {
227                 if (pym) pym = pym->next;
228                 else break;
229         }
230
231         return pym; /* found entry or NULL */
232 }
233         
234 static void bpymenu_set_tooltip (BPyMenu *pymenu, char *tip)
235 {
236         if (!pymenu) return;
237
238         if (pymenu->tooltip) MEM_freeN(pymenu->tooltip);
239         pymenu->tooltip = BLI_strdup(tip);
240
241         return;
242 }
243
244 /* bpymenu_AddEntry:
245  * try to find an existing pymenu entry with the given type and name;
246  * if found, update it with new info, otherwise create a new one and fill it.
247  */
248 static BPyMenu *bpymenu_AddEntry (short group, short version, char *name,
249         char *fname, int whichdir, char *tooltip)
250 {
251         BPyMenu *menu, *next = NULL, **iter;
252         int nameclash = 0;
253
254         if ((group < 0) || (group >= PYMENU_TOTAL)) return NULL;
255         if (!name || !fname) return NULL;
256
257         menu = bpymenu_FindEntry (group, name); /* already exists? */
258
259         /* if a menu with this name already exists in the same group:
260          * - if one script is in the default dir and the other in U.pythondir,
261          *   accept and let the new one override the other.
262          * - otherwise, report the error and return NULL. */
263         if (menu) {
264                 if (menu->dir < whichdir) { /* new one is in U.pythondir */
265                         nameclash = 1;
266                         if (menu->name) MEM_freeN(menu->name);
267                         if (menu->filename) MEM_freeN(menu->filename);
268                         if (menu->tooltip) MEM_freeN(menu->tooltip);
269                         if (menu->submenus) bpymenu_RemoveAllSubEntries(menu->submenus);
270                         next = menu->next;
271                 }
272                 else { /* they are in the same dir */
273                         if (DEBUG) {
274                                 printf("\nWarning: script %s's menu name is already in use.\n", fname);
275                                 printf ("Edit the script and change its Name: '%s' field, please.\n"
276                                                         "Note: if you really want two scripts in the same menu with\n"
277                                                         "the same name, keep one in the default dir and the other in\n"
278                                                         "the user defined dir, where it will take precedence.\n", name);
279                         }
280                         return NULL;
281                 }
282         }
283         else menu = MEM_mallocN(sizeof(BPyMenu), "pymenu");
284
285         if (!menu) return NULL;
286
287         menu->name = BLI_strdup(name);
288         menu->version = version;
289         menu->filename = BLI_strdup(fname);
290         menu->tooltip = NULL;
291         if (tooltip) menu->tooltip = BLI_strdup(tooltip);
292         menu->dir = whichdir;
293         menu->submenus = NULL;
294         menu->next = next; /* non-NULL if menu already existed */
295
296         if (nameclash) return menu; /* no need to place it, it's already at the list*/
297
298         iter = &BPyMenuTable[group];
299         while (*iter) iter = &((*iter)->next);
300
301         *iter = menu;
302         
303         return menu;
304 }
305
306 /* bpymenu_AddSubEntry:
307  * add a submenu to an existing python menu.
308  */
309 static int bpymenu_AddSubEntry (BPyMenu *mentry, char *name, char *arg)
310 {
311         BPySubMenu *smenu, **iter;
312
313         smenu = MEM_mallocN(sizeof(BPySubMenu), "pysubmenu");
314         if (!smenu) return -1;
315
316         smenu->name = BLI_strdup(name);
317         smenu->arg = BLI_strdup(arg);
318         smenu->next = NULL;
319
320         if (!smenu->name || !smenu->arg) return -1;
321
322         iter = &(mentry->submenus);
323         while (*iter) iter = &((*iter)->next);
324
325         *iter = smenu;
326
327         return 0;
328 }
329
330 /* bpymenu_CreateFromFile:
331  * parse the bpymenus data file where Python menu data is stored;
332  * based on this data, create and fill the pymenu structs.
333  */
334 static int bpymenu_CreateFromFile (void)
335 {
336         FILE *fp;
337         char line[255], w1[255], w2[255], tooltip[255], *tip;
338         int parsing, version, whichdir;
339         short group;
340         BPyMenu *pymenu = NULL;
341
342         /* init global bpymenu table (it is a list of pointers to struct BPyMenus
343          * for each available cathegory: import, export, etc.) */
344         for (group = 0; group < PYMENU_TOTAL; group++)
345                 BPyMenuTable[group] = NULL;
346
347         /* let's try to open the file with bpymenu data */
348         BLI_make_file_string ("/", line, bpymenu_gethome(), BPYMENU_DATAFILE);
349
350         fp = fopen(line, "rb");
351
352         if (!fp) {
353                 if (DEBUG) printf("BPyMenus error: couldn't open config file %s.\n", line);
354                 return -1;
355         }
356
357         fgets(line, 255, fp); /* header */
358
359         /* check if the U.pythondir we saved at the file is different from the
360          * current one.  If so, return to force updating from dirs */
361         w1[0] = '\0';
362         fscanf(fp, "# User defined scripts dir: %[^\n]\n", w1);
363         if (w1) {
364                 if (strcmp(w1, U.pythondir) != 0) return -1;
365                 w1[0] = '\0';
366         }
367
368         while (fgets(line, 255, fp)) { /* parsing file lines */
369
370                 switch (line[0]) { /* check first char */
371                         case '#': /* comment */
372                                 continue;
373                                 break;
374                         case '\n':
375                                 continue;
376                                 break;
377                         default:
378                                 parsing = sscanf(line, "%s {\n", w1); /* menu group */
379                                 break;
380                 }
381
382                 if (parsing == 1) { /* got menu group string */
383                         group = bpymenu_group_atoi(w1);
384                         if (group < 0 && DEBUG) { /* invalid type */
385                                 printf("BPyMenus error parsing config file: wrong group: %s, "
386                                         "will use 'Misc'.\n", w1);
387                         }
388                 }
389                 else continue;
390
391                 while (1) {
392                         tip = NULL; /* optional tooltip */
393                         fgets(line, 255, fp);
394                         if (line[0] == '}') break;
395                         else if (line[0] == '\n') continue;
396                         else if (line[0] == '\'') { /* menu entry */
397                                 parsing = sscanf(line, "'%[^']' %d %s %d '%[^']'\n", w1, &version, w2, &whichdir, tooltip);
398
399                                 if (parsing <= 0) { /* invalid line, get rid of it */
400                                         fgets(line, 255, fp);
401                                 }
402                                 else if (parsing == 5) tip = tooltip; /* has tooltip */
403
404                                 pymenu = bpymenu_AddEntry(group, (short)version, w1, w2, whichdir, tip);
405                                 if (!pymenu) {
406                                         puts("BPyMenus error: couldn't create bpymenu entry.\n");
407                                         fclose(fp);
408                                         return -1;
409                                 }
410                         }
411                         else if (line[0] == '|' && line[1] == '_') { /* menu sub-entry */
412                                 if (!pymenu) continue; /* no menu yet, skip this line */
413                                 sscanf(line, "|_%[^:]: %s\n", w1, w2);
414                                 bpymenu_AddSubEntry(pymenu, w1, w2);
415                         }
416                 }
417         }
418
419         fclose(fp);
420         return 0;
421 }
422
423 /* bpymenu_WriteDataFile:
424  * writes the registered scripts info to the user's home dir, for faster
425  * access when the scripts dir hasn't changed.
426 */
427 static void bpymenu_WriteDataFile(void)
428 {
429         BPyMenu *pymenu;
430         BPySubMenu *smenu;
431         FILE *fp;
432         char fname[FILE_MAXDIR+FILE_MAXFILE];
433         int i;
434
435         BLI_make_file_string("/", fname, bpymenu_gethome(), BPYMENU_DATAFILE);
436
437         fp = fopen(fname, "w");
438         if (!fp) {
439                 if (DEBUG) printf("BPyMenus error: couldn't write %s file.", fname);
440                 return;
441         }
442
443         fprintf(fp, "# Blender: registered menu entries for bpython scripts\n");
444
445         if (U.pythondir[0] != '\0')
446                 fprintf(fp, "# User defined scripts dir: %s\n", U.pythondir);
447
448         for (i = 0; i < PYMENU_TOTAL; i++) {
449                 pymenu = BPyMenuTable[i];
450                 if (!pymenu) continue;
451                 fprintf(fp, "\n%s {\n", BPyMenu_group_itoa(i));
452                 while (pymenu) {
453                         fprintf(fp,"'%s' %d %s %d", pymenu->name, pymenu->version, pymenu->filename, pymenu->dir);
454                         if (pymenu->tooltip) fprintf(fp, " '%s'\n", pymenu->tooltip);
455                         else fprintf(fp, "\n");
456                         smenu = pymenu->submenus;
457                         while (smenu) {
458                                 fprintf(fp, "|_%s: %s\n", smenu->name, smenu->arg);
459                                 smenu = smenu->next;
460                         }
461                         pymenu = pymenu->next;
462                 }
463                 fprintf(fp, "}\n");
464         }
465
466         fclose(fp);
467         return;
468 }
469
470 /* BPyMenu_PrintAllEntries:
471  * useful for debugging.
472 */
473 void BPyMenu_PrintAllEntries(void)
474 {
475         BPyMenu *pymenu;
476         BPySubMenu *smenu;
477         int i;
478
479         printf("# Blender: registered menu entries for bpython scripts\n");
480
481         for (i = 0; i < PYMENU_TOTAL; i++) {
482                 pymenu = BPyMenuTable[i];
483                 printf("\n%s {\n", BPyMenu_group_itoa(i));
484                 while (pymenu) {
485                         printf("'%s' %d %s %d", pymenu->name, pymenu->version, pymenu->filename, pymenu->dir);
486                         if (pymenu->tooltip) printf(" '%s'\n", pymenu->tooltip);
487                         else printf("\n");
488                         smenu = pymenu->submenus;
489                         while (smenu) {
490                                 printf("|_%s: %s\n", smenu->name, smenu->arg);
491                                 smenu = smenu->next;
492                         }
493                         pymenu = pymenu->next;
494                 }
495                 printf("}\n");
496         }
497 }
498
499 /* bpymenu_GetDataFromDir:
500  * this function scans the scripts dir looking for .py files with the
501  * right header and menu info, using that to fill the bpymenu structs.
502  * whichdir defines if the script is in the default scripts dir or the
503  * user defined one (U.pythondir: whichdir == 1).
504  * Speed is important.
505 */
506 static int bpymenu_CreateFromDir (char *dirname, int whichdir)
507 {
508         DIR *dir;
509         FILE *fp;
510         struct stat st;
511         struct dirent *dir_entry;
512         BPyMenu *pymenu;
513         char *s, *fname, str[FILE_MAXFILE+FILE_MAXDIR];
514         char line[100], w[100];
515         char name[100], submenu[100], subarg[100], tooltip[100];
516         int res = 0, version = 0;
517
518         dir = opendir(dirname);
519
520         if (!dir) return -1;
521
522 /* we scan the dir for filenames ending with .py and starting with the
523  * right 'magic number': '#!BPY'.  All others are ignored. */
524
525         while ((dir_entry = readdir(dir)) != NULL) {
526                 fname = dir_entry->d_name;
527                 /* ignore anything starting with a dot */
528                 if (fname[0] == '.') continue; /* like . and .. */
529
530                 /* also skip filenames whose extension isn't '.py' */
531                 s = strstr(fname, ".py");
532                 if (!s || *(s+3) != '\0') continue;
533
534                 BLI_make_file_string("/", str, dirname, fname);
535
536                 /* paranoia: check if this is really a file and not a disguised dir */
537                 if ((stat(str, &st) == -1) || !S_ISREG(st.st_mode)) continue;
538
539                 fp = fopen(str, "rb");
540
541                 if (!fp) {
542                         if (DEBUG) printf("BPyMenus error: couldn't open %s.\n", str);
543                         continue;
544                 }
545
546                 /* finally, look for the start string '#!BPY', with
547                  * or w/o white space(s) between #! and BPY */
548                 fgets(line, 100, fp);
549                 if (line[0] != '#' || line[1] != '!') goto discard;
550
551                 if (!strstr (line, "BPY")) goto discard;
552
553                 /* file passed the tests, look for the three double-quotes */
554                 while (fgets(line, 100, fp)) {
555                         if (line[0] == '"' && line[1] == '"' && line[2] == '"') {
556                                 res = 1; /* found */
557                                 break;
558                         }
559                 }
560
561                 if (!res) goto discard;
562
563                 /* Now we're ready to get the registration info.  A little more structure
564                  * was imposed to their format, for speed. The registration
565                  * lines must appear between the first pair of triple double-quotes and
566                  * follow this order (the single-quotes are part of the format):
567                  * 
568                  * Name: 'script name for the menu'
569                  * Group: 'group name' (defines menu)
570                  * Blender: <short int> (minimal Blender version)
571                  * Submenu: 'submenu name' related_1word_arg
572                  * Tooltip: 'tooltip for the menu'
573                  *
574                  * notes:
575                  * - there may be more than one submenu line, or none:
576                  * submenus and the tooltip are optional;
577                  * - the Blender version is the same number reported by
578                  * Blender.Get('version') in BPython or G.version in C;
579                  * - only the first letter of each token is checked, both lower
580                  * and upper cases, so that's all that matters for recognition:
581                  * n 'script name' is enough for the name line, for example. */ 
582
583                 /* first the name: */
584                 res = fscanf(fp, "%[^']'%[^'\r\n]'\n", w, name);
585                 if ((res != 2) || (w[0] != 'n' && w[0] != 'N')) {
586                         if (DEBUG) printf("BPyMenus error: wrong 'name' line in %s.\n", str);
587                         goto discard;
588                 }
589
590                 line[0] = '\0'; /* used as group for this part */
591
592                 /* minimal Blender version: */
593                 res = fscanf(fp, "%s %d\n", w, &version);
594                 if ((res != 2) || (w[0] != 'b' && w[0] != 'B')) {
595                         if (DEBUG) printf("BPyMenus error: wrong 'blender' line in %s.\n", str);
596                         goto discard;
597                 }
598
599                 /* the group: */
600                 res = fscanf(fp, "%[^']'%[^'\r\n]'\n", w, line);
601                 if ((res != 2) || (w[0] != 'g' && w[0] != 'G')) {
602                         if (DEBUG) printf("BPyMenus error: wrong 'group' line in %s.\n", str);
603                         goto discard;
604                 }
605
606                 res = bpymenu_group_atoi(line);
607                 if (res < 0) {
608                         if (DEBUG) printf("BPyMenus error: unknown 'group' %s in %s.\n", line, str);
609                         goto discard;
610                 }
611
612                 pymenu = bpymenu_AddEntry(res, (short)version, name, fname, whichdir, NULL);
613                 if (!pymenu) {
614                         if (DEBUG) printf("BPyMenus error: couldn't create entry for %s.\n", str);
615                         fclose(fp);
616                         closedir(dir);
617                         return -2;
618                 }
619
620                 /* the (optional) submenu(s): */
621                 while (fgets (line, 100, fp)) {
622                         res = sscanf(line, "%[^']'%[^'\r\n]'%s\n", w, submenu, subarg);
623                         if ((res != 3) || (w[0] != 's' && w[0] != 'S')) break;
624                         bpymenu_AddSubEntry(pymenu, submenu, subarg); 
625                 }       
626
627                 /* the (optional) tooltip: */
628                 res = sscanf(line, "%[^']'%[^'\r\n]'\n", w, tooltip);
629                 if ((res == 2) && (w[0] == 't' || w[0] == 'T')) {
630                         bpymenu_set_tooltip (pymenu, tooltip);
631                 }
632
633 discard:
634                 fclose (fp);
635                 continue;
636         }
637
638         closedir(dir);
639         return 0;
640 }
641
642 static int bpymenu_GetStatMTime(char *name, int is_file, time_t* mtime)
643 {
644         struct stat st;
645         int result;
646
647         result = stat(name, &st);
648
649         if (result == -1) return -1;
650
651         if (is_file) { if (!S_ISREG(st.st_mode)) return -2;     }
652         else if (!S_ISDIR(st.st_mode)) return -2;
653
654         *mtime = st.st_mtime;
655
656         return 0;
657 }
658
659 /* BPyMenu_Init:
660  * import the bpython menus data to Blender, either from:
661  * - the BPYMENU_DATAFILE file (?/.blender/Bpymenus) or
662  * - the scripts dir(s), case newer than the datafile (then update the file).
663  * then fill the bpymenu table with this data.
664  * if param usedir != 0, then the data is recreated from the dir(s) anyway.
665 */
666 int BPyMenu_Init(int usedir)
667 {
668         char fname[FILE_MAXDIR+FILE_MAXFILE];
669         char dirname[FILE_MAXDIR];
670         char *upydir = U.pythondir;
671         time_t tdir1, tdir2, tfile;
672         int res1, res2, resf = 0;
673
674         DEBUG = G.f & G_DEBUG; /* is Blender in debug mode (started with -d) ? */
675
676         /* init global bpymenu table (it is a list of pointers to struct BPyMenus
677          * for each available group: import, export, etc.) */
678         for (res1 = 0; res1 < PYMENU_TOTAL; res1++)
679                 BPyMenuTable[res1] = NULL;
680
681         if (U.pythondir[0] == '\0') upydir = NULL;
682
683         BLI_make_file_string ("/", dirname, bpymenu_gethome(), "scripts/");
684
685         res1 = bpymenu_GetStatMTime(dirname, 0, &tdir1);
686
687         if (res1 < 0) {
688                 tdir1 = 0;
689                 if (DEBUG) {
690                         printf ("\nDefault scripts dir: %s:\n%s\n", dirname, strerror(errno));
691                         if (upydir)
692                                 printf("Getting scripts menu data from user defined dir: %s.\n",upydir);
693                 }
694         }
695         else { syspath_append(dirname); }
696
697         if (upydir) {
698                 res2 = bpymenu_GetStatMTime(U.pythondir, 0, &tdir2);
699
700                 if (res2 < 0) {
701                         tdir2 = 0;
702                         if (DEBUG) printf("\nUser defined scripts dir: %s:\n%s.\n", upydir, strerror(errno));
703                         if (res1 < 0) {
704                         if (DEBUG) printf ("To have scripts in menus, please add them to the"
705                                                         "default scripts dir: %s\n"
706                                                         "and/or go to 'Info window -> File Paths tab' and set a valid\n"
707                                                         "path for the user defined scripts dir.\n", dirname);
708                         return -1;
709                         }
710                 }
711         }
712         else res2 = -1;
713
714         if ((res1 < 0) && (res2 < 0)) {
715                 if (DEBUG) {
716                         printf ("\nCannot register scripts in menus, no scripts dir"
717                                                         " available.\nExpected default dir in %s .\n", dirname);
718                 }
719                 return -1;
720         }
721
722         if (DEBUG) printf("\nRegistering scripts in Blender menus ...\n\n");
723
724         if (!usedir) { /* if we're not forced to use the dir */
725                 BLI_make_file_string("/", fname, bpymenu_gethome(), BPYMENU_DATAFILE);
726                 resf = bpymenu_GetStatMTime(fname, 1, &tfile);
727                 if (resf < 0) tfile = 0;
728         }
729
730         /* comparing dates */
731
732         if ((tfile > tdir1) && (tfile > tdir2) && !resf) { /* file is newer */
733                 resf = bpymenu_CreateFromFile(); /* -1 if an error occurred */
734                 if (!resf && DEBUG)
735                         printf("Getting menu data for scripts from file: %s\n\n", fname);
736         }
737         else resf = -1; /* -1 to use dirs: didn't use file or it was corrupted */
738
739         if (resf == -1) { /* use dirs */
740                 if (DEBUG) {
741                         printf("Getting menu data for scripts from dir(s):\n%s\n", dirname);
742                         if (upydir) printf("%s\n", upydir);
743                 }
744                 if (res1 == 0) bpymenu_CreateFromDir(dirname, 0);
745                 if (res2 == 0) bpymenu_CreateFromDir(U.pythondir, 1);
746
747                 /* check if we got any data */
748                 for (res1 = 0; res1 < PYMENU_TOTAL; res1++)
749                         if (BPyMenuTable[res1]) break;
750
751                 /* if we got, recreate the file */
752                 if (res1 < PYMENU_TOTAL) bpymenu_WriteDataFile();
753                 else if (DEBUG) {
754                         printf ("\nWarning: Registering scripts in menus -- no info found.\n"
755                                                         "Either your scripts dirs have no .py scripts or the scripts\n"
756                                                         "don't have a header with registration data.\n"
757                                                         "Default scripts dir is: %s\n", dirname);
758                         if (upydir)
759                                 printf("User defined scripts dir is: %s\n", upydir);
760                 }
761
762                 return 0;
763         }
764
765         return 0;
766 }