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"
20 #if !defined(_MSC_VER) && !defined(__SYMBIAN32__)
21 #include <unistd.h> /* ok, this isn't ANSI */
24 #if defined(_MSC_VER) && !defined(__SYMBIAN32__)
26 #define getcwd _getcwd
29 #if defined(__SYMBIAN32__)
30 static char* getcwd(char* buf
, int size
) { return 0; }
50 #define MKDIR mkdir_win32
53 char d_name
[MAX_PATH
];
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
;
77 DWORD err
= GetLastError();
78 if (err
== ERROR_PATH_NOT_FOUND
)
88 static void closedir(DIR * pDir
)
90 if (pDir
->hFind
!= INVALID_HANDLE_VALUE
)
92 FindClose(pDir
->hFind
);
98 static struct dirent
*readdir(DIR *pDir
)
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
);
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;
129 int isDirectory(struct dirent
*dp
, char *path
)
132 if (dp
->d_type
!= DT_UNKNOWN
)
134 return (dp
->d_type
== DT_DIR
);
140 /*fstat( dp->d_fd, &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
);
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
},
184 IoObject_addMethodTable_(self
, methodTable
);
189 IoDirectory
*IoDirectory_rawClone(IoDirectory
*proto
)
191 IoObject
*self
= IoObject_rawClonePrimitive(proto
);
192 IoObject_setDataPointer_(self
, cpalloc(IoObject_dataPointer(proto
), sizeof(IoDirectoryData
)));
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
);
211 IoDirectory
*IoDirectory_cloneWithPath_(IoDirectory
*self
, IoSymbol
*path
)
213 IoDirectory
*d
= IOCLONE(self
);
214 DATA(d
)->path
= IOREF(path
);
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
)
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
)
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));
256 IoObject
*IoDirectory_name(IoDirectory
*self
, IoObject
*locals
, IoMessage
*m
)
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
;
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
));
288 return IoDirectory_newWithPath_(IOSTATE
, pathString
);
291 return IoFile_newWithPath_(IOSTATE
, pathString
);
294 IoObject
*IoDirectory_exists(IoDirectory
*self
, IoObject
*locals
, IoMessage
*m
)
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
;
305 if (IoMessage_argCount(m
) > 0)
307 path
= IoMessage_locals_symbolArgAt_(m
, locals
, 0);
310 dirp
= opendir(CSTRING(path
));
314 return IOFALSE(self
);
317 (void)closedir(dirp
);
321 IoObject
*IoDirectory_items(IoDirectory
*self
, IoObject
*locals
, IoMessage
*m
)
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
));
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
);
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
);
361 if (stat(CSTRING(fullPath
), &st
) == -1)
366 if ((st
.st_mode
& S_IFMT
) == S_IFDIR
)
368 return IoDirectory_newWithPath_(state
, fullPath
);
372 return IoFile_newWithPath_(state
, fullPath
);
378 IoObject
*IoDirectory_at(IoDirectory
*self
, IoObject
*locals
, IoMessage
*m
)
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);
392 IoState_error_(IOSTATE, m, "Unable to open path %s", CSTRING(IoDirectory_justFullPath(self, name)));
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);
405 IoState_error_(IOSTATE, m, "Unable to open path %s", CSTRING(IoDirectory_justFullPath(self, name)));
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));
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);
432 (void)closedir(dirp);
437 IoObject
*IoDirectory_createSubdirectory(IoDirectory
*self
, IoObject
*locals
, IoMessage
*m
)
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
))
453 if (ISFILE(currentItem
))
455 IoState_error_(IOSTATE
, m
, "Attempt to create directory %s on top of existing file",
456 CSTRING(subfolderName
));
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
);
470 IoObject
*IoDirectory_create(IoDirectory
*self
, IoObject
*locals
, IoMessage
*m
)
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
)
485 "Returns a Number containing the number of file and directory
486 object at the receiver's path. ")
490 DIR *dirp
= opendir(CSTRING(DATA(self
)->path
));
495 IoState_error_(IOSTATE
, m
, "Unable to open directory %s", CSTRING(DATA(self
)->path
));
498 while ((dp
= readdir(dirp
)) != NULL
)
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);
516 buf
= (char *)getcwd(buf
, 1024);
517 #endif /* sparc || _sparc */
521 return UArray_newWithCString_copy_(".", 1);
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
533 int IoDirectory_SetCurrentWorkingDirectory(const char *path
)
538 IoObject
*IoDirectory_currentWorkingDirectory(IoDirectory
*self
, IoObject
*locals
, IoMessage
*m
)
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)
556 IoObject
*IoDirectory_setCurrentWorkingDirectory(IoDirectory
*self
, IoObject
*locals
, IoMessage
*m
)
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
);