void po_message_check_all (po_message_t message, po_message_iterator_t iterator, po_xerror_handler_t handler) { message_ty *mp = (message_ty *) message; /* Establish error handler. */ po_xerror = (void (*) (int, const message_ty *, const char *, size_t, size_t, int, const char *)) handler->xerror; po_xerror2 = (void (*) (int, const message_ty *, const char *, size_t, size_t, int, const char *, const message_ty *, const char *, size_t, size_t, int, const char *)) handler->xerror2; /* For plural checking, combine the message and its header into a small, two-element message list. */ { message_ty *header; /* Find the header. */ { message_list_ty *mlp; size_t j; header = NULL; mlp = msgdomain_list_sublist (iterator->file->mdlp, iterator->domain, false); if (mlp != NULL) for (j = 0; j < mlp->nitems; j++) if (is_header (mlp->item[j]) && !mlp->item[j]->obsolete) { header = mlp->item[j]; break; } } { message_ty *items[2]; struct message_list_ty ml; ml.item = items; ml.nitems = 0; ml.nitems_max = 2; ml.use_hashtable = false; if (header != NULL) message_list_append (&ml, header); if (mp != header) message_list_append (&ml, mp); check_message_list (&ml, 1, 1, 1, 0, 0, 0); } } /* Restore error handler. */ po_xerror = textmode_xerror; po_xerror2 = textmode_xerror2; }
void read_resources_file (message_list_ty *mlp, const char *filename) { const char *args[2]; const char *gettextexedir; const char *gettextlibdir; char *assembly_path; const char *libdirs[1]; struct locals locals; /* Prepare arguments. */ args[0] = filename; args[1] = NULL; /* Make it possible to override the .exe location. This is necessary for running the testsuite before "make install". */ gettextexedir = getenv ("GETTEXTCSHARPEXEDIR"); if (gettextexedir == NULL || gettextexedir[0] == '\0') gettextexedir = relocate (LIBDIR "/gettext"); /* Make it possible to override the .dll location. This is necessary for running the testsuite before "make install". */ gettextlibdir = getenv ("GETTEXTCSHARPLIBDIR"); if (gettextlibdir == NULL || gettextlibdir[0] == '\0') gettextlibdir = relocate (LIBDIR); /* Dump the resource and retrieve the resulting output. */ assembly_path = xconcatenated_filename (gettextexedir, "msgunfmt.net", ".exe"); libdirs[0] = gettextlibdir; if (execute_csharp_program (assembly_path, libdirs, 1, args, verbose, false, execute_and_read_po_output, &locals)) /* An error message should already have been provided. */ exit (EXIT_FAILURE); /* Add the output to mlp. */ { message_list_ty *read_mlp = locals.mdlp->item[0]->messages; size_t j; for (j = 0; j < read_mlp->nitems; j++) message_list_append (mlp, read_mlp->item[j]); } free (assembly_path); }
message_list_ty * message_list_copy (message_list_ty *mlp, int copy_level) { message_list_ty *result; size_t j; result = message_list_alloc (mlp->use_hashtable); for (j = 0; j < mlp->nitems; j++) { message_ty *mp = mlp->item[j]; message_list_append (result, copy_level ? mp : message_copy (mp)); } return result; }
/* Reads an existing .mo file and adds the messages to mlp. */ void read_mo_file (message_list_ty *mlp, const char *filename) { FILE *fp; struct binary_mo_file bf; struct mo_file_header header; unsigned int i; static lex_pos_ty pos = { __FILE__, __LINE__ }; if (strcmp (filename, "-") == 0 || strcmp (filename, "/dev/stdin") == 0) { fp = stdin; SET_BINARY (fileno (fp)); } else { fp = fopen (filename, "rb"); if (fp == NULL) error (EXIT_FAILURE, errno, _("error while opening \"%s\" for reading"), filename); } /* Read the file contents into memory. */ read_binary_mo_file (&bf, fp, filename); /* Get a 32-bit number from the file header. */ # define GET_HEADER_FIELD(field) \ get_uint32 (&bf, offsetof (struct mo_file_header, field)) /* We must grope the file to determine which endian it is. Perversity of the universe tends towards maximum, so it will probably not match the currently executing architecture. */ bf.endian = MO_BIG_ENDIAN; header.magic = GET_HEADER_FIELD (magic); if (header.magic != _MAGIC) { bf.endian = MO_LITTLE_ENDIAN; header.magic = GET_HEADER_FIELD (magic); if (header.magic != _MAGIC) { unrecognised: error (EXIT_FAILURE, 0, _("file \"%s\" is not in GNU .mo format"), filename); } } header.revision = GET_HEADER_FIELD (revision); /* We support only the major revisions 0 and 1. */ switch (header.revision >> 16) { case 0: case 1: /* Fill the header parts that apply to major revisions 0 and 1. */ header.nstrings = GET_HEADER_FIELD (nstrings); header.orig_tab_offset = GET_HEADER_FIELD (orig_tab_offset); header.trans_tab_offset = GET_HEADER_FIELD (trans_tab_offset); header.hash_tab_size = GET_HEADER_FIELD (hash_tab_size); header.hash_tab_offset = GET_HEADER_FIELD (hash_tab_offset); for (i = 0; i < header.nstrings; i++) { message_ty *mp; char *msgid; size_t msgid_len; char *msgstr; size_t msgstr_len; /* Read the msgid. */ msgid = get_string (&bf, header.orig_tab_offset + i * 8, &msgid_len); /* Read the msgstr. */ msgstr = get_string (&bf, header.trans_tab_offset + i * 8, &msgstr_len); mp = message_alloc (msgid, (strlen (msgid) + 1 < msgid_len ? msgid + strlen (msgid) + 1 : NULL), msgstr, msgstr_len, &pos); message_list_append (mlp, mp); } switch (header.revision & 0xffff) { case 0: break; case 1: default: /* Fill the header parts that apply to minor revision >= 1. */ header.n_sysdep_segments = GET_HEADER_FIELD (n_sysdep_segments); header.sysdep_segments_offset = GET_HEADER_FIELD (sysdep_segments_offset); header.n_sysdep_strings = GET_HEADER_FIELD (n_sysdep_strings); header.orig_sysdep_tab_offset = GET_HEADER_FIELD (orig_sysdep_tab_offset); header.trans_sysdep_tab_offset = GET_HEADER_FIELD (trans_sysdep_tab_offset); for (i = 0; i < header.n_sysdep_strings; i++) { message_ty *mp; char *msgid; size_t msgid_len; char *msgstr; size_t msgstr_len; nls_uint32 offset; /* Read the msgid. */ offset = get_uint32 (&bf, header.orig_sysdep_tab_offset + i * 4); msgid = get_sysdep_string (&bf, offset, &header, &msgid_len); /* Read the msgstr. */ offset = get_uint32 (&bf, header.trans_sysdep_tab_offset + i * 4); msgstr = get_sysdep_string (&bf, offset, &header, &msgstr_len); mp = message_alloc (msgid, (strlen (msgid) + 1 < msgid_len ? msgid + strlen (msgid) + 1 : NULL), msgstr, msgstr_len, &pos); message_list_append (mlp, mp); } break; } break; default: goto unrecognised; } if (fp != stdin) fclose (fp); }
/* Reads an existing .mo file and adds the messages to mlp. */ void read_mo_file (message_list_ty *mlp, const char *filename) { FILE *fp; struct binary_mo_file bf; struct mo_file_header header; unsigned int i; static lex_pos_ty pos = { __FILE__, __LINE__ }; if (strcmp (filename, "-") == 0 || strcmp (filename, "/dev/stdin") == 0) { fp = stdin; SET_BINARY (fileno (fp)); } else { fp = fopen (filename, "rb"); if (fp == NULL) error (EXIT_FAILURE, errno, _("error while opening \"%s\" for reading"), filename); } /* Read the file contents into memory. */ read_binary_mo_file (&bf, fp, filename); /* Get a 32-bit number from the file header. */ # define GET_HEADER_FIELD(field) \ get_uint32 (&bf, offsetof (struct mo_file_header, field)) /* We must grope the file to determine which endian it is. Perversity of the universe tends towards maximum, so it will probably not match the currently executing architecture. */ bf.endian = MO_BIG_ENDIAN; header.magic = GET_HEADER_FIELD (magic); if (header.magic != _MAGIC) { bf.endian = MO_LITTLE_ENDIAN; header.magic = GET_HEADER_FIELD (magic); if (header.magic != _MAGIC) { unrecognised: error (EXIT_FAILURE, 0, _("file \"%s\" is not in GNU .mo format"), filename); } } header.revision = GET_HEADER_FIELD (revision); /* We support only the major revisions 0 and 1. */ switch (header.revision >> 16) { case 0: case 1: /* Fill the header parts that apply to major revisions 0 and 1. */ header.nstrings = GET_HEADER_FIELD (nstrings); header.orig_tab_offset = GET_HEADER_FIELD (orig_tab_offset); header.trans_tab_offset = GET_HEADER_FIELD (trans_tab_offset); header.hash_tab_size = GET_HEADER_FIELD (hash_tab_size); header.hash_tab_offset = GET_HEADER_FIELD (hash_tab_offset); for (i = 0; i < header.nstrings; i++) { message_ty *mp; char *msgctxt; char *msgid; size_t msgid_len; char *separator; char *msgstr; size_t msgstr_len; /* Read the msgctxt and msgid. */ msgid = get_string (&bf, header.orig_tab_offset + i * 8, &msgid_len); /* Split into msgctxt and msgid. */ separator = strchr (msgid, MSGCTXT_SEPARATOR); if (separator != NULL) { /* The part before the MSGCTXT_SEPARATOR is the msgctxt. */ *separator = '\0'; msgctxt = msgid; msgid = separator + 1; msgid_len -= msgid - msgctxt; } else msgctxt = NULL; /* Read the msgstr. */ msgstr = get_string (&bf, header.trans_tab_offset + i * 8, &msgstr_len); mp = message_alloc (msgctxt, msgid, (strlen (msgid) + 1 < msgid_len ? msgid + strlen (msgid) + 1 : NULL), msgstr, msgstr_len, &pos); message_list_append (mlp, mp); } switch (header.revision & 0xffff) { case 0: break; case 1: default: /* Fill the header parts that apply to minor revision >= 1. */ header.n_sysdep_segments = GET_HEADER_FIELD (n_sysdep_segments); header.sysdep_segments_offset = GET_HEADER_FIELD (sysdep_segments_offset); header.n_sysdep_strings = GET_HEADER_FIELD (n_sysdep_strings); header.orig_sysdep_tab_offset = GET_HEADER_FIELD (orig_sysdep_tab_offset); header.trans_sysdep_tab_offset = GET_HEADER_FIELD (trans_sysdep_tab_offset); for (i = 0; i < header.n_sysdep_strings; i++) { message_ty *mp; char *msgctxt; char *msgid; size_t msgid_len; char *separator; char *msgstr; size_t msgstr_len; nls_uint32 offset; size_t f; /* Read the msgctxt and msgid. */ offset = get_uint32 (&bf, header.orig_sysdep_tab_offset + i * 4); msgid = get_sysdep_string (&bf, offset, &header, &msgid_len); /* Split into msgctxt and msgid. */ separator = strchr (msgid, MSGCTXT_SEPARATOR); if (separator != NULL) { /* The part before the MSGCTXT_SEPARATOR is the msgctxt. */ *separator = '\0'; msgctxt = msgid; msgid = separator + 1; msgid_len -= msgid - msgctxt; } else msgctxt = NULL; /* Read the msgstr. */ offset = get_uint32 (&bf, header.trans_sysdep_tab_offset + i * 4); msgstr = get_sysdep_string (&bf, offset, &header, &msgstr_len); mp = message_alloc (msgctxt, msgid, (strlen (msgid) + 1 < msgid_len ? msgid + strlen (msgid) + 1 : NULL), msgstr, msgstr_len, &pos); /* Only messages with c-format or objc-format annotation are recognized as having system-dependent strings by msgfmt. Which one of the two, we don't know. We have to guess, assuming that c-format is more probable than objc-format and that the .mo was likely produced by "msgfmt -c". */ for (f = format_c; ; f = format_objc) { bool valid = true; struct formatstring_parser *parser = formatstring_parsers[f]; const char *str_end; const char *str; str_end = msgid + msgid_len; for (str = msgid; str < str_end; str += strlen (str) + 1) { char *invalid_reason = NULL; void *descr = parser->parse (str, false, NULL, &invalid_reason); if (descr != NULL) parser->free (descr); else { free (invalid_reason); valid = false; break; } } if (valid) { str_end = msgstr + msgstr_len; for (str = msgstr; str < str_end; str += strlen (str) + 1) { char *invalid_reason = NULL; void *descr = parser->parse (str, true, NULL, &invalid_reason); if (descr != NULL) parser->free (descr); else { free (invalid_reason); valid = false; break; } } } if (valid) { /* Found the most likely among c-format, objc-format. */ mp->is_format[f] = yes; break; } /* Try next f. */ if (f == format_objc) break; } message_list_append (mlp, mp); } break; } break; default: goto unrecognised; } if (fp != stdin) fclose (fp); }