|
Packit |
78deda |
/**************************************************************************
|
|
Packit |
78deda |
libpm.c
|
|
Packit |
78deda |
***************************************************************************
|
|
Packit |
78deda |
This file contains fundamental libnetpbm services.
|
|
Packit |
78deda |
|
|
Packit |
78deda |
Some of the subroutines in this library are intended and documented
|
|
Packit |
78deda |
for use by Netpbm users, but most of them are just used by other
|
|
Packit |
78deda |
Netpbm library subroutines.
|
|
Packit |
78deda |
**************************************************************************/
|
|
Packit |
78deda |
|
|
Packit |
78deda |
#define _DEFAULT_SOURCE /* New name for SVID & BSD source defines */
|
|
Packit |
78deda |
#define _BSD_SOURCE /* Make sure strdup is in string.h */
|
|
Packit |
78deda |
#define _XOPEN_SOURCE 500 /* Make sure ftello, fseeko are defined */
|
|
Packit |
78deda |
|
|
Packit |
78deda |
#include "netpbm/pm_config.h"
|
|
Packit |
78deda |
|
|
Packit |
78deda |
#include <assert.h>
|
|
Packit |
78deda |
#include <unistd.h>
|
|
Packit |
78deda |
#include <stdio.h>
|
|
Packit |
78deda |
#include <stdarg.h>
|
|
Packit |
78deda |
#include <string.h>
|
|
Packit |
78deda |
#include <errno.h>
|
|
Packit |
78deda |
#include <setjmp.h>
|
|
Packit |
78deda |
#include <time.h>
|
|
Packit |
78deda |
#include <limits.h>
|
|
Packit |
78deda |
#if HAVE_FORK
|
|
Packit |
78deda |
#include <sys/wait.h>
|
|
Packit |
78deda |
#endif
|
|
Packit |
78deda |
#include <sys/types.h>
|
|
Packit |
78deda |
|
|
Packit |
78deda |
#include "netpbm/pm_c_util.h"
|
|
Packit |
78deda |
#include "netpbm/mallocvar.h"
|
|
Packit |
78deda |
#include "netpbm/version.h"
|
|
Packit |
78deda |
#include "netpbm/nstring.h"
|
|
Packit |
78deda |
#include "netpbm/shhopt.h"
|
|
Packit |
78deda |
#include "compile.h"
|
|
Packit |
78deda |
|
|
Packit |
78deda |
#include "pm.h"
|
|
Packit |
78deda |
|
|
Packit |
78deda |
/* The following are set by pm_init(), then used by subsequent calls to other
|
|
Packit |
78deda |
pm_xxx() functions.
|
|
Packit |
78deda |
*/
|
|
Packit |
78deda |
const char * pm_progname;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
int pm_plain_output;
|
|
Packit |
78deda |
/* Boolean: programs should produce output in plain format */
|
|
Packit |
78deda |
|
|
Packit |
78deda |
static bool pm_showmessages;
|
|
Packit |
78deda |
/* Programs should display informational messages (because the user didn't
|
|
Packit |
78deda |
specify the --quiet option).
|
|
Packit |
78deda |
*/
|
|
Packit |
78deda |
static jmp_buf * pm_jmpbufP = NULL;
|
|
Packit |
78deda |
/* A description of the point to which the program should hyperjump
|
|
Packit |
78deda |
if a libnetpbm function encounters an error (libnetpbm functions
|
|
Packit |
78deda |
don't normally return in that case).
|
|
Packit |
78deda |
|
|
Packit |
78deda |
User sets this to something in his own extra-library context.
|
|
Packit |
78deda |
Libnetpbm routines that have something that needs to be cleaned up
|
|
Packit |
78deda |
preempt it.
|
|
Packit |
78deda |
|
|
Packit |
78deda |
NULL, which is the default value, means when a libnetpbm function
|
|
Packit |
78deda |
encounters an error, it causes the process to exit.
|
|
Packit |
78deda |
*/
|
|
Packit |
78deda |
static pm_usererrormsgfn * userErrorMsgFn = NULL;
|
|
Packit |
78deda |
/* A function to call to issue an error message.
|
|
Packit |
78deda |
|
|
Packit |
78deda |
NULL means use the library default: print to Standard Error
|
|
Packit |
78deda |
*/
|
|
Packit |
78deda |
|
|
Packit |
78deda |
static pm_usermessagefn * userMessageFn = NULL;
|
|
Packit |
78deda |
/* A function to call to issue a non-error message.
|
|
Packit |
78deda |
|
|
Packit |
78deda |
NULL means use the library default: print to Standard Error
|
|
Packit |
78deda |
*/
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
void
|
|
Packit |
78deda |
pm_setjmpbuf(jmp_buf * const jmpbufP) {
|
|
Packit |
78deda |
pm_jmpbufP = jmpbufP;
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
void
|
|
Packit |
78deda |
pm_setjmpbufsave(jmp_buf * const jmpbufP,
|
|
Packit |
78deda |
jmp_buf ** const oldJmpbufPP) {
|
|
Packit |
78deda |
|
|
Packit |
78deda |
*oldJmpbufPP = pm_jmpbufP;
|
|
Packit |
78deda |
pm_jmpbufP = jmpbufP;
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
void
|
|
Packit |
78deda |
pm_longjmp(void) {
|
|
Packit |
78deda |
|
|
Packit |
78deda |
if (pm_jmpbufP)
|
|
Packit |
78deda |
longjmp(*pm_jmpbufP, 1);
|
|
Packit |
78deda |
else
|
|
Packit |
78deda |
exit(1);
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
void
|
|
Packit |
78deda |
pm_fork(int * const iAmParentP,
|
|
Packit |
78deda |
pid_t * const childPidP,
|
|
Packit |
78deda |
const char ** const errorP) {
|
|
Packit |
78deda |
/*----------------------------------------------------------------------------
|
|
Packit |
78deda |
Same as POSIX fork, except with a nicer interface and works
|
|
Packit |
78deda |
(fails cleanly) on systems that don't have POSIX fork().
|
|
Packit |
78deda |
-----------------------------------------------------------------------------*/
|
|
Packit |
78deda |
#if HAVE_FORK
|
|
Packit |
78deda |
int rc;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
rc = fork();
|
|
Packit |
78deda |
|
|
Packit |
78deda |
if (rc < 0) {
|
|
Packit |
78deda |
pm_asprintf(errorP, "Failed to fork a process. errno=%d (%s)",
|
|
Packit |
78deda |
errno, strerror(errno));
|
|
Packit |
78deda |
} else {
|
|
Packit |
78deda |
*errorP = NULL;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
if (rc == 0) {
|
|
Packit |
78deda |
*iAmParentP = FALSE;
|
|
Packit |
78deda |
} else {
|
|
Packit |
78deda |
*iAmParentP = TRUE;
|
|
Packit |
78deda |
*childPidP = rc;
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
#else
|
|
Packit |
78deda |
pm_asprintf(errorP, "Cannot fork a process, because this system does "
|
|
Packit |
78deda |
"not have POSIX fork()");
|
|
Packit |
78deda |
#endif
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
void
|
|
Packit |
78deda |
pm_waitpid(pid_t const pid,
|
|
Packit |
78deda |
int * const statusP,
|
|
Packit |
78deda |
int const options,
|
|
Packit |
78deda |
pid_t * const exitedPidP,
|
|
Packit |
78deda |
const char ** const errorP) {
|
|
Packit |
78deda |
|
|
Packit |
78deda |
#if HAVE_FORK
|
|
Packit |
78deda |
pid_t rc;
|
|
Packit |
78deda |
rc = waitpid(pid, statusP, options);
|
|
Packit |
78deda |
if (rc == (pid_t)-1) {
|
|
Packit |
78deda |
pm_asprintf(errorP, "Failed to wait for process exit. "
|
|
Packit |
78deda |
"waitpid() errno = %d (%s)",
|
|
Packit |
78deda |
errno, strerror(errno));
|
|
Packit |
78deda |
} else {
|
|
Packit |
78deda |
*exitedPidP = rc;
|
|
Packit |
78deda |
*errorP = NULL;
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
#else
|
|
Packit |
78deda |
pm_error("INTERNAL ERROR: Attempt to wait for a process we created on "
|
|
Packit |
78deda |
"a system on which we can't create processes");
|
|
Packit |
78deda |
#endif
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
void
|
|
Packit |
78deda |
pm_waitpidSimple(pid_t const pid) {
|
|
Packit |
78deda |
|
|
Packit |
78deda |
int status;
|
|
Packit |
78deda |
pid_t exitedPid;
|
|
Packit |
78deda |
const char * error;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
pm_waitpid(pid, &status, 0, &exitedPid, &error);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
if (error) {
|
|
Packit |
78deda |
pm_errormsg("%s", error);
|
|
Packit |
78deda |
pm_strfree(error);
|
|
Packit |
78deda |
pm_longjmp();
|
|
Packit |
78deda |
} else {
|
|
Packit |
78deda |
assert(exitedPid != 0);
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
void
|
|
Packit |
78deda |
pm_setusererrormsgfn(pm_usererrormsgfn * fn) {
|
|
Packit |
78deda |
|
|
Packit |
78deda |
userErrorMsgFn = fn;
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
void
|
|
Packit |
78deda |
pm_setusermessagefn(pm_usermessagefn * fn) {
|
|
Packit |
78deda |
|
|
Packit |
78deda |
userMessageFn = fn;
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
void
|
|
Packit |
78deda |
pm_usage(const char usage[]) {
|
|
Packit |
78deda |
pm_error("usage: %s %s", pm_progname, usage);
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
void PM_GNU_PRINTF_ATTR(1,2)
|
|
Packit |
78deda |
pm_message(const char format[], ...) {
|
|
Packit |
78deda |
|
|
Packit |
78deda |
va_list args;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
va_start(args, format);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
if (pm_showmessages) {
|
|
Packit |
78deda |
const char * msg;
|
|
Packit |
78deda |
pm_vasprintf(&msg, format, args);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
if (userMessageFn)
|
|
Packit |
78deda |
userMessageFn(msg);
|
|
Packit |
78deda |
else
|
|
Packit |
78deda |
fprintf(stderr, "%s: %s\n", pm_progname, msg);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
pm_strfree(msg);
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
va_end(args);
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
static void
|
|
Packit |
78deda |
errormsg(const char * const msg) {
|
|
Packit |
78deda |
|
|
Packit |
78deda |
if (userErrorMsgFn)
|
|
Packit |
78deda |
userErrorMsgFn(msg);
|
|
Packit |
78deda |
else
|
|
Packit |
78deda |
fprintf(stderr, "%s: %s\n", pm_progname, msg);
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
void PM_GNU_PRINTF_ATTR(1,2)
|
|
Packit |
78deda |
pm_errormsg(const char format[], ...) {
|
|
Packit |
78deda |
|
|
Packit |
78deda |
va_list args;
|
|
Packit |
78deda |
const char * msg;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
va_start(args, format);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
pm_vasprintf(&msg, format, args);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
errormsg(msg);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
pm_strfree(msg);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
va_end(args);
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
void PM_GNU_PRINTF_ATTR(1,2)
|
|
Packit |
78deda |
pm_error(const char format[], ...) {
|
|
Packit |
78deda |
va_list args;
|
|
Packit |
78deda |
const char * msg;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
va_start(args, format);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
pm_vasprintf(&msg, format, args);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
errormsg(msg);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
pm_strfree(msg);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
va_end(args);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
pm_longjmp();
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
int
|
|
Packit |
78deda |
pm_have_float_format(void) {
|
|
Packit |
78deda |
/*----------------------------------------------------------------------------
|
|
Packit |
78deda |
Return 1 if %f, %e, and %g work in format strings for pm_message, etc.;
|
|
Packit |
78deda |
0 otherwise.
|
|
Packit |
78deda |
|
|
Packit |
78deda |
Where they don't "work," that means the specifier just appears itself in
|
|
Packit |
78deda |
the formatted strings, e.g. "the number is g".
|
|
Packit |
78deda |
-----------------------------------------------------------------------------*/
|
|
Packit |
78deda |
return pm_vasprintf_knows_float();
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
static void *
|
|
Packit |
78deda |
mallocz(size_t const size) {
|
|
Packit |
78deda |
|
|
Packit |
78deda |
return malloc(MAX(1, size));
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
void *
|
|
Packit |
78deda |
pm_allocrow(unsigned int const cols,
|
|
Packit |
78deda |
unsigned int const size) {
|
|
Packit |
78deda |
|
|
Packit |
78deda |
unsigned char * itrow;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
if (cols != 0 && UINT_MAX / cols < size)
|
|
Packit |
78deda |
pm_error("Arithmetic overflow multiplying %u by %u to get the "
|
|
Packit |
78deda |
"size of a row to allocate.", cols, size);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
itrow = mallocz(cols * size);
|
|
Packit |
78deda |
if (itrow == NULL)
|
|
Packit |
78deda |
pm_error("out of memory allocating a row");
|
|
Packit |
78deda |
|
|
Packit |
78deda |
return itrow;
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
void
|
|
Packit |
78deda |
pm_freerow(void * const itrow) {
|
|
Packit |
78deda |
free(itrow);
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
char **
|
|
Packit |
78deda |
pm_allocarray(int const cols,
|
|
Packit |
78deda |
int const rows,
|
|
Packit |
78deda |
int const elementSize ) {
|
|
Packit |
78deda |
/*----------------------------------------------------------------------------
|
|
Packit |
78deda |
This is for backward compatibility. MALLOCARRAY2 is usually better.
|
|
Packit |
78deda |
|
|
Packit |
78deda |
A problem with pm_allocarray() is that its return type is char **
|
|
Packit |
78deda |
even though 'elementSize' can be other than 1. So users have
|
|
Packit |
78deda |
traditionally type cast the result. In the old days, that was just
|
|
Packit |
78deda |
messy; modern compilers can produce the wrong code if you do that.
|
|
Packit |
78deda |
-----------------------------------------------------------------------------*/
|
|
Packit |
78deda |
char ** retval;
|
|
Packit |
78deda |
void * result;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
pm_mallocarray2(&result, rows, cols, elementSize);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
if (result == NULL)
|
|
Packit |
78deda |
pm_error("Failed to allocate a raster array of %u columns x %u rows",
|
|
Packit |
78deda |
cols, rows);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
retval = result;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
return retval;
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
void
|
|
Packit |
78deda |
pm_freearray(char ** const rowIndex,
|
|
Packit |
78deda |
int const rows) {
|
|
Packit |
78deda |
|
|
Packit |
78deda |
void * const rowIndexVoid = rowIndex;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
pm_freearray2(rowIndexVoid);
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
/* Case-insensitive keyword matcher. */
|
|
Packit |
78deda |
|
|
Packit |
78deda |
int
|
|
Packit |
78deda |
pm_keymatch(const char * const strarg,
|
|
Packit |
78deda |
const char * const keywordarg,
|
|
Packit |
78deda |
int const minchars) {
|
|
Packit |
78deda |
int len;
|
|
Packit |
78deda |
const char * keyword;
|
|
Packit |
78deda |
const char * str;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
str = strarg;
|
|
Packit |
78deda |
keyword = keywordarg;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
len = strlen( str );
|
|
Packit |
78deda |
if ( len < minchars )
|
|
Packit |
78deda |
return 0;
|
|
Packit |
78deda |
while ( --len >= 0 )
|
|
Packit |
78deda |
{
|
|
Packit |
78deda |
register char c1, c2;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
c1 = *str++;
|
|
Packit |
78deda |
c2 = *keyword++;
|
|
Packit |
78deda |
if ( c2 == '\0' )
|
|
Packit |
78deda |
return 0;
|
|
Packit |
78deda |
if ( ISUPPER( c1 ) )
|
|
Packit |
78deda |
c1 = tolower( c1 );
|
|
Packit |
78deda |
if ( ISUPPER( c2 ) )
|
|
Packit |
78deda |
c2 = tolower( c2 );
|
|
Packit |
78deda |
if ( c1 != c2 )
|
|
Packit |
78deda |
return 0;
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
return 1;
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
/* Log base two hacks. */
|
|
Packit |
78deda |
|
|
Packit |
78deda |
int
|
|
Packit |
78deda |
pm_maxvaltobits(int const maxval) {
|
|
Packit |
78deda |
if ( maxval <= 1 )
|
|
Packit |
78deda |
return 1;
|
|
Packit |
78deda |
else if ( maxval <= 3 )
|
|
Packit |
78deda |
return 2;
|
|
Packit |
78deda |
else if ( maxval <= 7 )
|
|
Packit |
78deda |
return 3;
|
|
Packit |
78deda |
else if ( maxval <= 15 )
|
|
Packit |
78deda |
return 4;
|
|
Packit |
78deda |
else if ( maxval <= 31 )
|
|
Packit |
78deda |
return 5;
|
|
Packit |
78deda |
else if ( maxval <= 63 )
|
|
Packit |
78deda |
return 6;
|
|
Packit |
78deda |
else if ( maxval <= 127 )
|
|
Packit |
78deda |
return 7;
|
|
Packit |
78deda |
else if ( maxval <= 255 )
|
|
Packit |
78deda |
return 8;
|
|
Packit |
78deda |
else if ( maxval <= 511 )
|
|
Packit |
78deda |
return 9;
|
|
Packit |
78deda |
else if ( maxval <= 1023 )
|
|
Packit |
78deda |
return 10;
|
|
Packit |
78deda |
else if ( maxval <= 2047 )
|
|
Packit |
78deda |
return 11;
|
|
Packit |
78deda |
else if ( maxval <= 4095 )
|
|
Packit |
78deda |
return 12;
|
|
Packit |
78deda |
else if ( maxval <= 8191 )
|
|
Packit |
78deda |
return 13;
|
|
Packit |
78deda |
else if ( maxval <= 16383 )
|
|
Packit |
78deda |
return 14;
|
|
Packit |
78deda |
else if ( maxval <= 32767 )
|
|
Packit |
78deda |
return 15;
|
|
Packit |
78deda |
else if ( (long) maxval <= 65535L )
|
|
Packit |
78deda |
return 16;
|
|
Packit Service |
2370ca |
else
|
|
Packit |
78deda |
pm_error( "maxval of %d is too large!", maxval );
|
|
Packit |
78deda |
return -1; /* Should never come here */
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
|
|
Packit |
78deda |
int
|
|
Packit |
78deda |
pm_bitstomaxval(int const bits) {
|
|
Packit |
78deda |
return ( 1 << bits ) - 1;
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
unsigned int PURE_FN_ATTR
|
|
Packit |
78deda |
pm_lcm(unsigned int const x,
|
|
Packit |
78deda |
unsigned int const y,
|
|
Packit |
78deda |
unsigned int const z,
|
|
Packit |
78deda |
unsigned int const limit) {
|
|
Packit |
78deda |
/*----------------------------------------------------------------------------
|
|
Packit |
78deda |
Compute the least common multiple of 'x', 'y', and 'z'. If it's bigger than
|
|
Packit |
78deda |
'limit', though, just return 'limit'.
|
|
Packit |
78deda |
-----------------------------------------------------------------------------*/
|
|
Packit |
78deda |
unsigned int biggest;
|
|
Packit |
78deda |
unsigned int candidate;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
if (x == 0 || y == 0 || z == 0)
|
|
Packit |
78deda |
pm_error("pm_lcm(): Least common multiple of zero taken.");
|
|
Packit |
78deda |
|
|
Packit |
78deda |
biggest = MAX(x, MAX(y,z));
|
|
Packit |
78deda |
|
|
Packit |
78deda |
candidate = biggest;
|
|
Packit |
78deda |
while (((candidate % x) != 0 || /* not a multiple of x */
|
|
Packit |
78deda |
(candidate % y) != 0 || /* not a multiple of y */
|
|
Packit |
78deda |
(candidate % z) != 0 ) && /* not a multiple of z */
|
|
Packit |
78deda |
candidate <= limit)
|
|
Packit |
78deda |
candidate += biggest;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
if (candidate > limit)
|
|
Packit |
78deda |
candidate = limit;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
return candidate;
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
void
|
|
Packit |
78deda |
pm_init(const char * const progname,
|
|
Packit |
78deda |
unsigned int const flags) {
|
|
Packit |
78deda |
/*----------------------------------------------------------------------------
|
|
Packit |
78deda |
Initialize static variables that Netpbm library routines use.
|
|
Packit |
78deda |
|
|
Packit |
78deda |
Any user of Netpbm library routines is expected to call this at the
|
|
Packit |
78deda |
beginning of this program, before any other Netpbm library routines.
|
|
Packit |
78deda |
|
|
Packit |
78deda |
A program may call this via pm_proginit() instead, though.
|
|
Packit |
78deda |
-----------------------------------------------------------------------------*/
|
|
Packit |
78deda |
pm_setMessage(FALSE, NULL);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
pm_progname = progname;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
#ifdef O_BINARY
|
|
Packit |
78deda |
#ifdef HAVE_SETMODE
|
|
Packit |
78deda |
/* Set the stdin and stdout mode to binary. This means nothing on Unix,
|
|
Packit |
78deda |
but matters on Windows.
|
|
Packit |
78deda |
|
|
Packit |
78deda |
Note that stdin and stdout aren't necessarily image files. In
|
|
Packit |
78deda |
particular, stdout is sometimes text for human consumption,
|
|
Packit |
78deda |
typically printed on the terminal. Binary mode isn't really
|
|
Packit |
78deda |
appropriate for that case. We do this setting here without
|
|
Packit |
78deda |
any knowledge of how stdin and stdout are being used because it is
|
|
Packit |
78deda |
easy. But we do make an exception for the case that we know the
|
|
Packit |
78deda |
file is a terminal, to get a little closer to doing the right
|
|
Packit |
78deda |
thing.
|
|
Packit |
78deda |
*/
|
|
Packit |
78deda |
if (!isatty(0)) setmode(0,O_BINARY); /* Standard Input */
|
|
Packit |
78deda |
if (!isatty(1)) setmode(1,O_BINARY); /* Standard Output */
|
|
Packit |
78deda |
#endif /* HAVE_SETMODE */
|
|
Packit |
78deda |
#endif /* O_BINARY */
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
static const char *
|
|
Packit |
78deda |
dtMsg(time_t const dateTime) {
|
|
Packit |
78deda |
/*----------------------------------------------------------------------------
|
|
Packit |
78deda |
Text for the version message to indicate datetime 'dateTime'.
|
|
Packit |
78deda |
-----------------------------------------------------------------------------*/
|
|
Packit |
78deda |
struct tm * const brokenTimeP = localtime(&dateTime);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
char buffer[100];
|
|
Packit |
78deda |
|
|
Packit |
78deda |
strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", brokenTimeP);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
return pm_strdup(buffer);
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
static void
|
|
Packit |
78deda |
showVersion(void) {
|
|
Packit |
78deda |
|
|
Packit |
78deda |
pm_message("Using libnetpbm from Netpbm Version: %s", NETPBM_VERSION);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
/* SOURCE_DATETIME is defined when the user wants a reproducible build,
|
|
Packit |
78deda |
so wants the source code modification datetime instead of the build
|
|
Packit |
78deda |
datetime in the object code.
|
|
Packit |
78deda |
*/
|
|
Packit |
78deda |
#if defined(SOURCE_DATETIME)
|
|
Packit |
78deda |
{
|
|
Packit |
78deda |
const char * const sourceDtMsg = dtMsg(SOURCE_DATETIME);
|
|
Packit |
78deda |
pm_message("Built from source dated %s", sourceDtMsg);
|
|
Packit |
78deda |
pm_strfree(sourceDtMsg);
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
#else
|
|
Packit |
78deda |
#if defined(BUILD_DATETIME)
|
|
Packit |
78deda |
{
|
|
Packit |
78deda |
const char * const buildDtMsg = dtMsg(BUILD_DATETIME);
|
|
Packit |
78deda |
pm_message("Built at %s", buildDtMsg);
|
|
Packit |
78deda |
pm_strfree(buildDtMsg);
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
#endif
|
|
Packit |
78deda |
#endif
|
|
Packit |
78deda |
|
|
Packit |
78deda |
#if defined(COMPILED_BY)
|
|
Packit |
78deda |
pm_message("Built by %s", COMPILED_BY);
|
|
Packit |
78deda |
#endif
|
|
Packit |
78deda |
|
|
Packit |
78deda |
#ifdef BSD
|
|
Packit |
78deda |
pm_message( "BSD defined" );
|
|
Packit |
78deda |
#endif /*BSD*/
|
|
Packit |
78deda |
#ifdef SYSV
|
|
Packit |
78deda |
pm_message( "SYSV defined" );
|
|
Packit |
78deda |
#endif /*SYSV*/
|
|
Packit |
78deda |
#ifdef MSDOS
|
|
Packit |
78deda |
pm_message( "MSDOS defined" );
|
|
Packit |
78deda |
#endif /*MSDOS*/
|
|
Packit |
78deda |
#ifdef AMIGA
|
|
Packit |
78deda |
pm_message( "AMIGA defined" );
|
|
Packit |
78deda |
#endif /* AMIGA */
|
|
Packit |
78deda |
{
|
|
Packit |
78deda |
const char * rgbdef;
|
|
Packit |
78deda |
pm_message( "RGB_ENV='%s'", RGBENV );
|
|
Packit |
78deda |
rgbdef = getenv(RGBENV);
|
|
Packit |
78deda |
if( rgbdef )
|
|
Packit |
78deda |
pm_message( "RGBENV= '%s' (env vbl set to '%s')",
|
|
Packit |
78deda |
RGBENV, rgbdef );
|
|
Packit |
78deda |
else
|
|
Packit |
78deda |
pm_message( "RGBENV= '%s' (env vbl is unset)", RGBENV);
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
static void
|
|
Packit |
78deda |
showNetpbmHelp(const char progname[]) {
|
|
Packit |
78deda |
/*----------------------------------------------------------------------------
|
|
Packit |
78deda |
Tell the user where to get help for this program, assuming it is a Netpbm
|
|
Packit |
78deda |
program (a program that comes with the Netpbm package, as opposed to a
|
|
Packit |
78deda |
program that just uses the Netpbm libraries).
|
|
Packit |
78deda |
|
|
Packit |
78deda |
Tell him to go to the URL listed in the Netpbm configuration file.
|
|
Packit |
78deda |
The Netpbm configuration file is the file named by the NETPBM_CONF
|
|
Packit |
78deda |
environment variable, or /etc/netpbm if there is no such environment
|
|
Packit |
78deda |
variable.
|
|
Packit |
78deda |
|
|
Packit |
78deda |
If the configuration file doesn't exist or can't be read, or doesn't
|
|
Packit |
78deda |
contain a DOCURL value, tell him to go to a hardcoded source for
|
|
Packit |
78deda |
documentation.
|
|
Packit |
78deda |
-----------------------------------------------------------------------------*/
|
|
Packit |
78deda |
const char * netpbmConfigFileName;
|
|
Packit |
78deda |
FILE * netpbmConfigFile;
|
|
Packit |
78deda |
char * docurl;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
if (getenv("NETPBM_CONF"))
|
|
Packit |
78deda |
netpbmConfigFileName = getenv("NETPBM_CONF");
|
|
Packit |
78deda |
else
|
|
Packit |
78deda |
netpbmConfigFileName = "/etc/netpbm";
|
|
Packit |
78deda |
|
|
Packit |
78deda |
netpbmConfigFile = fopen(netpbmConfigFileName, "r");
|
|
Packit |
78deda |
if (netpbmConfigFile == NULL) {
|
|
Packit |
78deda |
pm_message("Unable to open Netpbm configuration file '%s'. "
|
|
Packit |
78deda |
"Errno = %d (%s). "
|
|
Packit |
78deda |
"Use the NETPBM_CONF environment variable "
|
|
Packit |
78deda |
"to control the identity of the Netpbm configuration file.",
|
|
Packit |
78deda |
netpbmConfigFileName,errno, strerror(errno));
|
|
Packit |
78deda |
docurl = NULL;
|
|
Packit |
78deda |
} else {
|
|
Packit |
78deda |
docurl = NULL; /* default */
|
|
Packit |
78deda |
while (!feof(netpbmConfigFile) && !ferror(netpbmConfigFile)) {
|
|
Packit |
78deda |
char line[80+1];
|
|
Packit |
78deda |
fgets(line, sizeof(line), netpbmConfigFile);
|
|
Packit |
78deda |
if (line[0] != '#') {
|
|
Packit |
78deda |
sscanf(line, "docurl=%s", docurl);
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
if (docurl == NULL)
|
|
Packit |
78deda |
pm_message("No 'docurl=' line in Netpbm configuration file '%s'.",
|
|
Packit |
78deda |
netpbmConfigFileName);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
fclose(netpbmConfigFile);
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
if (docurl == NULL)
|
|
Packit |
78deda |
pm_message("We have no reliable indication of where the Netpbm "
|
|
Packit |
78deda |
"documentation is, but try "
|
|
Packit |
78deda |
"http://netpbm.sourceforge.net or email "
|
|
Packit |
78deda |
"Bryan Henderson (bryanh@giraffe-data.com) for help.");
|
|
Packit |
78deda |
else
|
|
Packit |
78deda |
pm_message("This program is part of the Netpbm package. Find "
|
|
Packit |
78deda |
"documentation for it at %s/%s\n", docurl, progname);
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
static void
|
|
Packit |
78deda |
parseCommonOptions(int * const argcP,
|
|
Packit |
78deda |
const char ** const argv,
|
|
Packit |
78deda |
bool * const showMessagesP,
|
|
Packit |
78deda |
bool * const showVersionP,
|
|
Packit |
78deda |
bool * const showHelpP,
|
|
Packit |
78deda |
bool * const plainOutputP) {
|
|
Packit |
78deda |
|
|
Packit |
78deda |
unsigned int inCursor;
|
|
Packit |
78deda |
unsigned int outCursor;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
*showMessagesP = true; /* initial assumption */
|
|
Packit |
78deda |
*showVersionP = false; /* initial assumption */
|
|
Packit |
78deda |
*showHelpP = false; /* initial assumption */
|
|
Packit |
78deda |
*plainOutputP = false; /* initial assumption */
|
|
Packit |
78deda |
|
|
Packit |
78deda |
for (inCursor = 1, outCursor = 1; inCursor < *argcP; ++inCursor) {
|
|
Packit |
78deda |
if (strcaseeq(argv[inCursor], "-quiet") ||
|
|
Packit |
78deda |
strcaseeq(argv[inCursor], "--quiet"))
|
|
Packit |
78deda |
*showMessagesP = false;
|
|
Packit |
78deda |
else if (strcaseeq(argv[inCursor], "-version") ||
|
|
Packit |
78deda |
strcaseeq(argv[inCursor], "--version"))
|
|
Packit |
78deda |
*showVersionP = true;
|
|
Packit |
78deda |
else if (strcaseeq(argv[inCursor], "-help") ||
|
|
Packit |
78deda |
strcaseeq(argv[inCursor], "--help") ||
|
|
Packit |
78deda |
strcaseeq(argv[inCursor], "-?"))
|
|
Packit |
78deda |
*showHelpP = true;
|
|
Packit |
78deda |
else if (strcaseeq(argv[inCursor], "-plain") ||
|
|
Packit |
78deda |
strcaseeq(argv[inCursor], "--plain"))
|
|
Packit |
78deda |
*plainOutputP = true;
|
|
Packit |
78deda |
else
|
|
Packit |
78deda |
argv[outCursor++] = argv[inCursor];
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
*argcP = outCursor;
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
void
|
|
Packit |
78deda |
pm_proginit(int * const argcP,
|
|
Packit |
78deda |
const char ** const argv) {
|
|
Packit |
78deda |
/*----------------------------------------------------------------------------
|
|
Packit |
78deda |
Do various initialization things that all programs in the Netpbm package,
|
|
Packit |
78deda |
and programs that emulate such programs, should do.
|
|
Packit |
78deda |
|
|
Packit |
78deda |
This includes processing global options. We scan argv[], which has *argcP
|
|
Packit |
78deda |
elements, for common options and execute the functions for the ones we
|
|
Packit |
78deda |
find. We remove the common options from argv[], updating *argcP
|
|
Packit |
78deda |
accordingly.
|
|
Packit |
78deda |
|
|
Packit |
78deda |
This includes calling pm_init() to initialize the Netpbm libraries.
|
|
Packit |
78deda |
-----------------------------------------------------------------------------*/
|
|
Packit |
78deda |
const char * const progname = pm_arg0toprogname(argv[0]);
|
|
Packit |
78deda |
/* points to static memory in this library */
|
|
Packit |
78deda |
bool showMessages;
|
|
Packit |
78deda |
bool plain;
|
|
Packit |
78deda |
bool justShowVersion;
|
|
Packit |
78deda |
/* We're supposed to just show the version information, then exit the
|
|
Packit |
78deda |
program.
|
|
Packit |
78deda |
*/
|
|
Packit |
78deda |
bool justShowHelp;
|
|
Packit |
78deda |
/* We're supposed to just tell user where to get help, then exit the
|
|
Packit |
78deda |
program.
|
|
Packit |
78deda |
*/
|
|
Packit |
78deda |
|
|
Packit |
78deda |
pm_init(progname, 0);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
parseCommonOptions(argcP, argv,
|
|
Packit |
78deda |
&showMessages, &justShowVersion, &justShowHelp,
|
|
Packit |
78deda |
&plain);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
pm_plain_output = plain ? 1 : 0;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
pm_setMessage(showMessages ? 1 : 0, NULL);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
if (justShowVersion) {
|
|
Packit |
78deda |
showVersion();
|
|
Packit |
78deda |
exit(0);
|
|
Packit |
78deda |
} else if (justShowHelp) {
|
|
Packit |
78deda |
pm_error("Use 'man %s' for help.", progname);
|
|
Packit |
78deda |
/* If we can figure out a way to distinguish Netpbm programs from
|
|
Packit |
78deda |
other programs using the Netpbm libraries, we can do better here.
|
|
Packit |
78deda |
*/
|
|
Packit |
78deda |
if (0)
|
|
Packit |
78deda |
showNetpbmHelp(progname);
|
|
Packit |
78deda |
exit(0);
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
void
|
|
Packit |
78deda |
pm_setMessage(int const newState,
|
|
Packit |
78deda |
int * const oldStateP) {
|
|
Packit |
78deda |
|
|
Packit |
78deda |
if (oldStateP)
|
|
Packit |
78deda |
*oldStateP = pm_showmessages;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
pm_showmessages = !!newState;
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
int
|
|
Packit |
78deda |
pm_getMessage(void) {
|
|
Packit |
78deda |
|
|
Packit |
78deda |
return pm_showmessages;
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
static void
|
|
Packit |
78deda |
extractAfterLastSlash(const char * const fullPath,
|
|
Packit |
78deda |
char * const retval,
|
|
Packit |
78deda |
size_t const retvalSize) {
|
|
Packit |
78deda |
|
|
Packit |
78deda |
char * slashPos;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
/* Chop any directories off the left end */
|
|
Packit |
78deda |
slashPos = strrchr(fullPath, '/');
|
|
Packit |
78deda |
|
|
Packit |
78deda |
if (slashPos == NULL) {
|
|
Packit |
78deda |
strncpy(retval, fullPath, retvalSize);
|
|
Packit |
78deda |
retval[retvalSize-1] = '\0';
|
|
Packit |
78deda |
} else {
|
|
Packit |
78deda |
strncpy(retval, slashPos +1, retvalSize);
|
|
Packit |
78deda |
retval[retvalSize-1] = '\0';
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
static void
|
|
Packit |
78deda |
chopOffExe(char * const arg) {
|
|
Packit |
78deda |
/*----------------------------------------------------------------------------
|
|
Packit |
78deda |
Chop any .exe off the right end of 'arg'.
|
|
Packit |
78deda |
-----------------------------------------------------------------------------*/
|
|
Packit |
78deda |
if (strlen(arg) >= 4 && strcmp(arg+strlen(arg)-4, ".exe") == 0)
|
|
Packit |
78deda |
arg[strlen(arg)-4] = 0;
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
char *
|
|
Packit |
78deda |
pm_arg0toprogname(const char arg0[]) {
|
|
Packit |
78deda |
/*----------------------------------------------------------------------------
|
|
Packit |
78deda |
Given a value for argv[0] (a command name or file name passed to a
|
|
Packit |
78deda |
program in the standard C calling sequence), return the name of the
|
|
Packit |
78deda |
Netpbm program to which it refers.
|
|
Packit |
78deda |
|
|
Packit |
78deda |
In the most ordinary case, this is simply the argument itself.
|
|
Packit |
78deda |
|
|
Packit |
78deda |
But if the argument contains a slash, it is the part of the argument
|
|
Packit |
78deda |
after the last slash, and if there is a .exe on it (as there is for
|
|
Packit |
78deda |
DJGPP), that is removed.
|
|
Packit |
78deda |
|
|
Packit |
78deda |
The return value is in static storage within. It is NUL-terminated,
|
|
Packit |
78deda |
but truncated at 64 characters.
|
|
Packit |
78deda |
-----------------------------------------------------------------------------*/
|
|
Packit |
78deda |
#define MAX_RETVAL_SIZE 64
|
|
Packit |
78deda |
#if MSVCRT
|
|
Packit |
78deda |
/* Note that there exists _splitpath_s, which takes a size argument,
|
|
Packit |
78deda |
but it is only in "secure" extensions of MSVCRT that come only with
|
|
Packit |
78deda |
MSVC; but _splitpath() comes with Windows. MinGW has a header file
|
|
Packit |
78deda |
for it.
|
|
Packit |
78deda |
*/
|
|
Packit |
78deda |
static char retval[_MAX_FNAME];
|
|
Packit |
78deda |
_splitpath(arg0, 0, 0, retval, 0);
|
|
Packit |
78deda |
if (MAX_RETVAL_SIZE < _MAX_FNAME)
|
|
Packit |
78deda |
retval[MAX_RETVAL_SIZE] = '\0';
|
|
Packit |
78deda |
#else
|
|
Packit |
78deda |
static char retval[MAX_RETVAL_SIZE+1];
|
|
Packit |
78deda |
extractAfterLastSlash(arg0, retval, sizeof(retval));
|
|
Packit |
78deda |
chopOffExe(retval);
|
|
Packit |
78deda |
#endif
|
|
Packit |
78deda |
|
|
Packit |
78deda |
return retval;
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
unsigned int
|
|
Packit |
78deda |
pm_randseed(void) {
|
|
Packit |
78deda |
|
|
Packit |
78deda |
return time(NULL) ^ getpid();
|
|
Packit |
78deda |
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
unsigned int
|
|
Packit |
78deda |
pm_parse_width(const char * const arg) {
|
|
Packit |
78deda |
/*----------------------------------------------------------------------------
|
|
Packit |
78deda |
Return the image width represented by the decimal ASCIIZ string
|
|
Packit |
78deda |
'arg'. Fail if it doesn't validly represent a width or represents
|
|
Packit |
78deda |
a width that can't be conveniently used in computation.
|
|
Packit |
78deda |
-----------------------------------------------------------------------------*/
|
|
Packit |
78deda |
unsigned int width;
|
|
Packit |
78deda |
const char * error;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
pm_interpret_uint(arg, &width, &error);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
if (error) {
|
|
Packit |
78deda |
pm_error("'%s' is invalid as an image width. %s", arg, error);
|
|
Packit |
78deda |
pm_strfree(error);
|
|
Packit |
78deda |
} else {
|
|
Packit |
78deda |
if (width > INT_MAX-10)
|
|
Packit |
78deda |
pm_error("Width %u is too large for computations.", width);
|
|
Packit |
78deda |
if (width == 0)
|
|
Packit |
78deda |
pm_error("Width argument must be a positive number. You "
|
|
Packit |
78deda |
"specified 0.");
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
return width;
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
unsigned int
|
|
Packit |
78deda |
pm_parse_height(const char * const arg) {
|
|
Packit |
78deda |
/*----------------------------------------------------------------------------
|
|
Packit |
78deda |
Same as pm_parse_width(), but for height.
|
|
Packit |
78deda |
-----------------------------------------------------------------------------*/
|
|
Packit |
78deda |
unsigned int height;
|
|
Packit |
78deda |
const char * error;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
pm_interpret_uint(arg, &height, &error);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
if (error) {
|
|
Packit |
78deda |
pm_error("'%s' is invalid as an image height. %s", arg, error);
|
|
Packit |
78deda |
pm_strfree(error);
|
|
Packit |
78deda |
} else {
|
|
Packit |
78deda |
if (height > INT_MAX-10)
|
|
Packit |
78deda |
pm_error("Height %u is too large for computations.", height);
|
|
Packit |
78deda |
if (height == 0)
|
|
Packit |
78deda |
pm_error("Height argument must be a positive number. You "
|
|
Packit |
78deda |
"specified 0.");
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
return height;
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
|
|
Packit |
38c941 |
|
|
Packit |
78deda |
|