1 /* Copyright (C) 1996-2014 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
3 Contributed by Ulrich Drepper <drepper@gnu.org>, 1996.
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; version 2 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, see <http://www.gnu.org/licenses/>. */
29 #include <sys/param.h>
34 #include "../../crypt/md5.h"
35 #include "localedef.h"
36 #include "localeinfo.h"
38 #include "simple-hash.h"
40 #include "locfile-kw.h"
42 #define obstack_chunk_alloc xmalloc
43 #define obstack_chunk_free free
45 /* Temporary storage of the locale data before writing it to the archive. */
46 static locale_data_t to_archive
;
50 locfile_read (struct localedef_t
*result
, const struct charmap_t
*charmap
)
52 const char *filename
= result
->name
;
53 const char *repertoire_name
= result
->repertoire_name
;
54 int locale_mask
= result
->needed
& ~result
->avail
;
55 struct linereader
*ldfile
;
56 int not_here
= ALL_LOCALES
;
58 /* If no repertoire name was specified use the global one. */
59 if (repertoire_name
== NULL
)
60 repertoire_name
= repertoire_global
;
62 /* Open the locale definition file. */
63 ldfile
= lr_open (filename
, locfile_hash
);
66 if (filename
!= NULL
&& filename
[0] != '/')
68 char *i18npath
= getenv ("I18NPATH");
69 if (i18npath
!= NULL
&& *i18npath
!= '\0')
71 const size_t pathlen
= strlen (i18npath
);
72 char i18npathbuf
[pathlen
+ 1];
73 char path
[strlen (filename
) + 1 + pathlen
74 + sizeof ("/locales/") - 1];
76 i18npath
= memcpy (i18npathbuf
, i18npath
, pathlen
+ 1);
79 && (next
= strsep (&i18npath
, ":")) != NULL
)
81 stpcpy (stpcpy (stpcpy (path
, next
), "/locales/"), filename
);
83 ldfile
= lr_open (path
, locfile_hash
);
87 stpcpy (stpcpy (stpcpy (path
, next
), "/"), filename
);
89 ldfile
= lr_open (path
, locfile_hash
);
94 /* Test in the default directory. */
97 char path
[strlen (filename
) + 1 + sizeof (LOCSRCDIR
)];
99 stpcpy (stpcpy (stpcpy (path
, LOCSRCDIR
), "/"), filename
);
100 ldfile
= lr_open (path
, locfile_hash
);
108 /* Parse locale definition file and store result in RESULT. */
111 struct token
*now
= lr_token (ldfile
, charmap
, NULL
, NULL
, verbose
);
112 enum token_t nowtok
= now
->tok
;
115 if (nowtok
== tok_eof
)
118 if (nowtok
== tok_eol
)
119 /* Ignore empty lines. */
124 case tok_escape_char
:
125 case tok_comment_char
:
126 /* We need an argument. */
127 arg
= lr_token (ldfile
, charmap
, NULL
, NULL
, verbose
);
129 if (arg
->tok
!= tok_ident
)
131 SYNTAX_ERROR (_("bad argument"));
135 if (arg
->val
.str
.lenmb
!= 1)
137 lr_error (ldfile
, _("\
138 argument to `%s' must be a single character"),
139 nowtok
== tok_escape_char
140 ? "escape_char" : "comment_char");
142 lr_ignore_rest (ldfile
, 0);
146 if (nowtok
== tok_escape_char
)
147 ldfile
->escape_char
= *arg
->val
.str
.startmb
;
149 ldfile
->comment_char
= *arg
->val
.str
.startmb
;
152 case tok_repertoiremap
:
153 /* We need an argument. */
154 arg
= lr_token (ldfile
, charmap
, NULL
, NULL
, verbose
);
156 if (arg
->tok
!= tok_ident
)
158 SYNTAX_ERROR (_("bad argument"));
162 if (repertoire_name
== NULL
)
164 char *newp
= alloca (arg
->val
.str
.lenmb
+ 1);
166 *((char *) mempcpy (newp
, arg
->val
.str
.startmb
,
167 arg
->val
.str
.lenmb
)) = '\0';
168 repertoire_name
= newp
;
173 ctype_read (ldfile
, result
, charmap
, repertoire_name
,
174 (locale_mask
& CTYPE_LOCALE
) == 0);
175 result
->avail
|= locale_mask
& CTYPE_LOCALE
;
176 not_here
^= CTYPE_LOCALE
;
180 collate_read (ldfile
, result
, charmap
, repertoire_name
,
181 (locale_mask
& COLLATE_LOCALE
) == 0);
182 result
->avail
|= locale_mask
& COLLATE_LOCALE
;
183 not_here
^= COLLATE_LOCALE
;
186 case tok_lc_monetary
:
187 monetary_read (ldfile
, result
, charmap
, repertoire_name
,
188 (locale_mask
& MONETARY_LOCALE
) == 0);
189 result
->avail
|= locale_mask
& MONETARY_LOCALE
;
190 not_here
^= MONETARY_LOCALE
;
194 numeric_read (ldfile
, result
, charmap
, repertoire_name
,
195 (locale_mask
& NUMERIC_LOCALE
) == 0);
196 result
->avail
|= locale_mask
& NUMERIC_LOCALE
;
197 not_here
^= NUMERIC_LOCALE
;
201 time_read (ldfile
, result
, charmap
, repertoire_name
,
202 (locale_mask
& TIME_LOCALE
) == 0);
203 result
->avail
|= locale_mask
& TIME_LOCALE
;
204 not_here
^= TIME_LOCALE
;
207 case tok_lc_messages
:
208 messages_read (ldfile
, result
, charmap
, repertoire_name
,
209 (locale_mask
& MESSAGES_LOCALE
) == 0);
210 result
->avail
|= locale_mask
& MESSAGES_LOCALE
;
211 not_here
^= MESSAGES_LOCALE
;
215 paper_read (ldfile
, result
, charmap
, repertoire_name
,
216 (locale_mask
& PAPER_LOCALE
) == 0);
217 result
->avail
|= locale_mask
& PAPER_LOCALE
;
218 not_here
^= PAPER_LOCALE
;
222 name_read (ldfile
, result
, charmap
, repertoire_name
,
223 (locale_mask
& NAME_LOCALE
) == 0);
224 result
->avail
|= locale_mask
& NAME_LOCALE
;
225 not_here
^= NAME_LOCALE
;
229 address_read (ldfile
, result
, charmap
, repertoire_name
,
230 (locale_mask
& ADDRESS_LOCALE
) == 0);
231 result
->avail
|= locale_mask
& ADDRESS_LOCALE
;
232 not_here
^= ADDRESS_LOCALE
;
235 case tok_lc_telephone
:
236 telephone_read (ldfile
, result
, charmap
, repertoire_name
,
237 (locale_mask
& TELEPHONE_LOCALE
) == 0);
238 result
->avail
|= locale_mask
& TELEPHONE_LOCALE
;
239 not_here
^= TELEPHONE_LOCALE
;
242 case tok_lc_measurement
:
243 measurement_read (ldfile
, result
, charmap
, repertoire_name
,
244 (locale_mask
& MEASUREMENT_LOCALE
) == 0);
245 result
->avail
|= locale_mask
& MEASUREMENT_LOCALE
;
246 not_here
^= MEASUREMENT_LOCALE
;
249 case tok_lc_identification
:
250 identification_read (ldfile
, result
, charmap
, repertoire_name
,
251 (locale_mask
& IDENTIFICATION_LOCALE
) == 0);
252 result
->avail
|= locale_mask
& IDENTIFICATION_LOCALE
;
253 not_here
^= IDENTIFICATION_LOCALE
;
258 syntax error: not inside a locale definition section"));
262 /* The rest of the line must be empty. */
263 lr_ignore_rest (ldfile
, 1);
266 /* We read all of the file. */
269 /* Mark the categories which are not contained in the file. We assume
270 them to be available and the default data will be used. */
271 result
->avail
|= not_here
;
277 /* Semantic checking of locale specifications. */
279 static void (*const check_funcs
[]) (struct localedef_t
*,
280 const struct charmap_t
*) =
282 [LC_CTYPE
] = ctype_finish
,
283 [LC_COLLATE
] = collate_finish
,
284 [LC_MESSAGES
] = messages_finish
,
285 [LC_MONETARY
] = monetary_finish
,
286 [LC_NUMERIC
] = numeric_finish
,
287 [LC_TIME
] = time_finish
,
288 [LC_PAPER
] = paper_finish
,
289 [LC_NAME
] = name_finish
,
290 [LC_ADDRESS
] = address_finish
,
291 [LC_TELEPHONE
] = telephone_finish
,
292 [LC_MEASUREMENT
] = measurement_finish
,
293 [LC_IDENTIFICATION
] = identification_finish
297 check_all_categories (struct localedef_t
*definitions
,
298 const struct charmap_t
*charmap
)
302 for (cnt
= 0; cnt
< sizeof (check_funcs
) / sizeof (check_funcs
[0]); ++cnt
)
303 if (check_funcs
[cnt
] != NULL
)
304 check_funcs
[cnt
] (definitions
, charmap
);
308 /* Writing the locale data files. All files use the same output_path. */
310 static void (*const write_funcs
[]) (struct localedef_t
*,
311 const struct charmap_t
*, const char *) =
313 [LC_CTYPE
] = ctype_output
,
314 [LC_COLLATE
] = collate_output
,
315 [LC_MESSAGES
] = messages_output
,
316 [LC_MONETARY
] = monetary_output
,
317 [LC_NUMERIC
] = numeric_output
,
318 [LC_TIME
] = time_output
,
319 [LC_PAPER
] = paper_output
,
320 [LC_NAME
] = name_output
,
321 [LC_ADDRESS
] = address_output
,
322 [LC_TELEPHONE
] = telephone_output
,
323 [LC_MEASUREMENT
] = measurement_output
,
324 [LC_IDENTIFICATION
] = identification_output
329 write_all_categories (struct localedef_t
*definitions
,
330 const struct charmap_t
*charmap
, const char *locname
,
331 const char *output_path
)
335 for (cnt
= 0; cnt
< sizeof (write_funcs
) / sizeof (write_funcs
[0]); ++cnt
)
336 if (write_funcs
[cnt
] != NULL
)
337 write_funcs
[cnt
] (definitions
, charmap
, output_path
);
341 /* The data has to be added to the archive. Do this now. */
342 struct locarhandle ah
;
344 /* Open the archive. This call never returns if we cannot
345 successfully open the archive. */
347 open_archive (&ah
, false);
349 if (add_locale_to_archive (&ah
, locname
, to_archive
, true) != 0)
350 error (EXIT_FAILURE
, errno
, _("cannot add to locale archive"));
358 /* Return a NULL terminated list of the directories next to output_path
359 that have the same owner, group, permissions and device as output_path. */
361 siblings_uncached (const char *output_path
)
365 struct stat64 output_stat
;
370 /* Remove trailing slashes and trailing pathname component. */
371 len
= strlen (output_path
);
372 base
= (char *) alloca (len
);
373 memcpy (base
, output_path
, len
);
375 while (p
> base
&& p
[-1] == '/')
381 while (p
> base
&& p
[-1] != '/');
387 /* Get the properties of output_path. */
388 if (lstat64 (output_path
, &output_stat
) < 0 || !S_ISDIR (output_stat
.st_mode
))
391 /* Iterate through the directories in base directory. */
392 dirp
= opendir (base
);
399 struct dirent64
*other_dentry
;
400 const char *other_name
;
402 struct stat64 other_stat
;
404 other_dentry
= readdir64 (dirp
);
405 if (other_dentry
== NULL
)
408 other_name
= other_dentry
->d_name
;
409 if (strcmp (other_name
, ".") == 0 || strcmp (other_name
, "..") == 0)
412 other_path
= (char *) xmalloc (len
+ 1 + strlen (other_name
) + 2);
413 memcpy (other_path
, base
, len
);
414 other_path
[len
] = '/';
415 strcpy (other_path
+ len
+ 1, other_name
);
417 if (lstat64 (other_path
, &other_stat
) >= 0
418 && S_ISDIR (other_stat
.st_mode
)
419 && other_stat
.st_uid
== output_stat
.st_uid
420 && other_stat
.st_gid
== output_stat
.st_gid
421 && other_stat
.st_mode
== output_stat
.st_mode
422 && other_stat
.st_dev
== output_stat
.st_dev
)
424 /* Found a subdirectory. Add a trailing slash and store it. */
425 p
= other_path
+ len
+ 1 + strlen (other_name
);
428 elems
= (const char **) xrealloc ((char *) elems
,
429 (nelems
+ 2) * sizeof (char **));
430 elems
[nelems
++] = other_path
;
438 elems
[nelems
] = NULL
;
443 /* Return a NULL terminated list of the directories next to output_path
444 that have the same owner, group, permissions and device as output_path.
445 Cache the result for future calls. */
447 siblings (const char *output_path
)
449 static const char *last_output_path
;
450 static const char **last_result
;
452 if (output_path
!= last_output_path
)
454 if (last_result
!= NULL
)
458 for (p
= last_result
; *p
!= NULL
; p
++)
463 last_output_path
= output_path
;
464 last_result
= siblings_uncached (output_path
);
470 /* Read as many bytes from a file descriptor as possible. */
472 full_read (int fd
, void *bufarea
, size_t nbyte
)
474 char *buf
= (char *) bufarea
;
478 ssize_t retval
= read (fd
, buf
, nbyte
);
487 else if (errno
!= EINTR
)
490 return buf
- (char *) bufarea
;
494 /* Compare the contents of two regular files of the same size. Return 0
495 if they are equal, 1 if they are different, or -1 if an error occurs. */
497 compare_files (const char *filename1
, const char *filename2
, size_t size
,
503 fd1
= open (filename1
, O_RDONLY
);
506 fd2
= open (filename2
, O_RDONLY
);
509 char *buf1
= (char *) xmalloc (2 * blocksize
);
510 char *buf2
= buf1
+ blocksize
;
515 size_t bytes
= (size
< blocksize
? size
: blocksize
);
517 if (full_read (fd1
, buf1
, bytes
) < (ssize_t
) bytes
)
522 if (full_read (fd2
, buf2
, bytes
) < (ssize_t
) bytes
)
527 if (memcmp (buf1
, buf2
, bytes
) != 0)
543 /* True if the locale files use the opposite endianness to the
544 machine running localedef. */
545 bool swap_endianness_p
;
547 /* When called outside a start_locale_structure/end_locale_structure
548 or start_locale_prelude/end_locale_prelude block, record that the
549 next byte in FILE's obstack will be the first byte of a new element.
550 Do likewise for the first call inside a start_locale_structure/
551 end_locale_structure block. */
553 record_offset (struct locale_file
*file
)
555 if (file
->structure_stage
< 2)
557 assert (file
->next_element
< file
->n_elements
);
558 file
->offsets
[file
->next_element
++]
559 = (obstack_object_size (&file
->data
)
560 + (file
->n_elements
+ 2) * sizeof (uint32_t));
561 if (file
->structure_stage
== 1)
562 file
->structure_stage
= 2;
566 /* Initialize FILE for a new output file. N_ELEMENTS is the number
567 of elements in the file. */
569 init_locale_data (struct locale_file
*file
, size_t n_elements
)
571 file
->n_elements
= n_elements
;
572 file
->next_element
= 0;
573 file
->offsets
= xmalloc (sizeof (uint32_t) * n_elements
);
574 obstack_init (&file
->data
);
575 file
->structure_stage
= 0;
578 /* Align the size of FILE's obstack object to BOUNDARY bytes. */
580 align_locale_data (struct locale_file
*file
, size_t boundary
)
582 size_t size
= -obstack_object_size (&file
->data
) & (boundary
- 1);
583 obstack_blank (&file
->data
, size
);
584 memset (obstack_next_free (&file
->data
) - size
, 0, size
);
587 /* Record that FILE's next element contains no data. */
589 add_locale_empty (struct locale_file
*file
)
591 record_offset (file
);
594 /* Record that FILE's next element consists of SIZE bytes starting at DATA. */
596 add_locale_raw_data (struct locale_file
*file
, const void *data
, size_t size
)
598 record_offset (file
);
599 obstack_grow (&file
->data
, data
, size
);
602 /* Finish the current object on OBSTACK and use it as the data for FILE's
605 add_locale_raw_obstack (struct locale_file
*file
, struct obstack
*obstack
)
607 size_t size
= obstack_object_size (obstack
);
608 record_offset (file
);
609 obstack_grow (&file
->data
, obstack_finish (obstack
), size
);
612 /* Use STRING as FILE's next element. */
614 add_locale_string (struct locale_file
*file
, const char *string
)
616 record_offset (file
);
617 obstack_grow (&file
->data
, string
, strlen (string
) + 1);
620 /* Likewise for wide strings. */
622 add_locale_wstring (struct locale_file
*file
, const uint32_t *string
)
624 add_locale_uint32_array (file
, string
, wcslen ((const wchar_t *) string
) + 1);
627 /* Record that FILE's next element is the 32-bit integer VALUE. */
629 add_locale_uint32 (struct locale_file
*file
, uint32_t value
)
631 align_locale_data (file
, LOCFILE_ALIGN
);
632 record_offset (file
);
633 value
= maybe_swap_uint32 (value
);
634 obstack_grow (&file
->data
, &value
, sizeof (value
));
637 /* Record that FILE's next element is an array of N_ELEMS integers
640 add_locale_uint32_array (struct locale_file
*file
,
641 const uint32_t *data
, size_t n_elems
)
643 align_locale_data (file
, LOCFILE_ALIGN
);
644 record_offset (file
);
645 obstack_grow (&file
->data
, data
, n_elems
* sizeof (uint32_t));
646 maybe_swap_uint32_obstack (&file
->data
, n_elems
);
649 /* Record that FILE's next element is the single byte given by VALUE. */
651 add_locale_char (struct locale_file
*file
, char value
)
653 record_offset (file
);
654 obstack_1grow (&file
->data
, value
);
657 /* Start building an element that contains several different pieces of data.
658 Subsequent calls to add_locale_* will add data to the same element up
659 till the next call to end_locale_structure. The element's alignment
660 is dictated by the first piece of data added to it. */
662 start_locale_structure (struct locale_file
*file
)
664 assert (file
->structure_stage
== 0);
665 file
->structure_stage
= 1;
668 /* Finish a structure element that was started by start_locale_structure.
669 Empty structures are OK and behave like add_locale_empty. */
671 end_locale_structure (struct locale_file
*file
)
673 record_offset (file
);
674 assert (file
->structure_stage
== 2);
675 file
->structure_stage
= 0;
678 /* Start building data that goes before the next element's recorded offset.
679 Subsequent calls to add_locale_* will add data to the file without
680 treating any of it as the start of a new element. Calling
681 end_locale_prelude switches back to the usual behavior. */
683 start_locale_prelude (struct locale_file
*file
)
685 assert (file
->structure_stage
== 0);
686 file
->structure_stage
= 3;
689 /* End a block started by start_locale_prelude. */
691 end_locale_prelude (struct locale_file
*file
)
693 assert (file
->structure_stage
== 3);
694 file
->structure_stage
= 0;
697 /* Write a locale file, with contents given by FILE. */
699 write_locale_data (const char *output_path
, int catidx
, const char *category
,
700 struct locale_file
*file
)
705 const char **other_paths
;
710 assert (file
->n_elements
== file
->next_element
);
711 header
[0] = LIMAGIC (catidx
);
712 header
[1] = file
->n_elements
;
713 vec
[0].iov_len
= sizeof (header
);
714 vec
[0].iov_base
= header
;
715 vec
[1].iov_len
= sizeof (uint32_t) * file
->n_elements
;
716 vec
[1].iov_base
= file
->offsets
;
717 vec
[2].iov_len
= obstack_object_size (&file
->data
);
718 vec
[2].iov_base
= obstack_finish (&file
->data
);
719 maybe_swap_uint32_array (vec
[0].iov_base
, 2);
720 maybe_swap_uint32_array (vec
[1].iov_base
, file
->n_elements
);
724 /* The data will be added to the archive. For now we simply
725 generate the image which will be written. First determine
730 to_archive
[catidx
].size
= 0;
731 for (cnt
= 0; cnt
< n_elem
; ++cnt
)
732 to_archive
[catidx
].size
+= vec
[cnt
].iov_len
;
734 /* Allocate the memory for it. */
735 to_archive
[catidx
].addr
= xmalloc (to_archive
[catidx
].size
);
738 for (cnt
= 0, endp
= to_archive
[catidx
].addr
; cnt
< n_elem
; ++cnt
)
739 endp
= mempcpy (endp
, vec
[cnt
].iov_base
, vec
[cnt
].iov_len
);
741 /* Compute the MD5 sum for the data. */
742 __md5_buffer (to_archive
[catidx
].addr
, to_archive
[catidx
].size
,
743 to_archive
[catidx
].sum
);
748 fname
= xmalloc (strlen (output_path
) + 2 * strlen (category
) + 7);
750 /* Normally we write to the directory pointed to by the OUTPUT_PATH.
751 But for LC_MESSAGES we have to take care for the translation
752 data. This means we need to have a directory LC_MESSAGES in
753 which we place the file under the name SYS_LC_MESSAGES. */
754 sprintf (fname
, "%s%s", output_path
, category
);
756 if (strcmp (category
, "LC_MESSAGES") == 0)
760 if (stat64 (fname
, &st
) < 0)
762 if (mkdir (fname
, 0777) >= 0)
768 else if (!S_ISREG (st
.st_mode
))
775 /* Create the locale file with nlinks == 1; this avoids crashing processes
776 which currently use the locale and damaging files belonging to other
781 fd
= creat (fname
, 0666);
786 int save_err
= errno
;
790 sprintf (fname
, "%1$s%2$s/SYS_%2$s", output_path
, category
);
792 fd
= creat (fname
, 0666);
800 WITH_CUR_LOCALE (error (0, save_err
, _("\
801 cannot open output file `%s' for category `%s'"), fname
, category
));
810 maxiov
= sysconf (_SC_UIO_MAXIOV
);
813 /* Write the data using writev. But we must take care for the
814 limitation of the implementation. */
815 for (size_t cnt
= 0; cnt
< n_elem
; cnt
+= step
)
819 step
= MIN (maxiov
, step
);
821 if (writev (fd
, &vec
[cnt
], step
) < 0)
824 WITH_CUR_LOCALE (error (0, errno
, _("\
825 failure while writing data for category `%s'"), category
));
832 /* Compare the file with the locale data files for the same category in
833 other locales, and see if we can reuse it, to save disk space. */
834 other_paths
= siblings (output_path
);
835 if (other_paths
!= NULL
)
837 struct stat64 fname_stat
;
839 if (lstat64 (fname
, &fname_stat
) >= 0
840 && S_ISREG (fname_stat
.st_mode
))
842 const char *fname_tail
= fname
+ strlen (output_path
);
843 const char **other_p
;
848 for (other_p
= other_paths
; *other_p
; other_p
++)
850 seen_inodes
= (ino_t
*) xmalloc (seen_count
* sizeof (ino_t
));
853 for (other_p
= other_paths
; *other_p
; other_p
++)
855 const char *other_path
= *other_p
;
856 size_t other_path_len
= strlen (other_path
);
858 struct stat64 other_fname_stat
;
861 (char *) xmalloc (other_path_len
+ strlen (fname_tail
) + 1);
862 memcpy (other_fname
, other_path
, other_path_len
);
863 strcpy (other_fname
+ other_path_len
, fname_tail
);
865 if (lstat64 (other_fname
, &other_fname_stat
) >= 0
866 && S_ISREG (other_fname_stat
.st_mode
)
867 /* Consider only files on the same device.
868 Otherwise hard linking won't work anyway. */
869 && other_fname_stat
.st_dev
== fname_stat
.st_dev
870 /* Consider only files with the same permissions.
871 Otherwise there are security risks. */
872 && other_fname_stat
.st_uid
== fname_stat
.st_uid
873 && other_fname_stat
.st_gid
== fname_stat
.st_gid
874 && other_fname_stat
.st_mode
== fname_stat
.st_mode
875 /* Don't compare fname with itself. */
876 && other_fname_stat
.st_ino
!= fname_stat
.st_ino
877 /* Files must have the same size, otherwise they
878 cannot be the same. */
879 && other_fname_stat
.st_size
== fname_stat
.st_size
)
881 /* Skip this file if we have already read it (under a
885 for (i
= seen_count
- 1; i
>= 0; i
--)
886 if (seen_inodes
[i
] == other_fname_stat
.st_ino
)
890 /* Now compare fname and other_fname for real. */
893 #ifdef _STATBUF_ST_BLKSIZE
894 blocksize
= MAX (fname_stat
.st_blksize
,
895 other_fname_stat
.st_blksize
);
896 if (blocksize
> 8 * 1024)
897 blocksize
= 8 * 1024;
899 blocksize
= 8 * 1024;
902 if (compare_files (fname
, other_fname
,
903 fname_stat
.st_size
, blocksize
) == 0)
905 /* Found! other_fname is identical to fname. */
906 /* Link other_fname to fname. But use a temporary
907 file, in case hard links don't work on the
908 particular filesystem. */
910 (char *) xmalloc (strlen (fname
) + 4 + 1);
912 strcpy (stpcpy (tmp_fname
, fname
), ".tmp");
914 if (link (other_fname
, tmp_fname
) >= 0)
917 if (rename (tmp_fname
, fname
) < 0)
920 WITH_CUR_LOCALE (error (0, errno
, _("\
921 cannot create output file `%s' for category `%s'"), fname
, category
));
930 /* Don't compare with this file a second time. */
931 seen_inodes
[seen_count
++] = other_fname_stat
.st_ino
;
944 /* General handling of `copy'. */
946 handle_copy (struct linereader
*ldfile
, const struct charmap_t
*charmap
,
947 const char *repertoire_name
, struct localedef_t
*result
,
948 enum token_t token
, int locale
, const char *locale_name
,
954 now
= lr_token (ldfile
, charmap
, result
, NULL
, verbose
);
955 if (now
->tok
!= tok_string
)
956 lr_error (ldfile
, _("expecting string argument for `copy'"));
957 else if (!ignore_content
)
959 if (now
->val
.str
.startmb
== NULL
)
960 lr_error (ldfile
, _("\
961 locale name should consist only of portable characters"));
964 (void) add_to_readlist (locale
, now
->val
.str
.startmb
,
965 repertoire_name
, 1, NULL
);
966 result
->copy_name
[locale
] = now
->val
.str
.startmb
;
970 lr_ignore_rest (ldfile
, now
->tok
== tok_string
);
972 /* The rest of the line must be empty and the next keyword must be
974 while ((now
= lr_token (ldfile
, charmap
, result
, NULL
, verbose
))->tok
975 != tok_end
&& now
->tok
!= tok_eof
)
979 lr_error (ldfile
, _("\
980 no other keyword shall be specified when `copy' is used"));
984 lr_ignore_rest (ldfile
, 0);
987 if (now
->tok
!= tok_eof
)
989 /* Handle `END xxx'. */
990 now
= lr_token (ldfile
, charmap
, result
, NULL
, verbose
);
992 if (now
->tok
!= token
)
993 lr_error (ldfile
, _("\
994 `%1$s' definition does not end with `END %1$s'"), locale_name
);
996 lr_ignore_rest (ldfile
, now
->tok
== token
);
999 /* When we come here we reached the end of the file. */
1000 lr_error (ldfile
, _("%s: premature end of file"), locale_name
);