add an extra option into the command install, and allow to mount extended partitions.

This commit is contained in:
okuji 1999-11-02 12:54:19 +00:00
parent 8fb66b3a69
commit c6ec01220b
8 changed files with 160 additions and 95 deletions

View file

@ -1,3 +1,26 @@
1999-11-02 OKUJI Yoshinori <okuji@kuicr.kyoto-u.ac.jp>
* stage2/disk_io.c (real_open_partition): Check for the right
partition for any extended partition as well. Set EXT to I after
the check is done. Reported by Jeff Scheinberg
<jeffsh@erols.com>.
* stage2/builtins.c (color_func): Use the function
nul_terminate.
(device_func) [GRUB_UTIL]: Likewise.
(help_func): Likewise.
(install_func): Save CURRENT_DRIVE, CURRENT_PARTITION and
BUG_GEOM in SRC_DRIVE, SRC_PARTITION and SRC_GEOM respectively,
and use them when patching the Stage 2.
NUL-terminate the configuration filename CONFIG_FILENAME.
If IS_STAGE1_5 is true, then check if the "real config file"
option is present, and, if so, patch the Stage 2 CONFIG_FILENAME
with the configuration filename REAL_CONFIG_FILENAME.
(setkey_func): Use nul_terminate instead of the local function
null_terminate.
* stage2/char_io.c [!STAGE1_5] (nul_terminate): New function.
* stage2/shared.h (nul_terminate): Declared.
1999-11-01 OKUJI Yoshinori <okuji@kuicr.kyoto-u.ac.jp> 1999-11-01 OKUJI Yoshinori <okuji@kuicr.kyoto-u.ac.jp>
* docs/grub.texi: Add "I/O ports detection" into the menu. * docs/grub.texi: Add "I/O ports detection" into the menu.

2
NEWS
View file

@ -24,6 +24,8 @@ New in 0.5.94:
* The command "ioprobe" detects what I/O ports are used for a BIOS * The command "ioprobe" detects what I/O ports are used for a BIOS
drive. drive.
* OpenBSD support in the grub shell is improved. * OpenBSD support in the grub shell is improved.
* The command "install" can now patch a Stage 2 with a different
filename from "/boot/grub/menu.lst" even if a Stage 1.5 is used.
New in 0.5.93: New in 0.5.93:
* ELF format of FreeBSD kernel is supported. * ELF format of FreeBSD kernel is supported.

2
TODO
View file

@ -36,8 +36,6 @@ Priorities:
* Add ISA PnP support. * Add ISA PnP support.
* Accept any extended partition when using it for chain-loading. !!!
* Fix the completion so that it works for BSD partitions as well. !! * Fix the completion so that it works for BSD partitions as well. !!
* Add more filesystems support (XFS, NTFS, etc.) * Add more filesystems support (XFS, NTFS, etc.)

View file

