xref: /openbsd-src/gnu/usr.bin/binutils-2.17/intl/l10nflist.c (revision 3d8817e467ea46cf4772788d6804dd293abfb01a)
1*3d8817e4Smiod /* Handle list of needed message catalogs
2*3d8817e4Smiod    Copyright (C) 1995, 1996, 1997 Free Software Foundation, Inc.
3*3d8817e4Smiod    Contributed by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1995.
4*3d8817e4Smiod 
5*3d8817e4Smiod    This program is free software; you can redistribute it and/or modify
6*3d8817e4Smiod    it under the terms of the GNU General Public License as published by
7*3d8817e4Smiod    the Free Software Foundation; either version 2, or (at your option)
8*3d8817e4Smiod    any later version.
9*3d8817e4Smiod 
10*3d8817e4Smiod    This program is distributed in the hope that it will be useful,
11*3d8817e4Smiod    but WITHOUT ANY WARRANTY; without even the implied warranty of
12*3d8817e4Smiod    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13*3d8817e4Smiod    GNU General Public License for more details.
14*3d8817e4Smiod 
15*3d8817e4Smiod    You should have received a copy of the GNU General Public License
16*3d8817e4Smiod    along with this program; if not, write to the Free Software Foundation,
17*3d8817e4Smiod    Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.  */
18*3d8817e4Smiod 
19*3d8817e4Smiod #ifdef HAVE_CONFIG_H
20*3d8817e4Smiod # include <config.h>
21*3d8817e4Smiod #endif
22*3d8817e4Smiod 
23*3d8817e4Smiod 
24*3d8817e4Smiod #if defined HAVE_STRING_H || defined _LIBC
25*3d8817e4Smiod # ifndef _GNU_SOURCE
26*3d8817e4Smiod #  define _GNU_SOURCE	1
27*3d8817e4Smiod # endif
28*3d8817e4Smiod # include <string.h>
29*3d8817e4Smiod #else
30*3d8817e4Smiod # include <strings.h>
31*3d8817e4Smiod # ifndef memcpy
32*3d8817e4Smiod #  define memcpy(Dst, Src, Num) bcopy (Src, Dst, Num)
33*3d8817e4Smiod # endif
34*3d8817e4Smiod #endif
35*3d8817e4Smiod #if !HAVE_STRCHR && !defined _LIBC
36*3d8817e4Smiod # ifndef strchr
37*3d8817e4Smiod #  define strchr index
38*3d8817e4Smiod # endif
39*3d8817e4Smiod #endif
40*3d8817e4Smiod 
41*3d8817e4Smiod #if defined _LIBC || defined HAVE_ARGZ_H
42*3d8817e4Smiod # include <argz.h>
43*3d8817e4Smiod #endif
44*3d8817e4Smiod #include <ctype.h>
45*3d8817e4Smiod #include <sys/types.h>
46*3d8817e4Smiod 
47*3d8817e4Smiod #if defined STDC_HEADERS || defined _LIBC
48*3d8817e4Smiod # include <stdlib.h>
49*3d8817e4Smiod #endif
50*3d8817e4Smiod 
51*3d8817e4Smiod #include "loadinfo.h"
52*3d8817e4Smiod 
53*3d8817e4Smiod /* On some strange systems still no definition of NULL is found.  Sigh!  */
54*3d8817e4Smiod #ifndef NULL
55*3d8817e4Smiod # if defined __STDC__ && __STDC__
56*3d8817e4Smiod #  define NULL ((void *) 0)
57*3d8817e4Smiod # else
58*3d8817e4Smiod #  define NULL 0
59*3d8817e4Smiod # endif
60*3d8817e4Smiod #endif
61*3d8817e4Smiod 
62*3d8817e4Smiod /* @@ end of prolog @@ */
63*3d8817e4Smiod 
64*3d8817e4Smiod #ifdef _LIBC
65*3d8817e4Smiod /* Rename the non ANSI C functions.  This is required by the standard
66*3d8817e4Smiod    because some ANSI C functions will require linking with this object
67*3d8817e4Smiod    file and the name space must not be polluted.  */
68*3d8817e4Smiod # ifndef stpcpy
69*3d8817e4Smiod #  define stpcpy(dest, src) __stpcpy(dest, src)
70*3d8817e4Smiod # endif
71*3d8817e4Smiod #else
72*3d8817e4Smiod # ifndef HAVE_STPCPY
73*3d8817e4Smiod static char *stpcpy PARAMS ((char *dest, const char *src));
74*3d8817e4Smiod # endif
75*3d8817e4Smiod #endif
76*3d8817e4Smiod 
77*3d8817e4Smiod /* Define function which are usually not available.  */
78*3d8817e4Smiod 
79*3d8817e4Smiod #if !defined _LIBC && !defined HAVE___ARGZ_COUNT
80*3d8817e4Smiod /* Returns the number of strings in ARGZ.  */
81*3d8817e4Smiod static size_t argz_count__ PARAMS ((const char *argz, size_t len));
82*3d8817e4Smiod 
83*3d8817e4Smiod static size_t
argz_count__(argz,len)84*3d8817e4Smiod argz_count__ (argz, len)
85*3d8817e4Smiod      const char *argz;
86*3d8817e4Smiod      size_t len;
87*3d8817e4Smiod {
88*3d8817e4Smiod   size_t count = 0;
89*3d8817e4Smiod   while (len > 0)
90*3d8817e4Smiod     {
91*3d8817e4Smiod       size_t part_len = strlen (argz);
92*3d8817e4Smiod       argz += part_len + 1;
93*3d8817e4Smiod       len -= part_len + 1;
94*3d8817e4Smiod       count++;
95*3d8817e4Smiod     }
96*3d8817e4Smiod   return count;
97*3d8817e4Smiod }
98*3d8817e4Smiod # undef __argz_count
99*3d8817e4Smiod # define __argz_count(argz, len) argz_count__ (argz, len)
100*3d8817e4Smiod #endif	/* !_LIBC && !HAVE___ARGZ_COUNT */
101*3d8817e4Smiod 
102*3d8817e4Smiod #if !defined _LIBC && !defined HAVE___ARGZ_STRINGIFY
103*3d8817e4Smiod /* Make '\0' separated arg vector ARGZ printable by converting all the '\0's
104*3d8817e4Smiod    except the last into the character SEP.  */
105*3d8817e4Smiod static void argz_stringify__ PARAMS ((char *argz, size_t len, int sep));
106*3d8817e4Smiod 
107*3d8817e4Smiod static void
argz_stringify__(argz,len,sep)108*3d8817e4Smiod argz_stringify__ (argz, len, sep)
109*3d8817e4Smiod      char *argz;
110*3d8817e4Smiod      size_t len;
111*3d8817e4Smiod      int sep;
112*3d8817e4Smiod {
113*3d8817e4Smiod   while (len > 0)
114*3d8817e4Smiod     {
115*3d8817e4Smiod       size_t part_len = strlen (argz);
116*3d8817e4Smiod       argz += part_len;
117*3d8817e4Smiod       len -= part_len + 1;
118*3d8817e4Smiod       if (len > 0)
119*3d8817e4Smiod 	*argz++ = sep;
120*3d8817e4Smiod     }
121*3d8817e4Smiod }
122*3d8817e4Smiod # undef __argz_stringify
123*3d8817e4Smiod # define __argz_stringify(argz, len, sep) argz_stringify__ (argz, len, sep)
124*3d8817e4Smiod #endif	/* !_LIBC && !HAVE___ARGZ_STRINGIFY */
125*3d8817e4Smiod 
126*3d8817e4Smiod #if !defined _LIBC && !defined HAVE___ARGZ_NEXT
127*3d8817e4Smiod static char *argz_next__ PARAMS ((char *argz, size_t argz_len,
128*3d8817e4Smiod 				  const char *entry));
129*3d8817e4Smiod 
130*3d8817e4Smiod static char *
argz_next__(argz,argz_len,entry)131*3d8817e4Smiod argz_next__ (argz, argz_len, entry)
132*3d8817e4Smiod      char *argz;
133*3d8817e4Smiod      size_t argz_len;
134*3d8817e4Smiod      const char *entry;
135*3d8817e4Smiod {
136*3d8817e4Smiod   if (entry)
137*3d8817e4Smiod     {
138*3d8817e4Smiod       if (entry < argz + argz_len)
139*3d8817e4Smiod         entry = strchr (entry, '\0') + 1;
140*3d8817e4Smiod 
141*3d8817e4Smiod       return entry >= argz + argz_len ? NULL : (char *) entry;
142*3d8817e4Smiod     }
143*3d8817e4Smiod   else
144*3d8817e4Smiod     if (argz_len > 0)
145*3d8817e4Smiod       return argz;
146*3d8817e4Smiod     else
147*3d8817e4Smiod       return 0;
148*3d8817e4Smiod }
149*3d8817e4Smiod # undef __argz_next
150*3d8817e4Smiod # define __argz_next(argz, len, entry) argz_next__ (argz, len, entry)
151*3d8817e4Smiod #endif	/* !_LIBC && !HAVE___ARGZ_NEXT */
152*3d8817e4Smiod 
153*3d8817e4Smiod 
154*3d8817e4Smiod /* Return number of bits set in X.  */
155*3d8817e4Smiod static int pop PARAMS ((int x));
156*3d8817e4Smiod 
157*3d8817e4Smiod static inline int
pop(x)158*3d8817e4Smiod pop (x)
159*3d8817e4Smiod      int x;
160*3d8817e4Smiod {
161*3d8817e4Smiod   /* We assume that no more than 16 bits are used.  */
162*3d8817e4Smiod   x = ((x & ~0x5555) >> 1) + (x & 0x5555);
163*3d8817e4Smiod   x = ((x & ~0x3333) >> 2) + (x & 0x3333);
164*3d8817e4Smiod   x = ((x >> 4) + x) & 0x0f0f;
165*3d8817e4Smiod   x = ((x >> 8) + x) & 0xff;
166*3d8817e4Smiod 
167*3d8817e4Smiod   return x;
168*3d8817e4Smiod }
169*3d8817e4Smiod 
170*3d8817e4Smiod 
171*3d8817e4Smiod struct loaded_l10nfile *
_nl_make_l10nflist(l10nfile_list,dirlist,dirlist_len,mask,language,territory,codeset,normalized_codeset,modifier,special,sponsor,revision,filename,do_allocate)172*3d8817e4Smiod _nl_make_l10nflist (l10nfile_list, dirlist, dirlist_len, mask, language,
173*3d8817e4Smiod 		    territory, codeset, normalized_codeset, modifier, special,
174*3d8817e4Smiod 		    sponsor, revision, filename, do_allocate)
175*3d8817e4Smiod      struct loaded_l10nfile **l10nfile_list;
176*3d8817e4Smiod      const char *dirlist;
177*3d8817e4Smiod      size_t dirlist_len;
178*3d8817e4Smiod      int mask;
179*3d8817e4Smiod      const char *language;
180*3d8817e4Smiod      const char *territory;
181*3d8817e4Smiod      const char *codeset;
182*3d8817e4Smiod      const char *normalized_codeset;
183*3d8817e4Smiod      const char *modifier;
184*3d8817e4Smiod      const char *special;
185*3d8817e4Smiod      const char *sponsor;
186*3d8817e4Smiod      const char *revision;
187*3d8817e4Smiod      const char *filename;
188*3d8817e4Smiod      int do_allocate;
189*3d8817e4Smiod {
190*3d8817e4Smiod   char *abs_filename;
191*3d8817e4Smiod   struct loaded_l10nfile *last = NULL;
192*3d8817e4Smiod   struct loaded_l10nfile *retval;
193*3d8817e4Smiod   char *cp;
194*3d8817e4Smiod   size_t entries;
195*3d8817e4Smiod   int cnt;
196*3d8817e4Smiod 
197*3d8817e4Smiod   /* Allocate room for the full file name.  */
198*3d8817e4Smiod   abs_filename = (char *) malloc (dirlist_len
199*3d8817e4Smiod 				  + strlen (language)
200*3d8817e4Smiod 				  + ((mask & TERRITORY) != 0
201*3d8817e4Smiod 				     ? strlen (territory) + 1 : 0)
202*3d8817e4Smiod 				  + ((mask & XPG_CODESET) != 0
203*3d8817e4Smiod 				     ? strlen (codeset) + 1 : 0)
204*3d8817e4Smiod 				  + ((mask & XPG_NORM_CODESET) != 0
205*3d8817e4Smiod 				     ? strlen (normalized_codeset) + 1 : 0)
206*3d8817e4Smiod 				  + (((mask & XPG_MODIFIER) != 0
207*3d8817e4Smiod 				      || (mask & CEN_AUDIENCE) != 0)
208*3d8817e4Smiod 				     ? strlen (modifier) + 1 : 0)
209*3d8817e4Smiod 				  + ((mask & CEN_SPECIAL) != 0
210*3d8817e4Smiod 				     ? strlen (special) + 1 : 0)
211*3d8817e4Smiod 				  + (((mask & CEN_SPONSOR) != 0
212*3d8817e4Smiod 				      || (mask & CEN_REVISION) != 0)
213*3d8817e4Smiod 				     ? (1 + ((mask & CEN_SPONSOR) != 0
214*3d8817e4Smiod 					     ? strlen (sponsor) + 1 : 0)
215*3d8817e4Smiod 					+ ((mask & CEN_REVISION) != 0
216*3d8817e4Smiod 					   ? strlen (revision) + 1 : 0)) : 0)
217*3d8817e4Smiod 				  + 1 + strlen (filename) + 1);
218*3d8817e4Smiod 
219*3d8817e4Smiod   if (abs_filename == NULL)
220*3d8817e4Smiod     return NULL;
221*3d8817e4Smiod 
222*3d8817e4Smiod   retval = NULL;
223*3d8817e4Smiod   last = NULL;
224*3d8817e4Smiod 
225*3d8817e4Smiod   /* Construct file name.  */
226*3d8817e4Smiod   memcpy (abs_filename, dirlist, dirlist_len);
227*3d8817e4Smiod   __argz_stringify (abs_filename, dirlist_len, ':');
228*3d8817e4Smiod   cp = abs_filename + (dirlist_len - 1);
229*3d8817e4Smiod   *cp++ = '/';
230*3d8817e4Smiod   cp = stpcpy (cp, language);
231*3d8817e4Smiod 
232*3d8817e4Smiod   if ((mask & TERRITORY) != 0)
233*3d8817e4Smiod     {
234*3d8817e4Smiod       *cp++ = '_';
235*3d8817e4Smiod       cp = stpcpy (cp, territory);
236*3d8817e4Smiod     }
237*3d8817e4Smiod   if ((mask & XPG_CODESET) != 0)
238*3d8817e4Smiod     {
239*3d8817e4Smiod       *cp++ = '.';
240*3d8817e4Smiod       cp = stpcpy (cp, codeset);
241*3d8817e4Smiod     }
242*3d8817e4Smiod   if ((mask & XPG_NORM_CODESET) != 0)
243*3d8817e4Smiod     {
244*3d8817e4Smiod       *cp++ = '.';
245*3d8817e4Smiod       cp = stpcpy (cp, normalized_codeset);
246*3d8817e4Smiod     }
247*3d8817e4Smiod   if ((mask & (XPG_MODIFIER | CEN_AUDIENCE)) != 0)
248*3d8817e4Smiod     {
249*3d8817e4Smiod       /* This component can be part of both syntaces but has different
250*3d8817e4Smiod 	 leading characters.  For CEN we use `+', else `@'.  */
251*3d8817e4Smiod       *cp++ = (mask & CEN_AUDIENCE) != 0 ? '+' : '@';
252*3d8817e4Smiod       cp = stpcpy (cp, modifier);
253*3d8817e4Smiod     }
254*3d8817e4Smiod   if ((mask & CEN_SPECIAL) != 0)
255*3d8817e4Smiod     {
256*3d8817e4Smiod       *cp++ = '+';
257*3d8817e4Smiod       cp = stpcpy (cp, special);
258*3d8817e4Smiod     }
259*3d8817e4Smiod   if ((mask & (CEN_SPONSOR | CEN_REVISION)) != 0)
260*3d8817e4Smiod     {
261*3d8817e4Smiod       *cp++ = ',';
262*3d8817e4Smiod       if ((mask & CEN_SPONSOR) != 0)
263*3d8817e4Smiod 	cp = stpcpy (cp, sponsor);
264*3d8817e4Smiod       if ((mask & CEN_REVISION) != 0)
265*3d8817e4Smiod 	{
266*3d8817e4Smiod 	  *cp++ = '_';
267*3d8817e4Smiod 	  cp = stpcpy (cp, revision);
268*3d8817e4Smiod 	}
269*3d8817e4Smiod     }
270*3d8817e4Smiod 
271*3d8817e4Smiod   *cp++ = '/';
272*3d8817e4Smiod   stpcpy (cp, filename);
273*3d8817e4Smiod 
274*3d8817e4Smiod   /* Look in list of already loaded domains whether it is already
275*3d8817e4Smiod      available.  */
276*3d8817e4Smiod   last = NULL;
277*3d8817e4Smiod   for (retval = *l10nfile_list; retval != NULL; retval = retval->next)
278*3d8817e4Smiod     if (retval->filename != NULL)
279*3d8817e4Smiod       {
280*3d8817e4Smiod 	int compare = strcmp (retval->filename, abs_filename);
281*3d8817e4Smiod 	if (compare == 0)
282*3d8817e4Smiod 	  /* We found it!  */
283*3d8817e4Smiod 	  break;
284*3d8817e4Smiod 	if (compare < 0)
285*3d8817e4Smiod 	  {
286*3d8817e4Smiod 	    /* It's not in the list.  */
287*3d8817e4Smiod 	    retval = NULL;
288*3d8817e4Smiod 	    break;
289*3d8817e4Smiod 	  }
290*3d8817e4Smiod 
291*3d8817e4Smiod 	last = retval;
292*3d8817e4Smiod       }
293*3d8817e4Smiod 
294*3d8817e4Smiod   if (retval != NULL || do_allocate == 0)
295*3d8817e4Smiod     {
296*3d8817e4Smiod       free (abs_filename);
297*3d8817e4Smiod       return retval;
298*3d8817e4Smiod     }
299*3d8817e4Smiod 
300*3d8817e4Smiod   retval = (struct loaded_l10nfile *)
301*3d8817e4Smiod     malloc (sizeof (*retval) + (__argz_count (dirlist, dirlist_len)
302*3d8817e4Smiod 				* (1 << pop (mask))
303*3d8817e4Smiod 				* sizeof (struct loaded_l10nfile *)));
304*3d8817e4Smiod   if (retval == NULL)
305*3d8817e4Smiod     return NULL;
306*3d8817e4Smiod 
307*3d8817e4Smiod   retval->filename = abs_filename;
308*3d8817e4Smiod   retval->decided = (__argz_count (dirlist, dirlist_len) != 1
309*3d8817e4Smiod 		     || ((mask & XPG_CODESET) != 0
310*3d8817e4Smiod 			 && (mask & XPG_NORM_CODESET) != 0));
311*3d8817e4Smiod   retval->data = NULL;
312*3d8817e4Smiod 
313*3d8817e4Smiod   if (last == NULL)
314*3d8817e4Smiod     {
315*3d8817e4Smiod       retval->next = *l10nfile_list;
316*3d8817e4Smiod       *l10nfile_list = retval;
317*3d8817e4Smiod     }
318*3d8817e4Smiod   else
319*3d8817e4Smiod     {
320*3d8817e4Smiod       retval->next = last->next;
321*3d8817e4Smiod       last->next = retval;
322*3d8817e4Smiod     }
323*3d8817e4Smiod 
324*3d8817e4Smiod   entries = 0;
325*3d8817e4Smiod   /* If the DIRLIST is a real list the RETVAL entry corresponds not to
326*3d8817e4Smiod      a real file.  So we have to use the DIRLIST separation mechanism
327*3d8817e4Smiod      of the inner loop.  */
328*3d8817e4Smiod   cnt = __argz_count (dirlist, dirlist_len) == 1 ? mask - 1 : mask;
329*3d8817e4Smiod   for (; cnt >= 0; --cnt)
330*3d8817e4Smiod     if ((cnt & ~mask) == 0
331*3d8817e4Smiod 	&& ((cnt & CEN_SPECIFIC) == 0 || (cnt & XPG_SPECIFIC) == 0)
332*3d8817e4Smiod 	&& ((cnt & XPG_CODESET) == 0 || (cnt & XPG_NORM_CODESET) == 0))
333*3d8817e4Smiod       {
334*3d8817e4Smiod 	/* Iterate over all elements of the DIRLIST.  */
335*3d8817e4Smiod 	char *dir = NULL;
336*3d8817e4Smiod 
337*3d8817e4Smiod 	while ((dir = __argz_next ((char *) dirlist, dirlist_len, dir))
338*3d8817e4Smiod 	       != NULL)
339*3d8817e4Smiod 	  retval->successor[entries++]
340*3d8817e4Smiod 	    = _nl_make_l10nflist (l10nfile_list, dir, strlen (dir) + 1, cnt,
341*3d8817e4Smiod 				  language, territory, codeset,
342*3d8817e4Smiod 				  normalized_codeset, modifier, special,
343*3d8817e4Smiod 				  sponsor, revision, filename, 1);
344*3d8817e4Smiod       }
345*3d8817e4Smiod   retval->successor[entries] = NULL;
346*3d8817e4Smiod 
347*3d8817e4Smiod   return retval;
348*3d8817e4Smiod }
349*3d8817e4Smiod 
350*3d8817e4Smiod /* Normalize codeset name.  There is no standard for the codeset
351*3d8817e4Smiod    names.  Normalization allows the user to use any of the common
352*3d8817e4Smiod    names.  */
353*3d8817e4Smiod const char *
_nl_normalize_codeset(codeset,name_len)354*3d8817e4Smiod _nl_normalize_codeset (codeset, name_len)
355*3d8817e4Smiod      const unsigned char *codeset;
356*3d8817e4Smiod      size_t name_len;
357*3d8817e4Smiod {
358*3d8817e4Smiod   int len = 0;
359*3d8817e4Smiod   int only_digit = 1;
360*3d8817e4Smiod   char *retval;
361*3d8817e4Smiod   char *wp;
362*3d8817e4Smiod   size_t cnt;
363*3d8817e4Smiod 
364*3d8817e4Smiod   for (cnt = 0; cnt < name_len; ++cnt)
365*3d8817e4Smiod     if (isalnum (codeset[cnt]))
366*3d8817e4Smiod       {
367*3d8817e4Smiod 	++len;
368*3d8817e4Smiod 
369*3d8817e4Smiod 	if (isalpha (codeset[cnt]))
370*3d8817e4Smiod 	  only_digit = 0;
371*3d8817e4Smiod       }
372*3d8817e4Smiod 
373*3d8817e4Smiod   retval = (char *) malloc ((only_digit ? 3 : 0) + len + 1);
374*3d8817e4Smiod 
375*3d8817e4Smiod   if (retval != NULL)
376*3d8817e4Smiod     {
377*3d8817e4Smiod       if (only_digit)
378*3d8817e4Smiod 	wp = stpcpy (retval, "iso");
379*3d8817e4Smiod       else
380*3d8817e4Smiod 	wp = retval;
381*3d8817e4Smiod 
382*3d8817e4Smiod       for (cnt = 0; cnt < name_len; ++cnt)
383*3d8817e4Smiod 	if (isalpha (codeset[cnt]))
384*3d8817e4Smiod 	  *wp++ = tolower (codeset[cnt]);
385*3d8817e4Smiod 	else if (isdigit (codeset[cnt]))
386*3d8817e4Smiod 	  *wp++ = codeset[cnt];
387*3d8817e4Smiod 
388*3d8817e4Smiod       *wp = '\0';
389*3d8817e4Smiod     }
390*3d8817e4Smiod 
391*3d8817e4Smiod   return (const char *) retval;
392*3d8817e4Smiod }
393*3d8817e4Smiod 
394*3d8817e4Smiod 
395*3d8817e4Smiod /* @@ begin of epilog @@ */
396*3d8817e4Smiod 
397*3d8817e4Smiod /* We don't want libintl.a to depend on any other library.  So we
398*3d8817e4Smiod    avoid the non-standard function stpcpy.  In GNU C Library this
399*3d8817e4Smiod    function is available, though.  Also allow the symbol HAVE_STPCPY
400*3d8817e4Smiod    to be defined.  */
401*3d8817e4Smiod #if !_LIBC && !HAVE_STPCPY
402*3d8817e4Smiod static char *
stpcpy(dest,src)403*3d8817e4Smiod stpcpy (dest, src)
404*3d8817e4Smiod      char *dest;
405*3d8817e4Smiod      const char *src;
406*3d8817e4Smiod {
407*3d8817e4Smiod   while ((*dest++ = *src++) != '\0')
408*3d8817e4Smiod     /* Do nothing. */ ;
409*3d8817e4Smiod   return dest - 1;
410*3d8817e4Smiod }
411*3d8817e4Smiod #endif
412