1/*
2 *  GRUB  --  GRand Unified Bootloader
3 *  Copyright (C) 2000,2001,2002  Free Software Foundation, Inc.
4 *
5 *  This program is free software; you can redistribute it and/or modify
6 *  it under the terms of the GNU General Public License as published by
7 *  the Free Software Foundation; either version 2 of the License, or
8 *  (at your option) any later version.
9 *
10 *  This program is distributed in the hope that it will be useful,
11 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 *  GNU General Public License for more details.
14 *
15 *  You should have received a copy of the GNU General Public License
16 *  along with this program; if not, write to the Free Software
17 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19
20/* Based on "src/misc.c" in etherboot-5.0.5.  */
21
22#define GRUB	1
23#include <etherboot.h>
24
25void
26sleep (int secs)
27{
28  unsigned long tmo = currticks () + secs;
29
30  while (currticks () < tmo)
31    ;
32}
33
34void
35twiddle (void)
36{
37  static unsigned long lastticks = 0;
38  static int count = 0;
39  static const char tiddles[]="-\\|/";
40  unsigned long ticks;
41
42  if (debug)
43    {
44      if ((ticks = currticks ()) == lastticks)
45	return;
46
47      lastticks = ticks;
48      grub_putchar (tiddles[(count++) & 3]);
49      grub_putchar ('\b');
50    }
51}
52
53/* Because Etherboot uses its own formats for the printf family,
54   define separate definitions from GRUB.  */
55/**************************************************************************
56PRINTF and friends
57
58	Formats:
59		%[#]x	- 4 bytes long (8 hex digits, lower case)
60		%[#]X	- 4 bytes long (8 hex digits, upper case)
61		%[#]hx	- 2 bytes int (4 hex digits, lower case)
62		%[#]hX	- 2 bytes int (4 hex digits, upper case)
63		%[#]hhx	- 1 byte int (2 hex digits, lower case)
64		%[#]hhX	- 1 byte int (2 hex digits, upper case)
65			- optional # prefixes 0x or 0X
66		%d	- decimal int
67		%c	- char
68		%s	- string
69		%@	- Internet address in ddd.ddd.ddd.ddd notation
70		%!	- Ethernet address in xx:xx:xx:xx:xx:xx notation
71	Note: width specification not supported
72**************************************************************************/
73static int
74etherboot_vsprintf (char *buf, const char *fmt, const int *dp)
75{
76  char *p, *s;
77
78  s = buf;
79  for ( ; *fmt != '\0'; ++fmt)
80    {
81      if (*fmt != '%')
82	{
83	  buf ? *s++ = *fmt : grub_putchar (*fmt);
84	  continue;
85	}
86
87      if (*++fmt == 's')
88	{
89	  for (p = (char *) *dp++; *p != '\0'; p++)
90	    buf ? *s++ = *p : grub_putchar (*p);
91	}
92      else
93	{
94	  /* Length of item is bounded */
95	  char tmp[20], *q = tmp;
96	  int alt = 0;
97	  int shift = 28;
98
99	  if (*fmt == '#')
100	    {
101	      alt = 1;
102	      fmt++;
103	    }
104
105	  if (*fmt == 'h')
106	    {
107	      shift = 12;
108	      fmt++;
109	    }
110
111	  if (*fmt == 'h')
112	    {
113	      shift = 4;
114	      fmt++;
115	    }
116
117	  /*
118	   * Before each format q points to tmp buffer
119	   * After each format q points past end of item
120	   */
121	  if ((*fmt | 0x20) == 'x')
122	    {
123	      /* With x86 gcc, sizeof(long) == sizeof(int) */
124	      const long *lp = (const long *) dp;
125	      long h = *lp++;
126	      int ncase = (*fmt & 0x20);
127
128	      dp = (const int *) lp;
129	      if (alt)
130		{
131		  *q++ = '0';
132		  *q++ = 'X' | ncase;
133		}
134	      for (; shift >= 0; shift -= 4)
135		*q++ = "0123456789ABCDEF"[(h >> shift) & 0xF] | ncase;
136	    }
137	  else if (*fmt == 'd')
138	    {
139	      int i = *dp++;
140	      char *r;
141
142	      if (i < 0)
143		{
144		  *q++ = '-';
145		  i = -i;
146		}
147
148	      p = q;		/* save beginning of digits */
149	      do
150		{
151		  *q++ = '0' + (i % 10);
152		  i /= 10;
153		}
154	      while (i);
155
156	      /* reverse digits, stop in middle */
157	      r = q;		/* don't alter q */
158	      while (--r > p)
159		{
160		  i = *r;
161		  *r = *p;
162		  *p++ = i;
163		}
164	    }
165	  else if (*fmt == '@')
166	    {
167	      unsigned char *r;
168	      union
169	      {
170		long		l;
171		unsigned char	c[4];
172	      }
173	      u;
174	      const long *lp = (const long *) dp;
175
176	      u.l = *lp++;
177	      dp = (const int *) lp;
178
179	      for (r = &u.c[0]; r < &u.c[4]; ++r)
180		q += etherboot_sprintf (q, "%d.", *r);
181
182	      --q;
183	    }
184	  else if (*fmt == '!')
185	    {
186	      char *r;
187	      p = (char *) *dp++;
188
189	      for (r = p + ETH_ALEN; p < r; ++p)
190		q += etherboot_sprintf (q, "%hhX:", *p);
191
192	      --q;
193	    }
194	  else if (*fmt == 'c')
195	    *q++ = *dp++;
196	  else
197	    *q++ = *fmt;
198
199	  /* now output the saved string */
200	  for (p = tmp; p < q; ++p)
201	    buf ? *s++ = *p : grub_putchar (*p);
202	}
203    }
204
205  if (buf)
206    *s = '\0';
207
208  return (s - buf);
209}
210
211int
212etherboot_sprintf (char *buf, const char *fmt, ...)
213{
214  return etherboot_vsprintf (buf, fmt, ((const int *) &fmt) + 1);
215}
216
217void
218etherboot_printf (const char *fmt, ...)
219{
220  (void) etherboot_vsprintf (0, fmt, ((const int *) &fmt) + 1);
221}
222
223int
224inet_aton (char *p, in_addr *addr)
225{
226  unsigned long ip = 0;
227  int val;
228  int i;
229
230  for (i = 0; i < 4; i++)
231    {
232      val = getdec (&p);
233
234      if (val < 0 || val > 255)
235	return 0;
236
237      if (i != 3 && *p++ != '.')
238	return 0;
239
240      ip = (ip << 8) | val;
241    }
242
243  addr->s_addr = htonl (ip);
244
245  return 1;
246}
247
248int
249getdec (char **ptr)
250{
251  char *p = *ptr;
252  int ret = 0;
253
254  if (*p < '0' || *p > '9')
255    return -1;
256
257  while (*p >= '0' && *p <= '9')
258    {
259      ret = ret * 10 + (*p - '0');
260      p++;
261    }
262
263  *ptr = p;
264
265  return ret;
266}
267