@ -830,7 +830,7 @@ Load an initial ramdisk for a Linux format boot image and set the
appropriate parameters in the Linux setup area in memory. appropriate parameters in the Linux setup area in memory.
@end deffn @end deffn
@deffn Command install stage1_file [@option{d}] dest_dev file [addr] [@option{p}] [config_file] @deffn Command install stage1_file [@option{d}] dest_dev stage2_file [addr] [@option{p}] [config_file] [real_config_file]
This command is fairly complex, and you should not use this command This command is fairly complex, and you should not use this command
unless you are familiar with GRUB. In short, it will perform a full unless you are familiar with GRUB. In short, it will perform a full
install presuming the Stage 2 or Stage 1.5@footnote{They're loaded the install presuming the Stage 2 or Stage 1.5@footnote{They're loaded the
@ -839,19 +839,23 @@ is in its final install location.
In slightly more detail, it will load @var{stage1_file}, validate that In slightly more detail, it will load @var{stage1_file}, validate that
it is a GRUB Stage 1 of the right version number, install a blocklist for it is a GRUB Stage 1 of the right version number, install a blocklist for
loading @var{file} as a Stage 2. If the option @option{d} is present, the loading @var{stage2_file} as a Stage 2. If the option @option{d} is
Stage 1 will always look for the actual disk @var{file} was installed on, present, the Stage 1 will always look for the actual disk
rather than using the booting drive. The Stage 2 will be loaded at @var{stage2_file} was installed on, rather than using the booting
address @var{addr}, which must be @samp{0x8000} for a true Stage 2, and drive. The Stage 2 will be loaded at address @var{addr}, which must be
@samp{0x2000} for a Stage 1.5. If @var{addr} is not present, GRUB will @samp{0x8000} for a true Stage 2, and @samp{0x2000} for a Stage 1.5. If
determine the address automatically. It then writes the completed Stage 1 @var{addr} is not present, GRUB will determine the address
to the first block of the device @var{dest_dev}. If the options @option{p} automatically. It then writes the completed Stage 1 to the first block
or @var{config_file} are present, then it reads the first block of of the device @var{dest_dev}. If the options @option{p} or
stage2, modifies it with the values of the partition @var{file} was @var{config_file} are present, then it reads the first block of stage2,
found on (for @option{p}) or places the string @var{config_file} into the modifies it with the values of the partition @var{stage2_file} was found
area telling the stage2 where to look for a configuration file at boot on (for @option{p}) or places the string @var{config_file} into the area
time. This command preserves the DOS BPB (and for hard disks, the telling the stage2 where to look for a configuration file at boot
partition table) of the sector the Stage 1 is to be installed into. time. Likewise, if @var{real_config_file} is present and
@var{stage2_file} is a Stage 1.5, then the Stage 2 @var{config_file} is
patched with the configuration filename @var{real_config_file}. This
command preserves the DOS BPB (and for hard disks, the partition table)
of the sector the Stage 1 is to be installed into.
@end deffn @end deffn
@deffn Command ioprobe drive @deffn Command ioprobe drive

View file

@ -290,12 +290,7 @@ color_func (char *arg, int flags)
return -1; return -1;
str = ptr; str = ptr;
/* Find a space. */ nul_terminate (str);
for (; *ptr && ! grub_isspace (*ptr); ptr++)
;
/* Terminate the string STR. */
*ptr = 0;
/* Search for the color name. */ /* Search for the color name. */
for (i = 0; i < 8; i++) for (i = 0; i < 8; i++)
@ -451,7 +446,6 @@ device_func (char *arg, int flags)
#ifdef GRUB_UTIL #ifdef GRUB_UTIL
char *drive = arg; char *drive = arg;
char *device; char *device;
char *ptr;
/* Get the drive number from DRIVE. */ /* Get the drive number from DRIVE. */
if (! set_device (drive)) if (! set_device (drive))
@ -466,10 +460,7 @@ device_func (char *arg, int flags)
} }
/* Terminate DEVICE. */ /* Terminate DEVICE. */
ptr = device; nul_terminate (device);
while (*ptr && *ptr != ' ')
ptr++;
*ptr = 0;
assign_device_name (current_drive, device); assign_device_name (current_drive, device);
@ -951,16 +942,13 @@ help_func (char *arg, int flags)
do do
{ {
struct builtin **builtin; struct builtin **builtin;
char *ptr = arg;
char *next_arg; char *next_arg;
/* Get the next argument. */ /* Get the next argument. */
next_arg = skip_to (0, arg); next_arg = skip_to (0, arg);
/* Terminate ARG. */ /* Terminate ARG. */
while (*ptr && *ptr != ' ') nul_terminate (arg);
ptr++;
*ptr = 0;
for (builtin = builtin_table; *builtin; builtin++) for (builtin = builtin_table; *builtin; builtin++)
{ {
@ -1120,11 +1108,14 @@ install_func (char *arg, int flags)
char *old_sect = stage1_buffer + SECTOR_SIZE; char *old_sect = stage1_buffer + SECTOR_SIZE;
char *stage2_first_buffer = old_sect + SECTOR_SIZE; char *stage2_first_buffer = old_sect + SECTOR_SIZE;
char *stage2_second_buffer = stage2_first_buffer + SECTOR_SIZE; char *stage2_second_buffer = stage2_first_buffer + SECTOR_SIZE;
char *dummy = stage2_second_buffer + SECTOR_SIZE; /* XXX: Probably SECTOR_SIZE is reasonable. */
char *config_filename = stage2_second_buffer + SECTOR_SIZE;
char *dummy = config_filename + SECTOR_SIZE;
int new_drive = 0xFF; int new_drive = 0xFF;
int dest_drive, dest_sector; int dest_drive, dest_sector;
int src_drive, src_partition;
int i; int i;
struct geometry dest_geom; struct geometry dest_geom, src_geom;
int saved_sector; int saved_sector;
int stage2_first_sector, stage2_second_sector; int stage2_first_sector, stage2_second_sector;
char *ptr; char *ptr;
@ -1251,9 +1242,13 @@ install_func (char *arg, int flags)
if (! is_open) if (! is_open)
goto fail; goto fail;
src_drive = current_drive;
src_partition = current_partition;
src_geom = buf_geom;
if (! new_drive) if (! new_drive)
new_drive = current_drive; new_drive = src_drive;
else if (current_drive != dest_drive) else if (src_drive != dest_drive)
grub_printf ("Warning: the option `d' was not used, but the Stage 1 will" grub_printf ("Warning: the option `d' was not used, but the Stage 1 will"
" be installed on a\ndifferent drive than the drive where" " be installed on a\ndifferent drive than the drive where"
" the Stage 2 resides.\n"); " the Stage 2 resides.\n");
@ -1340,7 +1335,7 @@ install_func (char *arg, int flags)
if (*ptr == 'p') if (*ptr == 'p')
{ {
*((long *) (stage2_second_buffer + STAGE2_INSTALLPART)) *((long *) (stage2_second_buffer + STAGE2_INSTALLPART))
= current_partition; = src_partition;
if (is_stage1_5) if (is_stage1_5)
{ {
/* Reset the device information in FILE if it is a Stage 1.5. */ /* Reset the device information in FILE if it is a Stage 1.5. */
@ -1355,6 +1350,9 @@ install_func (char *arg, int flags)
if (*ptr) if (*ptr)
{ {
grub_strcpy (config_filename, ptr);
nul_terminate (config_filename);
if (! is_stage1_5) if (! is_stage1_5)
/* If it is a Stage 2, just copy PTR to CONFIG_FILE_LOCATION. */ /* If it is a Stage 2, just copy PTR to CONFIG_FILE_LOCATION. */
grub_strcpy (config_file_location, ptr); grub_strcpy (config_file_location, ptr);
@ -1362,7 +1360,6 @@ install_func (char *arg, int flags)
{ {
char *config_file; char *config_file;
unsigned long device; unsigned long device;
int tmp = current_drive;
/* Translate the external device syntax to the internal device /* Translate the external device syntax to the internal device
syntax. */ syntax. */
@ -1374,11 +1371,63 @@ install_func (char *arg, int flags)
} }
device = current_drive << 24 | current_partition; device = current_drive << 24 | current_partition;
current_drive = tmp;
grub_memmove (config_file_location, (char *) &device, grub_memmove (config_file_location, (char *) &device,
sizeof (device)); sizeof (device));
grub_strcpy (config_file_location + sizeof (device), config_file); grub_strcpy (config_file_location + sizeof (device), config_file);
} }
/* Check if the configuration filename is specified, if a Stage 1.5
is used. */
if (is_stage1_5)
{
char *real_config_filename = skip_to (0, ptr);
if (*real_config_filename)
{
/* Specified */
char *location;
is_open = grub_open (config_filename);
if (! is_open)
goto fail;
/* Skip the first sector. */
filepos = SECTOR_SIZE;
disk_read_hook = disk_read_savesect_func;
if (grub_read ((char *) SCRATCHADDR, SECTOR_SIZE) != SECTOR_SIZE)
goto fail;
disk_read_hook = 0;
grub_close ();
is_open = 0;
/* Sanity check. */
if (*((unsigned char *) SCRATCHADDR + STAGE2_STAGE2_ID)
!= STAGE2_ID_STAGE2)
{
errnum = ERR_BAD_VERSION;
goto fail;
}
/* Find a string for the configuration filename. */
location = (char *) SCRATCHADDR + STAGE2_VER_STR_OFFS;
while (*(location++))
;
/* Copy the name. */
grub_strcpy (location, real_config_filename);
/* Write it to the disk. */
buf_track = -1;
if (biosdisk (BIOSDISK_WRITE, current_drive, &buf_geom,
saved_sector, 1, SCRATCHSEG))
{
errnum = ERR_WRITE;
goto fail;
}
}
}
} }
/* Clear the cache. */ /* Clear the cache. */
@ -1386,7 +1435,7 @@ install_func (char *arg, int flags)
/* Write the modified first sector of Stage2 to the disk. */ /* Write the modified first sector of Stage2 to the disk. */
grub_memmove ((char *) SCRATCHADDR, stage2_first_buffer, SECTOR_SIZE); grub_memmove ((char *) SCRATCHADDR, stage2_first_buffer, SECTOR_SIZE);
if (biosdisk (BIOSDISK_WRITE, current_drive, &buf_geom, if (biosdisk (BIOSDISK_WRITE, src_drive, &src_geom,
stage2_first_sector, 1, SCRATCHSEG)) stage2_first_sector, 1, SCRATCHSEG))
{ {
errnum = ERR_WRITE; errnum = ERR_WRITE;
@ -1395,7 +1444,7 @@ install_func (char *arg, int flags)
/* Write the modified second sector of Stage2 to the disk. */ /* Write the modified second sector of Stage2 to the disk. */
grub_memmove ((char *) SCRATCHADDR, stage2_second_buffer, SECTOR_SIZE); grub_memmove ((char *) SCRATCHADDR, stage2_second_buffer, SECTOR_SIZE);
if (biosdisk (BIOSDISK_WRITE, current_drive, &buf_geom, if (biosdisk (BIOSDISK_WRITE, src_drive, &src_geom,
stage2_second_sector, 1, SCRATCHSEG)) stage2_second_sector, 1, SCRATCHSEG))
{ {
errnum = ERR_WRITE; errnum = ERR_WRITE;
@ -1429,7 +1478,7 @@ static struct builtin builtin_install =
"install", "install",
install_func, install_func,
BUILTIN_CMDLINE, BUILTIN_CMDLINE,
"install STAGE1 [d] DEVICE STAGE2 [ADDR] [p] [CONFIG_FILE]", "install STAGE1 [d] DEVICE STAGE2 [ADDR] [p] [CONFIG_FILE] [REAL_CONFIG_FILE]",
"Install STAGE1 on DEVICE, and install a blocklist for loading STAGE2" "Install STAGE1 on DEVICE, and install a blocklist for loading STAGE2"
" as a Stage 2. If the option `d' is present, the Stage 1 will always" " as a Stage 2. If the option `d' is present, the Stage 1 will always"
" look for the disk where STAGE2 was installed, rather than using" " look for the disk where STAGE2 was installed, rather than using"
@ -1438,7 +1487,9 @@ static struct builtin builtin_install =
" the option `p' or CONFIG_FILE is present, then the first block" " the option `p' or CONFIG_FILE is present, then the first block"
" of Stage 2 is patched with new values of the partition and name" " of Stage 2 is patched with new values of the partition and name"
" of the configuration file used by the true Stage 2 (for a Stage 1.5," " of the configuration file used by the true Stage 2 (for a Stage 1.5,"
" this is the name of the true Stage 2) at boot time." " this is the name of the true Stage 2) at boot time. If STAGE2 is a Stage"
" 1.5 and REAL_CONFIG_FILE is present, then the Stage 2 CONFIG_FILE is"
" patched with the configuration filename REAL_CONFIG_FILE."
}; };
@ -1875,7 +1926,7 @@ struct keysym
unsigned char keycode; /* keyboard scancode */ unsigned char keycode; /* keyboard scancode */
}; };
/* The table for key symbols. If the "unshifted" member of an entry is /* The table for key symbols. If the "shifted" member of an entry is
NULL, the entry does not have shifted state. */ NULL, the entry does not have shifted state. */
static struct keysym keysym_table[] = static struct keysym keysym_table[] =
{ {
@ -1956,13 +2007,6 @@ setkey_func (char *arg, int flags)
int to_code, from_code; int to_code, from_code;
int map_in_interrupt = 0; int map_in_interrupt = 0;
static void null_terminate (char *str)
{
while (*str && ! grub_isspace (*str))
str++;
*str = 0;
}
static int find_key_code (char *key) static int find_key_code (char *key)
{ {
int i; int i;
@ -1996,8 +2040,8 @@ setkey_func (char *arg, int flags)
to_key = arg; to_key = arg;
from_key = skip_to (0, to_key); from_key = skip_to (0, to_key);
null_terminate (to_key); nul_terminate (to_key);
null_terminate (from_key); nul_terminate (from_key);
to_code = find_ascii_code (to_key); to_code = find_ascii_code (to_key);
from_code = find_ascii_code (from_key); from_code = find_ascii_code (from_key);

View file

@ -19,10 +19,8 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/ */
#include "shared.h" #include "shared.h"
void void
print_error (void) print_error (void)
{ {
@ -35,7 +33,6 @@ print_error (void)
#endif /* STAGE1_5 */ #endif /* STAGE1_5 */
} }
char * char *
convert_to_ascii (char *buf, int c,...) convert_to_ascii (char *buf, int c,...)
{ {
@ -78,7 +75,6 @@ convert_to_ascii (char *buf, int c,...)
return ptr; return ptr;
} }
void void
grub_printf (const char *format,...) grub_printf (const char *format,...)
{ {
@ -123,7 +119,6 @@ grub_printf (const char *format,...)
} }
} }
#ifndef STAGE1_5 #ifndef STAGE1_5
int int
grub_sprintf (char *buffer, const char *format, ...) grub_sprintf (char *buffer, const char *format, ...)
@ -168,10 +163,6 @@ grub_sprintf (char *buffer, const char *format, ...)
*bp = 0; *bp = 0;
return bp - buffer; return bp - buffer;
} }
#endif /* ! STAGE1_5 */
#ifndef STAGE1_5
void void
init_page (void) init_page (void)
@ -611,10 +602,8 @@ get_cmdline (char *prompt, char *cmdline, int maxlen,
return 0; return 0;
} }
#endif /* STAGE1_5 */ #endif /* STAGE1_5 */
int int
safe_parse_maxint (char **str_ptr, int *myint_ptr) safe_parse_maxint (char **str_ptr, int *myint_ptr)
{ {
@ -669,7 +658,6 @@ safe_parse_maxint (char **str_ptr, int *myint_ptr)
return 1; return 1;
} }
int int
grub_tolower (int c) grub_tolower (int c)
{ {
@ -679,7 +667,6 @@ grub_tolower (int c)
return c; return c;
} }
int int
grub_isspace (int c) grub_isspace (int c)
{ {
@ -706,9 +693,7 @@ grub_memcmp (const char *s1, const char *s2, int n)
return 0; return 0;
} }
#endif /* ! STAGE1_5 */
#ifndef STAGE1_5
int int
grub_strncat (char *s1, const char *s2, int n) grub_strncat (char *s1, const char *s2, int n)
{ {
@ -727,9 +712,7 @@ grub_strncat (char *s1, const char *s2, int n)
return 1; return 1;
} }
#endif /* ! STAGE1_5 */
#ifndef STAGE1_5
int int
grub_strcmp (const char *s1, const char *s2) grub_strcmp (const char *s1, const char *s2)
{ {
@ -766,8 +749,18 @@ substring (char *s1, char *s2)
return 1; return 1;
} }
#ifndef STAGE1_5 #ifndef STAGE1_5
/* Terminate the string STR with NUL. */
char *
nul_terminate (char *str)
{
while (*str && ! grub_isspace (*str))
str++;
*str++ = 0;
return str;
}
char * char *
grub_strstr (const char *s1, const char *s2) grub_strstr (const char *s1, const char *s2)
{ {
@ -799,7 +792,6 @@ grub_strlen (const char *str)
} }
#endif /* ! STAGE1_5 */ #endif /* ! STAGE1_5 */
int int
memcheck (int addr, int len) memcheck (int addr, int len)
{ {
@ -840,7 +832,6 @@ memcheck (int addr, int len)
return ! errnum; return ! errnum;
} }
char * char *
grub_memmove (char *to, const char *from, int len) grub_memmove (char *to, const char *from, int len)
{ {
@ -877,7 +868,6 @@ grub_memmove (char *to, const char *from, int len)
return errnum ? NULL : to; return errnum ? NULL : to;
} }
#ifndef STAGE1_5 #ifndef STAGE1_5
void * void *
grub_memset (void *start, int c, int len) grub_memset (void *start, int c, int len)

View file

@ -494,7 +494,7 @@ real_open_partition (int flags)
slice_no = 0; slice_no = 0;
/* if this is the whole disk, return here */ /* if this is the whole disk, return here */
if (!flags && current_partition == 0xFFFFFFuL) if (! flags && current_partition == 0xFFFFFFuL)
return 1; return 1;
/* /*
@ -508,7 +508,7 @@ real_open_partition (int flags)
/* /*
* If the table isn't valid, we can't continue * If the table isn't valid, we can't continue
*/ */
if (!PC_MBR_CHECK_SIG (mbr_buf)) if (! PC_MBR_CHECK_SIG (mbr_buf))
{ {
errnum = ERR_BAD_PART_TABLE; errnum = ERR_BAD_PART_TABLE;
return 0; return 0;
@ -527,7 +527,9 @@ real_open_partition (int flags)
part_start = part_offset + PC_SLICE_START (mbr_buf, i); part_start = part_offset + PC_SLICE_START (mbr_buf, i);
part_length = PC_SLICE_LENGTH (mbr_buf, i); part_length = PC_SLICE_LENGTH (mbr_buf, i);
#ifndef STAGE1_5 #ifndef STAGE1_5
memmove (cur_part_desc, mbr_buf + PC_SLICE_OFFSET + (i << 4), 16); grub_memmove (cur_part_desc,
mbr_buf + PC_SLICE_OFFSET + (i << 4),
16);
#endif #endif
/* /*
@ -535,21 +537,11 @@ real_open_partition (int flags)
*/ */
if (current_slice) if (current_slice)
{ {
/* #ifndef STAGE1_5
* Is this an extended partition?
*/
if (IS_PC_SLICE_TYPE_EXTENDED (current_slice))
{
if (ext == -1)
{
ext = i;
}
}
# ifndef STAGE1_5
/* /*
* Display partition information * Display partition information
*/ */
else if (flags) if (flags && ! IS_PC_SLICE_TYPE_EXTENDED (current_slice))
{ {
current_partition |= 0xFFFF; current_partition |= 0xFFFF;
if (! do_completion) if (! do_completion)
@ -576,13 +568,15 @@ real_open_partition (int flags)
errnum = ERR_NONE; errnum = ERR_NONE;
} }
# endif /* ! STAGE1_5 */ #endif /* ! STAGE1_5 */
/* /*
* If we've found the right partition, we're done * If we've found the right partition, we're done
*/ */
else if (part_no == slice_no if (! flags
|| (part_no == 0xFF && (part_no == slice_no
&& IS_PC_SLICE_TYPE_BSD (current_slice))) || (part_no == 0xFF
&& IS_PC_SLICE_TYPE_BSD (current_slice))))
{ {
if ((current_partition & 0xFF00) != 0xFF00) if ((current_partition & 0xFF00) != 0xFF00)
{ {
@ -595,6 +589,15 @@ real_open_partition (int flags)
ext = -2; ext = -2;
break; break;
} }
/*
* Is this an extended partition?
*/
if (IS_PC_SLICE_TYPE_EXTENDED (current_slice))
{
if (ext == -1)
ext = i;
}
} }
/* /*
@ -609,7 +612,7 @@ real_open_partition (int flags)
} }
part_offset = ext_offset + PC_SLICE_START (mbr_buf, ext); part_offset = ext_offset + PC_SLICE_START (mbr_buf, ext);
if (!ext_offset) if (! ext_offset)
ext_offset = part_offset; ext_offset = part_offset;
} }
} }
@ -634,14 +637,14 @@ real_open_partition (int flags)
ext = -2; ext = -2;
} }
} }
# ifndef STAGE1_5 #ifndef STAGE1_5
else else
{ {
current_partition = 0xFFFFFF; current_partition = 0xFFFFFF;
check_and_print_mount (); check_and_print_mount ();
errnum = 0; errnum = 0;
} }
# endif /* STAGE1_5 */ #endif /* STAGE1_5 */
} }
} }

View file

@ -695,6 +695,7 @@ char *convert_to_ascii (char *buf, int c, ...);
int get_cmdline (char *prompt, char *cmdline, int maxlen, int get_cmdline (char *prompt, char *cmdline, int maxlen,
int echo_char, int history); int echo_char, int history);
int substring (char *s1, char *s2); int substring (char *s1, char *s2);
char *nul_terminate (char *str);
int get_based_digit (int c, int base); int get_based_digit (int c, int base);
int safe_parse_maxint (char **str_ptr, int *myint_ptr); int safe_parse_maxint (char **str_ptr, int *myint_ptr);
int memcheck (int start, int len); int memcheck (int start, int len);