Thomas Wouters | 0e3f591 | 2006-08-11 14:57:12 +0000 | [diff] [blame] | 1 | /***************************************************************** |
| 2 | This file should be kept compatible with Python 2.3, see PEP 291. |
| 3 | *****************************************************************/ |
Thomas Heller | d4c9320 | 2006-03-08 19:35:11 +0000 | [diff] [blame] | 4 | |
Thomas Wouters | a977329 | 2006-04-21 09:43:23 +0000 | [diff] [blame] | 5 | #if (PY_VERSION_HEX < 0x02050000) |
| 6 | typedef int Py_ssize_t; |
Thomas Wouters | a977329 | 2006-04-21 09:43:23 +0000 | [diff] [blame] | 7 | #endif |
| 8 | |
Thomas Heller | d4c9320 | 2006-03-08 19:35:11 +0000 | [diff] [blame] | 9 | #ifndef MS_WIN32 |
| 10 | #define max(a, b) ((a) > (b) ? (a) : (b)) |
| 11 | #define min(a, b) ((a) < (b) ? (a) : (b)) |
| 12 | |
| 13 | #define PARAMFLAG_FIN 0x1 |
| 14 | #define PARAMFLAG_FOUT 0x2 |
| 15 | #define PARAMFLAG_FLCID 0x4 |
| 16 | #endif |
| 17 | |
| 18 | /* |
| 19 | Backwards compatibility: |
| 20 | Python2.2 used LONG_LONG instead of PY_LONG_LONG |
| 21 | */ |
| 22 | #if defined(HAVE_LONG_LONG) && !defined(PY_LONG_LONG) |
| 23 | #define PY_LONG_LONG LONG_LONG |
| 24 | #endif |
| 25 | |
Thomas Wouters | 00ee7ba | 2006-08-21 19:07:27 +0000 | [diff] [blame] | 26 | typedef struct tagPyCArgObject PyCArgObject; |
Thomas Heller | d4c9320 | 2006-03-08 19:35:11 +0000 | [diff] [blame] | 27 | typedef struct tagCDataObject CDataObject; |
Thomas Wouters | 49fd7fa | 2006-04-21 10:40:58 +0000 | [diff] [blame] | 28 | typedef PyObject *(* GETFUNC)(void *, unsigned size); |
| 29 | typedef PyObject *(* SETFUNC)(void *, PyObject *value, unsigned size); |
Thomas Wouters | 00ee7ba | 2006-08-21 19:07:27 +0000 | [diff] [blame] | 30 | typedef PyCArgObject *(* PARAMFUNC)(CDataObject *obj); |
Thomas Heller | d4c9320 | 2006-03-08 19:35:11 +0000 | [diff] [blame] | 31 | |
| 32 | /* A default buffer in CDataObject, which can be used for small C types. If |
| 33 | this buffer is too small, PyMem_Malloc will be called to create a larger one, |
| 34 | and this one is not used. |
| 35 | |
| 36 | Making CDataObject a variable size object would be a better solution, but more |
| 37 | difficult in the presence of CFuncPtrObject. Maybe later. |
| 38 | */ |
| 39 | union value { |
| 40 | char c[16]; |
| 41 | short s; |
| 42 | int i; |
| 43 | long l; |
| 44 | float f; |
| 45 | double d; |
| 46 | #ifdef HAVE_LONG_LONG |
| 47 | PY_LONG_LONG ll; |
| 48 | #endif |
| 49 | }; |
| 50 | |
| 51 | /* |
| 52 | Hm. Are there CDataObject's which do not need the b_objects member? In |
| 53 | this case we probably should introduce b_flags to mark it as present... If |
| 54 | b_objects is not present/unused b_length is unneeded as well. |
| 55 | */ |
| 56 | |
| 57 | struct tagCDataObject { |
| 58 | PyObject_HEAD |
| 59 | char *b_ptr; /* pointer to memory block */ |
| 60 | int b_needsfree; /* need _we_ free the memory? */ |
| 61 | CDataObject *b_base; /* pointer to base object or NULL */ |
Thomas Heller | fe8f862 | 2006-03-14 19:53:09 +0000 | [diff] [blame] | 62 | Py_ssize_t b_size; /* size of memory block in bytes */ |
| 63 | Py_ssize_t b_length; /* number of references we need */ |
| 64 | Py_ssize_t b_index; /* index of this object into base's |
Thomas Heller | d4c9320 | 2006-03-08 19:35:11 +0000 | [diff] [blame] | 65 | b_object list */ |
Thomas Wouters | 0e3f591 | 2006-08-11 14:57:12 +0000 | [diff] [blame] | 66 | PyObject *b_objects; /* dictionary of references we need to keep, or Py_None */ |
Thomas Heller | d4c9320 | 2006-03-08 19:35:11 +0000 | [diff] [blame] | 67 | union value b_value; |
| 68 | }; |
| 69 | |
| 70 | typedef struct { |
Thomas Wouters | 49fd7fa | 2006-04-21 10:40:58 +0000 | [diff] [blame] | 71 | ffi_closure *pcl; /* the C callable */ |
| 72 | ffi_cif cif; |
| 73 | PyObject *converters; |
| 74 | PyObject *callable; |
| 75 | SETFUNC setfunc; |
| 76 | ffi_type *restype; |
| 77 | ffi_type *atypes[0]; |
| 78 | } ffi_info; |
| 79 | |
| 80 | typedef struct { |
Thomas Heller | d4c9320 | 2006-03-08 19:35:11 +0000 | [diff] [blame] | 81 | /* First part identical to tagCDataObject */ |
| 82 | PyObject_HEAD |
| 83 | char *b_ptr; /* pointer to memory block */ |
| 84 | int b_needsfree; /* need _we_ free the memory? */ |
| 85 | CDataObject *b_base; /* pointer to base object or NULL */ |
Thomas Heller | fe8f862 | 2006-03-14 19:53:09 +0000 | [diff] [blame] | 86 | Py_ssize_t b_size; /* size of memory block in bytes */ |
| 87 | Py_ssize_t b_length; /* number of references we need */ |
| 88 | Py_ssize_t b_index; /* index of this object into base's |
Thomas Heller | d4c9320 | 2006-03-08 19:35:11 +0000 | [diff] [blame] | 89 | b_object list */ |
| 90 | PyObject *b_objects; /* list of references we need to keep */ |
| 91 | union value b_value; |
| 92 | /* end of tagCDataObject, additional fields follow */ |
| 93 | |
Thomas Wouters | 49fd7fa | 2006-04-21 10:40:58 +0000 | [diff] [blame] | 94 | ffi_info *thunk; |
Thomas Heller | d4c9320 | 2006-03-08 19:35:11 +0000 | [diff] [blame] | 95 | PyObject *callable; |
| 96 | |
| 97 | /* These two fields will override the ones in the type's stgdict if |
| 98 | they are set */ |
| 99 | PyObject *converters; |
| 100 | PyObject *argtypes; |
| 101 | PyObject *restype; |
| 102 | PyObject *checker; |
| 103 | PyObject *errcheck; |
| 104 | #ifdef MS_WIN32 |
| 105 | int index; |
| 106 | GUID *iid; |
| 107 | #endif |
| 108 | PyObject *paramflags; |
| 109 | } CFuncPtrObject; |
| 110 | |
| 111 | extern PyTypeObject StgDict_Type; |
| 112 | #define StgDict_CheckExact(v) ((v)->ob_type == &StgDict_Type) |
| 113 | #define StgDict_Check(v) PyObject_TypeCheck(v, &StgDict_Type) |
| 114 | |
| 115 | extern int StructUnionType_update_stgdict(PyObject *fields, PyObject *type, int isStruct); |
Thomas Heller | fe8f862 | 2006-03-14 19:53:09 +0000 | [diff] [blame] | 116 | extern int PyType_stginfo(PyTypeObject *self, Py_ssize_t *psize, Py_ssize_t *palign, Py_ssize_t *plength); |
| 117 | extern int PyObject_stginfo(PyObject *self, Py_ssize_t *psize, Py_ssize_t *palign, Py_ssize_t *plength); |
Thomas Heller | d4c9320 | 2006-03-08 19:35:11 +0000 | [diff] [blame] | 118 | |
| 119 | |
| 120 | |
| 121 | extern PyTypeObject CData_Type; |
| 122 | #define CDataObject_CheckExact(v) ((v)->ob_type == &CData_Type) |
| 123 | #define CDataObject_Check(v) PyObject_TypeCheck(v, &CData_Type) |
| 124 | |
| 125 | extern PyTypeObject SimpleType_Type; |
| 126 | #define SimpleTypeObject_CheckExact(v) ((v)->ob_type == &SimpleType_Type) |
| 127 | #define SimpleTypeObject_Check(v) PyObject_TypeCheck(v, &SimpleType_Type) |
| 128 | |
| 129 | extern PyTypeObject CField_Type; |
| 130 | extern struct fielddesc *getentry(char *fmt); |
| 131 | |
| 132 | |
| 133 | extern PyObject * |
| 134 | CField_FromDesc(PyObject *desc, int index, |
| 135 | int *pfield_size, int bitsize, int *pbitofs, |
| 136 | int *psize, int *poffset, int *palign, |
| 137 | int pack, int is_big_endian); |
| 138 | |
| 139 | extern PyObject *CData_AtAddress(PyObject *type, void *buf); |
Thomas Heller | fe8f862 | 2006-03-14 19:53:09 +0000 | [diff] [blame] | 140 | extern PyObject *CData_FromBytes(PyObject *type, char *data, Py_ssize_t length); |
Thomas Heller | d4c9320 | 2006-03-08 19:35:11 +0000 | [diff] [blame] | 141 | |
| 142 | extern PyTypeObject ArrayType_Type; |
| 143 | extern PyTypeObject Array_Type; |
| 144 | extern PyTypeObject PointerType_Type; |
| 145 | extern PyTypeObject Pointer_Type; |
| 146 | extern PyTypeObject CFuncPtr_Type; |
| 147 | extern PyTypeObject CFuncPtrType_Type; |
| 148 | extern PyTypeObject StructType_Type; |
| 149 | |
| 150 | #define ArrayTypeObject_Check(v) PyObject_TypeCheck(v, &ArrayType_Type) |
| 151 | #define ArrayObject_Check(v) PyObject_TypeCheck(v, &Array_Type) |
| 152 | #define PointerObject_Check(v) PyObject_TypeCheck(v, &Pointer_Type) |
| 153 | #define PointerTypeObject_Check(v) PyObject_TypeCheck(v, &PointerType_Type) |
| 154 | #define CFuncPtrObject_Check(v) PyObject_TypeCheck(v, &CFuncPtr_Type) |
| 155 | #define CFuncPtrTypeObject_Check(v) PyObject_TypeCheck(v, &CFuncPtrType_Type) |
| 156 | #define StructTypeObject_Check(v) PyObject_TypeCheck(v, &StructType_Type) |
| 157 | |
| 158 | extern PyObject * |
Thomas Heller | fe8f862 | 2006-03-14 19:53:09 +0000 | [diff] [blame] | 159 | CreateArrayType(PyObject *itemtype, Py_ssize_t length); |
Thomas Heller | d4c9320 | 2006-03-08 19:35:11 +0000 | [diff] [blame] | 160 | |
| 161 | extern void init_callbacks_in_module(PyObject *m); |
| 162 | |
Thomas Heller | d4c9320 | 2006-03-08 19:35:11 +0000 | [diff] [blame] | 163 | extern PyMethodDef module_methods[]; |
| 164 | |
Thomas Wouters | 49fd7fa | 2006-04-21 10:40:58 +0000 | [diff] [blame] | 165 | extern ffi_info *AllocFunctionCallback(PyObject *callable, |
| 166 | PyObject *converters, |
| 167 | PyObject *restype, |
| 168 | int stdcall); |
Thomas Heller | d4c9320 | 2006-03-08 19:35:11 +0000 | [diff] [blame] | 169 | /* a table entry describing a predefined ctypes type */ |
| 170 | struct fielddesc { |
| 171 | char code; |
| 172 | SETFUNC setfunc; |
| 173 | GETFUNC getfunc; |
| 174 | ffi_type *pffi_type; /* always statically allocated */ |
| 175 | SETFUNC setfunc_swapped; |
| 176 | GETFUNC getfunc_swapped; |
| 177 | }; |
| 178 | |
| 179 | typedef struct { |
| 180 | PyObject_HEAD |
Thomas Heller | fe8f862 | 2006-03-14 19:53:09 +0000 | [diff] [blame] | 181 | Py_ssize_t offset; |
| 182 | Py_ssize_t size; |
| 183 | Py_ssize_t index; /* Index into CDataObject's |
Thomas Heller | d4c9320 | 2006-03-08 19:35:11 +0000 | [diff] [blame] | 184 | object array */ |
| 185 | PyObject *proto; /* a type or NULL */ |
| 186 | GETFUNC getfunc; /* getter function if proto is NULL */ |
| 187 | SETFUNC setfunc; /* setter function if proto is NULL */ |
Thomas Wouters | 0e3f591 | 2006-08-11 14:57:12 +0000 | [diff] [blame] | 188 | int anonymous; |
Thomas Heller | d4c9320 | 2006-03-08 19:35:11 +0000 | [diff] [blame] | 189 | } CFieldObject; |
| 190 | |
| 191 | /* A subclass of PyDictObject, used as the instance dictionary of ctypes |
| 192 | metatypes */ |
| 193 | typedef struct { |
| 194 | PyDictObject dict; /* first part identical to PyDictObject */ |
| 195 | /* The size and align fields are unneeded, they are in ffi_type as well. As |
| 196 | an experiment shows, it's trivial to get rid of them, the only thing to |
| 197 | remember is that in ArrayType_new the ffi_type fields must be filled in - |
| 198 | so far it was unneeded because libffi doesn't support arrays at all |
| 199 | (because they are passed as pointers to function calls anyway). But it's |
| 200 | too much risk to change that now, and there are other fields which doen't |
| 201 | belong into this structure anyway. Maybe in ctypes 2.0... (ctypes 2000?) |
| 202 | */ |
Thomas Heller | fe8f862 | 2006-03-14 19:53:09 +0000 | [diff] [blame] | 203 | Py_ssize_t size; /* number of bytes */ |
| 204 | Py_ssize_t align; /* alignment requirements */ |
| 205 | Py_ssize_t length; /* number of fields */ |
Thomas Wouters | 49fd7fa | 2006-04-21 10:40:58 +0000 | [diff] [blame] | 206 | ffi_type ffi_type_pointer; |
Thomas Heller | d4c9320 | 2006-03-08 19:35:11 +0000 | [diff] [blame] | 207 | PyObject *proto; /* Only for Pointer/ArrayObject */ |
| 208 | SETFUNC setfunc; /* Only for simple objects */ |
| 209 | GETFUNC getfunc; /* Only for simple objects */ |
Thomas Wouters | 00ee7ba | 2006-08-21 19:07:27 +0000 | [diff] [blame] | 210 | PARAMFUNC paramfunc; |
Thomas Heller | d4c9320 | 2006-03-08 19:35:11 +0000 | [diff] [blame] | 211 | |
| 212 | /* Following fields only used by CFuncPtrType_Type instances */ |
| 213 | PyObject *argtypes; /* tuple of CDataObjects */ |
| 214 | PyObject *converters; /* tuple([t.from_param for t in argtypes]) */ |
| 215 | PyObject *restype; /* CDataObject or NULL */ |
| 216 | PyObject *checker; |
| 217 | int flags; /* calling convention and such */ |
| 218 | } StgDictObject; |
| 219 | |
| 220 | /**************************************************************** |
| 221 | StgDictObject fields |
| 222 | |
| 223 | setfunc and getfunc is only set for simple data types, it is copied from the |
| 224 | corresponding fielddesc entry. These are functions to set and get the value |
| 225 | in a memory block. |
| 226 | They should probably by used by other types as well. |
| 227 | |
| 228 | proto is only used for Pointer and Array types - it points to the item type |
| 229 | object. |
| 230 | |
| 231 | Probably all the magic ctypes methods (like from_param) should have C |
| 232 | callable wrappers in the StgDictObject. For simple data type, for example, |
| 233 | the fielddesc table could have entries for C codec from_param functions or |
| 234 | other methods as well, if a subtype overrides this method in Python at |
| 235 | construction time, or assigns to it later, tp_setattro should update the |
| 236 | StgDictObject function to a generic one. |
| 237 | |
| 238 | Currently, CFuncPtr types have 'converters' and 'checker' entries in their |
| 239 | type dict. They are only used to cache attributes from other entries, whihc |
| 240 | is wrong. |
| 241 | |
| 242 | One use case is the .value attribute that all simple types have. But some |
| 243 | complex structures, like VARIANT, represent a single value also, and should |
| 244 | have this attribute. |
| 245 | |
| 246 | Another use case is a _check_retval_ function, which is called when a ctypes |
| 247 | type is used as return type of a function to validate and compute the return |
| 248 | value. |
| 249 | |
| 250 | Common ctypes protocol: |
| 251 | |
| 252 | - setfunc: store a python value in a memory block |
| 253 | - getfunc: convert data from a memory block into a python value |
| 254 | |
| 255 | - checkfunc: validate and convert a return value from a function call |
| 256 | - toparamfunc: convert a python value into a function argument |
| 257 | |
| 258 | *****************************************************************/ |
| 259 | |
| 260 | /* May return NULL, but does not set an exception! */ |
| 261 | extern StgDictObject *PyType_stgdict(PyObject *obj); |
| 262 | |
| 263 | /* May return NULL, but does not set an exception! */ |
| 264 | extern StgDictObject *PyObject_stgdict(PyObject *self); |
| 265 | |
| 266 | extern int StgDict_clone(StgDictObject *src, StgDictObject *dst); |
| 267 | |
| 268 | typedef int(* PPROC)(void); |
| 269 | |
| 270 | PyObject *_CallProc(PPROC pProc, |
| 271 | PyObject *arguments, |
| 272 | #ifdef MS_WIN32 |
| 273 | IUnknown *pIUnk, |
| 274 | GUID *iid, |
| 275 | #endif |
| 276 | int flags, |
| 277 | PyObject *argtypes, |
| 278 | PyObject *restype, |
| 279 | PyObject *checker); |
| 280 | |
| 281 | |
| 282 | #define FUNCFLAG_STDCALL 0x0 |
| 283 | #define FUNCFLAG_CDECL 0x1 |
| 284 | #define FUNCFLAG_HRESULT 0x2 |
| 285 | #define FUNCFLAG_PYTHONAPI 0x4 |
| 286 | |
| 287 | #define DICTFLAG_FINAL 0x1000 |
| 288 | |
Thomas Wouters | 00ee7ba | 2006-08-21 19:07:27 +0000 | [diff] [blame] | 289 | struct tagPyCArgObject { |
Thomas Heller | d4c9320 | 2006-03-08 19:35:11 +0000 | [diff] [blame] | 290 | PyObject_HEAD |
| 291 | ffi_type *pffi_type; |
| 292 | char tag; |
| 293 | union { |
| 294 | char c; |
| 295 | char b; |
| 296 | short h; |
| 297 | int i; |
| 298 | long l; |
| 299 | #ifdef HAVE_LONG_LONG |
| 300 | PY_LONG_LONG q; |
| 301 | #endif |
| 302 | double d; |
| 303 | float f; |
| 304 | void *p; |
| 305 | } value; |
| 306 | PyObject *obj; |
| 307 | int size; /* for the 'V' tag */ |
Thomas Wouters | 00ee7ba | 2006-08-21 19:07:27 +0000 | [diff] [blame] | 308 | }; |
Thomas Heller | d4c9320 | 2006-03-08 19:35:11 +0000 | [diff] [blame] | 309 | |
| 310 | extern PyTypeObject PyCArg_Type; |
| 311 | extern PyCArgObject *new_CArgObject(void); |
| 312 | #define PyCArg_CheckExact(v) ((v)->ob_type == &PyCArg_Type) |
| 313 | extern PyCArgObject *new_CArgObject(void); |
| 314 | |
| 315 | extern PyObject * |
| 316 | CData_get(PyObject *type, GETFUNC getfunc, PyObject *src, |
Thomas Heller | fe8f862 | 2006-03-14 19:53:09 +0000 | [diff] [blame] | 317 | Py_ssize_t index, Py_ssize_t size, char *ptr); |
Thomas Heller | d4c9320 | 2006-03-08 19:35:11 +0000 | [diff] [blame] | 318 | |
| 319 | extern int |
| 320 | CData_set(PyObject *dst, PyObject *type, SETFUNC setfunc, PyObject *value, |
Thomas Heller | fe8f862 | 2006-03-14 19:53:09 +0000 | [diff] [blame] | 321 | Py_ssize_t index, Py_ssize_t size, char *ptr); |
Thomas Heller | d4c9320 | 2006-03-08 19:35:11 +0000 | [diff] [blame] | 322 | |
| 323 | extern void Extend_Error_Info(PyObject *exc_class, char *fmt, ...); |
| 324 | |
| 325 | struct basespec { |
| 326 | CDataObject *base; |
Thomas Heller | fe8f862 | 2006-03-14 19:53:09 +0000 | [diff] [blame] | 327 | Py_ssize_t index; |
Thomas Heller | d4c9320 | 2006-03-08 19:35:11 +0000 | [diff] [blame] | 328 | char *adr; |
| 329 | }; |
| 330 | |
| 331 | extern char basespec_string[]; |
| 332 | |
| 333 | extern ffi_type *GetType(PyObject *obj); |
| 334 | |
| 335 | /* exception classes */ |
| 336 | extern PyObject *PyExc_ArgError; |
| 337 | |
| 338 | extern char *conversion_mode_encoding; |
| 339 | extern char *conversion_mode_errors; |
| 340 | |
| 341 | /* Python 2.4 macros, which are not available in Python 2.3 */ |
| 342 | |
| 343 | #ifndef Py_CLEAR |
| 344 | #define Py_CLEAR(op) \ |
| 345 | do { \ |
| 346 | if (op) { \ |
| 347 | PyObject *tmp = (PyObject *)(op); \ |
| 348 | (op) = NULL; \ |
| 349 | Py_DECREF(tmp); \ |
| 350 | } \ |
| 351 | } while (0) |
| 352 | #endif |
| 353 | |
| 354 | #ifndef Py_VISIT |
| 355 | /* Utility macro to help write tp_traverse functions. |
| 356 | * To use this macro, the tp_traverse function must name its arguments |
| 357 | * "visit" and "arg". This is intended to keep tp_traverse functions |
| 358 | * looking as much alike as possible. |
| 359 | */ |
| 360 | #define Py_VISIT(op) \ |
| 361 | do { \ |
| 362 | if (op) { \ |
| 363 | int vret = visit((op), arg); \ |
| 364 | if (vret) \ |
| 365 | return vret; \ |
| 366 | } \ |
| 367 | } while (0) |
| 368 | #endif |
| 369 | |
| 370 | /* Python's PyUnicode_*WideChar functions are broken ... */ |
| 371 | #if defined(Py_USING_UNICODE) && defined(HAVE_WCHAR_H) |
| 372 | # define CTYPES_UNICODE |
| 373 | #endif |
| 374 | |
| 375 | |
| 376 | #ifdef CTYPES_UNICODE |
| 377 | # undef PyUnicode_FromWideChar |
| 378 | # define PyUnicode_FromWideChar My_PyUnicode_FromWideChar |
| 379 | |
| 380 | # undef PyUnicode_AsWideChar |
| 381 | # define PyUnicode_AsWideChar My_PyUnicode_AsWideChar |
| 382 | |
Thomas Wouters | 0e3f591 | 2006-08-11 14:57:12 +0000 | [diff] [blame] | 383 | extern PyObject *My_PyUnicode_FromWideChar(const wchar_t *, Py_ssize_t); |
| 384 | extern int My_PyUnicode_AsWideChar(PyUnicodeObject *, wchar_t *, Py_ssize_t); |
Thomas Heller | d4c9320 | 2006-03-08 19:35:11 +0000 | [diff] [blame] | 385 | |
| 386 | #endif |
| 387 | |
| 388 | extern void FreeClosure(void *); |
| 389 | extern void *MallocClosure(void); |
| 390 | |
| 391 | extern void _AddTraceback(char *, char *, int); |
| 392 | |
Thomas Heller | fe8f862 | 2006-03-14 19:53:09 +0000 | [diff] [blame] | 393 | extern PyObject *CData_FromBaseObj(PyObject *type, PyObject *base, Py_ssize_t index, char *adr); |
Thomas Heller | d4c9320 | 2006-03-08 19:35:11 +0000 | [diff] [blame] | 394 | |
| 395 | /* XXX better name needed! */ |
| 396 | extern int IsSimpleSubType(PyObject *obj); |
| 397 | |
| 398 | |
| 399 | #ifdef MS_WIN32 |
| 400 | extern PyObject *ComError; |
| 401 | #endif |
| 402 | |
| 403 | /* |
| 404 | Local Variables: |
| 405 | compile-command: "python setup.py -q build install --home ~" |
| 406 | End: |
| 407 | */ |