OSDN Git Service

Merge branch 'master' of git.osdn.net:/gitroot/hengband/hengband
[hengband/hengband.git] / src / util / angband-files.c
1 #include "util/angband-files.h"
2 #include "util/string-processor.h"
3 #ifdef JP
4 #include "locale/japanese.h"
5 #endif
6
7 #ifdef SET_UID
8
9 #ifndef HAVE_USLEEP
10
11 /*
12  * For those systems that don't have "usleep()" but need it.
13  *
14  * Fake "usleep()" function grabbed from the inl netrek server -cba
15  */
16 int usleep(huge usecs)
17 {
18     struct timeval timer;
19
20     int nfds = 0;
21
22 #ifdef FD_SET
23     fd_set *no_fds = NULL;
24 #else
25     int *no_fds = NULL;
26 #endif
27     if (usecs > 4000000L)
28         core(_("不当な usleep() 呼び出し", "Illegal usleep() call"));
29
30     timer.tv_sec = (usecs / 1000000L);
31     timer.tv_usec = (usecs % 1000000L);
32     if (select(nfds, no_fds, no_fds, no_fds, &timer) < 0) {
33         if (errno != EINTR)
34             return -1;
35     }
36
37     return 0;
38 }
39 #endif
40
41 /*
42  * Hack -- External functions
43  */
44 #ifdef SET_UID
45 extern struct passwd *getpwuid(uid_t uid);
46 extern struct passwd *getpwnam(concptr name);
47 #endif
48
49 /*
50  * Find a default user name from the system.
51  */
52 void user_name(char *buf, int id)
53 {
54     struct passwd *pw;
55     if ((pw = getpwuid(id))) {
56         (void)strcpy(buf, pw->pw_name);
57         buf[16] = '\0';
58
59 #ifdef JP
60         if (!iskanji(buf[0]))
61 #endif
62             if (islower(buf[0]))
63                 buf[0] = toupper(buf[0]);
64
65         return;
66     }
67
68     strcpy(buf, "PLAYER");
69 }
70
71 #endif /* SET_UID */
72
73 #ifdef SET_UID
74 /*
75  * Extract a "parsed" path from an initial filename
76  * Normally, we simply copy the filename into the buffer
77  * But leading tilde symbols must be handled in a special way
78  * Replace "~user/" by the home directory of the user named "user"
79  * Replace "~/" by the home directory of the current user
80  */
81 errr path_parse(char *buf, int max, concptr file)
82 {
83     buf[0] = '\0';
84     if (!file)
85         return -1;
86
87     if (file[0] != '~') {
88         (void)strnfmt(buf, max, "%s", file);
89         return 0;
90     }
91
92     concptr u = file + 1;
93     concptr s = angband_strstr(u, PATH_SEP);
94     char user[128];
95     if (s && (s >= u + sizeof(user)))
96         return 1;
97
98     if (s) {
99         int i;
100         for (i = 0; u < s; ++i)
101             user[i] = *u++;
102         user[i] = '\0';
103         u = user;
104     }
105
106     if (u[0] == '\0')
107         u = getlogin();
108
109     struct passwd *pw;
110     if (u)
111         pw = getpwnam(u);
112     else
113         pw = getpwuid(getuid());
114
115     if (!pw)
116         return 1;
117
118     if (s)
119         strnfmt(buf, max, "%s%s", pw->pw_dir, s);
120     else
121         strnfmt(buf, max, "%s", pw->pw_dir);
122
123     return 0;
124 }
125 #else /* SET_UID */
126 /*
127  * Extract a "parsed" path from an initial filename
128  *
129  * This requires no special processing on simple machines,
130  * except for verifying the size of the filename.
131  */
132 errr path_parse(char *buf, int max, concptr file)
133 {
134     (void)strnfmt(buf, max, "%s", file);
135     return 0;
136 }
137 #endif /* SET_UID */
138
139 #ifndef HAVE_MKSTEMP
140
141 /*
142  * Hack -- acquire a "temporary" file name if possible
143  *
144  * This filename is always in "system-specific" form.
145  */
146 static errr path_temp(char *buf, int max)
147 {
148     concptr s = tmpnam(NULL);
149     if (!s)
150         return -1;
151
152 #if !defined(WIN32) || (defined(_MSC_VER) && (_MSC_VER >= 1900))
153     (void)strnfmt(buf, max, "%s", s);
154 #else
155     (void)strnfmt(buf, max, ".%s", s);
156 #endif
157
158     return 0;
159 }
160 #endif
161
162 /*!
163  * @brief ファイル入出力のためのパス生成する。/ Create a new path by appending a file (or directory) to a path.
164  * @param buf ファイルのフルを返すバッファ
165  * @param max bufのサイズ
166  * @param path ファイルパス
167  * @param file ファイル名
168  * @return エラーコード(ただし常に0を返す)
169  *
170  * This requires no special processing on simple machines, except
171  * for verifying the size of the filename, but note the ability to
172  * bypass the given "path" with certain special file-names.
173  *
174  * Note that the "file" may actually be a "sub-path", including
175  * a path and a file.
176  *
177  * Note that this function yields a path which must be "parsed"
178  * using the "parse" function above.
179  */
180 errr path_build(char *buf, int max, concptr path, concptr file)
181 {
182     if (file[0] == '~') {
183         (void)strnfmt(buf, max, "%s", file);
184     } else if (prefix(file, PATH_SEP) && !streq(PATH_SEP, "")) {
185         (void)strnfmt(buf, max, "%s", file);
186     } else if (!path[0]) {
187         (void)strnfmt(buf, max, "%s", file);
188     } else {
189         (void)strnfmt(buf, max, "%s%s%s", path, PATH_SEP, file);
190     }
191
192     return 0;
193 }
194
195 /*
196  * Hack -- replacement for "fopen()"
197  */
198 FILE *angband_fopen(concptr file, concptr mode)
199 {
200     char buf[1024];
201     if (path_parse(buf, 1024, file))
202         return (NULL);
203
204     return (fopen(buf, mode));
205 }
206
207 /*
208  * Hack -- replacement for "fclose()"
209  */
210 errr angband_fclose(FILE *fff)
211 {
212     if (!fff)
213         return -1;
214     if (fclose(fff) == EOF)
215         return 1;
216     return 0;
217 }
218
219 #ifdef HAVE_MKSTEMP
220 FILE *angband_fopen_temp(char *buf, int max)
221 {
222     strncpy(buf, "/tmp/anXXXXXX", max);
223     int fd = mkstemp(buf);
224     if (fd < 0)
225         return (NULL);
226
227     return (fdopen(fd, "w"));
228 }
229 #else /* HAVE_MKSTEMP */
230 FILE *angband_fopen_temp(char *buf, int max)
231 {
232     if (path_temp(buf, max))
233         return (NULL);
234     return (angband_fopen(buf, "w"));
235 }
236 #endif /* HAVE_MKSTEMP */
237
238 /*
239  * Hack -- replacement for "fgets()"
240  *
241  * Read a string, without a newline, to a file
242  *
243  * Process tabs, strip internal non-printables
244  */
245 errr angband_fgets(FILE *fff, char *buf, huge n)
246 {
247     huge i = 0;
248     char *s;
249     char tmp[1024];
250
251     if (fgets(tmp, 1024, fff)) {
252 #ifdef JP
253         guess_convert_to_system_encoding(tmp, sizeof(tmp));
254 #endif
255         for (s = tmp; *s; s++) {
256             if (*s == '\n') {
257                 buf[i] = '\0';
258                 return 0;
259             } else if (*s == '\t') {
260                 if (i + 8 >= n)
261                     break;
262
263                 buf[i++] = ' ';
264                 while (0 != (i % 8))
265                     buf[i++] = ' ';
266             }
267 #ifdef JP
268             else if (iskanji(*s)) {
269                 if (!s[1])
270                     break;
271                 buf[i++] = *s++;
272                 buf[i++] = *s;
273             } else if (iskana(*s)) {
274                 /* 半角かなに対応 */
275                 buf[i++] = *s;
276                 if (i >= n)
277                     break;
278             }
279 #endif
280             else if (isprint((unsigned char)*s)) {
281                 buf[i++] = *s;
282                 if (i >= n)
283                     break;
284             }
285         }
286
287         buf[i] = '\0';
288         return 0;
289     }
290
291     buf[0] = '\0';
292     return 1;
293 }
294
295 /*
296  * Hack -- replacement for "fputs()"
297  * Dump a string, plus a newline, to a file
298  * Process internal weirdness?
299  */
300 errr angband_fputs(FILE *fff, concptr buf, huge n)
301 {
302     n = n ? n : 0;
303     (void)fprintf(fff, "%s\n", buf);
304     return 0;
305 }
306
307 /*
308  * Several systems have no "O_BINARY" flag
309  */
310 #ifndef O_BINARY
311 #define O_BINARY 0
312 #endif /* O_BINARY */
313
314 /*
315  * Hack -- attempt to delete a file
316  */
317 errr fd_kill(concptr file)
318 {
319     char buf[1024];
320     if (path_parse(buf, 1024, file))
321         return -1;
322
323     (void)remove(buf);
324     return 0;
325 }
326
327 /*
328  * Hack -- attempt to move a file
329  */
330 errr fd_move(concptr file, concptr what)
331 {
332     char buf[1024];
333     char aux[1024];
334     if (path_parse(buf, 1024, file))
335         return -1;
336     if (path_parse(aux, 1024, what))
337         return -1;
338
339     (void)rename(buf, aux);
340     return 0;
341 }
342
343 /*
344  * Hack -- attempt to copy a file
345  */
346 errr fd_copy(concptr file, concptr what)
347 {
348     char buf[1024];
349     char aux[1024];
350     int read_num;
351     int src_fd, dst_fd;
352
353     if (path_parse(buf, 1024, file))
354         return -1;
355     if (path_parse(aux, 1024, what))
356         return -1;
357
358     src_fd = fd_open(buf, O_RDONLY);
359     if (src_fd < 0)
360         return -1;
361
362     dst_fd = fd_open(aux, O_WRONLY | O_TRUNC | O_CREAT);
363     if (dst_fd < 0)
364         return -1;
365
366     while ((read_num = read(src_fd, buf, 1024)) > 0) {
367         int write_num = 0;
368         while (write_num < read_num) {
369             int ret = write(dst_fd, buf + write_num, read_num - write_num);
370             if (ret < 0) {
371                 fd_close(src_fd);
372                 fd_close(dst_fd);
373
374                 return ret;
375             }
376
377             write_num += ret;
378         }
379     }
380
381     fd_close(src_fd);
382     fd_close(dst_fd);
383     return 0;
384 }
385
386 /*
387  * Hack -- attempt to open a file descriptor (create file)
388  * This function should fail if the file already exists
389  * Note that we assume that the file should be "binary"
390  */
391 int fd_make(concptr file, BIT_FLAGS mode)
392 {
393     char buf[1024];
394     if (path_parse(buf, 1024, file))
395         return -1;
396
397     return (open(buf, O_CREAT | O_EXCL | O_WRONLY | O_BINARY, mode));
398 }
399
400 /*
401  * Hack -- attempt to open a file descriptor (existing file)
402  *
403  * Note that we assume that the file should be "binary"
404  */
405 int fd_open(concptr file, int flags)
406 {
407     char buf[1024];
408     if (path_parse(buf, 1024, file))
409         return -1;
410
411     return (open(buf, flags | O_BINARY, 0));
412 }
413
414 /*
415  * Hack -- attempt to lock a file descriptor
416  *
417  * Legal lock types -- F_UNLCK, F_RDLCK, F_WRLCK
418  */
419 errr fd_lock(int fd, int what)
420 {
421     what = what ? what : 0;
422     if (fd < 0)
423         return -1;
424
425 #if defined(SET_UID) && defined(LOCK_UN) && defined(LOCK_EX)
426     if (what == F_UNLCK) {
427         (void)flock(fd, LOCK_UN);
428     } else {
429         if (flock(fd, LOCK_EX) != 0)
430             return 1;
431     }
432 #endif
433
434     return 0;
435 }
436
437 /*
438  * Hack -- attempt to seek on a file descriptor
439  */
440 errr fd_seek(int fd, huge n)
441 {
442     if (fd < 0)
443         return -1;
444
445     huge p = lseek(fd, n, SEEK_SET);
446     if (p != n)
447         return 1;
448
449     return 0;
450 }
451
452 /*
453  * Hack -- attempt to truncate a file descriptor
454  */
455 errr fd_chop(int fd, huge n)
456 {
457     n = n ? n : 0;
458     return fd >= 0 ? 0 : -1;
459 }
460
461 /*
462  * Hack -- attempt to read data from a file descriptor
463  */
464 errr fd_read(int fd, char *buf, huge n)
465 {
466     if (fd < 0)
467         return -1;
468 #ifndef SET_UID
469     while (n >= 16384) {
470         if (read(fd, buf, 16384) != 16384)
471             return 1;
472
473         buf += 16384;
474         n -= 16384;
475     }
476 #endif
477
478     if (read(fd, buf, n) != (int)n)
479         return 1;
480
481     return 0;
482 }
483
484 /*
485  * Hack -- Attempt to write data to a file descriptor
486  */
487 errr fd_write(int fd, concptr buf, huge n)
488 {
489     if (fd < 0)
490         return -1;
491
492 #ifndef SET_UID
493     while (n >= 16384) {
494         if (write(fd, buf, 16384) != 16384)
495             return 1;
496
497         buf += 16384;
498         n -= 16384;
499     }
500 #endif
501
502     if (write(fd, buf, n) != (int)n)
503         return 1;
504
505     return 0;
506 }
507
508 /*
509  * Hack -- attempt to close a file descriptor
510  */
511 errr fd_close(int fd)
512 {
513     if (fd < 0)
514         return -1;
515
516     (void)close(fd);
517     return 0;
518 }