OSDN Git Service

deda5c02e894d55a14b7dff021b0434dd93e2bae
[hengband/hengband.git] / src / main / info-initializer.c
1 #include "main/info-initializer.h"
2 #include "dungeon/dungeon.h"
3 #include "grid/feature.h"
4 #include "info-reader/artifact-reader.h"
5 #include "info-reader/dungeon-reader.h"
6 #include "info-reader/ego-reader.h"
7 #include "info-reader/feature-reader.h"
8 #include "info-reader/fixed-map-parser.h"
9 #include "info-reader/general-parser.h"
10 #include "info-reader/kind-reader.h"
11 #include "info-reader/magic-reader.h"
12 #include "info-reader/race-reader.h"
13 #include "info-reader/skill-reader.h"
14 #include "info-reader/vault-reader.h"
15 #include "io/files-util.h"
16 #include "io/uid-checker.h"
17 #include "main/angband-headers.h"
18 #include "monster-race/monster-race.h"
19 #include "object-enchant/object-ego.h"
20 #include "object/object-kind.h"
21 #include "player/player-class.h"
22 #include "player/player-skill.h"
23 #include "room/rooms-vault.h"
24 #include "system/angband-version.h"
25 #include "system/artifact-type-definition.h"
26 #include "util/angband-files.h"
27 #include "view/display-messages.h"
28 #include "world/world.h"
29 #include <sys/stat.h>
30 #ifndef WINDOWS
31 #include <sys/types.h> // Windows \82Å\82Í\8eg\82í\82ê\82Ä\82¢\82È\82¢.
32 #endif
33
34 /*!
35  * @brief \8aî\96{\8fî\95ñ\93Ç\82Ý\8d\9e\82Ý\82Ì\83\81\83C\83\93\83\8b\81[\83`\83\93 /
36  * Initialize misc. values
37  * @param player_ptr \83v\83\8c\81[\83\84\81[\82Ö\82Ì\8eQ\8fÆ\83|\83C\83\93\83^
38  * @return \83G\83\89\81[\83R\81[\83h
39  */
40 errr init_misc(player_type *player_ptr) { return parse_fixed_map(player_ptr, "misc.txt", 0, 0, 0, 0); }
41
42 /*!
43  * @brief raw\83t\83@\83C\83\8b\82©\82ç\82Ì\83f\81[\83^\82Ì\93Ç\82Ý\8eæ\82è\8f\88\97\9d
44  * Initialize the "*_info" array, by parsing a binary "image" file
45  * @param fd \83t\83@\83C\83\8b\83f\83B\83X\83N\83\8a\83v\83^
46  * @param head raw\83t\83@\83C\83\8b\82Ì\83w\83b\83_
47  * @return \83G\83\89\81[\83R\81[\83h
48  */
49 static errr init_info_raw(int fd, angband_header *head)
50 {
51     angband_header test;
52     if (fd_read(fd, (char *)(&test), sizeof(angband_header)) || (test.v_major != head->v_major) || (test.v_minor != head->v_minor)
53         || (test.v_patch != head->v_patch) || (test.info_num != head->info_num) || (test.info_len != head->info_len) || (test.head_size != head->head_size)
54         || (test.info_size != head->info_size)) {
55         return -1;
56     }
57
58     *head = test;
59     C_MAKE(head->info_ptr, head->info_size, char);
60     fd_read(fd, head->info_ptr, head->info_size);
61     if (head->name_size) {
62         C_MAKE(head->name_ptr, head->name_size, char);
63         fd_read(fd, head->name_ptr, head->name_size);
64     }
65
66     if (head->text_size) {
67         C_MAKE(head->text_ptr, head->text_size, char);
68         fd_read(fd, head->text_ptr, head->text_size);
69     }
70
71     if (head->tag_size) {
72         C_MAKE(head->tag_ptr, head->tag_size, char);
73         fd_read(fd, head->tag_ptr, head->tag_size);
74     }
75
76     return 0;
77 }
78
79 static void update_header(angband_header *head, void **info, char **name, char **text, char **tag)
80 {
81     if (info)
82         *info = head->info_ptr;
83
84     if (name)
85         *name = head->name_ptr;
86
87     if (text)
88         *text = head->text_ptr;
89
90     if (tag)
91         *tag = head->tag_ptr;
92 }
93
94 /*!
95  * @brief \83w\83b\83_\8d\\91¢\91Ì\82Ì\8dX\90V
96  * Initialize the header of an *_info.raw file.
97  * @param head raw\83t\83@\83C\83\8b\82Ì\83w\83b\83_
98  * @param num \83f\81[\83^\90\94
99  * @param len \83f\81[\83^\82Ì\92·\82³
100  * @return \83G\83\89\81[\83R\81[\83h
101  */
102 static void init_header(angband_header *head, IDX num, int len)
103 {
104     head->v_major = FAKE_VER_MAJOR;
105     head->v_minor = FAKE_VER_MINOR;
106     head->v_patch = FAKE_VER_PATCH;
107     head->v_extra = 0;
108
109     head->info_num = (IDX)num;
110     head->info_len = len;
111
112     head->head_size = sizeof(angband_header);
113     head->info_size = head->info_num * head->info_len;
114 }
115
116 /*!
117  * @brief \83e\83L\83X\83g\83t\83@\83C\83\8b\82Æraw\83t\83@\83C\83\8b\82Ì\8dX\90V\8e\9e\8d\8f\82ð\94ä\8ar\82·\82é
118  * Find the default paths to all of our important sub-directories.
119  * @param fd \83t\83@\83C\83\8b\83f\83B\83X\83N\83\8a\83v\83^
120  * @param template_file \83t\83@\83C\83\8b\96¼
121  * @return \83e\83L\83X\83g\82Ì\95û\82ª\90V\82µ\82¢\82©\81Araw\83t\83@\83C\83\8b\82ª\82È\82­\8dX\90V\82Ì\95K\97v\82ª\82 \82é\8fê\8d\87-1\81A\8dX\90V\82Ì\95K\97v\82ª\82È\82¢\8fê\8d\870\81B
122  */
123 static errr check_modification_date(int fd, concptr template_file)
124 {
125     struct stat txt_stat, raw_stat;
126     char buf[1024];
127     path_build(buf, sizeof(buf), ANGBAND_DIR_EDIT, template_file);
128     if (stat(buf, &txt_stat))
129         return 0;
130
131     if (fstat(fd, &raw_stat))
132         return -1;
133
134     if (txt_stat.st_mtime > raw_stat.st_mtime)
135         return -1;
136
137     return 0;
138 }
139
140 /*!
141  * @brief \83w\83b\83_\8d\\91¢\91Ì\82Ì\8dX\90V
142  * Initialize the "*_info" array
143  * @param filename \83t\83@\83C\83\8b\96¼(\8ag\92£\8eqtxt/raw)
144  * @param head \8f\88\97\9d\82É\97p\82¢\82é\83w\83b\83_\8d\\91¢\91Ì
145  * @param info \83f\81[\83^\95Û\8aÇ\90æ\82Ì\8d\\91¢\91Ì\83|\83C\83\93\83^
146  * @param name \96¼\8fÌ\97p\89Â\95Ï\95\8e\9a\97ñ\82Ì\95Û\8aÇ\90æ
147  * @param text \83e\83L\83X\83g\97p\89Â\95Ï\95\8e\9a\97ñ\82Ì\95Û\8aÇ\90æ
148  * @param tag \83^\83O\97p\89Â\95Ï\95\8e\9a\97ñ\82Ì\95Û\8aÇ\90æ
149  * @return \83G\83\89\81[\83R\81[\83h
150  * @note
151  * Note that we let each entry have a unique "name" and "text" string,
152  * even if the string happens to be empty (everyone has a unique '\0').
153  */
154 static errr init_info(player_type *player_ptr, concptr filename, angband_header *head, void **info, char **name, char **text, char **tag)
155 {
156     char buf[1024];
157     path_build(buf, sizeof(buf), ANGBAND_DIR_DATA, format(_("%s_j.raw", "%s.raw"), filename));
158     int fd = fd_open(buf, O_RDONLY);
159     errr err = 1;
160     if (fd >= 0) {
161         err = check_modification_date(fd, format("%s.txt", filename));
162         if (!err)
163             err = init_info_raw(fd, head);
164
165         (void)fd_close(fd);
166     }
167
168     BIT_FLAGS file_permission = 0644;
169     if (err == 0) {
170         update_header(head, info, name, text, tag);
171         return 0;
172     }
173
174     C_MAKE(head->info_ptr, head->info_size, char);
175     if (name)
176         C_MAKE(head->name_ptr, FAKE_NAME_SIZE, char);
177
178     if (text)
179         C_MAKE(head->text_ptr, FAKE_TEXT_SIZE, char);
180
181     if (tag)
182         C_MAKE(head->tag_ptr, FAKE_TAG_SIZE, char);
183
184     if (info)
185         *info = head->info_ptr;
186
187     if (name)
188         *name = head->name_ptr;
189
190     if (text)
191         *text = head->text_ptr;
192
193     if (tag)
194         *tag = head->tag_ptr;
195
196     path_build(buf, sizeof(buf), ANGBAND_DIR_EDIT, format("%s.txt", filename));
197     FILE *fp;
198     fp = angband_fopen(buf, "r");
199     if (!fp)
200         quit(format(_("'%s.txt'\83t\83@\83C\83\8b\82ð\83I\81[\83v\83\93\82Å\82«\82Ü\82¹\82ñ\81B", "Cannot open '%s.txt' file."), filename));
201
202     err = init_info_txt(fp, buf, head, head->parse_info_txt);
203     angband_fclose(fp);
204     if (err) {
205         concptr oops;
206         oops = (((err > 0) && (err < PARSE_ERROR_MAX)) ? err_str[err] : _("\96¢\92m\82Ì", "unknown"));
207 #ifdef JP
208         msg_format("'%s.txt'\83t\83@\83C\83\8b\82Ì %d \8ds\96Ú\82É\83G\83\89\81[\81B", filename, error_line);
209 #else
210         msg_format("Error %d at line %d of '%s.txt'.", err, error_line, filename);
211 #endif
212         msg_format(_("\83\8c\83R\81[\83h %d \82Í '%s' \83G\83\89\81[\82ª\82 \82è\82Ü\82·\81B", "Record %d contains a '%s' error."), error_idx, oops);
213         msg_format(_("\8d\\95¶ '%s'\81B", "Parsing '%s'."), buf);
214         msg_print(NULL);
215         quit(format(_("'%s.txt'\83t\83@\83C\83\8b\82É\83G\83\89\81[", "Error in '%s.txt' file."), filename));
216     }
217
218     if (head->retouch)
219         (*head->retouch)(head);
220
221     path_build(buf, sizeof(buf), ANGBAND_DIR_DATA, format(_("%s_j.raw", "%s.raw"), filename));
222     safe_setuid_grab(player_ptr);
223     (void)fd_kill(buf);
224     fd = fd_make(buf, file_permission);
225     safe_setuid_drop();
226     if (fd >= 0) {
227         fd_write(fd, (concptr)(head), head->head_size);
228         fd_write(fd, head->info_ptr, head->info_size);
229         fd_write(fd, head->name_ptr, head->name_size);
230         fd_write(fd, head->text_ptr, head->text_size);
231         fd_write(fd, head->tag_ptr, head->tag_size);
232         (void)fd_close(fd);
233     }
234
235     C_KILL(head->info_ptr, head->info_size, char);
236     if (name)
237         C_KILL(head->name_ptr, FAKE_NAME_SIZE, char);
238
239     if (text)
240         C_KILL(head->text_ptr, FAKE_TEXT_SIZE, char);
241
242     if (tag)
243         C_KILL(head->tag_ptr, FAKE_TAG_SIZE, char);
244
245     path_build(buf, sizeof(buf), ANGBAND_DIR_DATA, format(_("%s_j.raw", "%s.raw"), filename));
246     fd = fd_open(buf, O_RDONLY);
247     if (fd < 0)
248         quit(format(_("'%s_j.raw'\83t\83@\83C\83\8b\82ð\83\8d\81[\83h\82Å\82«\82Ü\82¹\82ñ\81B", "Cannot load '%s.raw' file."), filename));
249
250     err = init_info_raw(fd, head);
251     (void)fd_close(fd);
252     if (err)
253         quit(format(_("'%s_j.raw'\83t\83@\83C\83\8b\82ð\89ð\90Í\82Å\82«\82Ü\82¹\82ñ\81B", "Cannot parse '%s.raw' file."), filename));
254
255     update_header(head, info, name, text, tag);
256     return 0;
257 }
258
259 /*!
260  * @brief \92n\8c`\8fî\95ñ\93Ç\82Ý\8d\9e\82Ý\82Ì\83\81\83C\83\93\83\8b\81[\83`\83\93 /
261  * Initialize the "f_info" array
262  * @return \83G\83\89\81[\83R\81[\83h
263  */
264 errr init_f_info(player_type *player_ptr)
265 {
266     init_header(&f_head, max_f_idx, sizeof(feature_type));
267     f_head.parse_info_txt = parse_f_info;
268     f_head.retouch = retouch_f_info;
269     return init_info(player_ptr, "f_info", &f_head, (void *)&f_info, &f_name, NULL, &f_tag);
270 }
271
272 /*!
273  * @brief \83x\81[\83X\83A\83C\83e\83\80\8fî\95ñ\93Ç\82Ý\8d\9e\82Ý\82Ì\83\81\83C\83\93\83\8b\81[\83`\83\93 /
274  * Initialize the "k_info" array
275  * @return \83G\83\89\81[\83R\81[\83h
276  */
277 errr init_k_info(player_type *player_ptr)
278 {
279     init_header(&k_head, max_k_idx, sizeof(object_kind));
280     k_head.parse_info_txt = parse_k_info;
281     return init_info(player_ptr, "k_info", &k_head, (void *)&k_info, &k_name, &k_text, NULL);
282 }
283
284 /*!
285  * @brief \8cÅ\92è\83A\81[\83e\83B\83t\83@\83N\83g\8fî\95ñ\93Ç\82Ý\8d\9e\82Ý\82Ì\83\81\83C\83\93\83\8b\81[\83`\83\93 /
286  * Initialize the "a_info" array
287  * @return \83G\83\89\81[\83R\81[\83h
288  */
289 errr init_a_info(player_type *player_ptr)
290 {
291     init_header(&a_head, max_a_idx, sizeof(artifact_type));
292     a_head.parse_info_txt = parse_a_info;
293     return init_info(player_ptr, "a_info", &a_head, (void *)&a_info, &a_name, &a_text, NULL);
294 }
295
296 /*!
297  * @brief \8cÅ\92è\83A\81[\83e\83B\83t\83@\83N\83g\8fî\95ñ\93Ç\82Ý\8d\9e\82Ý\82Ì\83\81\83C\83\93\83\8b\81[\83`\83\93 /
298  * Initialize the "e_info" array
299  * @return \83G\83\89\81[\83R\81[\83h
300  */
301 errr init_e_info(player_type *player_ptr)
302 {
303     init_header(&e_head, max_e_idx, sizeof(ego_item_type));
304     e_head.parse_info_txt = parse_e_info;
305     return init_info(player_ptr, "e_info", &e_head, (void *)&e_info, &e_name, &e_text, NULL);
306 }
307
308 /*!
309  * @brief \83\82\83\93\83X\83^\81[\8eí\91°\8fî\95ñ\93Ç\82Ý\8d\9e\82Ý\82Ì\83\81\83C\83\93\83\8b\81[\83`\83\93 /
310  * Initialize the "r_info" array
311  * @return \83G\83\89\81[\83R\81[\83h
312  */
313 errr init_r_info(player_type *player_ptr)
314 {
315     init_header(&r_head, max_r_idx, sizeof(monster_race));
316     r_head.parse_info_txt = parse_r_info;
317     return init_info(player_ptr, "r_info", &r_head, (void *)&r_info, &r_name, &r_text, NULL);
318 }
319
320 /*!
321  * @brief \83_\83\93\83W\83\87\83\93\8fî\95ñ\93Ç\82Ý\8d\9e\82Ý\82Ì\83\81\83C\83\93\83\8b\81[\83`\83\93 /
322  * Initialize the "d_info" array
323  * @return \83G\83\89\81[\83R\81[\83h
324  */
325 errr init_d_info(player_type *player_ptr)
326 {
327     init_header(&d_head, current_world_ptr->max_d_idx, sizeof(dungeon_type));
328     d_head.parse_info_txt = parse_d_info;
329     return init_info(player_ptr, "d_info", &d_head, (void *)&d_info, &d_name, &d_text, NULL);
330 }
331
332 /*!
333  * @brief Vault\8fî\95ñ\93Ç\82Ý\8d\9e\82Ý\82Ì\83\81\83C\83\93\83\8b\81[\83`\83\93 /
334  * Initialize the "v_info" array
335  * @return \83G\83\89\81[\83R\81[\83h
336  * @note
337  * Note that we let each entry have a unique "name" and "text" string,
338  * even if the string happens to be empty (everyone has a unique '\0').
339  */
340 errr init_v_info(player_type *player_ptr)
341 {
342     init_header(&v_head, max_v_idx, sizeof(vault_type));
343     v_head.parse_info_txt = parse_v_info;
344     return init_info(player_ptr, "v_info", &v_head, (void *)&v_info, &v_name, &v_text, NULL);
345 }
346
347 /*!
348  * @brief \90E\8bÆ\8bZ\94\\8fî\95ñ\93Ç\82Ý\8d\9e\82Ý\82Ì\83\81\83C\83\93\83\8b\81[\83`\83\93 /
349  * Initialize the "s_info" array
350  * @return \83G\83\89\81[\83R\81[\83h
351  */
352 errr init_s_info(player_type *player_ptr)
353 {
354     init_header(&s_head, MAX_CLASS, sizeof(skill_table));
355     s_head.parse_info_txt = parse_s_info;
356     return init_info(player_ptr, "s_info", &s_head, (void *)&s_info, NULL, NULL, NULL);
357 }
358
359 /*!
360  * @brief \90E\8bÆ\96\82\96@\8fî\95ñ\93Ç\82Ý\8d\9e\82Ý\82Ì\83\81\83C\83\93\83\8b\81[\83`\83\93 /
361  * Initialize the "m_info" array
362  * @return \83G\83\89\81[\83R\81[\83h
363  */
364 errr init_m_info(player_type *player_ptr)
365 {
366     init_header(&m_head, MAX_CLASS, sizeof(player_magic));
367     m_head.parse_info_txt = parse_m_info;
368     return init_info(player_ptr, "m_info", &m_head, (void *)&m_info, NULL, NULL, NULL);
369 }