📄 dcigettext.c
字号:
known_translation_t, msgid) + msgid_len + domainname_len + 1); if (newp != NULL) { newp->domainname = mempcpy(newp->msgid, msgid1, msgid_len); memcpy(newp->domainname, domainname, domainname_len + 1); newp->category = category; newp->counter = _nl_msg_cat_cntr; newp->domain = domain; newp->translation = retval; newp->translation_length = retlen; /* Insert the entry in the search tree. */ foundp = (struct known_translation_t **) tsearch(newp, &root, transcmp); if (foundp == NULL || *foundp != newp) /* The insert failed. */ free(newp); } } else { /* We can update the existing entry. */ (*foundp)->counter = _nl_msg_cat_cntr; (*foundp)->domain = domain; (*foundp)->translation = retval; (*foundp)->translation_length = retlen; }#endif /* Now deal with plural. */ if (plural) retval = plural_lookup(domain, n, retval, retlen); return retval; } } } /* NOTREACHED */}unsigned char *_nl_find_msg(struct loaded_l10nfile *domain_file, struct binding *domainbinding, const unsigned char *msgid, size_t *lengthp){ struct loaded_domain *domain; size_t act; unsigned char *result; size_t resultlen; if (domain_file->decided == 0) _nl_load_domain(domain_file, domainbinding); if (domain_file->data == NULL) return NULL; domain = (struct loaded_domain *) domain_file->data; /* Locate the MSGID and its translation. */ if (domain->hash_size > 2 && domain->hash_tab != NULL) { /* Use the hashing table. */ nls_uint32 len = strlen(msgid); nls_uint32 hash_val = hash_string(msgid); nls_uint32 idx = hash_val % domain->hash_size; nls_uint32 incr = 1 + (hash_val % (domain->hash_size - 2)); while (1) { nls_uint32 nstr = W(domain->must_swap, domain->hash_tab[idx]); if (nstr == 0) /* Hash table entry is empty. */ return NULL; /* Compare msgid with the original string at index nstr-1. We compare the lengths with >=, not ==, because plural entries are represented by strings with an embedded NUL. */ if (W (domain->must_swap, domain->orig_tab[nstr - 1].length) >= len && (strcmp (msgid, domain->data + W(domain->must_swap, domain->orig_tab[nstr - 1].offset)) == 0)) { act = nstr - 1; goto found; } if (idx >= domain->hash_size - incr) idx -= domain->hash_size - incr; else idx += incr; } /* NOTREACHED */ } else { /* Try the default method: binary search in the sorted array of messages. */ size_t top, bottom; bottom = 0; top = domain->nstrings; while (bottom < top) { int cmp_val; act = (bottom + top) / 2; cmp_val = strcmp(msgid, (domain->data + W(domain->must_swap, domain->orig_tab[act]. offset))); if (cmp_val < 0) top = act; else if (cmp_val > 0) bottom = act + 1; else goto found; } /* No translation was found. */ return NULL; }found: /* The translation was found at index ACT. If we have to convert the string to use a different character set, this is the time. */ result = ((unsigned char *) domain->data + W(domain->must_swap, domain->trans_tab[act].offset)); resultlen = W(domain->must_swap, domain->trans_tab[act].length) + 1;#if HAVE_ICONV if (domain->codeset_cntr != (domainbinding != NULL ? domainbinding->codeset_cntr : 0)) { /* The domain's codeset has changed through bind_textdomain_codeset() since the message catalog was initialized or last accessed. We have to reinitialize the converter. */ _nl_free_domain_conv(domain); _nl_init_domain_conv(domain_file, domain, domainbinding); } if (domain->conv != (iconv_t) - 1) { /* We are supposed to do a conversion. First allocate an appropriate table with the same structure as the table of translations in the file, where we can put the pointers to the converted strings in. There is a slight complication with plural entries. They are represented by consecutive NUL terminated strings. We handle this case by converting RESULTLEN bytes, including NULs. */ if (domain->conv_tab == NULL && ((domain->conv_tab = (unsigned char **) calloc(domain->nstrings, sizeof(unsigned char *))) == NULL)) /* Mark that we didn't succeed allocating a table. */ domain->conv_tab = (unsigned char **) -1; if (domain->conv_tab == (unsigned char **) -1) /* Nothing we can do, no more memory. */ goto converted; if (domain->conv_tab[act] == NULL) { /* We haven't used this string so far, so it is not translated yet. Do this now. */ /* We use a bit more efficient memory handling. We allocate always larger blocks which get used over time. This is faster than many small allocations. */#define INITIAL_BLOCK_SIZE 4080 static unsigned char *freemem; static size_t freemem_size; const unsigned char *inbuf; unsigned char *outbuf; int malloc_count; transmem_block_t *transmem_list = NULL; inbuf = (const unsigned char *) result; outbuf = freemem + sizeof(size_t); malloc_count = 0; while (1) { transmem_block_t *newmem; ICONV_CONST char *inptr = (ICONV_CONST char *) inbuf; size_t inleft = resultlen; char *outptr = (unsigned char *) outbuf; size_t outleft; if (freemem_size < sizeof(size_t)) goto resize_freemem; outleft = freemem_size - sizeof(size_t); if (iconv(domain->conv, &inptr, &inleft, &outptr, &outleft) != (size_t) (-1)) { outbuf = (unsigned char *) outptr; break; } if (errno != E2BIG) { goto converted; }resize_freemem: /* We must allocate a new buffer or resize the old one. */ if (malloc_count > 0) { ++malloc_count; freemem_size = malloc_count * INITIAL_BLOCK_SIZE; newmem = (transmem_block_t *) realloc(transmem_list, freemem_size); } else { malloc_count = 1; freemem_size = INITIAL_BLOCK_SIZE; newmem = (transmem_block_t *) malloc(freemem_size); } if (newmem == NULL) { freemem = NULL; freemem_size = 0; goto converted; } transmem_list = newmem; freemem = newmem; outbuf = freemem + sizeof(size_t); } /* We have now in our buffer a converted string. Put this into the table of conversions. */ *(size_t *) freemem = outbuf - freemem - sizeof(size_t); domain->conv_tab[act] = (unsigned char *) freemem; /* Shrink freemem, but keep it aligned. */ freemem_size -= outbuf - freemem; freemem = outbuf; freemem += freemem_size & (alignof(size_t) - 1); freemem_size = freemem_size & ~(alignof(size_t) - 1); } /* Now domain->conv_tab[act] contains the translation of all the plural variants. */ result = domain->conv_tab[act] + sizeof(size_t); resultlen = *(size_t *) domain->conv_tab[act]; }converted: /* The result string is converted. */#endif /* HAVE_ICONV */ *lengthp = resultlen; return result;}/* Look up a plural variant. */static unsigned char *plural_lookup(struct loaded_l10nfile *domain, unsigned long int n, const unsigned char *translation, size_t translation_len){ struct loaded_domain *domaindata = (struct loaded_domain *) domain->data; unsigned long int indexx; const unsigned char *p; indexx = plural_eval(domaindata->plural, n); if (indexx >= domaindata->nplurals) /* This should never happen. It means the plural expression and the given maximum value do not match. */ indexx = 0; /* Skip INDEX strings at TRANSLATION. */ p = translation; while (indexx-- > 0) { p = strchr(p, '\0'); /* And skip over the NUL byte. */ p++; if (p >= translation + translation_len) /* This should never happen. It means the plural expression evaluated to a value larger than the number of variants available for MSGID1. */ return (unsigned char *) translation; } return (unsigned char *) p;}/* Function to evaluate the plural expression and return an index value. */static unsigned long intplural_eval(struct expression *pexp, unsigned long int n){ switch (pexp->nargs) { case 0: switch (pexp->operation) { case var: return n; case num: return pexp->val.num;default: break; } /* NOTREACHED */ break; case 1: { /* pexp->operation must be lnot. */ unsigned long int arg = plural_eval(pexp->val.args[0], n); return !arg; } case 2: { unsigned long int leftarg = plural_eval(pexp->val.args[0], n); if (pexp->operation == lor) return leftarg || plural_eval(pexp->val. args[1], n); else if (pexp->operation == land) return leftarg && plural_eval(pexp->val. args[1], n); else { unsigned long int rightarg = plural_eval(pexp->val.args[1], n); switch (pexp->operation) { case mult: return leftarg * rightarg; case divide: return leftarg / rightarg; case module: return leftarg % rightarg; case plus: return leftarg + rightarg; case minus: return leftarg - rightarg; case less_than: return leftarg < rightarg; case greater_than: return leftarg > rightarg; case less_or_equal: return leftarg <= rightarg; case greater_or_equal: return leftarg >= rightarg; case equal: return leftarg == rightarg; case not_equal: return leftarg != rightarg;default: break; } } /* NOTREACHED */ break; } case 3: { /* pexp->operation must be qmop. */ unsigned long int boolarg = plural_eval(pexp->val.args[0], n); return plural_eval(pexp->val. args[boolarg ? 1 : 2], n); } } /* NOTREACHED */ return 0;}/* Return string representation of locale CATEGORY. */static const unsigned char *category_to_name(int category){ const unsigned char *retval; switch (category) {#ifdef LC_COLLATE case LC_COLLATE: retval = "LC_COLLATE"; break;#endif#ifdef LC_CTYPE case LC_CTYPE: retval = "LC_CTYPE"; break;#endif#ifdef LC_MONETARY case LC_MONETARY: retval = "LC_MONETARY"; break;#endif#ifdef LC_NUMERIC case LC_NUMERIC: retval = "LC_NUMERIC"; break;#endif#ifdef LC_TIME case LC_TIME: retval = "LC_TIME"; break;#endif#ifdef LC_MESSAGES case LC_MESSAGES: retval = "LC_MESSAGES"; break;#endif#ifdef LC_RESPONSE case LC_RESPONSE: retval = "LC_RESPONSE"; break;#endif#ifdef LC_ALL case LC_ALL: /* This might not make sense but is perhaps better than any other value. */ retval = "LC_ALL"; break;#endifdefault: /* If you have a better idea for a default value let me know. */ retval = "LC_XXX"; } return retval;}/* Guess value of current locale from value of the environment variables. */static const unsigned char *guess_category_value(int category, const unsigned char *categoryname){ const unsigned char *language; const unsigned char *retval; /* Takes precedence to anything else, damn it's what the application wants! * ;-) --pasky */ if (LANGUAGE && *LANGUAGE) return LANGUAGE; /* The highest priority value is the `LANGUAGE' environment variable. But we don't use the value if the currently selected locale is the C locale. This is a GNU extension. */ /* XXX: This GNU extension breaks things for me and I can't see what is it * good for - I think it only makes things more difficult and arcane, since * it requires you to set up more variables than LANGUAGE, it's poorly * documented and so on. If this breaks anything, let me know at * pasky@ucw.cz, I'm really curious. If LANGUAGE exists, we just use it and * do no more tests. This is an ELinks extension. --pasky */ language = getenv("LANGUAGE"); if (language && language[0]) return language; /* We have to proceed with the POSIX methods of looking to `LC_ALL', `LC_xxx', and `LANG'. On some systems this can be done by the `setlocale' function itself. */#if (defined HAVE_SETLOCALE && defined HAVE_LC_MESSAGES && defined HAVE_LOCALE_NULL) retval = setlocale(category, NULL);#else /* Setting of LC_ALL overwrites all other. */ retval = getenv("LC_ALL"); if (retval == NULL || retval[0] == '\0') { /* Next comes the name of the desired category. */ retval = getenv(categoryname); if (retval == NULL || retval[0] == '\0') { /* Last possibility is the LANG environment variable. */ retval = getenv("LANG"); if (retval == NULL || retval[0] == '\0') /* We use C as the default domain. POSIX says this is implementation defined. */ retval = "C"; } }#endif return retval;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -