2000-05-03 Ulrich Drepper <drepper@redhat.com>
+ * libio/stdio.h: Make fseeko and ftello prototypes available is
+ __USE_LARGEFILE. Patch by Paul Eggert <eggert@twinsun.com>.
+
+ * sysdeps/generic/dl-environ.c (unsetenv): Follow change to the
+ real unsetenv implementation from 1999-07-29 [PR libc/1714].
+
+2000-05-03 Bruno Haible <haible@clisp.cons.org>
+
+ * intl/dcigettext.c (dcigettext): Do the defaulting of 'domainname'
+ before calling tfind.
+
+2000-03-05 Jakub Jelinek <jakub@redhat.com>
+
+ * resolv/resolv.h (res_querydomain): Remove redefinition to
+ __res_querydomain (reported by Owen Taylor <otaylor@redhat.com>).
+
+2000-05-03 Ulrich Drepper <drepper@redhat.com>
+
+ * po/gl.po: Update from translation team.
+
+ * manual/intro.texi (Program Basics): Change section title.
+ * manual/process.texi: Fix reference.
+ (Executing a File): Add reference exec in other section.
+ * manual/signal.texi: Fix reference.
+ * manual/startup.texi: Document syscall function.
+ Patches by Bryan Henderson <bryanh@giraffe-data.com>.
+
+2000-04-29 Bruno Haible <haible@clisp.cons.org>
+
+ * intl/libintl.h (bind_textdomain_codeset): New declaration.
+ * intl/bindtextdom.c (set_binding_values): New function.
+ (bindtextdomain): Call it.
+ (bind_textdomain_codeset): New function.
+ * intl/dcigettext.c (dcigettext): Pass binding to _nl_find_domain.
+ (free_mem): Free each binding's codeset.
+ * intl/gettextP.h (struct binding): Add codeset field.
+ (_nl_find_domain): Add domainbinding argument.
+ * intl/finddomain.c (_nl_find_domain): Add domainbinding argument.
+ Pass it to _nl_make_l10nflist.
+ * intl/loadinfo.h (struct loaded_l10nfile): Add domainbinding field.
+ (_nl_make_l10nflist): Add domainbinding argument.
+ * intl/l10nflist.c (_nl_make_l10nflist): Add domainbinding argument.
+ * intl/loadmsgcat.c (_nl_load_domain): Look at the domainbinding's
+ codeset when determining outcharset. If !_LIBC && HAVE_ICONV, call
+ locale_charset().
+ * manual/message.texi: New node "Charset conversion in gettext".
+
+2000-04-30 Bruno Haible <haible@clisp.cons.org>
+
+ * catgets/open_catalog.c (__open_catalog): Use __builtin_expect where
+ appropriate. Handle possible __read error.
+
+2000-04-29 Bruno Haible <haible@clisp.cons.org>
+
+ * intl/gettextP.h (__builtin_expect): Define as empty if not a
+ compiler builtin.
+ * intl/loadinfo.h (__builtin_expect): Likewise.
+ * intl/dcigettext.c (dcigettext, _nl_find_msg): Use
+ __builtin_expect where appropriate.
+ * intl/loadmsgcat.c (_nl_load_domain): Likewise.
+ * intl/localealias.c (extend_alias_table): Return an error indicator.
+ (read_alias_file): Bail out if extend_alias_table fails.
+
+2000-04-29 Bruno Haible <haible@clisp.cons.org>
+
+ * intl/loadmsgcat.c: Define _GNU_SOURCE as early as possible.
+ * intl/localealias.c: Likewise.
+
+2000-05-01 Bruno Haible <haible@clisp.cons.org>
+
+ * intl/loadmsgcat.c (_nl_load_domain): Initialize domain->conv_tab.
+ Initialize domain->plural and domain->nplurals even if there is no
+ nullentry.
+
+2000-05-01 Bruno Haible <haible@clisp.cons.org>
+
+ * intl/dcigettext.c (_nl_find_msg): Terminate __gconv loop if return
+ value is == __GCONV_OK or == __GCONV_EMPTY_INPUT, not != __GCONV_OK.
+ In case of failure, goto converted.
+
+2000-05-01 Bruno Haible <haible@clisp.cons.org>
+
+ * wcsmbs/wcsmbsload.c (norm_add_slashes): Move away.
+ * iconv/gconv_int.h (norm_add_slashes): Move to here.
+ * intl/loadmsgcat.c (_nl_load_domain): Normalize strings passed to
+ __gconv_open.
+
+2000-04-29 Bruno Haible <haible@clisp.cons.org>
+
+ * intl/dcigettext.c (transcmp): Compare the domains as well.
+ (dcigettext): Call strlen (msgid1) after testing msgid1 against NULL,
+ not before.
+ * intl/loadmsgcat.c (_nl_load_domain): Deal with EINTR. Include
+ <errno.h>.
+
+2000-05-03 Ulrich Drepper <drepper@redhat.com>
+
* string/bits/string2.h: Declare __strdup and __strndup if necessary.
Reported by Bruno Haible.
__libc_lock_lock (catalog->lock);
/* Check whether there was no other thread faster. */
- if (catalog->status != closed)
+ if (__builtin_expect (catalog->status != closed, 0))
/* While we waited some other thread tried to open the catalog. */
goto unlock_return;
{
const char *run_nlspath = catalog->nlspath;
#define ENOUGH(n) \
- if (bufact + (n) >=bufmax) \
+ if (__builtin_expect (bufact + (n) >= bufmax, 0)) \
{ \
char *old_buf = buf; \
bufmax += 256 + (n); \
{
size_t now = __read (fd, (((char *) &catalog->file_ptr)
+ (st.st_size - todo)), todo);
- if (now == 0)
+ if (now == 0 || now == (size_t) -1)
{
+#ifdef EINTR
+ if (now == (size_t) -1 && errno == EINTR)
+ continue;
+#endif
free ((void *) catalog->file_ptr);
catalog->status = nonexisting;
goto close_unlock_return;
extern struct gconv_module *__gconv_modules_db;
+/* The gconv functions expects the name to be in upper case and complete,
+ including the trailing slashes if necessary. */
+#define norm_add_slashes(str) \
+ ({ \
+ const char *cp = (str); \
+ char *result; \
+ char *tmp; \
+ size_t cnt = 0; \
+ \
+ while (*cp != '\0') \
+ if (*cp++ == '/') \
+ ++cnt; \
+ \
+ tmp = result = alloca (cp - (str) + 3); \
+ cp = (str); \
+ while (*cp != '\0') \
+ *tmp++ = _toupper (*cp++); \
+ if (cnt < 2) \
+ { \
+ *tmp++ = '/'; \
+ if (cnt < 1) \
+ *tmp++ = '/'; \
+ } \
+ *tmp = '\0'; \
+ result; \
+ })
+
+
/* Return in *HANDLE decriptor for transformation from FROMSET to TOSET. */
extern int __gconv_open (const char *__toset, const char *__fromset,
__gconv_t *__handle, int flags)
prefix. So we have to make a difference here. */
#ifdef _LIBC
# define BINDTEXTDOMAIN __bindtextdomain
+# define BIND_TEXTDOMAIN_CODESET __bind_textdomain_codeset
# ifndef strdup
# define strdup(str) __strdup (str)
# endif
#else
# define BINDTEXTDOMAIN bindtextdomain__
+# define BIND_TEXTDOMAIN_CODESET bind_textdomain_codeset__
#endif
-/* Specify that the DOMAINNAME message catalog will be found
- in DIRNAME rather than in the system locale data base. */
-char *
-BINDTEXTDOMAIN (domainname, dirname)
+/* Specifies the directory name *DIRNAMEP and the output codeset *CODESETP
+ to be used for the DOMAINNAME message catalog.
+ If *DIRNAMEP or *CODESETP is NULL, the corresponding attribute is not
+ modified, only the current value is returned.
+ If DIRNAMEP or CODESETP is NULL, the corresponding attribute is neither
+ modified nor returned. */
+static void
+set_binding_values (domainname, dirnamep, codesetp)
const char *domainname;
- const char *dirname;
+ const char **dirnamep;
+ const char **codesetp;
{
struct binding *binding;
- char *result;
+ int modified;
/* Some sanity checks. */
if (domainname == NULL || domainname[0] == '\0')
- return NULL;
+ {
+ if (dirnamep)
+ *dirnamep = NULL;
+ if (codesetp)
+ *codesetp = NULL;
+ return;
+ }
__libc_rwlock_wrlock (_nl_state_lock);
+ modified = 0;
+
for (binding = _nl_domain_bindings; binding != NULL; binding = binding->next)
{
int compare = strcmp (domainname, binding->domainname);
}
}
- if (dirname == NULL)
- /* The current binding has be to returned. */
- result = binding == NULL ? (char *) _nl_default_dirname : binding->dirname;
- else if (binding != NULL)
+ if (binding != NULL)
{
- /* The domain is already bound. If the new value and the old
- one are equal we simply do nothing. Otherwise replace the
- old binding. */
- result = binding->dirname;
- if (strcmp (dirname, result) != 0)
+ if (dirnamep)
{
- if (strcmp (dirname, _nl_default_dirname) == 0)
- result = (char *) _nl_default_dirname;
+ const char *dirname = *dirnamep;
+
+ if (dirname == NULL)
+ /* The current binding has be to returned. */
+ *dirnamep = binding->dirname;
else
{
+ /* The domain is already bound. If the new value and the old
+ one are equal we simply do nothing. Otherwise replace the
+ old binding. */
+ char *result = binding->dirname;
+ if (strcmp (dirname, result) != 0)
+ {
+ if (strcmp (dirname, _nl_default_dirname) == 0)
+ result = (char *) _nl_default_dirname;
+ else
+ {
#if defined _LIBC || defined HAVE_STRDUP
- result = strdup (dirname);
+ result = strdup (dirname);
#else
- size_t len = strlen (dirname) + 1;
- result = (char *) malloc (len);
- if (result != NULL)
- memcpy (result, dirname, len);
+ size_t len = strlen (dirname) + 1;
+ result = (char *) malloc (len);
+ if (__builtin_expect (result != NULL, 1))
+ memcpy (result, dirname, len);
#endif
+ }
+
+ if (__builtin_expect (result != NULL, 1))
+ {
+ if (binding->dirname != _nl_default_dirname)
+ free (binding->dirname);
+
+ binding->dirname = result;
+ modified = 1;
+ }
+ }
+ *dirnamep = result;
}
+ }
+
+ if (codesetp)
+ {
+ const char *codeset = *codesetp;
- if (result != NULL)
+ if (codeset == NULL)
+ /* The current binding has be to returned. */
+ *codesetp = binding->codeset;
+ else
{
- if (binding->dirname != _nl_default_dirname)
- free (binding->dirname);
+ /* The domain is already bound. If the new value and the old
+ one are equal we simply do nothing. Otherwise replace the
+ old binding. */
+ char *result = binding->codeset;
+ if (result == NULL || strcmp (codeset, result) != 0)
+ {
+#if defined _LIBC || defined HAVE_STRDUP
+ result = strdup (codeset);
+#else
+ size_t len = strlen (codeset) + 1;
+ result = (char *) malloc (len);
+ if (__builtin_expect (result != NULL, 1))
+ memcpy (result, codeset, len);
+#endif
- binding->dirname = result;
+ if (__builtin_expect (result != NULL, 1))
+ {
+ if (binding->codeset != NULL)
+ free (binding->codeset);
+
+ binding->codeset = result;
+ modified = 1;
+ }
+ }
+ *codesetp = result;
}
}
}
+ else if ((dirnamep == NULL || *dirnamep == NULL)
+ && (codesetp == NULL || *codesetp == NULL))
+ {
+ /* Simply return the default values. */
+ if (dirnamep)
+ *dirnamep = _nl_default_dirname;
+ if (codesetp)
+ *codesetp = NULL;
+ }
else
{
/* We have to create a new binding. */
struct binding *new_binding =
(struct binding *) malloc (sizeof (*new_binding) + len);
- if (new_binding == NULL)
- result = NULL;
- else
+ if (__builtin_expect (new_binding == NULL, 0))
+ goto failed;
+
+ memcpy (new_binding->domainname, domainname, len);
+
+ if (dirnamep)
{
- memcpy (new_binding->domainname, domainname, len);
+ const char *dirname = *dirnamep;
- if (strcmp (dirname, _nl_default_dirname) == 0)
- result = new_binding->dirname = (char *) _nl_default_dirname;
+ if (dirname == NULL)
+ /* The default value. */
+ dirname = _nl_default_dirname;
else
{
+ if (strcmp (dirname, _nl_default_dirname) == 0)
+ dirname = _nl_default_dirname;
+ else
+ {
+ char *result;
#if defined _LIBC || defined HAVE_STRDUP
- result = new_binding->dirname = strdup (dirname);
+ result = strdup (dirname);
+ if (__builtin_expect (result == NULL, 0))
+ goto failed_dirname;
#else
- len = strlen (dirname) + 1;
- result = new_binding->dirname = (char *) malloc (len);
- if (result != NULL)
- memcpy (new_binding->dirname, dirname, len);
+ size_t len = strlen (dirname) + 1;
+ result = (char *) malloc (len);
+ if (__builtin_expect (result == NULL, 0))
+ goto failed_dirname;
+ memcpy (result, dirname, len);
#endif
+ dirname = result;
+ }
}
+ *dirnamep = dirname;
+ new_binding->dirname = (char *) dirname;
}
+ else
+ /* The default value. */
+ new_binding->dirname = (char *) _nl_default_dirname;
- if (result != NULL)
+ if (codesetp)
{
- /* Now enqueue it. */
- if (_nl_domain_bindings == NULL
- || strcmp (domainname, _nl_domain_bindings->domainname) < 0)
- {
- new_binding->next = _nl_domain_bindings;
- _nl_domain_bindings = new_binding;
- }
- else
+ const char *codeset = *codesetp;
+
+ if (codeset != NULL)
{
- binding = _nl_domain_bindings;
- while (binding->next != NULL
- && strcmp (domainname, binding->next->domainname) > 0)
- binding = binding->next;
+ char *result;
- new_binding->next = binding->next;
- binding->next = new_binding;
+#if defined _LIBC || defined HAVE_STRDUP
+ result = strdup (codeset);
+ if (__builtin_expect (result == NULL, 0))
+ goto failed_codeset;
+#else
+ size_t len = strlen (codeset) + 1;
+ result = (char *) malloc (len);
+ if (__builtin_expect (result == NULL, 0))
+ goto failed_codeset;
+ memcpy (result, codeset, len);
+#endif
+ codeset = result;
}
+ *codesetp = codeset;
+ new_binding->codeset = (char *) codeset;
+ }
+ else
+ new_binding->codeset = NULL;
+
+ /* Now enqueue it. */
+ if (_nl_domain_bindings == NULL
+ || strcmp (domainname, _nl_domain_bindings->domainname) < 0)
+ {
+ new_binding->next = _nl_domain_bindings;
+ _nl_domain_bindings = new_binding;
+ }
+ else
+ {
+ binding = _nl_domain_bindings;
+ while (binding->next != NULL
+ && strcmp (domainname, binding->next->domainname) > 0)
+ binding = binding->next;
+
+ new_binding->next = binding->next;
+ binding->next = new_binding;
+ }
+
+ modified = 1;
+
+ /* Here we deal with memory allocation failures. */
+ if (0)
+ {
+ failed_codeset:
+ if (new_binding->dirname != _nl_default_dirname)
+ free (new_binding->dirname);
+ failed_dirname:
+ free (new_binding);
+ failed:
+ if (dirnamep)
+ *dirnamep = NULL;
+ if (codesetp)
+ *codesetp = NULL;
}
- else if (new_binding != NULL)
- free (new_binding);
}
- /* For a succesful call we flush the caches. */
- if (result != NULL)
+ /* If we modified any binding, we flush the caches. */
+ if (modified)
++_nl_msg_cat_cntr;
__libc_rwlock_unlock (_nl_state_lock);
+}
+
+/* Specify that the DOMAINNAME message catalog will be found
+ in DIRNAME rather than in the system locale data base. */
+char *
+BINDTEXTDOMAIN (domainname, dirname)
+ const char *domainname;
+ const char *dirname;
+{
+ set_binding_values (domainname, &dirname, NULL);
+ return (char *) dirname;
+}
- return result;
+/* Specify the character encoding in which the messages from the
+ DOMAINNAME message catalog will be returned. */
+char *
+BIND_TEXTDOMAIN_CODESET (domainname, codeset)
+ const char *domainname;
+ const char *codeset;
+{
+ set_binding_values (domainname, NULL, &codeset);
+ return (char *) codeset;
}
#ifdef _LIBC
-/* Alias for function name in GNU C Library. */
+/* Aliases for function names in GNU C Library. */
weak_alias (__bindtextdomain, bindtextdomain);
+weak_alias (__bind_textdomain_codeset, bind_textdomain_codeset);
#endif
result = strcmp (s1->msgid, s2->msgid);
if (result == 0)
{
- result = strcmp (s1->msgid, s2->msgid);
+ result = strcmp (s1->domain, s2->domain);
if (result == 0)
{
result = s1->plindex - s2->plindex;
#if defined HAVE_TSEARCH || defined _LIBC
struct known_translation_t *search;
struct known_translation_t **foundp = NULL;
- size_t msgid_len = strlen (msgid1) + 1;
+ size_t msgid_len;
#endif
size_t domainname_len;
__libc_rwlock_rdlock (_nl_state_lock);
+ /* If DOMAINNAME is NULL, we are interested in the default domain. If
+ CATEGORY is not LC_MESSAGES this might not make much sense but the
+ definition left this undefined. */
+ if (domainname == NULL)
+ domainname = _nl_current_default_domain;
+
#if defined HAVE_TSEARCH || defined _LIBC
+ msgid_len = strlen (msgid1) + 1;
+
if (plural == 0)
{
/* Try to find the translation among those which we found at
/* See whether this is a SUID binary or not. */
DETERMINE_SECURE;
- /* If DOMAINNAME is NULL, we are interested in the default domain. If
- CATEGORY is not LC_MESSAGES this might not make much sense but the
- definition left this undefined. */
- if (domainname == NULL)
- domainname = _nl_current_default_domain;
-
/* First find matching binding. */
for (binding = _nl_domain_bindings; binding != NULL; binding = binding->next)
{
/* Find structure describing the message catalog matching the
DOMAINNAME and CATEGORY. */
- domain = _nl_find_domain (dirname, single_locale, xdomainname);
+ domain = _nl_find_domain (dirname, single_locale, xdomainname, binding);
if (domain != NULL)
{
/* Insert the entry in the search tree. */
foundp = (struct known_translation_t **)
tsearch (newp, &root, transcmp);
- if (&newp != foundp)
+ if (__builtin_expect (&newp != foundp, 0))
/* The insert failed. */
free (newp);
}
/* Mark that we didn't succeed allocating a table. */
domain->conv_tab = (char **) -1;
- if (domain->conv_tab == (char **) -1)
+ if (__builtin_expect (domain->conv_tab == (char **) -1, 0))
/* Nothing we can do, no more memory. */
goto converted;
__libc_lock_lock (lock);
+ while (1)
+ {
# ifdef _LIBC
- {
- size_t written;
- int res;
-
- while ((res = __gconv (domain->conv,
- &inbuf, inbuf + resultlen,
- &outbuf, outbuf + freemem_size,
- &written)) == __GCONV_OK)
- {
- if (res != __GCONV_FULL_OUTPUT)
- goto out;
-
- /* We must resize the buffer. */
- freemem_size = MAX (2 * freemem_size, 4064);
- freemem = (char *) malloc (freemem_size);
- if (freemem == NULL)
- goto out;
-
- inbuf = result;
- outbuf = freemem + 4;
- }
- }
+ size_t non_reversible;
+ int res;
+
+ res = __gconv (domain->conv,
+ &inbuf, inbuf + resultlen,
+ &outbuf, outbuf + freemem_size,
+ &non_reversible);
+
+ if (res == __GCONV_OK || res == __GCONV_EMPTY_INPUT)
+ break;
+
+ if (res != __GCONV_FULL_OUTPUT)
+ {
+ __libc_lock_unlock (lock);
+ goto converted;
+ }
+
+ inbuf = result;
# else
# if HAVE_ICONV
- for (;;)
- {
const char *inptr = (const char *) inbuf;
size_t inleft = resultlen;
char *outptr = (char *) outbuf;
size_t outleft = freemem_size;
if (iconv (domain->conv, &inptr, &inleft, &outptr, &outleft)
- != (size_t)(-1))
+ != (size_t) (-1))
{
outbuf = (unsigned char *) outptr;
break;
}
if (errno != E2BIG)
- goto out;
+ {
+ __libc_lock_unlock (lock);
+ goto converted;
+ }
+# endif
+# endif
/* We must resize the buffer. */
freemem_size = 2 * freemem_size;
if (freemem_size < 4064)
freemem_size = 4064;
freemem = (char *) malloc (freemem_size);
- if (freemem == NULL)
- goto out;
+ if (__builtin_expect (freemem == NULL, 0))
+ {
+ __libc_lock_unlock (lock);
+ goto converted;
+ }
outbuf = freemem + 4;
}
-# endif
-# endif
/* We have now in our buffer a converted string. Put this
into the table of conversions. */
/* Shrink freemem, but keep it aligned. */
freemem_size -= outbuf - freemem;
freemem = outbuf;
- freemem += freemem_size & 3;
- freemem_size = freemem_size & ~3;
+ freemem += freemem_size & (__alignof__ (nls_uint32) - 1);
+ freemem_size = freemem_size & ~ (__alignof__ (nls_uint32) - 1);
- out:
__libc_lock_unlock (lock);
}
struct binding *runp;
for (runp = _nl_domain_bindings; runp != NULL; runp = runp->next)
- if (runp->dirname != _nl_default_dirname)
- /* Yes, this is a pointer comparison. */
- free (runp->dirname);
+ {
+ if (runp->dirname != _nl_default_dirname)
+ /* Yes, this is a pointer comparison. */
+ free (runp->dirname);
+ if (runp->codeset != NULL)
+ free (runp->codeset);
+ }
if (_nl_current_default_domain != _nl_default_default_domain)
/* Yes, again a pointer comparison. */
free ((char *) _nl_current_default_domain);
- /* Remove the search tree with the know translations. */
+ /* Remove the search tree with the known translations. */
__tdestroy (root, free);
}
established bindings. */
struct loaded_l10nfile *
internal_function
-_nl_find_domain (dirname, locale, domainname)
+_nl_find_domain (dirname, locale, domainname, domainbinding)
const char *dirname;
char *locale;
const char *domainname;
+ struct binding *domainbinding;
{
struct loaded_l10nfile *retval;
const char *language;
be one data set in the list of loaded domains. */
retval = _nl_make_l10nflist (&_nl_loaded_domains, dirname,
strlen (dirname) + 1, 0, locale, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, domainname, 0);
+ NULL, NULL, NULL, NULL, NULL, domainname,
+ domainbinding, 0);
if (retval != NULL)
{
/* We know something about this locale. */
retval = _nl_make_l10nflist (&_nl_loaded_domains, dirname,
strlen (dirname) + 1, mask, language, territory,
codeset, normalized_codeset, modifier, special,
- sponsor, revision, domainname, 1);
+ sponsor, revision, domainname, domainbinding,
+ 1);
if (retval == NULL)
/* This means we are out of core. */
return NULL;
# define internal_function
#endif
+/* Tell the compiler when a conditional or integer expression is
+ almost always true or almost always false. */
+#ifndef HAVE_BUILTIN_EXPECT
+# define __builtin_expect(expr, val) (expr)
+#endif
+
#ifndef W
# define W(flag, data) ((flag) ? SWAP (data) : (data))
#endif
{
struct binding *next;
char *dirname;
+ char *codeset;
#ifdef __GNUC__
char domainname[0];
#else
struct loaded_l10nfile *_nl_find_domain PARAMS ((const char *__dirname,
char *__locale,
- const char *__domainname))
+ const char *__domainname,
+ struct binding *__domainbinding))
internal_function;
void _nl_load_domain PARAMS ((struct loaded_l10nfile *__domain))
internal_function;
struct loaded_l10nfile *
_nl_make_l10nflist (l10nfile_list, dirlist, dirlist_len, mask, language,
territory, codeset, normalized_codeset, modifier, special,
- sponsor, revision, filename, do_allocate)
+ sponsor, revision, filename, domainbinding, do_allocate)
struct loaded_l10nfile **l10nfile_list;
const char *dirlist;
size_t dirlist_len;
const char *sponsor;
const char *revision;
const char *filename;
+ struct binding *domainbinding;
int do_allocate;
{
char *abs_filename;
return NULL;
retval->filename = abs_filename;
+ retval->domainbinding = domainbinding;
retval->decided = (__argz_count (dirlist, dirlist_len) != 1
|| ((mask & XPG_CODESET) != 0
&& (mask & XPG_NORM_CODESET) != 0));
= _nl_make_l10nflist (l10nfile_list, dir, strlen (dir) + 1, cnt,
language, territory, codeset,
normalized_codeset, modifier, special,
- sponsor, revision, filename, 1);
+ sponsor, revision, filename, domainbinding,
+ 1);
}
retval->successor[entries] = NULL;
extern char *bindtextdomain (__const char *__domainname,
__const char *__dirname) __THROW;
+/* Specify the character encoding in which the messages from the
+ DOMAINNAME message catalog will be returned. */
+extern char *bind_textdomain_codeset (__const char *__domainname,
+ __const char *__codeset) __THROW;
+
/* Optimized version of the function above. */
#if defined __OPTIMIZE__
# define internal_function
#endif
+/* Tell the compiler when a conditional or integer expression is
+ almost always true or almost always false. */
+#ifndef HAVE_BUILTIN_EXPECT
+# define __builtin_expect(expr, val) (expr)
+#endif
+
/* Encoding of locale name parts. */
#define CEN_REVISION 1
#define CEN_SPONSOR 2
struct loaded_l10nfile
{
const char *filename;
+ struct binding *domainbinding;
int decided;
const void *data;
const char *normalized_codeset,
const char *modifier, const char *special,
const char *sponsor, const char *revision,
- const char *filename, int do_allocate));
+ const char *filename,
+ struct binding *domainbinding, int do_allocate));
extern const char *_nl_expand_alias PARAMS ((const char *name));
write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
+/* Tell glibc's <string.h> to provide a prototype for mempcpy().
+ This must come before <config.h> because <config.h> may include
+ <features.h>, and once <features.h> has been included, it's too late. */
+#ifndef _GNU_SOURCE
+# define _GNU_SOURCE 1
+#endif
+
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <ctype.h>
+#include <errno.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#endif
#if defined HAVE_STRING_H || defined _LIBC
-# ifndef _GNU_SOURCE
-# define _GNU_SOURCE 1
-# endif
# include <string.h>
#else
# include <strings.h>
return;
/* We must know about the size of the file. */
- if (fstat (fd, &st) != 0
- || (size = (size_t) st.st_size) != st.st_size
- || size < sizeof (struct mo_file_header))
+ if (__builtin_expect (fstat (fd, &st) != 0, 0)
+ || __builtin_expect ((size = (size_t) st.st_size) != st.st_size, 0)
+ || __builtin_expect (size < sizeof (struct mo_file_header), 0))
{
/* Something went wrong. */
close (fd);
data = (struct mo_file_header *) mmap (NULL, size, PROT_READ,
MAP_PRIVATE, fd, 0);
- if (data != (struct mo_file_header *) -1)
+ if (__builtin_expect (data != (struct mo_file_header *) -1, 1))
{
/* mmap() call was successful. */
close (fd);
do
{
long int nb = (long int) read (fd, read_ptr, to_read);
- if (nb == -1)
+ if (nb <= 0)
{
+#ifdef EINTR
+ if (nb == -1 && errno == EINTR)
+ continue;
+#endif
close (fd);
return;
}
-
read_ptr += nb;
to_read -= nb;
}
/* Using the magic number we can test whether it really is a message
catalog file. */
- if (data->magic != _MAGIC && data->magic != _MAGIC_SWAPPED)
+ if (__builtin_expect (data->magic != _MAGIC && data->magic != _MAGIC_SWAPPED,
+ 0))
{
/* The magic number is wrong: not a message catalog file. */
#ifdef HAVE_MMAP
domain->conv = (iconv_t) -1;
# endif
#endif
+ domain->conv_tab = NULL;
nullentry = _nl_find_msg (domain_file, "", 0);
if (nullentry != NULL)
{
+#if defined _LIBC || HAVE_ICONV
const char *charsetstr;
- const char *plural;
- const char *nplurals;
-#if defined _LIBC || HAVE_ICONV
charsetstr = strstr (nullentry, "charset=");
if (charsetstr != NULL)
{
/* The output charset should normally be determined by the
locale. But sometimes the locale is not used or not correctly
- set up so we provide a possibility to override this. */
- outcharset = getenv ("OUTPUT_CHARSET");
- if (outcharset == NULL || outcharset[0] == '\0')
- outcharset = (*_nl_current[LC_CTYPE])->values[_NL_ITEM_INDEX (CODESET)].string;
+ set up, so we provide a possibility for the user to override
+ this. Moreover, the value specified through
+ bind_textdomain_codeset overrides both. */
+ if (domain_file->domainbinding != NULL
+ && domain_file->domainbinding->codeset != NULL)
+ outcharset = domain_file->domainbinding->codeset;
+ else
+ {
+ outcharset = getenv ("OUTPUT_CHARSET");
+ if (outcharset == NULL || outcharset[0] == '\0')
+ {
+# ifdef _LIBC
+ outcharset = (*_nl_current[LC_CTYPE])->values[_NL_ITEM_INDEX (CODESET)].string;
+# else
+# if HAVE_ICONV
+ extern const char *locale_charset (void);
+ outcharset = locale_charset ();
+ if (outcharset == NULL)
+ outcharset = "";
+# endif
+# endif
+ }
+ }
# ifdef _LIBC
+ outcharset = norm_add_slashes (outcharset);
+ charset = norm_add_slashes (charset);
if (__gconv_open (outcharset, charset, &domain->conv,
GCONV_AVOID_NOCONV)
!= __GCONV_OK)
# endif
}
#endif /* _LIBC || HAVE_ICONV */
+ }
+
+ /* Also look for a plural specification. */
+ if (nullentry != NULL)
+ {
+ const char *plural;
+ const char *nplurals;
- /* Also look for a plural specification. */
plural = strstr (nullentry, "plural=");
nplurals = strstr (nullentry, "nplurals=");
if (plural == NULL || nplurals == NULL)
- {
- /* By default we are using the Germanic form: singular form only
- for `one', the plural form otherwise. Yes, this is also what
- English is using since English is a Germanic language. */
- no_plural:
- domain->plural = &germanic_plural;
- domain->nplurals = 2;
- }
+ goto no_plural;
else
{
/* First get the number. */
domain->plural = args.res;
}
}
+ else
+ {
+ /* By default we are using the Germanic form: singular form only
+ for `one', the plural form otherwise. Yes, this is also what
+ English is using since English is a Germanic language. */
+ no_plural:
+ domain->plural = &germanic_plural;
+ domain->nplurals = 2;
+ }
}
write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
+/* Tell glibc's <string.h> to provide a prototype for mempcpy().
+ This must come before <config.h> because <config.h> may include
+ <features.h>, and once <features.h> has been included, it's too late. */
+#ifndef _GNU_SOURCE
+# define _GNU_SOURCE 1
+#endif
+
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#endif
#if defined HAVE_STRING_H || defined _LIBC
-# ifndef _GNU_SOURCE
-# define _GNU_SOURCE 1
-# endif
# include <string.h>
#else
# include <strings.h>
/* Prototypes for local functions. */
static size_t read_alias_file PARAMS ((const char *fname, int fname_len))
internal_function;
-static void extend_alias_table PARAMS ((void));
+static int extend_alias_table PARAMS ((void));
static int alias_compare PARAMS ((const struct alias_map *map1,
const struct alias_map *map2));
*cp++ = '\0';
if (nmap >= maxmap)
- extend_alias_table ();
+ if (__builtin_expect (extend_alias_table (), 0))
+ {
+ FREE_BLOCKS (block_list);
+ return added;
+ }
alias_len = strlen (alias) + 1;
value_len = strlen (value) + 1;
}
-static void
+static int
extend_alias_table ()
{
size_t new_size;
* sizeof (struct alias_map)));
if (new_map == NULL)
/* Simply don't extend: we don't have any more core. */
- return;
+ return -1;
map = new_map;
maxmap = new_size;
+ return 0;
}
/* Define ISO C stdio on top of C++ iostreams.
- Copyright (C) 1991, 94, 95, 96, 97, 98, 99 Free Software Foundation, Inc.
+ Copyright (C) 1991, 1994-1999, 2000 Free Software Foundation, Inc.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public License as
#ifndef __USE_FILE_OFFSET64
-# ifdef __USE_UNIX98
+# ifdef __USE_LARGEFILE
/* Seek to a certain position on STREAM. */
extern int fseeko (FILE *__stream, __off_t __off, int __whence) __THROW;
/* Return the current position of STREAM. */
extern int fsetpos (FILE *__stream, __const fpos_t *__pos) __THROW;
#else
# ifdef __REDIRECT
-# ifdef __USE_UNIX98
+# ifdef __USE_LARGEFILE
extern int __REDIRECT (fseeko,
(FILE *__stream, __off64_t __off, int __whence) __THROW,
fseeko64);
(FILE *__stream, __const fpos_t *__pos) __THROW,
fsetpos64);
# else
-# ifdef __USE_UNIX98
+# ifdef __USE_LARGEFILE
# define fseeko fseeko64
# define ftello ftello64
# endif
#endif
#ifdef __USE_LARGEFILE64
-# ifdef __USE_UNIX98
extern int fseeko64 (FILE *__stream, __off64_t __off, int __whence) __THROW;
extern __off64_t ftello64 (FILE *__stream) __THROW;
-# endif
extern int fgetpos64 (FILE *__restrict __stream, fpos64_t *__restrict __pos)
__THROW;
extern int fsetpos64 (FILE *__stream, __const fpos64_t *__pos) __THROW;
critical sections of your program.
@item
-@ref{Process Startup}, tells how your programs can access their
+@ref{Program Basics}, tells how your programs can access their
command-line arguments and environment variables.
@item
categories:
@menu
-* Translation with gettext:: What has to be done to translate a message.
-* Locating gettext catalog:: How to determine which catalog to be used.
-* Advanced gettext functions:: Additional functions for more complicated
- situations.
-* GUI program problems:: How to use @code{gettext} in GUI programs.
-* Using gettextized software:: The possibilities of the user to influence
- the way @code{gettext} works.
+* Translation with gettext:: What has to be done to translate a message.
+* Locating gettext catalog:: How to determine which catalog to be used.
+* Advanced gettext functions:: Additional functions for more complicated
+ situations.
+* Charset conversion in gettext:: How to specify the output character set
+ @code{gettext} uses.
+* GUI program problems:: How to use @code{gettext} in GUI programs.
+* Using gettextized software:: The possibilities of the user to influence
+ the way @code{gettext} works.
@end menu
@node Translation with gettext
variable.
The @code{bindtextdomain} function can be used several times and if the
-@var{domainname} argument is different the previously bounded domains
+@var{domainname} argument is different the previously bound domains
will not be overwritten.
If the program which wish to use @code{bindtextdomain} at some point of
@end table
+@node Charset conversion in gettext
+@subsubsection How to specify the output character set @code{gettext} uses
+
+@code{gettext} not only looks up a translation in a message catalog. It
+also converts the translation on the fly to the desired output character
+set. This is useful if the user is working in a different character set
+than the translator who created the message catalog, because it avoids
+distributing variants of message catalogs which differ only in the
+character set.
+
+The output character set is, by default, the value of @code{nl_langinfo
+(CODESET)}, which depends on the @code{LC_CTYPE} part of the current
+locale. But programs which store strings in a locale independent way
+(e.g. UTF-8) can request that @code{gettext} and related functions
+return the translations in that encoding, by use of the
+@code{bind_textdomain_codeset} function.
+
+Note that the @var{msgid} argument to @code{gettext} is not subject to
+character set conversion. Also, when @code{gettext} does not find a
+translation for @var{msgid}, it returns @var{msgid} unchanged --
+independently of the current output character set. It is therefore
+recommended that all @var{msgid}s be US-ASCII strings.
+
+@comment libintl.h
+@comment GNU
+@deftypefun {char *} bind_textdomain_codeset (const char *@var{domainname}, const char *@var{codeset})
+The @code{bind_textdomain_codeset} function can be used to specify the
+output character set for message catalogs for domain @var{domainname}.
+
+If the @var{codeset} parameter is the null pointer,
+@code{bind_textdomain_codeset} returns the currently selected codeset
+for the domain with the name @var{domainname}. It returns @code{NULL} if
+no codeset has yet been selected.
+
+The @code{bind_textdomain_codeset} function can be used several times.
+If used multiple times with the same @var{domainname} argument, the
+later call overrides the settings made by the earlier one.
+
+The @code{bind_textdomain_codeset} function returns a pointer to a
+string containing the name of the selected codeset. The string is
+allocated internally in the function and must not be changed by the
+user. If the system went out of core during the execution of
+@code{bind_textdomain_codeset}, the return value is @code{NULL} and the
+global variable @var{errno} is set accordingly. @end deftypefun
+
+
@node GUI program problems
@subsubsection How to use @code{gettext} in GUI programs
@{
textdomain ("test-package");
bindtextdomain ("test-package", "/usr/local/share/locale");
- puts (gettext ("Hello, world!");
+ puts (gettext ("Hello, world!"));
@}
@end smallexample
-@node Processes, Job Control, Process Startup, Top
+@node Processes, Job Control, Program Basics, Top
@c %MENU% How to create processes and run other programs
@chapter Processes
a file as a process image. You can use these functions to make a child
process execute a new program after it has been forked.
+To see the effects of @code{exec} from the point of view of the called
+program, @xref{Program Basics}.
+
@pindex unistd.h
The functions in this family differ in how you specify the arguments,
but otherwise they all do the same thing. They are declared in the
-@node Signal Handling, Process Startup, Non-Local Exits, Top
+@node Signal Handling, Program Basics, Non-Local Exits, Top
@c %MENU% How to send, block, and handle signals
@chapter Signal Handling
-@node Process Startup, Processes, Signal Handling, Top
+@node Program Basics, Processes, Signal Handling, Top
@c %MENU% Writing the beginning and end of your program
-@chapter Process Startup and Termination
+@chapter The Basic Program/System Interface
@cindex process
+@cindex program
+@cindex address space
+@cindex thread of control
@dfn{Processes} are the primitive units for allocation of system
resources. Each process has its own address space and (usually) one
thread of control. A process executes a program; you can have multiple
processes executing the same program, but each process has its own copy
of the program within its own address space and executes it
-independently of the other copies.
-
-This chapter explains what your program should do to handle the startup
-of a process, to terminate its process, and to receive information
-(arguments and the environment) from the parent process.
+independently of the other copies. Though it may have multiple threads
+of control within the same program and a program may be composed of
+multiple logically separate modules, a process always executes exactly
+one program.
+
+Note that we are using a specific definition of ``program'' for the
+purposes of this manual, which corresponds to a common definition in the
+context of Unix system. In popular usage, ``program'' enjoys a much
+broader definition; it can refer for example to a system's kernel, an
+editor macro, a complex package of software, or a discrete section of
+code executing within a process.
+
+Writing the program is what this manual is all about. This chapter
+explains the most basic interface between your program and the system
+that runs, or calls, it. This includes passing of parameters (arguments
+and environment) from the system, requesting basic services from the
+system, and telling the system the program is done.
+
+A program starts another program with the @code{exec} family of system calls.
+This chapter looks at program startup from the execee's point of view. To
+see the event from the execor's point of view, @xref{Executing a File}.
@menu
* Program Arguments:: Parsing your program's command-line arguments.
-* Environment Variables:: How to access parameters inherited from
- a parent process.
-* Program Termination:: How to cause a process to terminate and
- return status information to its parent.
+* Environment Variables:: Less direct parameters affecting your program
+* System Calls:: Requesting service from the system
+* Program Termination:: Telling the system you're done; return status
@end menu
@node Program Arguments
@end smallexample
The first two arguments are just the same. The third argument
-@var{envp} gives the process's environment; it is the same as the value
+@var{envp} gives the program's environment; it is the same as the value
of @code{environ}. @xref{Environment Variables}. POSIX.1 does not
allow this three-argument form, so to be portable it is best to write
@code{main} to take two arguments, and use the value of @code{environ}.
This is the name that the user used to log in. Since the value in the
environment can be tweaked arbitrarily, this is not a reliable way to
-identify the user who is running a process; a function like
+identify the user who is running a program; a function like
@code{getlogin} (@pxref{Who Logged In}) is better for that purpose.
For most purposes, it is better to use @code{LOGNAME}, precisely because
@c !!! GNU also has COREFILE, CORESERVER, EXECSERVERS
@end table
+@node System Calls
+@section System Calls
+
+@cindex system call
+A system call is a request for service that a program makes of the
+kernel. The service is generally something that only the kernel has
+the privilege to do, such as doing I/O. Programmers don't normally
+need to be concerned with system calls because there are functions in
+the GNU C library to do virtually everything that system calls do.
+These functions work by making system calls themselves. For example,
+there is a system call that changes the permissions of a file, but
+you don't need to know about it because you can just use the GNU C
+library's @code{chmod} function.
+
+@cindex kernel call
+System calls are sometimes called kernel calls.
+
+However, there are times when you want to make a system call explicitly,
+and for that, the GNU C library provides the @code{syscall} function.
+@code{syscall} is harder to use and less portable than functions like
+@code{chmod}, but easier and more portable than coding the system call
+in assembler instructions.
+
+@code{syscall} is most useful when you are working with a system call
+which is special to your system or is newer than the GNU C library you
+are using. @code{syscall} is implemented in an entirely generic way;
+the function does not know anything about what a particular system
+call does or even if it is valid.
+
+The description of @code{syscall} in this section assumes a certain
+protocol for system calls on the various platforms on which the GNU C
+library runs. That protocol is not defined by any strong authority, but
+we won't describe it here either because anyone who is coding
+@code{syscall} probably won't accept anything less than kernel and C
+library source code as a specification of the interface between them
+anyway.
+
+
+@code{syscall} is declared in @file{unistd.h}.
+
+@comment unistd.h
+@comment ???
+@deftypefun long int syscall (long int @var{sysno}, ...)
+
+@code{syscall} performs a generic system call.
+
+@cindex system call number
+@var{sysno} is the system call number. Each kind of system call is
+identified by a number. Macros for all the possible system call numbers
+are defined in @file{sys/syscall.h}
+
+The remaining arguments are the arguments for the system call, in
+order, and their meanings depend on the kind of system call. Each kind
+of system call has a definite number of arguments, from zero to five.
+If you code more arguments than the system call takes, the extra ones to
+the right are ignored.
+
+The return value is the return value from the system call, unless the
+system call failed. In that case, @code{syscall} returns @code{-1} and
+sets @code{errno} to an error code that the system call returned. Note
+that system calls do not return @code{-1} when they succeed.
+@cindex errno
+
+If you specify an invalid @var{sysno}, @code{syscall} returns @code{-1}
+with @code{errno} = @code{ENOSYS}.
+
+Example:
+
+@smallexample
+
+#include <unistd.h>
+#include <sys/syscall.h>
+#include <errno.h>
+
+...
+
+int rc;
+
+rc = syscall(SYS_chmod, "/etc/passwd", 0444);
+
+if (rc == -1)
+ fprintf(stderr, "chmod failed, errno = %d\n", errno);
+
+@end smallexample
+
+This, if all the compatibility stars are aligned, is equivalent to the
+following preferable code:
+
+@smallexample
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <errno.h>
+
+...
+
+int rc;
+
+rc = chmod("/etc/passwd", 0444);
+if (rc == -1)
+ fprintf(stderr, "chmod failed, errno = %d\n", errno);
+
+@end smallexample
+
+@end deftypefun
+
+
@node Program Termination
@section Program Termination
@cindex program termination
@node Normal Termination
@subsection Normal Termination
-A process terminates normally when the program calls @code{exit}.
-Returning from @code{main} is equivalent to calling @code{exit}, and
-the value that @code{main} returns is used as the argument to @code{exit}.
+A process terminates normally when its program signals it is done by
+calling @code{exit}. Returning from @code{main} is equivalent to
+calling @code{exit}, and the value that @code{main} returns is used as
+the argument to @code{exit}.
@comment stdlib.h
@comment ISO
@deftypefun void exit (int @var{status})
-The @code{exit} function terminates the process with status
-@var{status}. This function does not return.
+The @code{exit} function tells the system that the program is done, which
+causes it to terminate the process.
+
+@var{status} is the program's exit status, which becomes part of the
+process' termination status. This function does not return.
@end deftypefun
Normal termination causes the following actions:
mean that there was difficulty in opening the files.
@end deftypevr
+Don't confuse a program's exit status with a process' termination status.
+There are lots of ways a process can terminate besides having it's program
+finish. In the event that the process termination @emph{is} caused by program
+termination (i.e. @code{exit}), though, the program's exit status becomes
+part of the process' termination status.
+
@node Cleanups on Exit
@subsection Cleanups on Exit
@file{stdlib.h}.
@end deftypefun
-When a process terminates for any reason---either by an explicit
-termination call, or termination as a result of a signal---the
+When a process terminates for any reason---either because the program
+terminates, or as a result of a signal---the
following things happen:
@itemize @bullet
terminates; see @ref{I/O on Streams}.
@item
-The low-order 8 bits of the return status code are saved to be reported
-back to the parent process via @code{wait} or @code{waitpid}; see
-@ref{Process Completion}.
+A process exit status is saved to be reported back to the parent process
+via @code{wait} or @code{waitpid}; see @ref{Process Completion}. If the
+program exited, this status includes as its low-order 8 bits the program
+exit status.
+
@item
Any child processes of the process being terminated are assigned a new
#: sunrpc/pmap_rmt.c:185
msgid "broadcast: ioctl (get interface configuration)"
-msgstr "multidifusión: ioctl (obte-la configuración do interfaz)"
+msgstr "multidifusión: ioctl (obte-la configuración da interface)"
#: sunrpc/pmap_rmt.c:194
msgid "broadcast: ioctl (get interface flags)"
-msgstr "multidifusión: ioctl (obte-los parámetros do interfaz)"
+msgstr "multidifusión: ioctl (obte-los parámetros da interface)"
#: login/programs/request.c:167
msgid "buffer overflow"
#: sunrpc/get_myaddr.c:77
msgid "get_myaddress: ioctl (get interface configuration)"
-msgstr "get_myaddress: ioctl (obte-la configuración do interfaz)"
+msgstr "get_myaddress: ioctl (obte-la configuración da interface)"
#: nss/getent.c:54
msgid "getent - get entries from administrative database."
#define p_query __p_query
#define res_close __res_close
#define res_isourserver __res_isourserver
-#define res_querydomain __res_querydomain
#define res_send __res_send
__BEGIN_DECLS
-/*Environment handling for dynamic loader.
- Copyright (C) 1995, 1996, 1997, 1998 Free Software Foundation, Inc.
+/* Environment handling for dynamic loader.
+ Copyright (C) 1995, 1996, 1997, 1998, 2000 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
const size_t len = strlen (name);
char **ep;
- for (ep = _environ; *ep != NULL; ++ep)
+ ep = _environ;
+ while (*ep != NULL)
if (!strncmp (*ep, name, len) && (*ep)[len] == '=')
{
/* Found it. Remove this pointer by moving later ones back. */
while (*dp++);
/* Continue the loop in case NAME appears again. */
}
+ else
+ ++ep;
}
})
-/* The gconv functions expects the name to be complete, including the
- trailing shashes if necessary. */
-#define norm_add_slashes(str) \
- ({ \
- const char *cp = str; \
- char *result; \
- char *tmp; \
- size_t cnt = 0; \
- \
- while (*cp != '\0') \
- if (*cp++ == '/') \
- ++cnt; \
- \
- tmp = result = alloca (cp - str + 3); \
- cp = str; \
- while (*cp != '\0') \
- *tmp++ = _toupper (*cp++); \
- if (cnt < 2) \
- { \
- *tmp++ = '/'; \
- if (cnt < 1) \
- *tmp++ = '/'; \
- } \
- *tmp = '\0'; \
- result; \
- })
-
-
/* We must modify global data. */
__libc_lock_define_initialized (static, lock)