baae2220143d28762e2fc8aace387f197b01ef13
[blender-staging.git] / source / blender / python / api2_2x / Sys.c
1 /* 
2  * $Id$
3  *
4  * ***** BEGIN GPL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 59 Temple Place - Suite 330, Boston, MA        02111-1307, USA.
19  *
20  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
21  * All rights reserved.
22  *
23  * This is a new part of Blender.
24  *
25  * Contributor(s): Willian P. Germano, Campbell Barton
26  *
27  * ***** END GPL LICENSE BLOCK *****
28 */
29
30 #include "Sys.h" /*This must come first*/
31
32 #include "BKE_utildefines.h"
33 #include "BKE_global.h"
34 #include "BLI_blenlib.h"
35 #include "DNA_scene_types.h" /* G.scene-"r.cfra */
36 #include "PIL_time.h"
37 #include "gen_utils.h"
38
39 #ifdef WIN32
40 #define DIRSEP '\\'
41 #define DIRSEP_STR "\\"
42 #else
43 #define DIRSEP '/'
44 #define DIRSEP_STR "/"
45 #endif
46
47
48 /*****************************************************************************/
49 /* Python API function prototypes for the sys module.                        */
50 /*****************************************************************************/
51 static PyObject *M_sys_basename( PyObject * self, PyObject * value );
52 static PyObject *M_sys_dirname( PyObject * self, PyObject * value );
53 static PyObject *M_sys_join( PyObject * self, PyObject * args );
54 static PyObject *M_sys_splitext( PyObject * self, PyObject * value );
55 static PyObject *M_sys_makename( PyObject * self, PyObject * args,
56         PyObject * kw );
57 static PyObject *M_sys_exists( PyObject * self, PyObject * value );
58 static PyObject *M_sys_time( PyObject * self );
59 static PyObject *M_sys_sleep( PyObject * self, PyObject * args );
60 static PyObject *M_sys_expandpath( PyObject *self, PyObject *value);
61 static PyObject *M_sys_cleanpath( PyObject *self, PyObject *value);
62
63 /*****************************************************************************/
64 /* The following string definitions are used for documentation strings.      */
65 /* In Python these will be written to the console when doing a               */
66 /* Blender.sys.__doc__                                                       */
67 /*****************************************************************************/
68 static char M_sys_doc[] = "The Blender.sys submodule\n\
69 \n\
70 This is a minimal system module to supply simple functionality available\n\
71 in the default Python module os.";
72
73 static char M_sys_basename_doc[] =
74         "(path) - Split 'path' in dir and filename.\n\
75 Return the filename.";
76
77 static char M_sys_dirname_doc[] =
78         "(path) - Split 'path' in dir and filename.\n\
79 Return the dir.";
80
81 static char M_sys_join_doc[] =
82         "(dir, file) - Join dir and file to form a full filename.\n\
83 Return the filename.";
84
85 static char M_sys_splitext_doc[] =
86         "(path) - Split 'path' in root and extension:\n\
87 /this/that/file.ext -> ('/this/that/file','.ext').\n\
88 Return the pair (root, extension).";
89
90 static char M_sys_makename_doc[] =
91         "(path = Blender.Get('filename'), ext = \"\", strip = 0) -\n\
92 Strip dir and extension from path, leaving only a name, then append 'ext'\n\
93 to it (if given) and return the resulting string.\n\n\
94 (path) - string: a pathname -- Blender.Get('filename') if 'path' isn't given;\n\
95 (ext = \"\") - string: the extension to append.\n\
96 (strip = 0) - int: strip dirname from 'path' if given and non-zero.\n\
97 Ex: makename('/path/to/file/myfile.foo','-01.abc') returns 'myfile-01.abc'\n\
98 Ex: makename(ext='.txt') returns 'untitled.txt' if Blender.Get('filename')\n\
99 returns a path to the file 'untitled.blend'";
100
101 static char M_sys_time_doc[] =
102         "() - Return a float representing time elapsed in seconds.\n\
103 Each successive call is garanteed to return values greater than or\n\
104 equal to the previous call.";
105
106 static char M_sys_sleep_doc[] =
107         "(milliseconds = 10) - Sleep for the specified time.\n\
108 (milliseconds = 10) - the amount of time in milliseconds to sleep.\n\
109 This function can be necessary in tight 'get event' loops.";
110
111 static char M_sys_exists_doc[] =
112         "(path) - Check if the given pathname exists.\n\
113 The return value is as follows:\n\
114 \t 0: path doesn't exist;\n\
115 \t 1: path is an existing filename;\n\
116 \t 2: path is an existing dirname;\n\
117 \t-1: path exists but is neither a regular file nor a dir.";
118
119 static char M_sys_expandpath_doc[] =
120 "(path) - Expand this Blender internal path to a proper file system path.\n\
121 (path) - the string path to convert.\n\n\
122 Note: internally Blender paths can contain two special character sequences:\n\
123 - '//' (at start) for base path directory (the current .blend's dir path);\n\
124 - '#' characters in the filename will be replaced by the frame number.\n\n\
125 This function expands these to their actual content, returning a valid path.\n\
126 If the special chars are not found in the given path, it is simply returned.";
127
128 static char M_sys_cleanpath_doc[] =
129 "(path) - Removes parts of a path that are not needed paths such as '../foo/../bar/' and '//./././'";
130
131 /*****************************************************************************/
132 /* Python method structure definition for Blender.sys module:                */
133 /*****************************************************************************/
134 struct PyMethodDef M_sys_methods[] = {
135         {"basename", M_sys_basename, METH_O, M_sys_basename_doc},
136         {"dirname", M_sys_dirname, METH_O, M_sys_dirname_doc},
137         {"join", M_sys_join, METH_VARARGS, M_sys_join_doc},
138         {"splitext", M_sys_splitext, METH_O, M_sys_splitext_doc},
139         {"makename", ( PyCFunction ) M_sys_makename,
140          METH_VARARGS | METH_KEYWORDS,
141          M_sys_makename_doc},
142         {"exists", M_sys_exists, METH_O, M_sys_exists_doc},
143         {"sleep", M_sys_sleep, METH_VARARGS, M_sys_sleep_doc},
144         {"time", ( PyCFunction ) M_sys_time, METH_NOARGS, M_sys_time_doc},
145         {"expandpath", M_sys_expandpath, METH_O, M_sys_expandpath_doc},
146         {"cleanpath", M_sys_cleanpath, METH_O, M_sys_cleanpath_doc},
147         {NULL, NULL, 0, NULL}
148 };
149
150 /* Module Functions */
151
152 static PyObject *g_sysmodule = NULL;    /* pointer to Blender.sys module */
153
154 PyObject *sys_Init( void )
155 {
156         PyObject *submodule, *dict;
157
158         submodule = Py_InitModule3( "Blender.sys", M_sys_methods, M_sys_doc );
159
160         g_sysmodule = submodule;
161
162         dict = PyModule_GetDict( submodule );
163         
164         EXPP_dict_set_item_str( dict, "dirsep", PyString_FromString(DIRSEP_STR) );
165         EXPP_dict_set_item_str( dict, "sep", PyString_FromString(DIRSEP_STR) );
166
167         return submodule;
168 }
169
170 static PyObject *M_sys_basename( PyObject * self, PyObject * value )
171 {
172         char *name = PyString_AsString(value);
173         char *p, basename[FILE_MAXDIR + FILE_MAXFILE];
174         int n, len;
175
176         if( !name )
177                 return EXPP_ReturnPyObjError( PyExc_TypeError,
178                                               "expected string argument" );
179
180         len = strlen( name );
181         
182 #ifdef WIN32
183         p = MAX2(strrchr( name, '/' ), strrchr( name, '\\' ));
184 #else
185         p = strrchr( name, DIRSEP );
186 #endif
187
188         if( p ) {
189                 n = name + len - p - 1; /* - 1 because we don't want the sep */
190
191                 if( n > FILE_MAXDIR + FILE_MAXFILE )
192                         return EXPP_ReturnPyObjError( PyExc_RuntimeError,
193                                                       "path too long" );
194
195                 BLI_strncpy( basename, p + 1, n + 1 );
196                 return PyString_FromString( basename );
197         }
198
199         return PyString_FromString( name );
200 }
201
202 static PyObject *M_sys_dirname( PyObject * self, PyObject * value )
203 {
204         char *name = PyString_AsString(value);
205         char *p, dirname[FILE_MAXDIR + FILE_MAXFILE];
206         int n;
207
208         if( !name )
209                 return EXPP_ReturnPyObjError( PyExc_TypeError,
210                                               "expected string argument" );
211
212 #ifdef WIN32
213         p = MAX2(strrchr( name, '/' ), strrchr( name, '\\' ));
214 #else
215         p = strrchr( name, DIRSEP );
216 #endif
217
218         if( p ) {
219                 n = p - name;
220
221                 if( n > FILE_MAXDIR + FILE_MAXFILE )
222                         return EXPP_ReturnPyObjError( PyExc_RuntimeError,
223                                                       "path too long" );
224
225                 BLI_strncpy( dirname, name, n + 1 );
226                 return PyString_FromString( dirname );
227         }
228
229         return PyString_FromString( "." );
230 }
231
232 static PyObject *M_sys_join( PyObject * self, PyObject * args )
233 {
234         char *name = NULL, *path = NULL;
235         char filename[FILE_MAXDIR + FILE_MAXFILE];
236         int pathlen = 0, namelen = 0;
237
238         if( !PyArg_ParseTuple( args, "ss", &path, &name ) )
239                 return EXPP_ReturnPyObjError( PyExc_TypeError,
240                                               "expected string argument" );
241
242         pathlen = strlen( path ) + 1;
243         namelen = strlen( name ) + 1;   /* + 1 to account for '\0' for BLI_strncpy */
244
245         if( pathlen + namelen > FILE_MAXDIR + FILE_MAXFILE - 1 )
246                 return EXPP_ReturnPyObjError( PyExc_RuntimeError,
247                                               "filename is too long." );
248
249         BLI_strncpy( filename, path, pathlen );
250
251         if( filename[pathlen - 2] != DIRSEP ) {
252                 filename[pathlen - 1] = DIRSEP;
253                 pathlen += 1;
254         }
255
256         BLI_strncpy( filename + pathlen - 1, name, namelen );
257
258         return PyString_FromString( filename );
259 }
260
261 static PyObject *M_sys_splitext( PyObject * self, PyObject * value )
262 {
263         char *name = PyString_AsString(value);
264         char *dot, *p, path[FILE_MAXDIR + FILE_MAXFILE], ext[FILE_MAXDIR + FILE_MAXFILE];
265         int n, len;
266
267         if( !name )
268                 return EXPP_ReturnPyObjError( PyExc_TypeError,
269                                               "expected string argument" );
270
271         len = strlen( name );
272         dot = strrchr( name, '.' );
273
274         if( !dot )
275                 return Py_BuildValue( "ss", name, "" );
276
277         p = strrchr( name, DIRSEP );
278
279         if( p ) {
280                 if( p > dot )
281                         return Py_BuildValue( "ss", name, "" );
282         }
283
284         n = name + len - dot;
285
286         /* loong extensions are supported -- foolish, but Python's os.path.splitext
287          * supports them, so ... */
288          
289         if( n >= FILE_MAXDIR + FILE_MAXFILE || ( len - n ) >= FILE_MAXDIR + FILE_MAXFILE )
290                 return EXPP_ReturnPyObjError( PyExc_RuntimeError, "path too long" );
291
292         BLI_strncpy( ext, dot, n + 1 );
293         BLI_strncpy( path, name, dot - name + 1 );
294
295         return Py_BuildValue( "ss", path, ext );
296 }
297
298 static PyObject *M_sys_makename( PyObject * self, PyObject * args,
299                                  PyObject * kw )
300 {
301         char *path = G.sce, *ext = NULL;
302         int strip = 0;
303         static char *kwlist[] = { "path", "ext", "strip", NULL };
304         char *dot = NULL, *p = NULL, basename[FILE_MAXDIR + FILE_MAXFILE];
305         int n, len, lenext = 0;
306
307         if( !PyArg_ParseTupleAndKeywords( args, kw, "|ssi", kwlist,
308                                           &path, &ext, &strip ) )
309                 return EXPP_ReturnPyObjError( PyExc_TypeError,
310                                               "expected one or two strings and an int (or nothing) as arguments" );
311
312         len = strlen( path ) + 1;       /* + 1 to consider ending '\0' */
313         if( ext )
314                 lenext = strlen( ext ) + 1;
315
316         if( ( len + lenext ) > FILE_MAXDIR + FILE_MAXFILE )
317                 return EXPP_ReturnPyObjError( PyExc_RuntimeError,
318                                               "path too long" );
319
320         p = strrchr( path, DIRSEP );
321
322         if( p && strip ) {
323                 n = path + len - p;
324                 BLI_strncpy( basename, p + 1, n );      /* + 1 to skip the sep */
325         } else
326                 BLI_strncpy( basename, path, len );
327
328         dot = strrchr( basename, '.' );
329
330         /* now the extension: always remove the one in basename */
331         if( dot || ext ) {
332                 if( !ext )
333                         basename[dot - basename] = '\0';
334                 else {          /* if user gave an ext, append it */
335
336                         if( dot )
337                                 n = dot - basename;
338                         else
339                                 n = strlen( basename );
340
341                         BLI_strncpy( basename + n, ext, lenext );
342                 }
343         }
344
345         return PyString_FromString( basename );
346 }
347
348 static PyObject *M_sys_time( PyObject * self )
349 {       
350         return PyFloat_FromDouble( PIL_check_seconds_timer(  ) );
351 }
352
353 static PyObject *M_sys_sleep( PyObject * self, PyObject * args )
354 {
355         int millisecs = 10;
356
357         if( !PyArg_ParseTuple( args, "|i", &millisecs ) )
358                 return EXPP_ReturnPyObjError( PyExc_TypeError,
359                                               "expected int argument" );
360
361         PIL_sleep_ms( millisecs );
362
363         return EXPP_incr_ret( Py_None );
364 }
365
366 static PyObject *M_sys_exists( PyObject * self, PyObject * value )
367 {
368         char *fname = PyString_AsString(value);
369         
370         int mode = 0, i = -1;
371
372         if( !fname )
373                 return EXPP_ReturnPyObjError( PyExc_TypeError,
374                                               "expected string (pathname) argument" );
375
376         mode = BLI_exist(fname);
377         
378         if( mode == 0 )
379                 i = 0;
380         else if( S_ISREG( mode ) )
381                 i = 1;
382         else if( S_ISDIR( mode ) )
383                 i = 2;
384         /* i stays as -1 if path exists but is neither a regular file nor a dir */
385         
386         return PyInt_FromLong(i);
387 }
388
389 static PyObject *M_sys_expandpath( PyObject * self, PyObject * value )
390 {
391         char *path = PyString_AsString(value);
392         char expanded[FILE_MAXDIR + FILE_MAXFILE];
393
394         if (!path)
395                 return EXPP_ReturnPyObjError( PyExc_TypeError,
396                         "expected string argument" );
397         
398         BLI_strncpy(expanded, path, FILE_MAXDIR + FILE_MAXFILE);
399         BLI_convertstringcode(expanded, G.sce);
400         BLI_convertstringframe(expanded, G.scene->r.cfra);
401
402         return PyString_FromString(expanded);
403 }
404
405 static PyObject *M_sys_cleanpath( PyObject * self, PyObject * value )
406 {
407         char *path = PyString_AsString(value);
408         char cleaned[FILE_MAXDIR + FILE_MAXFILE];
409         int trailing_slash = 0, last;
410         if (!path)
411                 return EXPP_ReturnPyObjError( PyExc_TypeError,
412                         "expected string argument" );
413         last = strlen(path)-1;
414         if ((last >= 0) && ((path[last]=='/') || (path[last]=='\\'))) {
415                 trailing_slash = 1;
416         }
417         BLI_strncpy(cleaned, path, FILE_MAXDIR + FILE_MAXFILE);
418         BLI_cleanup_file(NULL, cleaned);
419         
420         if (trailing_slash) {
421                 BLI_add_slash(cleaned);
422         }
423         
424         return PyString_FromString(cleaned);
425 }