feisty meow concerns codebase 2.140
directory.cpp
Go to the documentation of this file.
1/*****************************************************************************\
2* *
3* Name : directory *
4* Author : Chris Koeritz *
5* *
6*******************************************************************************
7* Copyright (c) 2001-$now By Author. This program is free software; you can *
8* redistribute it and/or modify it under the terms of the GNU General Public *
9* License as published by the Free Software Foundation; either version 2 of *
10* the License or (at your option) any later version. This is online at: *
11* http://www.fsf.org/copyleft/gpl.html *
12* Please send any updates to: fred@gruntose.com *
13\*****************************************************************************/
14
15#include "directory.h"
16#include "filename.h"
17
19#include <basis/astring.h>
20#include <basis/contracts.h>
21#include <basis/functions.h>
25
26#include <stdio.h>
27#include <stdlib.h>
28#include <sys/stat.h>
29
30#include "../algorithms/sorts.h"
31#if defined(__UNIX__) || defined(__GNU_WINDOWS__)
32 #include <dirent.h>
33 #include <fnmatch.h>
34 #include <string.h>
35 #include <unistd.h>
36#endif
37//#ifdef _MSC_VER
38// #include <direct.h>
39//#endif
40
41/*
42#ifdef __WIN32__
43 const int MAX_ABS_PATH = 2048;
44#elif defined(__APPLE__)
45 const int MAX_ABS_PATH = 2048;
46#else
47 const int MAX_ABS_PATH = MAX_ABS_PATH;
48#endif
49*/
50
51//#define DEBUG_DIRECTORY
52 // uncomment for noisier runs.
53
54#undef LOG
55#define LOG(s) CLASS_EMERGENCY_LOG(program_wide_logger::get(), s)
56
57using namespace algorithms;
58using namespace basis;
59using namespace loggers;
60using namespace structures;
61
62namespace filesystem {
63
64directory::directory(const astring &path, const char *pattern)
65: _scanned_okay(false),
66 _path(new astring),
67 _files(new string_array),
68 _folders(new string_array),
69 _pattern(new astring(pattern))
70{ reset(path, pattern); }
71
73: _scanned_okay(false),
74 _path(new astring),
75 _files(new string_array),
76 _folders(new string_array),
77 _pattern(new astring)
78{ reset(*to_copy._path, to_copy._pattern->observe()); }
79
81{
82 _scanned_okay = false;
83 WHACK(_path);
84 WHACK(_files);
85 WHACK(_folders);
86 WHACK(_pattern);
87}
88
89const astring &directory::path() const { return *_path; }
90
91const astring &directory::pattern() const { return *_pattern; }
92
94{
95 if (this == &to_copy) return *this; // oops.
96 _scanned_okay = false;
97 reset(*to_copy._path, to_copy._pattern->observe());
98 return *this;
99}
100
102{
103 char abs_path[MAX_ABS_PATH + 1];
104 abs_path[0] = '\0';
105//#ifdef _MSC_VER
106// if (!_fullpath(abs_path, rel_path.s(), MAX_ABS_PATH)) return "";
107// return abs_path;
108//#else
109 if (!realpath(rel_path.s(), abs_path)) return "";
110 return abs_path;
111//#endif
112}
113
115{
116 astring to_return("."); // failure result.
117//#ifdef _MSC_VER
118// flexichar buffer[MAX_ABS_PATH + 1] = { '\0' };
119// GetCurrentDirectory(MAX_ABS_PATH, buffer);
120// to_return = from_unicode_temp(buffer);
121//#else
122 char buffer[MAX_ABS_PATH + 1] = { '\0' };
123 if (realpath(".", buffer)) to_return = buffer;
124//#endif
125 return to_return;
126}
127
128bool directory::reset(const astring &path, const char *pattern)
129{ *_path = path; *_pattern = pattern; return rescan(); }
130
131bool directory::move_up(const char *pattern)
132{
133 astring currdir = current();
134 return reset(currdir + "/..", pattern);
135}
136
137bool directory::move_down(const astring &subdir, const char *pattern)
138{
139 astring currdir = current();
140 return reset(currdir + "/" + subdir, pattern);
141}
142
143const string_array &directory::files() const { return *_files; }
144
145const string_array &directory::directories() const { return *_folders; }
146
148{
149 FUNCDEF("rescan");
150 _scanned_okay = false;
151 _files->reset();
152 _folders->reset();
153 astring cur_dir = ".";
154 astring par_dir = "..";
155/*
156#ifdef _MSC_VER
157 // start reading the directory.
158 WIN32_FIND_DATA wfd;
159 astring real_path_spec = *_path + "/" + *_pattern;
160 HANDLE search_handle = FindFirstFile(to_unicode_temp(real_path_spec), &wfd);
161 if (search_handle == INVALID_HANDLE_VALUE) return false; // bad path.
162 do {
163 // ignore the two standard directory entries.
164 astring filename_transcoded(from_unicode_temp(wfd.cFileName));
165 if (!strcmp(filename_transcoded.s(), cur_dir.s())) continue;
166 if (!strcmp(filename_transcoded.s(), par_dir.s())) continue;
167
168#ifdef UNICODE
169 #ifdef DEBUG_DIRECTORY
170 to_unicode_persist(kludgemart, filename_transcoded);
171 if (memcmp((wchar_t*)kludgemart, wfd.cFileName, wcslen(wfd.cFileName)*2))
172 printf("failed to compare the string before and after transcoding\n");
173 #endif
174#endif
175
176//wprintf(to_unicode_temp("file is %ls\n"), (wchar_t*)to_unicode_temp(filename_transcoded));
177
178 filename temp_name(*_path, filename_transcoded.s());
179
180 // add this to the appropriate list.
181 if (temp_name.is_directory()) {
182 _folders->concatenate(filename_transcoded);
183 } else {
184 _files->concatenate(filename_transcoded);
185
186#ifdef UNICODE
187 #ifdef DEBUG_DIRECTORY
188 to_unicode_persist(kludgemart2, temp_name.raw());
189 FILE *fpjunk = _wfopen(kludgemart2, to_unicode_temp("rb"));
190 if (!fpjunk)
191 LOG(astring("failed to open the file for testing: ") + temp_name.raw() + "\n");
192 if (fpjunk) fclose(fpjunk);
193 #endif
194#endif
195
196 }
197 } while (FindNextFile(search_handle, &wfd));
198 FindClose(search_handle);
199#else
200*/
201 DIR *dir = opendir(_path->s());
202//hmmm: could check errno to determine what caused the problem.
203 if (!dir) return false;
204 dirent *entry = readdir(dir);
205 while (entry) {
206 char *file = entry->d_name;
207 bool add_it = true;
208 if (!strcmp(file, cur_dir.s())) add_it = false;
209 if (!strcmp(file, par_dir.s())) add_it = false;
210 // make sure that the filename matches the pattern also.
211 if (add_it && !fnmatch(_pattern->s(), file, 0)) {
212 filename temp_name(*_path, file);
213 if (!temp_name.is_normal()) {
214//#ifdef DEBUG_DIRECTORY
215 LOG(astring("skipping abnormal file: ") + temp_name);
216//#endif
217 entry = readdir(dir);
218 continue; // cannot be adding goofy named pipes etc; cannot manage those.
219 }
220 // add this to the appropriate list.
221 if (temp_name.is_directory())
222 _folders->concatenate(file);
223 else
224 _files->concatenate(file);
225 }
226 entry = readdir(dir);
227 }
228 closedir(dir);
229//#endif
230 shell_sort(_files->access(), _files->length());
231 shell_sort(_folders->access(), _folders->length());
232
233 _scanned_okay = true;
234 return true;
235}
236
238{
239#if defined(__UNIX__) || defined(__GNU_WINDOWS__)
240 int mk_ret = mkdir(path.s(), 0777);
241#else
242 int mk_ret = mkdir(path.s());
243#endif
244 return !mk_ret;
245}
246
248{
249#if defined(__UNIX__) || defined(__GNU_WINDOWS__)
250 int rm_ret = rmdir(path.s());
251#else
252 int rm_ret = rmdir(path.s());
253#endif
254 return !rm_ret;
255}
256
257bool directory::recursive_create(const astring &directory_name)
258{
259 FUNCDEF("recursive_create");
260 filename dir(directory_name);
261 string_array pieces;
262 bool rooted;
263 dir.separate(rooted, pieces);
264 for (int i = 0; i < pieces.length(); i++) {
265 // check each location along the way.
266 string_array partial = pieces.subarray(0, i);
267 filename curr;
268 curr.join(rooted, partial); // this is our current location.
269 // make sure, if we see a drive letter component, that we call it
270 // a proper directory name.
271 if (curr.raw()[curr.raw().end()] == ':')
272 curr = curr.raw() + "/";
273 if (curr.exists()) {
274 if (curr.is_directory()) {
275 continue; // that's good.
276 }
277 return false; // if it's an existing file, we're hosed.
278 }
279 // the directory at this place doesn't exist yet. let's create it.
280 if (!directory::make_directory(curr.raw())) return false;
281 }
282 return true;
283}
284
285} // namespace.
286
#define mkdir
Definition Xos2defs.h:34
#define rmdir
Definition Xos2defs.h:39
#define LOG(s)
void reset(int number=0, const contents *initial_contents=NULL_POINTER)
Resizes this array and sets the contents from an array of contents.
Definition array.h:349
array & concatenate(const array &to_concatenate)
Appends the array "to_concatenate" onto "this" and returns "this".
Definition array.h:379
array subarray(int start, int end) const
Returns the array segment between the indices "start" and "end".
Definition array.h:443
contents * access()
A non-constant access of the underlying C-array. BE REALLY CAREFUL.
Definition array.h:175
int length() const
Returns the current reported length of the allocated C array.
Definition array.h:115
Provides a dynamically resizable ASCII character string.
Definition astring.h:35
const char * s() const
synonym for observe. the 's' stands for "string", if that helps.
Definition astring.h:113
int end() const
returns the index of the last (non-null) character in the string.
Definition astring.h:86
virtual const char * observe() const
observes the underlying pointer to the zero-terminated string.
Definition astring.cpp:140
Implements a scanner that finds all filenames in the directory specified.
Definition directory.h:27
directory(const basis::astring &path, const char *pattern="*")
opens up the "path" specified and scans for files and subdirectories.
Definition directory.cpp:64
bool move_down(const basis::astring &subdir, const char *pattern="*")
changes down into a "subdir" of this directory.
static basis::astring absolute_path(const basis::astring &relative_path)
returns the absolute path to a file with "relative_path".
static bool recursive_create(const basis::astring &directory_name)
returns true if the "directory_name" can be created or already exists.
const structures::string_array & directories() const
these are the directory names from the folder.
static bool remove_directory(const basis::astring &path)
returns true if the directory "path" could be removed.
directory & operator=(const directory &to_copy)
Definition directory.cpp:93
const structures::string_array & files() const
returns the list of files that we found in this directory.
const basis::astring & path() const
returns the directory that we manage.
Definition directory.cpp:89
bool move_up(const char *pattern="*")
resets the directory to be its own parent.
const basis::astring & pattern() const
returns the pattern that the directory class scans for.
Definition directory.cpp:91
static basis::astring current()
returns the current directory, as reported by the operating system.
bool rescan()
reads our current directory's contents over again.
bool reset(const basis::astring &path, const char *pattern="*")
gets rid of any current files and rescans the directory at "path".
static bool make_directory(const basis::astring &path)
returns true if the directory "path" could be created.
Provides operations commonly needed on file names.
Definition filename.h:64
bool exists() const
returns true if the file exists.
Definition filename.cpp:426
void join(bool rooted, const structures::string_array &pieces)
undoes a separate() operation to get the filename back.
Definition filename.cpp:503
bool is_normal() const
Definition filename.cpp:357
void separate(bool &rooted, structures::string_array &pieces) const
breaks the filename into its component parts.
Definition filename.cpp:482
bool is_directory() const
Definition filename.cpp:325
const basis::astring & raw() const
returns the astring that we're holding onto for the path.
Definition filename.cpp:97
An array of strings with some additional helpful methods.
#define FUNCDEF(func_in)
FUNCDEF sets the name of a function (and plugs it into the callstack).
Definition enhance_cpp.h:54
#define MAX_ABS_PATH
Definition filename.h:37
void shell_sort(type v[], int n, bool reverse=false)
shell sort algorithm.
Definition sorts.h:55
The guards collection helps in testing preconditions and reporting errors.
Definition array.h:30
void WHACK(contents *&ptr)
deletion with clearing of the pointer.
Definition functions.h:121
A platform independent way to obtain the timestamp of a file.
A logger that sends to the console screen using the standard output device.
A dynamic container class that holds any kind of object via pointers.
Definition amorph.h:55
Support for unicode builds.
Aids in achievement of platform independence.