Updating built in Io code to use += instead of x = x + y
[io/quag.git] / libs / iovm / source / IoDirectory.c
bloba95dffa5751d2877f9b365948aa11eb879c1a688
1 /*#io
2 Directory ioDoc(
3 docCopyright("Steve Dekorte", 2002)
4 docLicense("BSD revised")
5 docDescription("""The Directory object supports accessing filesystem directories. A note on paths;
6 if a path begins with a "/" it's the root,
7 if it beings with a "./" it's the launch path,
8 if not specified, "./" is assumed.""")
9 docCredits("""Cygwin code by Mike Austin. WIN32 code by Daniel Vollmer.""")
10 docCategory("FileSystem")
13 #include "IoDirectory.h"
14 #include "IoState.h"
15 #include "IoNumber.h"
16 #include "IoList.h"
17 #include "IoFile.h"
18 #include <sys/stat.h>
20 #if !defined(_MSC_VER) && !defined(__SYMBIAN32__)
21 #include <unistd.h> /* ok, this isn't ANSI */
22 #endif
24 #if defined(_MSC_VER) && !defined(__SYMBIAN32__)
25 #include <direct.h>
26 #define getcwd _getcwd
27 #endif
29 #if defined(__SYMBIAN32__)
30 static char* getcwd(char* buf, int size) { return 0; }
31 #endif
33 #ifndef _WIN32
35 #include <dirent.h>
36 #include <sys/file.h>
37 #include <unistd.h>
38 #define MKDIR mkdir
40 #else
42 #include <windows.h>
43 #define S_IRGRP 0
44 #define S_IXGRP 0
45 #define S_IROTH 0
46 #define S_IXOTH 0
47 #define S_IRWXU 0
49 #define DT_DIR 0x01
50 #define MKDIR mkdir_win32
52 struct dirent {
53 char d_name[MAX_PATH];
54 unsigned char d_type;
57 typedef struct {
58 WIN32_FIND_DATA wfd;
59 HANDLE hFind;
60 struct dirent de;
61 unsigned char valid;
62 } DIR;
64 static DIR *opendir(char *pSpec)
66 DIR *pDir = io_calloc(1, sizeof *pDir);
67 char *longer_string = io_calloc(1, (strlen(pSpec) + 3) * sizeof *longer_string);
69 strcpy(longer_string, pSpec);
70 strcat(longer_string, "/*");
71 pDir->hFind = FindFirstFile(longer_string, &pDir->wfd);
72 io_free(longer_string);
73 pDir->valid = pDir->hFind != INVALID_HANDLE_VALUE;
75 if (!pDir->valid)
77 DWORD err = GetLastError();
78 if (err == ERROR_PATH_NOT_FOUND)
80 io_free(pDir);
81 return (DIR*)0;
85 return pDir;
88 static void closedir(DIR * pDir)
90 if (pDir->hFind != INVALID_HANDLE_VALUE)
92 FindClose(pDir->hFind);
95 io_free(pDir);
98 static struct dirent *readdir(DIR *pDir)
100 if (pDir->valid)
102 strcpy(pDir->de.d_name, pDir->wfd.cFileName);
103 pDir->de.d_type = (pDir->wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0 ? DT_DIR : 0;
104 pDir->valid = FindNextFile(pDir->hFind, &pDir->wfd);
105 return &pDir->de;
108 return NULL;
111 typedef int mode_t_win32;
113 int mkdir_win32(const char *path, mode_t_win32 mode)
115 /* returns zero on sucess */
116 LPCTSTR lpPathName = path;
117 LPSECURITY_ATTRIBUTES lpSecurityAttributes = NULL;
118 return (CreateDirectory(lpPathName, lpSecurityAttributes) != 0);
121 int chdir(const char *path)
123 LPCTSTR lpPathName = path;
124 return SetCurrentDirectory(lpPathName) ? 1 : -1;
127 #endif
129 int isDirectory(struct dirent *dp, char *path)
131 #ifdef DT_UNKNOWN
132 if (dp->d_type != DT_UNKNOWN)
134 return (dp->d_type == DT_DIR);
136 else
137 #endif
139 struct stat st;
140 /*fstat( dp->d_fd, &st );*/
141 stat(path, &st);
142 return ( (st.st_mode & S_IFMT) == S_IFDIR );
146 #define DATA(self) ((IoDirectoryData *)IoObject_dataPointer(self))
148 IoTag *IoDirectory_newTag(void *state)
150 IoTag *tag = IoTag_newWithName_("Directory");
151 IoTag_state_(tag, state);
152 IoTag_cloneFunc_(tag, (IoTagCloneFunc *)IoDirectory_rawClone);
153 IoTag_freeFunc_(tag, (IoTagFreeFunc *)IoDirectory_free);
154 IoTag_markFunc_(tag, (IoTagMarkFunc *)IoDirectory_mark);
155 return tag;
158 IoDirectory *IoDirectory_proto(void *state)
160 IoObject *self = IoObject_new(state);
161 IoObject_tag_(self, IoDirectory_newTag(state));
163 IoObject_setDataPointer_(self, io_calloc(1, sizeof(IoDirectoryData)));
164 DATA(self)->path = IOSYMBOL(".");
166 IoState_registerProtoWithFunc_((IoState *)state, self, IoDirectory_proto);
169 IoMethodTable methodTable[] = {
170 {"setPath", IoDirectory_setPath},
171 {"path", IoDirectory_path},
172 {"name", IoDirectory_name},
173 {"exists", IoDirectory_exists},
174 {"items", IoDirectory_items},
175 {"at", IoDirectory_at},
176 {"size", IoDirectory_size},
177 {"create", IoDirectory_create},
178 {"createSubdirectory", IoDirectory_createSubdirectory},
179 {"currentWorkingDirectory", IoDirectory_currentWorkingDirectory},
180 {"setCurrentWorkingDirectory", IoDirectory_setCurrentWorkingDirectory},
181 {NULL, NULL},
184 IoObject_addMethodTable_(self, methodTable);
186 return self;
189 IoDirectory *IoDirectory_rawClone(IoDirectory *proto)
191 IoObject *self = IoObject_rawClonePrimitive(proto);
192 IoObject_setDataPointer_(self, cpalloc(IoObject_dataPointer(proto), sizeof(IoDirectoryData)));
193 return self;
196 IoDirectory *IoDirectory_new(void *state)
198 IoDirectory *proto = IoState_protoWithInitFunction_((IoState *)state, IoDirectory_proto);
199 return IOCLONE(proto);
202 // -----------------------------------------------------------
204 IoDirectory *IoDirectory_newWithPath_(void *state, IoSymbol *path)
206 IoDirectory *self = IoDirectory_new(state);
207 DATA(self)->path = IOREF(path);
208 return self;
211 IoDirectory *IoDirectory_cloneWithPath_(IoDirectory *self, IoSymbol *path)
213 IoDirectory *d = IOCLONE(self);
214 DATA(d)->path = IOREF(path);
215 return d;
218 void IoDirectory_free(IoDirectory *self)
220 io_free(IoObject_dataPointer(self));
223 void IoDirectory_mark(IoDirectory *self)
225 IoObject_shouldMark((IoObject *)DATA(self)->path);
228 // -----------------------------------------------------------
230 IoObject *IoDirectory_path(IoDirectory *self, IoObject *locals, IoMessage *m)
232 /*#io
233 docSlot("path", "Returns the directory path. The default path is '.'.")
236 return DATA(self)->path;
239 IoObject *IoDirectory_setPath(IoDirectory *self, IoObject *locals, IoMessage *m)
241 /*#io
242 docSlot("setPath(aString)", "Sets the directory path. Returns self. ")
245 DATA(self)->path = IOREF(IoMessage_locals_symbolArgAt_(m, locals, 0));
249 UArray *path = IoSeq_rawUArray(DATA(self)->path);
250 printf("IoDirectory_setPath path = \"%s\" %i\n", UArray_asCString(path), UArray_itemSize(path));
253 return self;
256 IoObject *IoDirectory_name(IoDirectory *self, IoObject *locals, IoMessage *m)
258 /*#io
259 docSlot("name", "Returns the receiver's last path component. ")
262 return IoSeq_lastPathComponent(DATA(self)->path, locals, m);
265 IoObject *IoDirectory_itemForDirent_(IoDirectory *self, struct dirent *dp)
267 IoSymbol *pathString;
268 int isDir;
269 UArray *path = IoSeq_rawUArray(DATA(self)->path);
270 UArray *ba = UArray_clone(path);
273 printf("IoDirectory_itemForDirent_ path = \"%s\" %i\n", p, path->itemSize);
274 printf("IoDirectory_itemForDirent_ ba = \"%s\" %i\n", UArray_asCString(ba), ba->itemSize);
276 if (UArray_size(ba) && !IS_PATH_SEPERATOR(UArray_longAt_(ba, UArray_size(ba) - 1)))
278 UArray_appendCString_(ba, IO_PATH_SEPARATOR);
281 UArray_appendCString_(ba, dp->d_name);
282 pathString = IoState_symbolWithUArray_copy_(IOSTATE, ba, 0);
284 isDir = isDirectory(dp, CSTRING(pathString));
286 if (isDir)
288 return IoDirectory_newWithPath_(IOSTATE, pathString);
291 return IoFile_newWithPath_(IOSTATE, pathString);
294 IoObject *IoDirectory_exists(IoDirectory *self, IoObject *locals, IoMessage *m)
296 /*#io
297 docSlot("exists(optionalPath)",
298 "Returns true if the Directory path exists, and false otherwise.
299 If optionalPath string is provided, it tests the existance of that path instead. ")
302 IoSymbol *path = DATA(self)->path;
303 DIR *dirp;
305 if (IoMessage_argCount(m) > 0)
307 path = IoMessage_locals_symbolArgAt_(m, locals, 0);
310 dirp = opendir(CSTRING(path));
312 if (!dirp)
314 return IOFALSE(self);
317 (void)closedir(dirp);
318 return IOTRUE(self);
321 IoObject *IoDirectory_items(IoDirectory *self, IoObject *locals, IoMessage *m)
323 /*#io
324 docSlot("items",
325 "Returns a list object containing File and Directory objects
326 for the files and directories of the receiver's path. ")
329 IoList *items = IoList_new(IOSTATE);
330 IoDirectoryData *data = DATA(self);
331 DIR *dirp = opendir(CSTRING(data->path));
332 struct dirent *dp;
334 if (!dirp)
336 IoState_error_(IOSTATE, m, "Unable to open directory %s", CSTRING(DATA(self)->path));
339 while ((dp = readdir(dirp)) != NULL)
341 IoList_rawAppend_(items, IoDirectory_itemForDirent_(self, dp));
344 (void)closedir(dirp);
345 return items;
348 IoObject *IoDirectory_justFullPath(IoDirectory *self, IoSymbol *name)
350 UArray *fullPath = UArray_clone(IoSeq_rawUArray(DATA(self)->path));
351 UArray_appendPath_(fullPath, IoSeq_rawUArray(name));
352 return IoState_symbolWithUArray_copy_(IOSTATE, fullPath, 0);
355 IoObject *IoDirectory_justAt(IoDirectory *self, IoSymbol *name)
357 IoState *state = IOSTATE;
358 IoSymbol *fullPath = IoDirectory_justFullPath(self, name);
359 struct stat st;
361 if (stat(CSTRING(fullPath), &st) == -1)
363 return IONIL(self);
366 if ((st.st_mode & S_IFMT) == S_IFDIR)
368 return IoDirectory_newWithPath_(state, fullPath);
370 else
372 return IoFile_newWithPath_(state, fullPath);
375 return IONIL(self);
378 IoObject *IoDirectory_at(IoDirectory *self, IoObject *locals, IoMessage *m)
380 /*#io
381 docSlot("at(aString)",
382 "Returns a File or Directory object matching the name specified
383 by aString or Nil if no such file or directory exists. ")
386 IoSymbol *name = IoMessage_locals_symbolArgAt_(m, locals, 0);
387 return IoDirectory_justAt(self, name);
389 IoObject *item = IoDirectory_justAt(self, name);
390 if (ISNIL(item))
392 IoState_error_(IOSTATE, m, "Unable to open path %s", CSTRING(IoDirectory_justFullPath(self, name)));
394 return item;
399 IoObject *IoDirectory_atPut(IoDirectory *self, IoObject *locals, IoMessage *m)
401 IoSymbol *name = IoMessage_locals_symbolArgAt_(m, locals, 0);
402 IoObject *item = IoDirectory_justAt(self, name);
403 if (ISNIL(item))
405 IoState_error_(IOSTATE, m, "Unable to open path %s", CSTRING(IoDirectory_justFullPath(self, name)));
407 return item;
412 IoObject *IoDirectory_itemNamed(IoDirectory *self, IoObject *locals, IoMessage *m)
414 IoSymbol *itemName = IoMessage_locals_symbolArgAt_(m, locals, 0);
415 char *name = CSTRING(itemName);
416 DIR *dirp = opendir(CSTRING(DATA(self)->path));
417 struct dirent *dp;
418 if (!dirp)
420 IoState_error_(IOSTATE, m, "Unable to open directory %s", CSTRING(DATA(self)->path));
423 while ((dp = readdir(dirp)) != NULL)
425 if (strcmp(dp->d_name, name) == 0)
427 IoObject *item = IoDirectory_itemForDirent_(self, dp);
428 (void)closedir(dirp);
429 return item;
432 (void)closedir(dirp);
433 return IONIL(self);
437 IoObject *IoDirectory_createSubdirectory(IoDirectory *self, IoObject *locals, IoMessage *m)
439 /*#io
440 docSlot("createSubdirectory(name)",
441 "Create a subdirectory with the specified name.")
444 IoState *state = IOSTATE;
445 IoSymbol *subfolderName = IoMessage_locals_symbolArgAt_(m, locals, 0);
446 IoObject *currentItem = IoDirectory_justAt(self, subfolderName);
448 if (ISDIRECTORY(currentItem))
450 return currentItem;
453 if (ISFILE(currentItem))
455 IoState_error_(IOSTATE, m, "Attempt to create directory %s on top of existing file",
456 CSTRING(subfolderName));
458 else
460 IoSymbol *fullPath = IoDirectory_justFullPath(self, subfolderName);
462 MKDIR(CSTRING(fullPath), S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH);
463 return IoDirectory_newWithPath_(state, fullPath);
466 return IONIL(self);
470 IoObject *IoDirectory_create(IoDirectory *self, IoObject *locals, IoMessage *m)
472 /*#io
473 docSlot("create",
474 "Create the directory if it doesn't exist.")
477 int r = MKDIR(CSTRING(DATA(self)->path), S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH);
478 return IOBOOL(self, r == 0);
481 IoObject *IoDirectory_size(IoDirectory *self, IoObject *locals, IoMessage *m)
483 /*#io
484 docSlot("size",
485 "Returns a Number containing the number of file and directory
486 object at the receiver's path. ")
489 int count = 0;
490 DIR *dirp = opendir(CSTRING(DATA(self)->path));
491 struct dirent *dp;
493 if (!dirp)
495 IoState_error_(IOSTATE, m, "Unable to open directory %s", CSTRING(DATA(self)->path));
498 while ((dp = readdir(dirp)) != NULL)
500 count ++;
503 (void)closedir(dirp);
504 return IONUMBER((double)count);
508 /* -------------------------------- */
510 UArray *IoDirectory_CurrentWorkingDirectoryAsUArray(void)
512 #if defined(sparc) || defined(__sparc)
513 char *buf = getcwd(NULL, FILENAME_MAX + 1);
514 #else
515 char *buf = NULL;
516 buf = (char *)getcwd(buf, 1024);
517 #endif /* sparc || _sparc */
519 if (!buf)
521 return UArray_newWithCString_copy_(".", 1);
523 else
525 UArray *ba = UArray_newWithData_type_size_copy_((unsigned char *)buf, CTYPE_uint8_t, strlen(buf), 1);
526 UArray_setEncoding_(ba, CENCODING_UTF8);
527 UArray_convertToFixedSizeType(ba);
528 // io_free(buf); OSX get cwd man page says we should io_free this, but MallocDebug doesn't like it
529 return ba;
533 int IoDirectory_SetCurrentWorkingDirectory(const char *path)
535 return chdir(path);
538 IoObject *IoDirectory_currentWorkingDirectory(IoDirectory *self, IoObject *locals, IoMessage *m)
540 /*#io
541 docSlot("currentWorkingDirectory",
542 "Returns the current working directory path.")
545 return IoState_symbolWithUArray_copy_(IOSTATE,
546 IoDirectory_CurrentWorkingDirectoryAsUArray(), 0);
550 int IoDirectory_SetCurrentWorkingDirectory(char *p)
552 return chdir(p);
556 IoObject *IoDirectory_setCurrentWorkingDirectory(IoDirectory *self, IoObject *locals, IoMessage *m)
558 /*#io
559 docSlot("setCurrentWorkingDirectory(pathString)",
560 "Set's the current working directory path.
561 Returns true on success or false on error.")
564 IoSymbol *path = IoMessage_locals_symbolArgAt_(m, locals, 0);
566 if(chdir(CSTRING(path)) == -1)
568 return IOSUCCESS(self);
571 return IOFAILURE(self);