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 25 void 26 sleep (int secs) 27 { 28 unsigned long tmo = currticks () + secs; 29 30 while (currticks () < tmo) 31 ; 32 } 33 34 void 35 twiddle (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 /************************************************************************** 56 PRINTF 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 **************************************************************************/ 73 static int 74 etherboot_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 211 int 212 etherboot_sprintf (char *buf, const char *fmt, ...) 213 { 214 return etherboot_vsprintf (buf, fmt, ((const int *) &fmt) + 1); 215 } 216 217 void 218 etherboot_printf (const char *fmt, ...) 219 { 220 (void) etherboot_vsprintf (0, fmt, ((const int *) &fmt) + 1); 221 } 222 223 int 224 inet_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 248 int 249 getdec (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