OSDN Git Service

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