OpenSolaris_b135/grub/grub-0.97/netboot/misc.c

Compare this file to the similar file:
Show the results in this format:

/*
 *  GRUB  --  GRand Unified Bootloader
 *  Copyright (C) 2000,2001,2002  Free Software Foundation, Inc.
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

/* Based on "src/misc.c" in etherboot-5.0.5.  */

#include "grub.h"
#include "timer.h"

#include "nic.h"

/**************************************************************************
RANDOM - compute a random number between 0 and 2147483647L or 2147483562?
**************************************************************************/
int32_t random(void)
{
	static int32_t seed = 0;
	int32_t q;
	if (!seed) /* Initialize linear congruential generator */
		seed = currticks() + *(int32_t *)&arptable[ARP_CLIENT].node
		       + ((int16_t *)arptable[ARP_CLIENT].node)[2];
	/* simplified version of the LCG given in Bruce Schneier's
	   "Applied Cryptography" */
	q = seed/53668;
	if ((seed = 40014*(seed-53668*q) - 12211*q) < 0) seed += 2147483563L;
	return seed;
}

/**************************************************************************
POLL INTERRUPTIONS
**************************************************************************/
void poll_interruptions(void)
{
	if (checkkey() != -1 && ASCII_CHAR(getkey()) == K_INTR) {
		user_abort++;
	}
}

/**************************************************************************
SLEEP
**************************************************************************/
void sleep(int secs)
{
	unsigned long tmo;

	for (tmo = currticks()+secs*TICKS_PER_SEC; currticks() < tmo; ) {
		poll_interruptions();
	}
}

/**************************************************************************
INTERRUPTIBLE SLEEP
**************************************************************************/
void interruptible_sleep(int secs)
{
	printf("<sleep>\n");
	return sleep(secs);
}

/**************************************************************************
TWIDDLE
**************************************************************************/
void twiddle(void)
{
#ifdef BAR_PROGRESS
	static int count=0;
	static const char tiddles[]="-\\|/";
	static unsigned long lastticks = 0;
	unsigned long ticks;
#endif
#ifdef FREEBSD_PXEEMU
	extern char pxeemu_nbp_active;
	if(pxeemu_nbp_active != 0)
		return;
#endif
#ifdef	BAR_PROGRESS
	/* Limit the maximum rate at which characters are printed */
	ticks = currticks();
	if ((lastticks + (TICKS_PER_SEC/18)) > ticks)
		return;
	lastticks = ticks;

	putchar(tiddles[(count++)&3]);
	putchar('\b');
#else
	//putchar('.');
#endif	/* BAR_PROGRESS */
}


/* Because Etherboot uses its own formats for the printf family,
   define separate definitions from GRUB.  */
