]> git.proxmox.com Git - grub2.git/blame - kern/misc.c
2005-01-22 Vincent Pelletier <subdino2004@yahoo.fr>
[grub2.git] / kern / misc.c
CommitLineData
6a161fa9 1/* misc.c - definitions of misc functions */
2/*
4b13b216 3 * GRUB -- GRand Unified Bootloader
8c8cc205 4 * Copyright (C) 1999,2000,2001,2002,2003,2004 Free Software Foundation, Inc.
6a161fa9 5 *
4b13b216 6 * GRUB is free software; you can redistribute it and/or modify
6a161fa9 7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
4b13b216 17 * along with GRUB; if not, write to the Free Software
6a161fa9 18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20
4b13b216 21#include <grub/misc.h>
22#include <grub/err.h>
23#include <grub/mm.h>
6a161fa9 24#include <stdarg.h>
4b13b216 25#include <grub/term.h>
26#include <grub/env.h>
6a161fa9 27
28void *
4b13b216 29grub_memmove (void *dest, const void *src, grub_size_t n)
6a161fa9 30{
31 char *d = (char *) dest;
a5ffe966 32 const char *s = (const char *) src;
33
34 if (d < s)
35 while (n--)
36 *d++ = *s++;
37 else
38 {
39 d += n;
40 s += n;
41
42 while (n--)
43 *--d = *--s;
44 }
6a161fa9 45
46 return dest;
47}
062b24c2 48void *memmove (void *dest, const void *src, grub_size_t n)
49 __attribute__ ((alias ("grub_memmove")));
8c8cc205 50/* GCC emits references to memcpy() for struct copies etc. */
4b13b216 51void *memcpy (void *dest, const void *src, grub_size_t n)
52 __attribute__ ((alias ("grub_memmove")));
6a161fa9 53
a5ffe966 54char *
4b13b216 55grub_strcpy (char *dest, const char *src)
a5ffe966 56{
57 char *p = dest;
58
59 while ((*p++ = *src++) != '\0')
60 ;
61
62 return dest;
63}
64
a35eed7c 65char *
4b13b216 66grub_strncpy (char *dest, const char *src, int c)
a35eed7c 67{
68 char *p = dest;
e15199cb 69
70 while ((*p++ = *src++) != '\0' && --c)
71 ;
a35eed7c 72
73 return dest;
74}
75
9a5c1ade 76char *
4b13b216 77grub_stpcpy (char *dest, const char *src)
9a5c1ade 78{
79 char *d = dest;
80 const char *s = src;
81
82 do
83 *d++ = *s;
84 while (*s++ != '\0');
85
86 return d - 1;
87}
88
a5ffe966 89char *
4b13b216 90grub_strcat (char *dest, const char *src)
a5ffe966 91{
92 char *p = dest;
93
94 while (*p)
95 p++;
96
97 while ((*p++ = *src++) != '\0')
98 ;
99
100 return dest;
101}
a5ffe966 102
ad0bd20b 103char *
104grub_strncat (char *dest, const char *src, int c)
105{
106 char *p = dest;
107
108 while (*p)
109 p++;
110
111 while ((*p++ = *src++) != '\0' && --c)
112 ;
113 *(--p) = '\0';
114
115 return dest;
116}
117
6a161fa9 118int
4b13b216 119grub_printf (const char *fmt, ...)
6a161fa9 120{
121 va_list ap;
122 int ret;
123
124 va_start (ap, fmt);
4b13b216 125 ret = grub_vprintf (fmt, ap);
6a161fa9 126 va_end (ap);
127
128 return ret;
129}
130
131int
4b13b216 132grub_vprintf (const char *fmt, va_list args)
6a161fa9 133{
4b13b216 134 return grub_vsprintf (0, fmt, args);
6a161fa9 135}
136
137int
4b13b216 138grub_memcmp (const void *s1, const void *s2, grub_size_t n)
6a161fa9 139{
140 const char *t1 = s1;
141 const char *t2 = s2;
142
143 while (n--)
144 {
145 if (*t1 != *t2)
146 return (int) *t1 - (int) *t2;
147
148 t1++;
149 t2++;
150 }
151
152 return 0;
153}
062b24c2 154void *memcmp (const void *s1, const void *s2, grub_size_t n)
155 __attribute__ ((alias ("grub_memcmp")));
6a161fa9 156
157int
4b13b216 158grub_strcmp (const char *s1, const char *s2)
6a161fa9 159{
160 while (*s1 && *s2)
161 {
162 if (*s1 != *s2)
163 return (int) *s1 - (int) *s2;
164
165 s1++;
166 s2++;
167 }
168
169 return (int) *s1 - (int) *s2;
170}
171
a35eed7c 172int
4b13b216 173grub_strncmp (const char *s1, const char *s2, int c)
a35eed7c 174{
175 int p = 1;
176
177 while (*s1 && *s2 && p < c)
178 {
179 if (*s1 != *s2)
180 return (int) *s1 - (int) *s2;
181
182 s1++;
183 s2++;
184 p++;
185 }
186
187 return (int) *s1 - (int) *s2;
188}
189
64372eb4 190int
191grub_strncasecmp (const char *s1, const char *s2, int c)
192{
193 int p = 1;
194
195 while (grub_tolower (*s1) && grub_tolower (*s2) && p < c)
196 {
197 if (grub_tolower (*s1) != grub_tolower (*s2))
198 return (int) grub_tolower (*s1) - (int) grub_tolower (*s2);
199
200 s1++;
201 s2++;
202 p++;
203 }
204
205 return (int) *s1 - (int) *s2;
206}
207
6a161fa9 208char *
4b13b216 209grub_strchr (const char *s, int c)
6a161fa9 210{
211 while (*s)
212 {
213 if (*s == c)
214 return (char *) s;
215 s++;
216 }
217
218 return 0;
219}
220
221char *
4b13b216 222grub_strrchr (const char *s, int c)
6a161fa9 223{
224 char *p = 0;
225
226 while (*s)
227 {
228 if (*s == c)
229 p = (char *) s;
230 s++;
231 }
232
233 return p;
234}
235
236int
4b13b216 237grub_isspace (int c)
6a161fa9 238{
239 return (c == '\n' || c == '\r' || c == ' ' || c == '\t');
240}
241
242int
4b13b216 243grub_isprint (int c)
6a161fa9 244{
245 return (c >= ' ' && c <= '~');
246}
247
248int
4b13b216 249grub_isalpha (int c)
6a161fa9 250{
251 return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
252}
253
db1771cf 254int
4b13b216 255grub_isdigit (int c)
db1771cf 256{
257 return (c >= '0' && c <= '9');
258}
259
260int
4b13b216 261grub_isgraph (int c)
db1771cf 262{
263 return (c >= '!' && c <= '~');
264}
265
6a161fa9 266int
4b13b216 267grub_tolower (int c)
6a161fa9 268{
269 if (c >= 'A' && c <= 'Z')
270 return c - 'A' + 'a';
271
272 return c;
273}
274
275unsigned long
4b13b216 276grub_strtoul (const char *str, char **end, int base)
6a161fa9 277{
278 unsigned long num = 0;
279 int found = 0;
280
281 /* Skip white spaces. */
4b13b216 282 while (*str && grub_isspace (*str))
6a161fa9 283 str++;
284
285 /* Guess the base, if not specified. The prefix `0x' means 16, and
286 the prefix `0' means 8. */
287 if (str[0] == '0')
288 {
289 if (str[1] == 'x')
290 {
291 if (base == 0 || base == 16)
292 {
293 base = 16;
294 str += 2;
295 }
296 }
297 else if (str[1] >= '0' && str[1] <= '7')
298 base = 8;
299 }
300
301 if (base == 0)
302 base = 10;
303
304 while (*str)
305 {
306 unsigned long digit;
307
4b13b216 308 digit = grub_tolower (*str) - '0';
6a161fa9 309 if (digit > 9)
310 {
311 digit += '0' - 'a' + 10;
312 if (digit >= (unsigned long) base)
313 break;
314 }
315
316 found = 1;
317
318 if (num > (~0UL - digit) / base)
319 {
4b13b216 320 grub_error (GRUB_ERR_OUT_OF_RANGE, "overflow is detected");
6a161fa9 321 return 0;
322 }
323
e15199cb 324 num = num * base + digit;
6a161fa9 325 str++;
326 }
327
328 if (! found)
329 {
4b13b216 330 grub_error (GRUB_ERR_BAD_NUMBER, "unrecognized number");
6a161fa9 331 return 0;
332 }
333
334 if (end)
335 *end = (char *) str;
336
337 return num;
338}
339
340char *
4b13b216 341grub_strdup (const char *s)
6a161fa9 342{
4b13b216 343 grub_size_t len;
6a161fa9 344 char *p;
345
4b13b216 346 len = grub_strlen (s) + 1;
347 p = (char *) grub_malloc (len);
5aded270 348 if (! p)
349 return 0;
350
4b13b216 351 return grub_memcpy (p, s, len);
5aded270 352}
353
354char *
4b13b216 355grub_strndup (const char *s, grub_size_t n)
5aded270 356{
4b13b216 357 grub_size_t len = 0;
5aded270 358 char *p = (char *) s;
359
360 while (*(p++) && len < n)
361 len++;
362
4b13b216 363 len = grub_strlen (s) + 1;
364 p = (char *) grub_malloc (len);
6a161fa9 365 if (! p)
366 return 0;
367
4b13b216 368 return grub_memcpy (p, s, len);
6a161fa9 369}
370
371void *
4b13b216 372grub_memset (void *s, int c, grub_size_t n)
6a161fa9 373{
374 unsigned char *p = (unsigned char *) s;
375
376 while (n--)
377 *p++ = (unsigned char) c;
378
379 return s;
380}
062b24c2 381void *memset (void *s, int c, grub_size_t n)
382 __attribute__ ((alias ("grub_memset")));
6a161fa9 383
4b13b216 384grub_size_t
385grub_strlen (const char *s)
6a161fa9 386{
a5ffe966 387 const char *p = s;
6a161fa9 388
389 while (*p)
390 p++;
391
392 return p - s;
393}
394
395static inline void
4b13b216 396grub_reverse (char *str)
6a161fa9 397{
4b13b216 398 char *p = str + grub_strlen (str) - 1;
6a161fa9 399
400 while (str < p)
401 {
402 char tmp;
403
404 tmp = *str;
405 *str = *p;
406 *p = tmp;
407 str++;
408 p--;
409 }
410}
411
a5ffe966 412static char *
4b13b216 413grub_itoa (char *str, int c, unsigned n)
6a161fa9 414{
415 unsigned base = (c == 'x') ? 16 : 10;
416 char *p;
417
418 if ((int) n < 0 && c == 'd')
419 {
420 n = (unsigned) (-((int) n));
421 *str++ = '-';
422 }
423
424 p = str;
425 do
426 {
427 unsigned d = n % base;
428 *p++ = (d > 9) ? d + 'a' - 10 : d + '0';
429 }
430 while (n /= base);
431 *p = 0;
432
4b13b216 433 grub_reverse (str);
6a161fa9 434 return p;
435}
436
db1771cf 437static char *
4b13b216 438grub_ftoa (char *str, double f, int round)
db1771cf 439{
440 unsigned int intp;
441 unsigned int fractp;
442 unsigned int power = 1;
443 int i;
444
445 for (i = 0; i < round; i++)
446 power *= 10;
447
448 intp = f;
449 fractp = (f - (float) intp) * power;
450
4b13b216 451 grub_sprintf (str, "%d.%d", intp, fractp);
db1771cf 452 return str;
453}
454
6a161fa9 455int
4b13b216 456grub_vsprintf (char *str, const char *fmt, va_list args)
6a161fa9 457{
458 char c;
459 int count = 0;
18d9c7cd 460 auto void write_char (unsigned char ch);
6a161fa9 461 auto void write_str (const char *s);
db1771cf 462 auto void write_fill (const char ch, int n);
6a161fa9 463
18d9c7cd 464 void write_char (unsigned char ch)
6a161fa9 465 {
466 if (str)
a5ffe966 467 *str++ = ch;
6a161fa9 468 else
4b13b216 469 grub_putchar (ch);
6a161fa9 470
471 count++;
472 }
473
474 void write_str (const char *s)
475 {
476 while (*s)
477 write_char (*s++);
478 }
db1771cf 479
480 void write_fill (const char ch, int n)
481 {
482 int i;
483 for (i = 0; i < n; i++)
484 write_char (ch);
485 }
6a161fa9 486
487 while ((c = *fmt++) != 0)
488 {
489 if (c != '%')
490 write_char (c);
491 else
492 {
493 char tmp[16];
494 char *p;
db1771cf 495 unsigned int format1 = 0;
496 unsigned int format2 = 3;
497 char zerofill = ' ';
498 int rightfill = 0;
6a161fa9 499 int n;
500
db1771cf 501 if (*fmt && *fmt =='-')
502 {
503 rightfill = 1;
504 fmt++;
505 }
6a161fa9 506
db1771cf 507 p = (char *) fmt;
508 /* Read formatting parameters. */
4b13b216 509 while (*p && grub_isdigit (*p))
db1771cf 510 p++;
511
512 if (p > fmt)
513 {
514 char s[p - fmt];
4b13b216 515 grub_strncpy (s, fmt, p - fmt);
db1771cf 516 if (s[0] == '0')
517 zerofill = '0';
4b13b216 518 format1 = grub_strtoul (s, 0, 10);
db1771cf 519 fmt = p;
520 if (*p && *p == '.')
521 {
522 p++;
523 fmt++;
4b13b216 524 while (*p && grub_isdigit (*p))
db1771cf 525 p++;
526
527 if (p > fmt)
528 {
529 char fstr[p - fmt];
4b13b216 530 grub_strncpy (fstr, fmt, p - fmt);
531 format2 = grub_strtoul (fstr, 0, 10);
db1771cf 532 fmt = p;
533 }
534 }
535 }
536
537 c = *fmt++;
538
6a161fa9 539 switch (c)
540 {
541 case 'p':
542 write_str ("0x");
543 c = 'x';
544 /* fall through */
545 case 'x':
546 case 'u':
547 case 'd':
548 n = va_arg (args, int);
4b13b216 549 grub_itoa (tmp, c, n);
550 if (!rightfill && grub_strlen (tmp) < format1)
551 write_fill (zerofill, format1 - grub_strlen (tmp));
6a161fa9 552 write_str (tmp);
4b13b216 553 if (rightfill && grub_strlen (tmp) < format1)
554 write_fill (zerofill, format1 - grub_strlen (tmp));
6a161fa9 555 break;
db1771cf 556
6a161fa9 557 case 'c':
558 n = va_arg (args, int);
18d9c7cd 559 write_char (n & 0xff);
560 break;
561
db1771cf 562 case 'f':
563 {
564 float f;
565 f = va_arg (args, double);
4b13b216 566 grub_ftoa (tmp, f, format2);
567 if (!rightfill && grub_strlen (tmp) < format1)
568 write_fill (zerofill, format1 - grub_strlen (tmp));
db1771cf 569 write_str (tmp);
4b13b216 570 if (rightfill && grub_strlen (tmp) < format1)
571 write_fill (zerofill, format1 - grub_strlen (tmp));
db1771cf 572 break;
573 }
574
18d9c7cd 575 case 'C':
576 {
4b13b216 577 grub_uint32_t code = va_arg (args, grub_uint32_t);
18d9c7cd 578 int shift;
579 unsigned mask;
580
581 if (code <= 0x7f)
582 {
583 shift = 0;
584 mask = 0;
585 }
586 else if (code <= 0x7ff)
587 {
588 shift = 6;
589 mask = 0xc0;
590 }
591 else if (code <= 0xffff)
592 {
593 shift = 12;
594 mask = 0xe0;
595 }
596 else if (code <= 0x1fffff)
597 {
598 shift = 18;
599 mask = 0xf0;
600 }
601 else if (code <= 0x3ffffff)
602 {
603 shift = 24;
604 mask = 0xf8;
605 }
606 else if (code <= 0x7fffffff)
607 {
608 shift = 30;
609 mask = 0xfc;
610 }
611 else
612 {
613 code = '?';
614 shift = 0;
615 mask = 0;
616 }
617
618 write_char (mask | (code >> shift));
619
620 for (shift -= 6; shift >= 0; shift -= 6)
621 write_char (0x80 | (0x3f & (code >> shift)));
622 }
6a161fa9 623 break;
624
625 case 's':
626 p = va_arg (args, char *);
627 if (p)
db1771cf 628 {
4b13b216 629 if (!rightfill && grub_strlen (p) < format1)
630 write_fill (zerofill, format1 - grub_strlen (p));
db1771cf 631
632 write_str (p);
633
4b13b216 634 if (rightfill && grub_strlen (p) < format1)
635 write_fill (zerofill, format1 - grub_strlen (p));
db1771cf 636 }
6a161fa9 637 else
638 write_str ("(null)");
db1771cf 639
6a161fa9 640 break;
641
642 default:
643 write_char (c);
644 break;
645 }
646 }
647 }
648
649 if (str)
650 *str = '\0';
1f7315a3 651
652 if (count && !str)
4b13b216 653 grub_refresh ();
6a161fa9 654
655 return count;
656}
657
658int
4b13b216 659grub_sprintf (char *str, const char *fmt, ...)
6a161fa9 660{
661 va_list ap;
662 int ret;
663
664 va_start (ap, fmt);
4b13b216 665 ret = grub_vsprintf (str, fmt, ap);
6a161fa9 666 va_end (ap);
667
668 return ret;
669}
db1771cf 670
aa033560 671/* Convert UTF-16 to UTF8. */
672grub_uint8_t *
673grub_utf16_to_utf8 (grub_uint8_t *dest, grub_uint16_t *src,
674 grub_size_t size)
675{
676 grub_uint32_t code_high = 0;
677
678 while (size--)
679 {
680 grub_uint32_t code = *src++;
681
682 if (code_high)
683 {
684 if (code >= 0xDC00 && code <= 0xDFFF)
685 {
686 /* Surrogate pair. */
687 code = ((code_high - 0xD800) << 12) + (code - 0xDC00) + 0x10000;
688
689 *dest++ = (code >> 18) | 0xF0;
690 *dest++ = ((code >> 12) & 0x3F) | 0x80;
691 *dest++ = ((code >> 6) & 0x3F) | 0x80;
692 *dest++ = (code & 0x3F) | 0x80;
693 }
694 else
695 {
696 /* Error... */
697 *dest++ = '?';
698 }
699
700 code_high = 0;
701 }
702 else
703 {
704 if (code <= 0x007F)
705 *dest++ = code;
706 else if (code <= 0x07FF)
707 {
708 *dest++ = (code >> 6) | 0xC0;
709 *dest++ = (code & 0x3F) | 0x80;
710 }
711 else if (code >= 0xD800 && code <= 0xDBFF)
712 {
713 code_high = code;
714 continue;
715 }
716 else if (code >= 0xDC00 && code <= 0xDFFF)
717 {
718 /* Error... */
719 *dest++ = '?';
720 }
721 else
722 {
723 *dest++ = (code >> 16) | 0xE0;
724 *dest++ = ((code >> 12) & 0x3F) | 0x80;
725 *dest++ = (code & 0x3F) | 0x80;
726 }
727 }
728 }
729
730 return dest;
731}
732
4b13b216 733grub_err_t
734grub_split_cmdline (const char *cmdline, grub_err_t (* getline) (char **), int *argc, char ***argv)
db1771cf 735{
736 /* XXX: Fixed size buffer, perhaps this buffer should be dynamically
737 allocated. */
738 char buffer[1024];
739 char *bp = buffer;
740 char *rd = (char *) cmdline;
741 char unputbuf;
742 int unput = 0;
743 char *args;
744 int i;
745
746 auto char getchar (void);
747 auto void unputc (char c);
748 auto void getenvvar (void);
749 auto int getarg (void);
750
751 /* Get one character from the commandline. If the caller reads
752 beyond the end of the string a new line will be read. This
753 function will not chech for errors, the caller has to check for
4b13b216 754 grub_errno. */
db1771cf 755 char getchar (void)
756 {
757 int c;
758 if (unput)
759 {
760 unput = 0;
761 return unputbuf;
762 }
763
764 if (! rd)
765 {
766 getline (&rd);
767 /* Error is ignored here, the caller will check for this
768 when it reads beyond the EOL. */
769 c = *(rd)++;
770 return c;
771 }
772
773 c = *(rd)++;
774 if (! c)
775 {
776 rd = 0;
777 return '\n';
778 }
779
780 return c;
781 }
782
783 void unputc (char c)
784 {
785 unputbuf = c;
786 unput = 1;
787 }
788
789 /* Read a variable name from the commandline and insert its content
790 into the buffer. */
791 void getenvvar (void)
792 {
793 char varname[100];
794 char *p = varname;
795 char *val;
796 char c;
797
798 c = getchar ();
799 if (c == '{')
800 while ((c = getchar ()) != '}')
801 *(p++) = c;
802 else
803 {
804 /* XXX: An env. variable can have characters and digits in
805 its name, are more characters allowed here? */
4b13b216 806 while (c && (grub_isalpha (c) || grub_isdigit (c)))
db1771cf 807 {
808 *(p++) = c;
809 c = getchar ();
810 }
811 unputc (c);
812 }
813 *p = '\0';
814
815 /* The variable does not exist. */
4b13b216 816 val = grub_env_get (varname);
db1771cf 817 if (! val)
818 return;
819
820 /* Copy the contents of the variable into the buffer. */
821 for (p = val; *p; p++)
822 *(bp++) = *p;
823 }
824
825 /* Read one argument. Return 1 if no variables can be read anymore,
826 otherwise return 0. If there is an error, return 1, the caller
4b13b216 827 has to check grub_errno. */
db1771cf 828 int getarg (void)
829 {
830 char c;
831
832 /* Skip all whitespaces before an argument. */
833 do {
834 c = getchar ();
835 } while (c == ' ' || c == '\t');
836
837 do {
838 switch (c)
839 {
840 case '"':
841 /* Double quote. */
842 while ((c = getchar ()))
843 {
4b13b216 844 if (grub_errno)
db1771cf 845 return 1;
846 /* Read in an escaped character. */
847 if (c == '\\')
848 {
849 c = getchar ();
850 *(bp++) = c;
851 continue;
852 }
853 else if (c == '"')
854 break;
855 /* Read a variable. */
856 if (c == '$')
857 {
858 getenvvar ();
859 continue;
860 }
861 *(bp++) = c;
862 }
863 break;
864
865 case '\'':
866 /* Single quote. */
867 while ((c = getchar ()) != '\'')
868 {
4b13b216 869 if (grub_errno)
db1771cf 870 return 1;
871
872 *(bp++) = c;
873 }
874 break;
875
876 case '\n':
877 /* This was not a argument afterall. */
878 return 1;
879
880 default:
881 /* A normal option. */
4b13b216 882 while (c && (grub_isalpha (c)
883 || grub_isdigit (c) || grub_isgraph (c)))
db1771cf 884 {
885 /* Read in an escaped character. */
886 if (c == '\\')
887 {
888 c = getchar ();
889 *(bp++) = c;
890 c = getchar ();
891 continue;
892 }
893 /* Read a variable. */
894 if (c == '$')
895 {
896 getenvvar ();
897 c = getchar ();
898 continue;
899 }
900 *(bp++) = c;
901 c = getchar ();
902 }
903 unputc (c);
904
905 break;
906 }
4b13b216 907 } while (! grub_isspace (c) && c != '\'' && c != '"');
db1771cf 908
909 return 0;
910 }
911
912 /* Read in all arguments and count them. */
913 *argc = 0;
914 while (1)
915 {
916 if (getarg ())
917 break;
918 *(bp++) = '\0';
919 (*argc)++;
920 }
921
922 /* Check if there were no errors. */
4b13b216 923 if (grub_errno)
924 return grub_errno;
db1771cf 925
926 /* Reserve memory for the return values. */
4b13b216 927 args = grub_malloc (bp - buffer);
db1771cf 928 if (! args)
4b13b216 929 return grub_errno;
930 grub_memcpy (args, buffer, bp - buffer);
db1771cf 931
4b13b216 932 *argv = grub_malloc (sizeof (char *) * (*argc + 1));
db1771cf 933 if (! *argv)
934 {
4b13b216 935 grub_free (args);
936 return grub_errno;
db1771cf 937 }
938
939 /* The arguments are separated with 0's, setup argv so it points to
940 the right values. */
941 bp = args;
942 for (i = 0; i < *argc; i++)
943 {
944 (*argv)[i] = bp;
945 while (*bp)
946 bp++;
947 bp++;
948 }
949
950 (*argc)--;
951 return 0;
952}