From: Bruno Haible Date: Wed, 5 Sep 2001 12:02:41 +0000 (+0000) Subject: Change the .mo file writer to accept a list of messages, not a hash table. X-Git-Tag: v0.11~518 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=a57087bc91cecd5c058565714777fad7841d0a78;p=thirdparty%2Fgettext.git Change the .mo file writer to accept a list of messages, not a hash table. --- diff --git a/src/ChangeLog b/src/ChangeLog index b3139ee11..e1ea0ca49 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,23 @@ +2001-09-02 Bruno Haible + + * msgfmt.h (struct hashtable_entry): Remove type. + (verbose): New declaration. + * msgfmt.c (msg_domain): Add a message list field. + (verbose): Make non-static. + (main): Pass the message list, not the hash table, to + msgdomain_write_mo. Free the message list when done. + (new_domain): Initialize the message list to empty. + (format_directive_message): Change type of entry to 'message_ty *'. + Store msgid in it. + * write-mo.h: Don't include hash.h. + (msgdomain_write_mo): Change argument type from hash table to message + list. + * write-mo.c (id_str_pair): Add const. + (write_table): Change argument type from hash table to message list. + Use 'message_ty' instead of 'struct hashtable_entry'. + (msgdomain_write_mo): Change argument type from hash table to message + list. + 2001-09-01 Bruno Haible * msgfmt.h: New file, extracted from msgfmt.c. diff --git a/src/msgfmt.c b/src/msgfmt.c index fc5ff6079..68d975714 100644 --- a/src/msgfmt.c +++ b/src/msgfmt.c @@ -75,6 +75,8 @@ static const char *output_file_name; each output file. */ struct msg_domain { + /* List for mapping message IDs to message strings. */ + message_list_ty *mlp; /* Table for mapping message IDs to message strings. */ hash_table symbol_tab; /* Name of domain these ID/String pairs are part of. */ @@ -91,7 +93,7 @@ static struct msg_domain *current_domain; 'error' or 'multiline_error' to emit verbosity messages, because 'error' and 'multiline_error' during PO file parsing cause the program to exit with EXIT_FAILURE. See function lex_end(). */ -static bool verbose = false; +bool verbose = false; /* If true check strings according to format string rules for the language. */ @@ -309,11 +311,13 @@ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\ for (domain = domain_list; domain != NULL; domain = domain->next) { - if (msgdomain_write_mo (&domain->symbol_tab, domain->domain_name, + if (msgdomain_write_mo (domain->mlp, domain->domain_name, domain->file_name)) exit_status = EXIT_FAILURE; - /* Hashing table is not used anmore. */ + /* List is not used anymore. */ + message_list_free (domain->mlp); + /* Hashing table is not used anymore. */ delete_hash (&domain->symbol_tab); } @@ -452,6 +456,7 @@ new_domain (name, file_name) struct msg_domain *domain; domain = (struct msg_domain *) xmalloc (sizeof (struct msg_domain)); + domain->mlp = message_list_alloc (); if (init_hash (&domain->symbol_tab, 100) != 0) error (EXIT_FAILURE, errno, _("while creating hash table")); domain->domain_name = name; @@ -628,10 +633,8 @@ check_pair (msgid, msgid_pos, msgid_plural, msgstr, msgstr_len, msgstr_pos, /* The rest of the file is similar to read-po.c. The differences are: - - The result is a hash table of msgid -> struct hashtable_entry, not - a linear list. This is more efficient, because the order of the - entries does not matter and the only lookup operation performed on - the message set is the duplicate lookup. + - The result is both a message_list_ty and a hash table mapping + msgid -> message_ty. This is useful to speed up the duplicate lookup. - Comments are not stored, they are discarded right away. - The header entry check is performed on-the-fly. */ @@ -729,7 +732,7 @@ format_directive_message (that, msgid_string, msgid_pos, msgid_plural, bool obsolete; { msgfmt_class_ty *this = (msgfmt_class_ty *) that; - struct hashtable_entry *entry; + message_ty *entry; size_t i; /* Don't emit untranslated entries. Also don't emit fuzzy entries, unless @@ -824,12 +827,11 @@ some header fields still have the initial default value")); /* We found a valid pair of msgid/msgstr. Construct struct to describe msgstr definition. */ - entry = (struct hashtable_entry *) xmalloc (sizeof (*entry)); - + entry = message_alloc (NULL, NULL, NULL, 0, msgstr_pos); + entry->msgid = msgid_string; entry->msgid_plural = msgid_plural; entry->msgstr = msgstr_string; entry->msgstr_len = msgstr_len; - entry->pos = *msgstr_pos; /* Do some more checks on both strings. */ check_pair (msgid_string, msgid_pos, msgid_plural, @@ -867,13 +869,13 @@ duplicate message definition")); /* We don't need the just constructed entries' parameter string (allocated in po-gram.y). */ + free (msgid_string); free (msgstr_string); } + else + message_list_append (current_domain->mlp, entry); } - /* We do not need the msgid string in any case. */ - free (msgid_string); - /* Prepare for next message. */ this->is_fuzzy = false; for (i = 0; i < NFORMATS; i++) diff --git a/src/msgfmt.h b/src/msgfmt.h index 1dbe2ec97..758e96f82 100644 --- a/src/msgfmt.h +++ b/src/msgfmt.h @@ -19,16 +19,12 @@ #ifndef _MSGFMT_H #define _MSGFMT_H -#include "pos.h" +#include "message.h" -/* Contains information about the definition of one translation. - The msgid is the hash table key. This is a mini 'struct message_ty'. */ -struct hashtable_entry -{ - char *msgid_plural; /* The msgid's plural, if present. */ - char *msgstr; /* The msgstr strings. */ - size_t msgstr_len; /* The number of bytes in msgstr, including NULs. */ - lex_pos_ty pos; /* Position in the source PO file. */ -}; +/* Be more verbose. Use only 'fprintf' and 'multiline_warning' but not + 'error' or 'multiline_error' to emit verbosity messages, because 'error' + and 'multiline_error' during PO file parsing cause the program to exit + with EXIT_FAILURE. See function lex_end(). */ +extern bool verbose; #endif /* _MSGFMT_H */ diff --git a/src/write-mo.c b/src/write-mo.c index d74de578e..fa1488c4b 100644 --- a/src/write-mo.c +++ b/src/write-mo.c @@ -36,6 +36,7 @@ #include "error.h" #include "hash.h" +#include "message.h" #include "system.h" #include "libgettext.h" @@ -62,18 +63,18 @@ bool no_hash_table; /* Prototypes for local functions. Needed to ensure compiler checking of function argument counts despite of K&R C function definition syntax. */ static int compare_id PARAMS ((const void *pval1, const void *pval2)); -static void write_table PARAMS ((FILE *output_file, hash_table *tab)); +static void write_table PARAMS ((FILE *output_file, message_list_ty *mlp)); /* Define the data structure which we need to represent the data to be written out. */ struct id_str_pair { - char *id; + const char *id; size_t id_len; - char *id_plural; + const char *id_plural; size_t id_plural_len; - char *str; + const char *str; size_t str_len; }; @@ -89,9 +90,9 @@ compare_id (pval1, pval2) static void -write_table (output_file, tab) +write_table (output_file, mlp) FILE *output_file; - hash_table *tab; + message_list_ty *mlp; { static char null = '\0'; /* This should be explained: @@ -115,66 +116,63 @@ write_table (output_file, tab) Formulas: [Knuth, The Art of Computer Programming, Volume 3, Sorting and Searching, 1973, Addison Wesley] */ nls_uint32 hash_tab_size = - (no_hash_table ? 0 : next_prime ((tab->filled * 4) / 3)); + (no_hash_table ? 0 : next_prime ((mlp->nitems * 4) / 3)); nls_uint32 *hash_tab; /* Header of the .mo file to be written. */ struct mo_file_header header; struct id_str_pair *msg_arr; - void *ptr; - size_t cnt; - const void *id; - size_t id_len; - struct hashtable_entry *entry; + size_t cnt, j; + message_ty *entry; struct string_desc sd; /* Fill the structure describing the header. */ header.magic = _MAGIC; /* Magic number. */ header.revision = MO_REVISION_NUMBER; /* Revision number of file format. */ - header.nstrings = tab->filled; /* Number of strings. */ + header.nstrings = mlp->nitems; /* Number of strings. */ header.orig_tab_offset = sizeof (header); /* Offset of table for original string offsets. */ header.trans_tab_offset = sizeof (header) - + tab->filled * sizeof (struct string_desc); + + mlp->nitems * sizeof (struct string_desc); /* Offset of table for translation string offsets. */ header.hash_tab_size = hash_tab_size; /* Size of used hashing table. */ header.hash_tab_offset = no_hash_table ? 0 : sizeof (header) - + 2 * (tab->filled * sizeof (struct string_desc)); + + 2 * (mlp->nitems * sizeof (struct string_desc)); /* Offset of hashing table. */ /* Write the header out. */ fwrite (&header, sizeof (header), 1, output_file); /* Allocate table for the all elements of the hashing table. */ - msg_arr = (struct id_str_pair *) alloca (tab->filled * sizeof (msg_arr[0])); + msg_arr = (struct id_str_pair *) alloca (mlp->nitems * sizeof (msg_arr[0])); - /* Read values from hashing table into array. */ - for (cnt = 0, ptr = NULL; - iterate_table (tab, &ptr, &id, &id_len, (void **) &entry) >= 0; - ++cnt) + /* Read values from list into array. */ + for (j = 0; j < mlp->nitems; j++) { - msg_arr[cnt].id = (char *) id; - msg_arr[cnt].id_len = id_len; - msg_arr[cnt].id_plural = entry->msgid_plural; - msg_arr[cnt].id_plural_len = + entry = mlp->item[j]; + + msg_arr[j].id = entry->msgid; + msg_arr[j].id_len = strlen (entry->msgid) + 1; + msg_arr[j].id_plural = entry->msgid_plural; + msg_arr[j].id_plural_len = (entry->msgid_plural != NULL ? strlen (entry->msgid_plural) + 1 : 0); - msg_arr[cnt].str = entry->msgstr; - msg_arr[cnt].str_len = entry->msgstr_len; + msg_arr[j].str = entry->msgstr; + msg_arr[j].str_len = entry->msgstr_len; } /* Sort the table according to original string. */ - qsort (msg_arr, tab->filled, sizeof (msg_arr[0]), compare_id); + qsort (msg_arr, mlp->nitems, sizeof (msg_arr[0]), compare_id); /* Set offset to first byte after all the tables. */ sd.offset = roundup (sizeof (header) - + tab->filled * sizeof (sd) - + tab->filled * sizeof (sd) + + mlp->nitems * sizeof (sd) + + mlp->nitems * sizeof (sd) + hash_tab_size * sizeof (nls_uint32), alignment); /* Write out length and starting offset for all original strings. */ - for (cnt = 0; cnt < tab->filled; ++cnt) + for (cnt = 0; cnt < mlp->nitems; ++cnt) { /* Subtract 1 because of the terminating NUL. */ sd.length = msg_arr[cnt].id_len + msg_arr[cnt].id_plural_len - 1; @@ -183,7 +181,7 @@ write_table (output_file, tab) } /* Write out length and starting offset for all translation strings. */ - for (cnt = 0; cnt < tab->filled; ++cnt) + for (cnt = 0; cnt < mlp->nitems; ++cnt) { /* Subtract 1 because of the terminating NUL. */ sd.length = msg_arr[cnt].str_len - 1; @@ -200,7 +198,7 @@ write_table (output_file, tab) /* Insert all value in the hash table, following the algorithm described above. */ - for (cnt = 0; cnt < tab->filled; ++cnt) + for (cnt = 0; cnt < mlp->nitems; ++cnt) { nls_uint32 hash_val = hash_string (msg_arr[cnt].id); nls_uint32 idx = hash_val % hash_tab_size; @@ -226,12 +224,12 @@ write_table (output_file, tab) } /* Write bytes to make first string to be aligned. */ - cnt = sizeof (header) + 2 * tab->filled * sizeof (sd) + cnt = sizeof (header) + 2 * mlp->nitems * sizeof (sd) + hash_tab_size * sizeof (nls_uint32); fwrite (&null, 1, roundup (cnt, alignment) - cnt, output_file); /* Now write the original strings. */ - for (cnt = 0; cnt < tab->filled; ++cnt) + for (cnt = 0; cnt < mlp->nitems; ++cnt) { size_t len = msg_arr[cnt].id_len + msg_arr[cnt].id_plural_len; @@ -243,28 +241,26 @@ write_table (output_file, tab) } /* Now write the translation strings. */ - for (cnt = 0; cnt < tab->filled; ++cnt) + for (cnt = 0; cnt < mlp->nitems; ++cnt) { size_t len = msg_arr[cnt].str_len; fwrite (msg_arr[cnt].str, len, 1, output_file); fwrite (&null, 1, roundup (len, alignment) - len, output_file); - - free (msg_arr[cnt].str); } } int -msgdomain_write_mo (tab, domain_name, file_name) - hash_table *tab; +msgdomain_write_mo (mlp, domain_name, file_name) + message_list_ty *mlp; const char *domain_name; const char *file_name; { FILE *output_file; /* If no entry for this domain don't even create the file. */ - if (tab->filled != 0) + if (mlp->nitems != 0) { if (strcmp (domain_name, "-") == 0) { @@ -284,7 +280,7 @@ msgdomain_write_mo (tab, domain_name, file_name) if (output_file != NULL) { - write_table (output_file, tab); + write_table (output_file, mlp); /* Make sure nothing went wrong. */ if (fflush (output_file) || ferror (output_file)) diff --git a/src/write-mo.h b/src/write-mo.h index 973b0047e..2f9c7dbeb 100644 --- a/src/write-mo.h +++ b/src/write-mo.h @@ -22,7 +22,6 @@ #include #include "msgfmt.h" -#include "hash.h" /* Alignment of strings in resulting .mo file. */ extern size_t alignment; @@ -30,12 +29,12 @@ extern size_t alignment; /* True if no hash table in .mo is wanted. */ extern bool no_hash_table; -/* Write a GNU mo file. tab is a hash table containing the messages to be - output, mapping 'const char *msgid' to 'struct hashtable_entry *'. +/* Write a GNU mo file. mlp is a list containing the messages to be output. domain_name is the domain name, file_name is the desired file name. Return 0 if ok, nonzero on error. */ extern int - msgdomain_write_mo PARAMS ((hash_table *tab, const char *domain_name, + msgdomain_write_mo PARAMS ((message_list_ty *mlp, + const char *domain_name, const char *file_name)); #endif /* _WRITE_MO_H */