1 #include "util/angband-files.h"
2 #include "locale/japanese.h"
3 #include "system/angband-exceptions.h"
4 #include "util/string-processor.h"
13 * For those systems that don't have "usleep()" but need it.
15 * Fake "usleep()" function grabbed from the inl netrek server -cba
17 int usleep(ulong usecs)
23 fd_set *no_fds = nullptr;
24 if (usecs > 4000000L) {
25 core(_("不当な usleep() 呼び出し", "Illegal usleep() call"));
28 timer.tv_sec = (usecs / 1000000L);
29 timer.tv_usec = (usecs % 1000000L);
30 if (select(nfds, no_fds, no_fds, no_fds, &timer) < 0) {
41 * Hack -- External functions
44 struct passwd *getpwuid(uid_t uid);
45 struct passwd *getpwnam(concptr name);
49 * Find a default user name from the system.
51 void user_name(char *buf, int id)
54 if ((pw = getpwuid(id))) {
55 (void)strcpy(buf, pw->pw_name);
61 if (islower(buf[0])) {
62 buf[0] = toupper(buf[0]);
68 strcpy(buf, "PLAYER");
73 std::filesystem::path path_parse(const std::filesystem::path &path)
77 * Extract a "parsed" path from an initial filename
78 * Normally, we simply copy the filename into the buffer
79 * But leading tilde symbols must be handled in a special way
80 * Replace "~user/" by the home directory of the user named "user"
81 * Replace "~/" by the home directory of the current user
83 const auto &file = path.string();
84 if (file.empty() || (file[0] != '~')) {
88 auto u = file.data() + 1;
89 auto s = angband_strstr(u, PATH_SEP);
90 constexpr auto user_size = 128;
91 char user[user_size]{};
92 if ((s != nullptr) && (s >= u + user_size)) {
93 THROW_EXCEPTION(std::runtime_error, "User name is too long!");
98 for (i = 0; u < s; ++i) {
113 pw = getpwuid(getuid());
117 THROW_EXCEPTION(std::runtime_error, "Failed to get User ID!");
124 std::stringstream ss;
125 ss << pw->pw_dir << s;
137 * Hack -- acquire a "temporary" file name if possible
139 * This filename is always in "system-specific" form.
141 static errr path_temp(char *buf, int max)
143 concptr s = tmpnam(nullptr);
148 #if !defined(WIN32) || (defined(_MSC_VER) && (_MSC_VER >= 1900))
149 (void)strnfmt(buf, max, "%s", s);
151 (void)strnfmt(buf, max, ".%s", s);
159 * @brief OSの差異を吸収しつつ、絶対パスを生成する.
160 * @param path file 引数があるディレクトリ
161 * @param file ファイル名またはディレクトリ名
163 std::filesystem::path path_build(const std::filesystem::path &path, std::string_view file)
165 if ((file[0] == '~') || (prefix(file, PATH_SEP)) || path.empty()) {
169 const auto path_ret = std::filesystem::path(path).append(file);
170 constexpr auto max_path_length = 1024;
171 const auto path_str = path_ret.string();
172 if (path_str.length() > max_path_length) {
173 THROW_EXCEPTION(std::runtime_error, format("Path is too long! %s", path_str.data()));
179 static std::string make_file_mode(const FileOpenMode mode, const bool is_binary)
181 std::stringstream ss;
183 case FileOpenMode::READ:
186 case FileOpenMode::WRITE:
189 case FileOpenMode::APPEND:
193 THROW_EXCEPTION(std::logic_error, "Invalid file mode is specified!");
204 * @brief OSごとの差異を吸収してファイルを開く
205 * @param path ファイルの相対パスまたは絶対パス
206 * @param mode ファイルを開くモード
207 * @param is_binary バイナリモードか否か (無指定の場合false:テキストモード)
210 FILE *angband_fopen(const std::filesystem::path &path, const FileOpenMode mode, const bool is_binary)
212 const auto &parsed_path = path_parse(path);
213 const auto &open_mode = make_file_mode(mode, is_binary);
214 return fopen(parsed_path.string().data(), open_mode.data());
218 * Hack -- replacement for "fclose()"
220 errr angband_fclose(FILE *fff)
225 if (fclose(fff) == EOF) {
232 FILE *angband_fopen_temp(char *buf, int max)
234 strncpy(buf, "/tmp/anXXXXXX", max);
235 int fd = mkstemp(buf);
240 return fdopen(fd, "w");
242 #else /* HAVE_MKSTEMP */
243 FILE *angband_fopen_temp(char *buf, int max)
245 if (path_temp(buf, max)) {
248 return angband_fopen(buf, FileOpenMode::WRITE);
250 #endif /* HAVE_MKSTEMP */
253 * Hack -- replacement for "fgets()"
255 * Read a string, without a newline, to a file
257 * Process tabs, replace internal non-printables with '?'
259 errr angband_fgets(FILE *fff, char *buf, ulong n)
267 // Reserve for null termination
270 std::vector<char> file_read_tmp(FILE_READ_BUFF_SIZE);
271 if (fgets(file_read_tmp.data(), file_read_tmp.size(), fff)) {
273 guess_convert_to_system_encoding(file_read_tmp.data(), FILE_READ_BUFF_SIZE);
275 for (s = file_read_tmp.data(); *s; s++) {
279 } else if (*s == '\t') {
285 while (0 != (i % 8)) {
290 else if (iskanji(*s)) {
299 } else if (iskana(*s)) {
307 else if (isprint((unsigned char)*s)) {
329 * Hack -- replacement for "fputs()"
330 * Dump a string, plus a newline, to a file
331 * Process internal weirdness?
333 errr angband_fputs(FILE *fff, concptr buf, ulong n)
336 (void)fprintf(fff, "%s\n", buf);
341 * Several systems have no "O_BINARY" flag
345 #endif /* O_BINARY */
348 * @brief OSごとの差異を吸収してファイルを削除する
349 * @param file ファイルの相対パスまたは絶対パス
351 void fd_kill(const std::filesystem::path &path)
353 const auto &parsed_path = path_parse(path);
356 std::filesystem::remove(parsed_path, ec);
360 * @brief OSごとの差異を吸収してファイルを移動する
361 * @param path_from 移動元のファイルの相対パスまたは絶対パス
362 * @param path_to 移動先のファイルの相対パスまたは絶対パス
364 void fd_move(const std::filesystem::path &path_from, const std::filesystem::path &path_to)
366 const auto &abs_path_from = path_parse(path_from);
367 const auto &abs_path_to = path_parse(path_to);
370 std::filesystem::rename(abs_path_from, abs_path_to, ec);
374 * @brief OSごとの差異を吸収してファイルを作成する
375 * @param path 作成先ファイルの相対パスまたは絶対パス
376 * @param can_write_group グループに書き込みを許可するか否か
378 int fd_make(const std::filesystem::path &path, bool can_write_group)
380 const auto permission = can_write_group ? 0644 : 0664;
381 const auto &parsed_path = path_parse(path);
382 return open(parsed_path.string().data(), O_CREAT | O_EXCL | O_WRONLY | O_BINARY, permission);
386 * @brief OSごとの差異を吸収してファイルを開く
387 * @param path ファイルの相対パスまたは絶対パス
388 * @param mode ファイルのオープンモード (読み書き、Append/Trunc等)
390 int fd_open(const std::filesystem::path &path, int mode)
392 const auto &path_abs = path_parse(path);
393 return open(path_abs.string().data(), mode | O_BINARY, 0);
397 * Hack -- attempt to lock a file descriptor
399 * Legal lock types -- F_UNLCK, F_RDLCK, F_WRLCK
401 errr fd_lock(int fd, int what)
403 what = what ? what : 0;
408 #if defined(SET_UID) && defined(LOCK_UN) && defined(LOCK_EX)
409 if (what == F_UNLCK) {
410 (void)flock(fd, LOCK_UN);
412 if (flock(fd, LOCK_EX) != 0) {
422 * Hack -- attempt to seek on a file descriptor
424 errr fd_seek(int fd, ulong n)
430 ulong p = lseek(fd, n, SEEK_SET);
439 * Hack -- attempt to read data from a file descriptor
441 errr fd_read(int fd, char *buf, ulong n)
448 if (read(fd, buf, 16384) != 16384) {
457 if (read(fd, buf, n) != (int)n) {
465 * Hack -- Attempt to write data to a file descriptor
467 errr fd_write(int fd, concptr buf, ulong n)
475 if (write(fd, buf, 16384) != 16384) {
484 if (write(fd, buf, n) != (int)n) {
492 * Hack -- attempt to close a file descriptor
494 errr fd_close(int fd)