/**************************************************************************
PRINTF and friends

	Formats:
		%[#]x	- 4 bytes long (8 hex digits, lower case)
		%[#]X	- 4 bytes long (8 hex digits, upper case)
		%[#]hx	- 2 bytes int (4 hex digits, lower case)
		%[#]hX	- 2 bytes int (4 hex digits, upper case)
		%[#]hhx	- 1 byte int (2 hex digits, lower case)
		%[#]hhX	- 1 byte int (2 hex digits, upper case)
			- optional # prefixes 0x or 0X
		%d	- decimal int
		%c	- char
		%s	- string
		%@	- Internet address in ddd.ddd.ddd.ddd notation
		%!	- Ethernet address in xx:xx:xx:xx:xx:xx notation
	Note: width specification not supported
**************************************************************************/
static int
etherboot_vsprintf (char *buf, const char *fmt, const int *dp)
{
  char *p, *s;
  
  s = buf;
  for ( ; *fmt != '\0'; ++fmt)
    {
      if (*fmt != '%')
	{
	  buf ? *s++ = *fmt : grub_putchar (*fmt);
	  continue;
	}
      
      if (*++fmt == 's')
	{
	  for (p = (char *) *dp++; *p != '\0'; p++)
	    buf ? *s++ = *p : grub_putchar (*p);
	}
      else
	{
	  /* Length of item is bounded */
	  char tmp[20], *q = tmp;
	  int alt = 0;
	  int shift = 28;
	  
	  if (*fmt == '#')
	    {
	      alt = 1;
	      fmt++;
	    }
	  
	  if (*fmt == 'h')
	    {
	      shift = 12;
	      fmt++;
	    }
	  
	  if (*fmt == 'h')
	    {
	      shift = 4;
	      fmt++;
	    }
	  
	  /*
	   * Before each format q points to tmp buffer
	   * After each format q points past end of item
	   */
	  if ((*fmt | 0x20) == 'x')
	    {
	      /* With x86 gcc, sizeof(long) == sizeof(int) */
	      const long *lp = (const long *) dp;
	      long h = *lp++;
	      int ncase = (*fmt & 0x20);
	      
	      dp = (const int *) lp;
	      if (alt)
		{
		  *q++ = '0';
		  *q++ = 'X' | ncase;
		}
	      for (; shift >= 0; shift -= 4)
		*q++ = "0123456789ABCDEF"[(h >> shift) & 0xF] | ncase;
	    }
	  else if (*fmt == 'd')
	    {
	      int i = *dp++;
	      char *r;
	      
	      if (i < 0)
		{
		  *q++ = '-';
		  i = -i;
		}
	      
	      p = q;		/* save beginning of digits */
	      do
		{
		  *q++ = '0' + (i % 10);
		  i /= 10;
		}
	      while (i);
	      
	      /* reverse digits, stop in middle */
	      r = q;		/* don't alter q */
	      while (--r > p)
		{
		  i = *r;
		  *r = *p;
		  *p++ = i;
		}
	    }
	  else if (*fmt == '@')
	    {
	      unsigned char *r;
	      union
	      {
		long		l;
		unsigned char	c[4];
	      }
	      u;
	      const long *lp = (const long *) dp;
	      
	      u.l = *lp++;
	      dp = (const int *) lp;
	      
	      for (r = &u.c[0]; r < &u.c[4]; ++r)
		q += etherboot_sprintf (q, "%d.", *r);
	      
	      --q;
	    }
	  else if (*fmt == '!')
	    {
	      char *r;
	      p = (char *) *dp++;
	      
	      for (r = p + ETH_ALEN; p < r; ++p)
		q += etherboot_sprintf (q, "%hhX:", *p);
	      
	      --q;
	    }
	  else if (*fmt == 'c')
	    *q++ = *dp++;
	  else
	    *q++ = *fmt;
	  
	  /* now output the saved string */
	  for (p = tmp; p < q; ++p)
	    buf ? *s++ = *p : grub_putchar (*p);
	}
    }
  
  if (buf)
    *s = '\0';
  
  return (s - buf);
}

int
etherboot_sprintf (char *buf, const char *fmt, ...)
{
  return etherboot_vsprintf (buf, fmt, ((const int *) &fmt) + 1);
}

void
etherboot_printf (const char *fmt, ...)
{
  (void) etherboot_vsprintf (0, fmt, ((const int *) &fmt) + 1);
}

int
inet_aton (char *p, in_addr *addr)
{
  unsigned long ip = 0;
  int val;
  int i;
  
  for (i = 0; i < 4; i++)
    {
      val = getdec (&p);
      
      if (val < 0 || val > 255)
	return 0;
      
      if (i != 3 && *p++ != '.')
	return 0;
      
      ip = (ip << 8) | val;
    }

  addr->s_addr = htonl (ip);

  return 1;
}

int
getdec (char **ptr)
{
  char *p = *ptr;
  int ret = 0;
  
  if (*p < '0' || *p > '9')
    return -1;
  
  while (*p >= '0' && *p <= '9')
    {
      ret = ret * 10 + (*p - '0');
      p++;
    }
  
  *ptr = p;
  
  return ret;
}