813 lines
20 KiB
C
813 lines
20 KiB
C
/*
|
|
* The IKE Scanner (ike-scan) is Copyright (C) 2003-2007 Roy Hills,
|
|
* NTA Monitor Ltd.
|
|
*
|
|
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
*
|
|
* In addition, as a special exception, the copyright holders give
|
|
* permission to link the code of portions of this program with the
|
|
* OpenSSL library, and distribute linked combinations including the two.
|
|
*
|
|
* You must obey the GNU General Public License in all respects
|
|
* for all of the code used other than OpenSSL. If you modify
|
|
* file(s) with this exception, you may extend this exception to your
|
|
* version of the file(s), but you are not obligated to do so. If you
|
|
* do not wish to do so, delete this exception statement from your
|
|
* version.
|
|
*
|
|
* If this license is unacceptable to you, I may be willing to negotiate
|
|
* alternative licenses (contact ike-scan@nta-monitor.com).
|
|
*
|
|
* You are encouraged to send comments, improvements or suggestions to
|
|
* me at ike-scan@nta-monitor.com.
|
|
*
|
|
* $Id: utils.c 9884 2007-01-14 19:05:39Z rsh $
|
|
*
|
|
* Author: Roy Hills
|
|
* Date: 5 April 2004
|
|
*
|
|
* This file contains various utility functions used by ike-scan.
|
|
*
|
|
* These functions were originally in ike-scan.c, but were moved to utils.c
|
|
* because ike-scan.c was getting rather large.
|
|
*/
|
|
|
|
#include "ike-scan.h"
|
|
|
|
static char rcsid[] = "$Id: utils.c 9884 2007-01-14 19:05:39Z rsh $"; /* RCS ID for ident(1) */
|
|
|
|
|
|
/*
|
|
* timeval_diff -- Calculates the difference between two timevals
|
|
* and returns this difference in a third timeval.
|
|
*
|
|
* Inputs:
|
|
*
|
|
* a = First timeval
|
|
* b = Second timeval
|
|
* diff = Difference between timevals (a - b).
|
|
*
|
|
* Returns:
|
|
*
|
|
* None.
|
|
*/
|
|
void
|
|
timeval_diff(const struct timeval *a, const struct timeval *b,
|
|
struct timeval *diff) {
|
|
struct timeval temp;
|
|
|
|
temp.tv_sec = b->tv_sec;
|
|
temp.tv_usec = b->tv_usec;
|
|
|
|
/* Perform the carry for the later subtraction by updating b. */
|
|
if (a->tv_usec < temp.tv_usec) {
|
|
int nsec = (temp.tv_usec - a->tv_usec) / 1000000 + 1;
|
|
temp.tv_usec -= 1000000 * nsec;
|
|
temp.tv_sec += nsec;
|
|
}
|
|
if (a->tv_usec - temp.tv_usec > 1000000) {
|
|
int nsec = (a->tv_usec - temp.tv_usec) / 1000000;
|
|
temp.tv_usec += 1000000 * nsec;
|
|
temp.tv_sec -= nsec;
|
|
}
|
|
|
|
/* Compute the time difference
|
|
tv_usec is certainly positive. */
|
|
diff->tv_sec = a->tv_sec - temp.tv_sec;
|
|
diff->tv_usec = a->tv_usec - temp.tv_usec;
|
|
}
|
|
|
|
/*
|
|
* times_close_enough -- Check if two times are less than fuzz ms apart
|
|
*
|
|
* Inputs:
|
|
*
|
|
* t1 First time value
|
|
* t2 Second time value
|
|
* fuzz Fuzz value
|
|
*
|
|
* Returns:
|
|
*
|
|
* 1 if t1 and t2 are within fuzz ms of each other. Otherwise 0.
|
|
*/
|
|
int
|
|
times_close_enough(struct timeval *t1, struct timeval *t2, unsigned fuzz) {
|
|
struct timeval diff;
|
|
int diff_ms;
|
|
|
|
timeval_diff(t1, t2, &diff); /* diff = t1 - t2 */
|
|
diff_ms = abs(1000*diff.tv_sec + diff.tv_usec/1000);
|
|
if (diff_ms <= fuzz) {
|
|
return 1;
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* hstr_i -- Convert two-digit hex string to unsigned integer
|
|
*
|
|
* Inputs:
|
|
*
|
|
* cptr Two-digit hex string
|
|
*
|
|
* Returns:
|
|
*
|
|
* Number corresponding to input hex value.
|
|
*
|
|
* An input of "0A" or "0a" would return 10.
|
|
* Note that this function does no sanity checking, it's up to the
|
|
* caller to ensure that *cptr points to at least two hex digits.
|
|
*
|
|
* This function is a modified version of hstr_i at www.snippets.org.
|
|
*/
|
|
unsigned int
|
|
hstr_i(const char *cptr)
|
|
{
|
|
unsigned int i;
|
|
unsigned int j = 0;
|
|
int k;
|
|
|
|
for (k=0; k<2; k++) {
|
|
i = *cptr++ - '0';
|
|
if (9 < i)
|
|
i -= 7;
|
|
j <<= 4;
|
|
j |= (i & 0x0f);
|
|
}
|
|
return j;
|
|
}
|
|
|
|
/*
|
|
* hex2data -- Convert hex string to binary data
|
|
*
|
|
* Inputs:
|
|
*
|
|
* string The string to convert
|
|
* data_len (output) The length of the resultant binary data
|
|
*
|
|
* Returns:
|
|
*
|
|
* Pointer to the binary data.
|
|
*
|
|
* The returned pointer points to malloc'ed storage which should be
|
|
* free'ed by the caller when it's no longer needed. If the length of
|
|
* the input string is not even, the function will return NULL and
|
|
* set data_len to 0.
|
|
*/
|
|
unsigned char *
|
|
hex2data(const char *string, size_t *data_len) {
|
|
unsigned char *data;
|
|
unsigned char *cp;
|
|
unsigned i;
|
|
size_t len;
|
|
|
|
if (strlen(string) %2 ) { /* Length is odd */
|
|
*data_len = 0;
|
|
return NULL;
|
|
}
|
|
|
|
len = strlen(string) / 2;
|
|
data = Malloc(len);
|
|
cp = data;
|
|
for (i=0; i<len; i++)
|
|
*cp++=hstr_i(&string[i*2]);
|
|
*data_len = len;
|
|
return data;
|
|
}
|
|
|
|
/*
|
|
* hex_or_str -- Convert hex or string to binary data
|
|
*
|
|
* Inputs:
|
|
*
|
|
* string The hex or string to convert
|
|
* data_len (output) The length of the resultant binary data
|
|
*
|
|
* Returns:
|
|
*
|
|
* Pointer to the binary data, or NULL if an error occurred.
|
|
*
|
|
* The input string must be in one of the following two formats:
|
|
*
|
|
* 0x<hex-data> Input is in hex format
|
|
* string Input is in string format
|
|
*
|
|
* The returned pointer points to malloc'ed storage which should be
|
|
* free'ed by the caller when it's no longer needed. If the length of
|
|
* the inputs string is not even, the function will return NULL and
|
|
* set data_len to 0.
|
|
*/
|
|
unsigned char *
|
|
hex_or_str(const char *string, size_t *data_len) {
|
|
|
|
if (strlen(string) < 1) { /* Input string too short */
|
|
*data_len = 0;
|
|
return NULL;
|
|
}
|
|
|
|
if (string[0] == '0' && string[1] == 'x') { /* Hex input format */
|
|
return hex2data((string+2), data_len);
|
|
} else { /* Assume string input format */
|
|
unsigned char *data;
|
|
size_t len;
|
|
|
|
len = strlen(string);
|
|
data = Malloc(len);
|
|
memcpy(data, string, len);
|
|
*data_len = len;
|
|
return data;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* hex_or_num -- Convert hex or number to binary data
|
|
*
|
|
* Inputs:
|
|
*
|
|
* string The hex or string to convert
|
|
* data_len (output) The length of the resultant binary data
|
|
*
|
|
* Returns:
|
|
*
|
|
* Pointer to the binary data, or NULL if an error occurred.
|
|
*
|
|
* The input string must be in one of the following two formats:
|
|
*
|
|
* 0x<hex-data> Input is in hex format
|
|
* decimal number Input is in numeric format
|
|
*
|
|
* For numeric input, the binary data will be a 32-bit value in
|
|
* big endian format.
|
|
*
|
|
* The returned pointer points to malloc'ed storage which should be
|
|
* free'ed by the caller when it's no longer needed. If the length of
|
|
* the inputs string is not even, the function will return NULL and
|
|
* set data_len to 0.
|
|
*/
|
|
unsigned char *
|
|
hex_or_num(const char *string, size_t *data_len) {
|
|
|
|
if (strlen(string) < 1) { /* Input string too short */
|
|
*data_len = 0;
|
|
return NULL;
|
|
}
|
|
|
|
if (string[0] == '0' && string[1] == 'x') { /* Hex input format */
|
|
return hex2data((string+2), data_len);
|
|
} else { /* Assume number input format */
|
|
unsigned char *data;
|
|
size_t len = 4; /* 32-bit value */
|
|
unsigned long value;
|
|
unsigned long value_be;
|
|
|
|
value = Strtoul(string, 10);
|
|
value_be = htonl(value);
|
|
data = Malloc(len);
|
|
memcpy(data, &value_be, len);
|
|
|
|
*data_len = len;
|
|
return data;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* make_message -- allocate a sufficiently large string and print into it.
|
|
*
|
|
* Inputs:
|
|
*
|
|
* Format and variable number of arguments.
|
|
*
|
|
* Outputs:
|
|
*
|
|
* Pointer to the string,
|
|
*
|
|
* The code for this function is from the Debian Linux "woody" sprintf man
|
|
* page. Modified slightly to use wrapper functions for malloc and realloc.
|
|
*/
|
|
char *
|
|
make_message(const char *fmt, ...) {
|
|
int n;
|
|
/* Guess we need no more than 100 bytes. */
|
|
size_t size = 100;
|
|
char *p;
|
|
va_list ap;
|
|
p = Malloc (size);
|
|
while (1) {
|
|
/* Try to print in the allocated space. */
|
|
va_start(ap, fmt);
|
|
n = vsnprintf (p, size, fmt, ap);
|
|
va_end(ap);
|
|
/* If that worked, return the string. */
|
|
if (n > -1 && n < size)
|
|
return p;
|
|
/* Else try again with more space. */
|
|
if (n > -1) /* glibc 2.1 */
|
|
size = n+1; /* precisely what is needed */
|
|
else /* glibc 2.0 */
|
|
size *= 2; /* twice the old size */
|
|
p = Realloc (p, size);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* numstr -- Convert an unsigned integer to a string
|
|
*
|
|
* Inputs:
|
|
*
|
|
* num The number to convert
|
|
*
|
|
* Returns:
|
|
*
|
|
* Pointer to the string representation of the number.
|
|
*
|
|
* I'm surprised that there is not a standard library function to do this.
|
|
*/
|
|
char *
|
|
numstr(unsigned num) {
|
|
static char buf[21]; /* Large enough for biggest 64-bit integer */
|
|
|
|
snprintf(buf, sizeof(buf), "%d", num);
|
|
return buf;
|
|
}
|
|
|
|
/*
|
|
* printable -- Convert string to printable form using C-style escapes
|
|
*
|
|
* Inputs:
|
|
*
|
|
* string Pointer to input string.
|
|
* size Size of input string. 0 means that string is null-terminated.
|
|
*
|
|
* Returns:
|
|
*
|
|
* Pointer to the printable string.
|
|
*
|
|
* Any non-printable characters are replaced by C-Style escapes, e.g.
|
|
* "\n" for newline. As a result, the returned string may be longer than
|
|
* the one supplied.
|
|
*
|
|
* This function makes two passes through the input string: one to
|
|
* determine the required output length, then a second to perform the
|
|
* conversion.
|
|
*
|
|
* The pointer returned points to malloc'ed storage which should be
|
|
* free'ed by the caller when it's no longer needed.
|
|
*/
|
|
char *
|
|
printable(const unsigned char *string, size_t size) {
|
|
char *result;
|
|
char *r;
|
|
const unsigned char *cp;
|
|
size_t outlen;
|
|
unsigned i;
|
|
/*
|
|
* If the input string is NULL, return an empty string.
|
|
*/
|
|
if (string == NULL) {
|
|
result = Malloc(1);
|
|
result[0] = '\0';
|
|
return result;
|
|
}
|
|
/*
|
|
* Determine required size of output string.
|
|
*/
|
|
if (!size)
|
|
size = strlen((const char *) string);
|
|
|
|
outlen = size;
|
|
cp = string;
|
|
for (i=0; i<size; i++) {
|
|
switch (*cp) {
|
|
case '\\':
|
|
case '\b':
|
|
case '\f':
|
|
case '\n':
|
|
case '\r':
|
|
case '\t':
|
|
case '\v':
|
|
outlen++;
|
|
break;
|
|
default:
|
|
if(!isprint(*cp))
|
|
outlen += 3;
|
|
}
|
|
cp++;
|
|
}
|
|
outlen++; /* One more for the ending NULL */
|
|
|
|
result = Malloc(outlen);
|
|
|
|
cp = string;
|
|
r = result;
|
|
for (i=0; i<size; i++) {
|
|
switch (*cp) {
|
|
case '\\':
|
|
*r++ = '\\';
|
|
*r++ = '\\';
|
|
break;
|
|
case '\b':
|
|
*r++ = '\\';
|
|
*r++ = 'b';
|
|
break;
|
|
case '\f':
|
|
*r++ = '\\';
|
|
*r++ = 'f';
|
|
break;
|
|
case '\n':
|
|
*r++ = '\\';
|
|
*r++ = 'n';
|
|
break;
|
|
case '\r':
|
|
*r++ = '\\';
|
|
*r++ = 'r';
|
|
break;
|
|
case '\t':
|
|
*r++ = '\\';
|
|
*r++ = 't';
|
|
break;
|
|
case '\v':
|
|
*r++ = '\\';
|
|
*r++ = 'v';
|
|
break;
|
|
default:
|
|
if (isprint(*cp)) {
|
|
*r++ = *cp; /* Printable character */
|
|
} else {
|
|
*r++ = '\\';
|
|
sprintf(r, "%.3o", *cp);
|
|
r += 3;
|
|
}
|
|
break;
|
|
}
|
|
cp++;
|
|
}
|
|
*r = '\0';
|
|
|
|
return result;
|
|
}
|
|
|
|
/*
|
|
* hexstring -- Convert data to printable hex string form
|
|
*
|
|
* Inputs:
|
|
*
|
|
* string Pointer to input data.
|
|
* size Size of input data.
|
|
*
|
|
* Returns:
|
|
*
|
|
* Pointer to the printable hex string.
|
|
*
|
|
* Each byte in the input data will be represented by two hex digits
|
|
* in the output string. Therefore the output string will be twice
|
|
* as long as the input data plus one extra byte for the trailing NULL.
|
|
*
|
|
* The pointer returned points to malloc'ed storage which should be
|
|
* free'ed by the caller when it's no longer needed.
|
|
*/
|
|
char *
|
|
hexstring(const unsigned char *data, size_t size) {
|
|
char *result;
|
|
char *r;
|
|
const unsigned char *cp;
|
|
unsigned i;
|
|
/*
|
|
* If the input data is NULL, return an empty string.
|
|
*/
|
|
if (data == NULL) {
|
|
result = Malloc(1);
|
|
result[0] = '\0';
|
|
return result;
|
|
}
|
|
/*
|
|
* Create and return hex string.
|
|
*/
|
|
result = Malloc(2*size + 1);
|
|
cp = data;
|
|
r = result;
|
|
for (i=0; i<size; i++) {
|
|
sprintf(r, "%.2x", *cp++);
|
|
r += 2;
|
|
}
|
|
*r = '\0';
|
|
|
|
return result;
|
|
}
|
|
|
|
/*
|
|
* print_times -- Print absolute and delta time for debugging
|
|
*
|
|
* Inputs:
|
|
*
|
|
* None.
|
|
*
|
|
* Returns:
|
|
*
|
|
* None.
|
|
*
|
|
* This function is only used for debugging. It should not be called
|
|
* from production code.
|
|
*/
|
|
void
|
|
print_times(void) {
|
|
static struct timeval time_first; /* When print_times() was first called */
|
|
static struct timeval time_last; /* When print_times() was last called */
|
|
static int first_call=1;
|
|
struct timeval time_now;
|
|
struct timeval time_delta1;
|
|
struct timeval time_delta2;
|
|
|
|
Gettimeofday(&time_now);
|
|
|
|
if (first_call) {
|
|
first_call=0;
|
|
time_first.tv_sec = time_now.tv_sec;
|
|
time_first.tv_usec = time_now.tv_usec;
|
|
printf("%lu.%.6lu (0.000000) [0.000000]\n",
|
|
(unsigned long)time_now.tv_sec, (unsigned long)time_now.tv_usec);
|
|
} else {
|
|
timeval_diff(&time_now, &time_last, &time_delta1);
|
|
timeval_diff(&time_now, &time_first, &time_delta2);
|
|
printf("%lu.%.6lu (%lu.%.6lu) [%lu.%.6lu]\n",
|
|
(unsigned long)time_now.tv_sec,
|
|
(unsigned long)time_now.tv_usec,
|
|
(unsigned long)time_delta1.tv_sec,
|
|
(unsigned long)time_delta1.tv_usec,
|
|
(unsigned long)time_delta2.tv_sec,
|
|
(unsigned long)time_delta2.tv_usec);
|
|
}
|
|
time_last.tv_sec = time_now.tv_sec;
|
|
time_last.tv_usec = time_now.tv_usec;
|
|
}
|
|
|
|
/*
|
|
* sig_alarm -- Signal handler for SIGALRM
|
|
*
|
|
* Inputs:
|
|
*
|
|
* signo The signal number (ignored)
|
|
*
|
|
* Returns:
|
|
*
|
|
* None.
|
|
*
|
|
* This function is used as the signal handler for SIGALRM.
|
|
* It doesn't perform any processing; it merely returns to
|
|
* interrupt the current system call.
|
|
*/
|
|
void sig_alarm(int signo) {
|
|
return; /* just interrupt the current system call */
|
|
}
|
|
|
|
/*
|
|
* id_to_name -- Return name associated with given id, or id number
|
|
*
|
|
* Inputs:
|
|
*
|
|
* id The id to find in the map
|
|
* id_name_map Pointer to the id-to-name map
|
|
*
|
|
* Returns:
|
|
*
|
|
* A pointer to the name associated with the id if an association is
|
|
* found in the map, otherwise the numeric id. Returns NULL on error.
|
|
*
|
|
* This function uses a sequential search through the map to find the
|
|
* ID and associated name. This is OK when the map is relatively small,
|
|
* but could be time consuming if the map contains a large number of
|
|
* entries.
|
|
*/
|
|
const char *
|
|
id_to_name(unsigned id, const id_name_map map[]) {
|
|
int found = 0;
|
|
int i = 0;
|
|
|
|
if (map == NULL)
|
|
return NULL;
|
|
|
|
while (map[i].id != -1) {
|
|
if (id == map[i].id) {
|
|
found = 1;
|
|
break;
|
|
}
|
|
i++;
|
|
}
|
|
|
|
if (found)
|
|
return map[i].name;
|
|
else
|
|
return numstr(id);
|
|
}
|
|
|
|
/*
|
|
* name_to_id -- Return id associated with given name
|
|
*
|
|
* Inputs:
|
|
*
|
|
* name The name to find in the map
|
|
* id_name_map Pointer to the id-to-name map
|
|
*
|
|
* Returns:
|
|
*
|
|
* The id associated with the name if an association is found in the
|
|
* map, otherwise -1.
|
|
*
|
|
* This function uses a sequential search through the map to find the
|
|
* ID and associated name. This is OK when the map is relatively small,
|
|
* but could be time consuming if the map contains a large number of
|
|
* entries.
|
|
*
|
|
* The search is case-blind.
|
|
*/
|
|
int
|
|
name_to_id(const char *name, const id_name_map map[]) {
|
|
int found = 0;
|
|
int i = 0;
|
|
|
|
if (map == NULL)
|
|
return -1;
|
|
|
|
while (map[i].id != -1) {
|
|
if ((str_ccmp(name,map[i].name)) == 0) {
|
|
found = 1;
|
|
break;
|
|
}
|
|
i++;
|
|
}
|
|
|
|
if (found)
|
|
return map[i].id;
|
|
else
|
|
return -1;
|
|
}
|
|
|
|
/* Standard BSD internet checksum routine */
|
|
uint16_t
|
|
in_cksum(uint16_t *ptr, size_t nbytes) {
|
|
|
|
register uint32_t sum;
|
|
uint16_t oddbyte;
|
|
register uint16_t answer;
|
|
|
|
/*
|
|
* Our algorithm is simple, using a 32-bit accumulator (sum),
|
|
* we add sequential 16-bit words to it, and at the end, fold back
|
|
* all the carry bits from the top 16 bits into the lower 16 bits.
|
|
*/
|
|
|
|
sum = 0;
|
|
while (nbytes > 1) {
|
|
sum += *ptr++;
|
|
nbytes -= 2;
|
|
}
|
|
|
|
/* mop up an odd byte, if necessary */
|
|
if (nbytes == 1) {
|
|
oddbyte = 0; /* make sure top half is zero */
|
|
*((u_char *) &oddbyte) = *(u_char *)ptr; /* one byte only */
|
|
sum += oddbyte;
|
|
}
|
|
|
|
/*
|
|
* Add back carry outs from top 16 bits to low 16 bits.
|
|
*/
|
|
|
|
sum = (sum >> 16) + (sum & 0xffff); /* add high-16 to low-16 */
|
|
sum += (sum >> 16); /* add carry */
|
|
answer = ~sum; /* ones-complement, then truncate to 16 bits */
|
|
return(answer);
|
|
}
|
|
|
|
/*
|
|
* random_byte -- Return a random byte in range 0..255
|
|
*
|
|
* Inputs: None
|
|
*
|
|
* Returns: The random byte
|
|
*/
|
|
uint8_t
|
|
random_byte(void) {
|
|
static union {
|
|
uint32_t longword;
|
|
uint8_t byte[4];
|
|
} random_data;
|
|
static int num_bytes = 0; /* Number of bytes available */
|
|
|
|
if (num_bytes == 0) {
|
|
uint32_t random_value;
|
|
|
|
random_value = genrand_int32();
|
|
random_data.longword = htonl(random_value);
|
|
num_bytes = 4;
|
|
}
|
|
return random_data.byte[--num_bytes];
|
|
}
|
|
|
|
/*
|
|
* random_ip -- Return a random IP address
|
|
*
|
|
* Imputs: None
|
|
* Returns: A random IP address
|
|
*
|
|
* This returns a random IP address as a 32-bit value in host byte
|
|
* order.
|
|
*
|
|
* It will not return the following IP address ranges, because they
|
|
* are invalid:
|
|
*
|
|
* 0/8, 1/8 or 2/8 - IANA reserved
|
|
* 127/8 - Localhost
|
|
* Class D (Multicast)
|
|
* Class E (Reserved)
|
|
*/
|
|
uint32_t
|
|
random_ip(void) {
|
|
uint32_t random_value;
|
|
int acceptable;
|
|
|
|
do {
|
|
random_value = genrand_int32();
|
|
if ((random_value & 0xff000000) == 0x7f000000 || /* 127.x.x.x */
|
|
random_value > 0xefffffff || /* Class D or E */
|
|
random_value < 0x03000000) { /* 0/8, 1/8 or 2/8 */
|
|
acceptable = 0;
|
|
} else {
|
|
acceptable = 1;
|
|
}
|
|
} while (!acceptable);
|
|
|
|
return random_value;
|
|
}
|
|
|
|
/*
|
|
* str_ccmp -- Case-blind string comparison
|
|
*
|
|
* Inputs:
|
|
*
|
|
* s1 -- The first input string
|
|
* s2 -- The second input string
|
|
*
|
|
* Returns:
|
|
*
|
|
* An integer indicating whether s1 is less than (-1), the same as (0),
|
|
* or greater than (1) s2.
|
|
*
|
|
* This function performs the same function, and takes the same arguments
|
|
* as the common library function strcasecmp. This function is used
|
|
* instead because strcasecmp is not portable.
|
|
*/
|
|
int
|
|
str_ccmp( const char *s1, const char *s2 ) {
|
|
int c1, c2;
|
|
|
|
for( ; ; s1++, s2++ ){
|
|
c1 = tolower( (unsigned char) *s1 );
|
|
c2 = tolower( (unsigned char) *s2 );
|
|
|
|
if( c1 > c2 ) return 1;
|
|
if( c1 < c2 ) return -1;
|
|
if( c1 == 0 && c2 == 0 ) return 0;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* name_or_number -- Calculate the numeric value of a string containing
|
|
* either a name from a map, or a number.
|
|
*
|
|
* Inputs:
|
|
*
|
|
* string The input string
|
|
* map The ID/name map
|
|
*/
|
|
unsigned
|
|
name_or_number(const char *string, const id_name_map map[]) {
|
|
int result;
|
|
char *endptr;
|
|
|
|
result=strtoul(string, &endptr, 0);
|
|
if (endptr != string) /* Successful conversion */
|
|
return result;
|
|
|
|
result=name_to_id(string, map);
|
|
if (result == -1)
|
|
err_msg("Invalid value: %s", string);
|
|
|
|
return result;
|
|
}
|
|
|
|
void utils_use_rcsid(void) {
|
|
fprintf(stderr, "%s\n", rcsid); /* Use rcsid to stop compiler optimising away */
|
|
}
|