/* * gnu_key_2_text * * Extracts msgstr from the GNU MO file */ char * gnu_key_2_text(Msg_g_node *gmnp, const char *codeset, struct msg_pack *mp) { char *result, *msgstr; size_t msgstr_len; unsigned int midx; int ret; char *conv_msgstr, *conv_dst; size_t *p; size_t conv_msgstr_len, buflen; iconv_t fd; int conversion, new_encoding; unsigned int num_of_str; #ifdef GETTEXT_DEBUG (void) printf("*************** gnu_key_2_text(" "0x%p, \"%s\", 0x%p)\n", (void *)gmnp, codeset ? codeset : "(null)", (void *)mp); printgnumsg(gmnp, 0); printmp(mp, 0); #endif /* first checks if header entry has been processed */ if (!(gmnp->flag & ST_CHK)) { char *msg_header; msg_header = gnu_msgsearch(gmnp, "", NULL, NULL); ret = parse_header((const char *)msg_header, gmnp); if (ret == -1) { /* fatal error */ DFLTMSG(result, mp->msgid1, mp->msgid2, mp->n, mp->plural); return (result); } gmnp->flag |= ST_CHK; } msgstr = gnu_msgsearch(gmnp, mp->msgid1, &msgstr_len, &midx); if (msgstr == mp->msgid1) { /* not found */ DFLTMSG(result, mp->msgid1, mp->msgid2, mp->n, mp->plural); return (result); } #ifdef GETTEXT_DEBUG printgnumsg(gmnp, 0); #endif if (!gmnp->dst_encoding) { /* * destination encoding has not been set. */ char *dupcodeset = strdup(codeset); if (!dupcodeset) { /* strdup failed */ result = dfltmsgstr(gmnp, msgstr, msgstr_len, mp); return (result); } gmnp->dst_encoding = dupcodeset; if (strcmp(gmnp->dst_encoding, gmnp->src_encoding) == 0) { /* * target encoding and src encoding * are the same. * No conversion required. */ conversion = 0; } else { /* * target encoding is different from * src encoding. * New conversion required. */ /* sanity check */ if (gmnp->fd && (gmnp->fd != (iconv_t)-1)) { (void) iconv_close(gmnp->fd); gmnp->fd = (iconv_t)-1; } if (gmnp->conv_msgstr) free_conv_msgstr(gmnp); conversion = 1; new_encoding = 1; } } else { /* * dst encoding has been already set. */ if (strcmp(gmnp->dst_encoding, codeset) == 0) { /* * dst encoding and target encoding are the same. */ if (strcmp(gmnp->dst_encoding, gmnp->src_encoding) == 0) { /* * dst encoding and src encoding are the same. * No conversion required. */ conversion = 0; } else { /* * dst encoding is different from src encoding. * current conversion is valid. */ conversion = 1; new_encoding = 0; /* checks if iconv_open has succeeded before */ if (gmnp->fd == (iconv_t)-1) { /* * iconv_open should have failed before * Assume this conversion is invalid */ conversion = 0; } else { if (!gmnp->conv_msgstr) { /* * memory allocation for * conv_msgstr should * have failed before. */ new_encoding = 1; if (gmnp->fd) (void) iconv_close( gmnp->fd); gmnp->fd = (iconv_t)-1; } } } } else { /* * dst encoding is different from target encoding. * It has changed since before. */ char *dupcodeset = strdup(codeset); if (!dupcodeset) { result = dfltmsgstr(gmnp, msgstr, msgstr_len, mp); return (result); } free(gmnp->dst_encoding); gmnp->dst_encoding = dupcodeset; if (strcmp(gmnp->dst_encoding, gmnp->src_encoding) == 0) { /* * dst encoding and src encoding are the same. * now, no conversion required. */ conversion = 0; } else { /* * dst encoding is different from src encoding. * new conversion required. */ conversion = 1; new_encoding = 1; } if (gmnp->fd && (gmnp->fd != (iconv_t)-1)) { (void) iconv_close(gmnp->fd); } if (gmnp->fd != (iconv_t)-1) { gmnp->fd = (iconv_t)-1; } if (gmnp->conv_msgstr) free_conv_msgstr(gmnp); } } if (conversion == 0) { /* no conversion */ result = dfltmsgstr(gmnp, msgstr, msgstr_len, mp); return (result); } /* conversion required */ if (new_encoding == 0) { /* dst codeset hasn't been changed since before */ if (!gmnp->conv_msgstr[midx]) { /* this msgstr hasn't been converted yet */ conv_msgstr_len = do_conv(gmnp->fd, &conv_dst, (const char *)msgstr, msgstr_len); if (conv_msgstr_len == (size_t)-1) { result = dfltmsgstr(gmnp, msgstr, msgstr_len, mp); return (result); } buflen = (conv_msgstr_len + sizeof (size_t)); /* allign to sizeof (size_t) */ if (buflen % sizeof (size_t)) buflen += (sizeof (size_t) - (buflen % sizeof (size_t))); p = (size_t *)malloc(buflen); if (!p) { free(conv_dst); result = dfltmsgstr(gmnp, msgstr, msgstr_len, mp); return (result); } *p = conv_msgstr_len; (void) memcpy(p + 1, conv_dst, conv_msgstr_len); free(conv_dst); gmnp->conv_msgstr[midx] = (char *)p; conv_msgstr = (char *)(p + 1); } else { /* this msgstr is in the conversion cache */ /* LINTED */ size_t *cmsg = (size_t *)gmnp->conv_msgstr[midx]; conv_msgstr_len = *cmsg; conv_msgstr = (char *)(cmsg + 1); } result = dfltmsgstr(gmnp, conv_msgstr, conv_msgstr_len, mp); return (result); } /* new conversion */ #ifdef GETTEXT_DEBUG (void) printf("******* calling iconv_open()\n"); (void) printf(" dst: \"%s\", src: \"%s\"\n", gmnp->dst_encoding, gmnp->src_encoding); #endif fd = iconv_open(gmnp->dst_encoding, gmnp->src_encoding); gmnp->fd = fd; if (fd == (iconv_t)-1) { /* * iconv_open() failed. * no conversion */ result = dfltmsgstr(gmnp, msgstr, msgstr_len, mp); return (result); } num_of_str = SWAP(gmnp, gmnp->msg_file_info->num_of_str); gmnp->conv_msgstr = (char **)calloc((size_t)num_of_str, sizeof (char *)); if (!gmnp->conv_msgstr) { /* malloc failed */ result = dfltmsgstr(gmnp, msgstr, msgstr_len, mp); return (result); } conv_msgstr_len = do_conv(gmnp->fd, &conv_dst, (const char *)msgstr, msgstr_len); if (conv_msgstr_len == (size_t)-1) { free_conv_msgstr(gmnp); result = dfltmsgstr(gmnp, msgstr, msgstr_len, mp); return (result); } buflen = (conv_msgstr_len + sizeof (size_t)); /* allign to sizeof (size_t) */ if (buflen % sizeof (size_t)) buflen += (sizeof (size_t) - (buflen % sizeof (size_t))); p = (size_t *)malloc(buflen); if (!p) { free(conv_dst); free_conv_msgstr(gmnp); result = dfltmsgstr(gmnp, msgstr, msgstr_len, mp); return (result); } *p = conv_msgstr_len; (void) memcpy(p + 1, conv_dst, conv_msgstr_len); free(conv_dst); gmnp->conv_msgstr[midx] = (char *)p; conv_msgstr = (char *)(p + 1); result = dfltmsgstr(gmnp, conv_msgstr, conv_msgstr_len, mp); return (result); }
int main(int argc, char **argv) { int ch, i; int opt_l = 0, opt_s = 0, opt_c = 0; char *opt_f = NULL, *opt_t = NULL; FILE *fp; while ((ch=getopt(argc, argv, "cslf:t:")) != -1) { switch (ch) { case 'c': opt_c = 1; break; case 's': opt_s = 1; break; case 'l': /* list */ opt_l = 1; break; case 'f': /* from */ opt_f = strdup(optarg); break; case 't': /* to */ opt_t = strdup(optarg); break; default: usage(); } } argc-=optind; argv+=optind; if (opt_l) { if (argc>0 || opt_s || opt_f != NULL || opt_t != NULL) { warnx("%s: -l should be specified solely.", getprogname()); usage(); } show_codesets(); } else { if (opt_f == NULL || opt_t == NULL) usage(); if (argc == 0) do_conv(stdin, opt_f, opt_t, opt_s, opt_c); else { for (i=0; i<argc; i++) { fp = fopen(argv[i], "r"); if (fp == NULL) errx(EXIT_FAILURE, "%s: %s:%s", getprogname(), argv[i], strerror(errno)); do_conv(fp, opt_f, opt_t, opt_s, opt_c); fclose(fp); } } } return(EXIT_SUCCESS); }