1 #include "util/angband-files.h"
2 #include "locale/japanese.h"
3 #include "util/string-processor.h"
12 * For those systems that don't have "usleep()" but need it.
14 * Fake "usleep()" function grabbed from the inl netrek server -cba
16 int usleep(ulong usecs)
22 fd_set *no_fds = nullptr;
23 if (usecs > 4000000L) {
24 core(_("不当な usleep() 呼び出し", "Illegal usleep() call"));
27 timer.tv_sec = (usecs / 1000000L);
28 timer.tv_usec = (usecs % 1000000L);
29 if (select(nfds, no_fds, no_fds, no_fds, &timer) < 0) {
40 * Hack -- External functions
43 struct passwd *getpwuid(uid_t uid);
44 struct passwd *getpwnam(concptr name);
48 * Find a default user name from the system.
50 void user_name(char *buf, int id)
53 if ((pw = getpwuid(id))) {
54 (void)strcpy(buf, pw->pw_name);
60 if (islower(buf[0])) {
61 buf[0] = toupper(buf[0]);
67 strcpy(buf, "PLAYER");
72 std::filesystem::path path_parse(std::string_view file)
76 * Extract a "parsed" path from an initial filename
77 * Normally, we simply copy the filename into the buffer
78 * But leading tilde symbols must be handled in a special way
79 * Replace "~user/" by the home directory of the user named "user"
80 * Replace "~/" by the home directory of the current user
82 if (file.empty() || (file[0] != '~')) {
86 auto u = file.data() + 1;
87 auto s = angband_strstr(u, PATH_SEP);
88 constexpr auto user_size = 128;
89 char user[user_size]{};
90 if ((s != nullptr) && (s >= u + user_size)) {
91 throw std::runtime_error("User name is too long!");
96 for (i = 0; u < s; ++i) {
111 pw = getpwuid(getuid());
115 throw std::runtime_error("Failed to get User ID!");
122 std::stringstream ss;
123 ss << pw->pw_dir << s;
135 * Hack -- acquire a "temporary" file name if possible
137 * This filename is always in "system-specific" form.
139 static errr path_temp(char *buf, int max)
141 concptr s = tmpnam(nullptr);
146 #if !defined(WIN32) || (defined(_MSC_VER) && (_MSC_VER >= 1900))
147 (void)strnfmt(buf, max, "%s", s);
149 (void)strnfmt(buf, max, ".%s", s);
157 * @brief OSの差異を吸収しつつ、絶対パスを生成する.
158 * @param buf ファイルのフルを返すバッファ
160 * @param path file 引数があるディレクトリ
161 * @param file ファイル名またはディレクトリ名
162 * @todo buf, max は削除してファイル名が長すぎたら例外を送出する。またreturn で絶対パスを返すように書き換える.
164 std::filesystem::path path_build(const std::filesystem::path &path, std::string_view file)
166 if ((file[0] == '~') || (prefix(file, PATH_SEP)) || path.empty()) {
170 return std::filesystem::path(path).append(file);
173 static std::string make_file_mode(const FileOpenMode mode, const bool is_binary)
175 std::stringstream ss;
177 case FileOpenMode::READ:
180 case FileOpenMode::WRITE:
183 case FileOpenMode::APPEND:
187 throw std::logic_error("Invalid file mode is specified!");
198 * @brief OSごとの差異を吸収してファイルを開く
199 * @param file ファイルの相対パスまたは絶対パス
200 * @param mode ファイルを開くモード
201 * @param is_binary バイナリモードか否か (無指定の場合false:テキストモード)
204 FILE *angband_fopen(const std::filesystem::path &file, const FileOpenMode mode, const bool is_binary)
206 const auto &path = path_parse(file.string());
207 const auto &open_mode = make_file_mode(mode, is_binary);
208 return fopen(path.string().data(), open_mode.data());
212 * Hack -- replacement for "fclose()"
214 errr angband_fclose(FILE *fff)
219 if (fclose(fff) == EOF) {
226 FILE *angband_fopen_temp(char *buf, int max)
228 strncpy(buf, "/tmp/anXXXXXX", max);
229 int fd = mkstemp(buf);
234 return fdopen(fd, "w");
236 #else /* HAVE_MKSTEMP */
237 FILE *angband_fopen_temp(char *buf, int max)
239 if (path_temp(buf, max)) {
242 return angband_fopen(buf, FileOpenMode::WRITE);
244 #endif /* HAVE_MKSTEMP */
247 * Hack -- replacement for "fgets()"
249 * Read a string, without a newline, to a file
251 * Process tabs, replace internal non-printables with '?'
253 errr angband_fgets(FILE *fff, char *buf, ulong n)
261 // Reserve for null termination
264 std::vector<char> file_read__tmp(FILE_READ_BUFF_SIZE);
265 if (fgets(file_read__tmp.data(), file_read__tmp.size(), fff)) {
267 guess_convert_to_system_encoding(file_read__tmp.data(), FILE_READ_BUFF_SIZE);
269 for (s = file_read__tmp.data(); *s; s++) {
273 } else if (*s == '\t') {
279 while (0 != (i % 8)) {
284 else if (iskanji(*s)) {
293 } else if (iskana(*s)) {
301 else if (isprint((unsigned char)*s)) {
323 * Hack -- replacement for "fputs()"
324 * Dump a string, plus a newline, to a file
325 * Process internal weirdness?
327 errr angband_fputs(FILE *fff, concptr buf, ulong n)
330 (void)fprintf(fff, "%s\n", buf);
335 * Several systems have no "O_BINARY" flag
339 #endif /* O_BINARY */
342 * @brief OSごとの差異を吸収してファイルを削除する
343 * @param file ファイルの相対パスまたは絶対パス
345 void fd_kill(std::string_view file)
347 const auto &path = path_parse(file);
348 if (!std::filesystem::exists(path)) {
352 std::filesystem::remove(path);
356 * @brief OSごとの差異を吸収してファイルを移動する
357 * @param from 移動元のファイルの相対パスまたは絶対パス
358 * @param to 移動先のファイルの相対パスまたは絶対パス
360 void fd_move(std::string_view from, std::string_view to)
362 const auto &path_from = path_parse(from);
363 if (!std::filesystem::exists(path_from)) {
367 const auto &path_to = path_parse(to);
368 const auto directory = std::filesystem::path(path_to).remove_filename();
369 if (!std::filesystem::exists(directory)) {
370 std::filesystem::create_directory(directory);
373 std::filesystem::rename(path_from, path_to);
377 * @brief OSごとの差異を吸収してファイルを作成する
378 * @param file 作成先ファイルの相対パスまたは絶対パス
379 * @param can_write_group グループに書き込みを許可するか否か
381 int fd_make(std::string_view file, bool can_write_group)
383 const auto permission = can_write_group ? 0644 : 0664;
384 const auto &path = path_parse(file);
385 return open(path.string().data(), O_CREAT | O_EXCL | O_WRONLY | O_BINARY, permission);
389 * @brief OSごとの差異を吸収してファイルを開く
390 * @param file ファイルの相対パスまたは絶対パス
391 * @param mode ファイルのオープンモード (読み書き、Append/Trunc等)
393 int fd_open(std::string_view file, int mode)
395 const auto &path = path_parse(file);
396 return open(path.string().data(), mode | O_BINARY, 0);
400 * Hack -- attempt to lock a file descriptor
402 * Legal lock types -- F_UNLCK, F_RDLCK, F_WRLCK
404 errr fd_lock(int fd, int what)
406 what = what ? what : 0;
411 #if defined(SET_UID) && defined(LOCK_UN) && defined(LOCK_EX)
412 if (what == F_UNLCK) {
413 (void)flock(fd, LOCK_UN);
415 if (flock(fd, LOCK_EX) != 0) {
425 * Hack -- attempt to seek on a file descriptor
427 errr fd_seek(int fd, ulong n)
433 ulong p = lseek(fd, n, SEEK_SET);
442 * Hack -- attempt to read data from a file descriptor
444 errr fd_read(int fd, char *buf, ulong n)
451 if (read(fd, buf, 16384) != 16384) {
460 if (read(fd, buf, n) != (int)n) {
468 * Hack -- Attempt to write data to a file descriptor
470 errr fd_write(int fd, concptr buf, ulong n)
478 if (write(fd, buf, 16384) != 16384) {
487 if (write(fd, buf, n) != (int)n) {
495 * Hack -- attempt to close a file descriptor
497 errr fd_close(int fd)