|
Packit |
78deda |
/* ppmtoarbtxt.c - convert PPM to a custom text-based format
|
|
Packit |
78deda |
**
|
|
Packit |
78deda |
** Renamed from ppmtotxt.c by Bryan Henderson in January 2003.
|
|
Packit |
78deda |
**
|
|
Packit |
78deda |
** Copyright (C) 1995 by Peter Kirchgessner
|
|
Packit |
78deda |
**
|
|
Packit |
78deda |
** Permission to use, copy, modify, and distribute this software and its
|
|
Packit |
78deda |
** documentation for any purpose and without fee is hereby granted, provided
|
|
Packit |
78deda |
** that the above copyright notice appear in all copies and that both that
|
|
Packit |
78deda |
** copyright notice and this permission notice appear in supporting
|
|
Packit |
78deda |
** documentation. This software is provided "as is" without express or
|
|
Packit |
78deda |
** implied warranty.
|
|
Packit |
78deda |
*/
|
|
Packit |
78deda |
|
|
Packit |
78deda |
#include <assert.h>
|
|
Packit |
78deda |
#include <string.h>
|
|
Packit |
78deda |
#ifdef __GLIBC__
|
|
Packit |
78deda |
#include <printf.h> /* Necessary for parse_printf_format() */
|
|
Packit |
78deda |
#endif
|
|
Packit |
78deda |
|
|
Packit |
78deda |
#include "pm_c_util.h"
|
|
Packit |
78deda |
#include "mallocvar.h"
|
|
Packit |
78deda |
#include "nstring.h"
|
|
Packit |
78deda |
#include "shhopt.h"
|
|
Packit |
78deda |
#include "ppm.h"
|
|
Packit |
78deda |
|
|
Packit |
78deda |
/* HAVE_PARSE_PRINTF_FORMAT means the system library has
|
|
Packit |
78deda |
parse_printf_format(), declared in <printf.h>. This essentially means
|
|
Packit |
78deda |
systems with GNU libc.
|
|
Packit |
78deda |
*/
|
|
Packit |
78deda |
|
|
Packit |
78deda |
#ifndef HAVE_PARSE_PRINTF_FORMAT
|
|
Packit |
78deda |
#ifdef PA_FLAG_MASK /* Defined in printf.h */
|
|
Packit |
78deda |
#define HAVE_PARSE_PRINTF_FORMAT 1
|
|
Packit |
78deda |
#else
|
|
Packit |
78deda |
#define HAVE_PARSE_PRINTF_FORMAT 0
|
|
Packit |
78deda |
#endif
|
|
Packit |
78deda |
#endif
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
struct CmdlineInfo {
|
|
Packit |
78deda |
/* All the information the user supplied in the command line,
|
|
Packit |
78deda |
in a form easy for the program to use.
|
|
Packit |
78deda |
*/
|
|
Packit |
78deda |
const char * inputFileName;
|
|
Packit |
78deda |
const char * bodySklFileName;
|
|
Packit |
78deda |
const char * hd;
|
|
Packit |
78deda |
const char * tl;
|
|
Packit |
78deda |
unsigned int debug;
|
|
Packit |
78deda |
};
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
static void
|
|
Packit |
78deda |
parseCommandLine(int argc, const char ** argv,
|
|
Packit |
78deda |
struct CmdlineInfo * const cmdlineP) {
|
|
Packit |
78deda |
/*----------------------------------------------------------------------------
|
|
Packit |
78deda |
Note that many of the strings that this function returns in the
|
|
Packit |
78deda |
*cmdline_p structure are actually in the supplied argv array. And
|
|
Packit |
78deda |
sometimes, one of these strings is actually just a suffix of an entry
|
|
Packit |
78deda |
in argv!
|
|
Packit |
78deda |
-----------------------------------------------------------------------------*/
|
|
Packit |
78deda |
optEntry * option_def;
|
|
Packit |
78deda |
/* Instructions to OptParseOptions3 on how to parse our options.
|
|
Packit |
78deda |
*/
|
|
Packit |
78deda |
optStruct3 opt;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
unsigned int hdSpec, tlSpec;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
unsigned int option_def_index;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
MALLOCARRAY(option_def, 100);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
option_def_index = 0; /* incremented by OPTENTRY */
|
|
Packit |
78deda |
OPTENT3(0, "hd", OPT_STRING, &cmdlineP->hd,
|
|
Packit |
78deda |
&hdSpec, 0);
|
|
Packit |
78deda |
OPTENT3(0, "tl", OPT_STRING, &cmdlineP->tl,
|
|
Packit |
78deda |
&tlSpec, 0);
|
|
Packit |
78deda |
OPTENT3(0, "debug", OPT_FLAG, NULL,
|
|
Packit |
78deda |
&cmdlineP->debug, 0);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
opt.opt_table = option_def;
|
|
Packit |
78deda |
opt.short_allowed = FALSE; /* We have no short (old-fashioned) options */
|
|
Packit |
78deda |
opt.allowNegNum = FALSE; /* We have no parms that are negative numbers */
|
|
Packit |
78deda |
|
|
Packit |
78deda |
pm_optParseOptions3(&argc, (char **)argv, opt, sizeof(opt), 0);
|
|
Packit |
78deda |
free(option_def);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
if (!hdSpec)
|
|
Packit |
78deda |
cmdlineP->hd = NULL;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
if (!tlSpec)
|
|
Packit |
78deda |
cmdlineP->tl = NULL;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
if (argc-1 < 1)
|
|
Packit |
78deda |
pm_error("You must specify the body skeleton file name as an "
|
|
Packit |
78deda |
"argument");
|
|
Packit |
78deda |
else {
|
|
Packit |
78deda |
cmdlineP->bodySklFileName = strdup(argv[1]);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
if (argc-1 < 2)
|
|
Packit |
78deda |
cmdlineP->inputFileName = strdup("-"); /* he wants stdin */
|
|
Packit |
78deda |
else {
|
|
Packit |
78deda |
cmdlineP->inputFileName = strdup(argv[2]);
|
|
Packit |
78deda |
if (argc-1 > 2)
|
|
Packit |
78deda |
pm_error("Too many arguments. The only possible arguments "
|
|
Packit |
78deda |
"are the body skeleton file name and input image "
|
|
Packit |
78deda |
"file name");
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
typedef enum {
|
|
Packit |
78deda |
/* The types of object we handle */
|
|
Packit |
78deda |
BDATA, IRED, IGREEN, IBLUE, ILUM, FRED, FGREEN, FBLUE, FLUM,
|
|
Packit |
78deda |
WIDTH, HEIGHT, POSX, POSY
|
|
Packit |
78deda |
} SkeletonObjectType;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
typedef enum {
|
|
Packit |
78deda |
OBJTYP_ICOLOR, OBJTYP_FCOLOR, OBJTYP_INT, OBJTYP_BDATA
|
|
Packit |
78deda |
} SkeletonObjectClass;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
/* Maximum size for a format string ("%d" etc.) */
|
|
Packit |
78deda |
/* Add one to this size for the terminating '\0'. */
|
|
Packit |
78deda |
#define MAXFORMAT 16
|
|
Packit |
78deda |
|
|
Packit |
78deda |
typedef union {
|
|
Packit |
78deda |
/* The data we keep for each object */
|
|
Packit |
78deda |
struct Bndat {
|
|
Packit |
78deda |
char * bdat; /* Binary data (text with newlines etc.) */
|
|
Packit |
78deda |
unsigned int ndat;
|
|
Packit |
78deda |
} binData;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
struct Icdat {
|
|
Packit |
78deda |
char icformat[MAXFORMAT+1]; /* Integer colors */
|
|
Packit |
78deda |
unsigned int icolmin, icolmax;
|
|
Packit |
78deda |
} icolData;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
struct Fcdat {
|
|
Packit |
78deda |
char fcformat[MAXFORMAT+1]; /* Float colors */
|
|
Packit |
78deda |
double fcolmin, fcolmax;
|
|
Packit |
78deda |
} fcolData;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
struct Idat {
|
|
Packit |
78deda |
char iformat[MAXFORMAT+1]; /* Integer data */
|
|
Packit |
78deda |
} iData;
|
|
Packit |
78deda |
} SkeletonObjectData;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
/* Each object has a type and some data */
|
|
Packit |
78deda |
typedef struct {
|
|
Packit |
78deda |
SkeletonObjectType objType;
|
|
Packit |
78deda |
SkeletonObjectData odata;
|
|
Packit |
78deda |
} SkeletonObject;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
#define MAX_SKL_HEAD_OBJ 64
|
|
Packit |
78deda |
#define MAX_SKL_BODY_OBJ 256
|
|
Packit |
78deda |
#define MAX_SKL_TAIL_OBJ 64
|
|
Packit |
78deda |
#define MAX_LINE_BUF 1024
|
|
Packit |
78deda |
#define MAX_OBJ_BUF 80
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
static void
|
|
Packit |
78deda |
dumpSkeleton(SkeletonObject ** const skeletonPList,
|
|
Packit |
78deda |
unsigned int const nSkeleton) {
|
|
Packit |
78deda |
|
|
Packit |
78deda |
unsigned int i;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
pm_message("%u objects", nSkeleton);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
for (i = 0; i < nSkeleton; ++i) {
|
|
Packit |
78deda |
SkeletonObject * const skeletonP = skeletonPList[i];
|
|
Packit |
78deda |
|
|
Packit |
78deda |
pm_message(" Object: Type %u", skeletonP->objType);
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
static void
|
|
Packit |
78deda |
dumpAllSkeleton(SkeletonObject ** const bodySkeletonPList,
|
|
Packit |
78deda |
unsigned int const bodyNskl,
|
|
Packit |
78deda |
SkeletonObject ** const headSkeletonPList,
|
|
Packit |
78deda |
unsigned int const headNskl,
|
|
Packit |
78deda |
SkeletonObject ** const tailSkeletonPList,
|
|
Packit |
78deda |
unsigned int const tailNskl) {
|
|
Packit |
78deda |
|
|
Packit |
78deda |
pm_message("Body skeleton:");
|
|
Packit |
78deda |
dumpSkeleton(bodySkeletonPList, bodyNskl);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
pm_message("Head skeleton:");
|
|
Packit |
78deda |
dumpSkeleton(headSkeletonPList, headNskl);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
pm_message("Tail skeleton:");
|
|
Packit |
78deda |
dumpSkeleton(tailSkeletonPList, tailNskl);
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
static void
|
|
Packit |
78deda |
writeBndat(FILE * const ofP,
|
|
Packit |
78deda |
SkeletonObject * const objectP) {
|
|
Packit |
78deda |
|
|
Packit |
78deda |
struct Bndat * const bdataP = &objectP->odata.binData;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
fwrite(bdataP->bdat, bdataP->ndat, 1, ofP);
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
static void
|
|
Packit |
78deda |
writeIcol(FILE * const ofP,
|
|
Packit |
78deda |
SkeletonObject * const objectP,
|
|
Packit |
78deda |
double const value) {
|
|
Packit |
78deda |
|
|
Packit |
78deda |
/* Unlike Netpbm, the output format does not have an upper limit for
|
|
Packit |
78deda |
maxval. Here we allow all values representable by unsigned int.
|
|
Packit |
78deda |
*/
|
|
Packit |
78deda |
|
|
Packit |
78deda |
struct Icdat * const icdataP = &objectP->odata.icolData;
|
|
Packit |
78deda |
unsigned int const outValue =
|
|
Packit |
78deda |
ROUNDU( icdataP->icolmin +
|
|
Packit |
78deda |
((double)icdataP->icolmax - icdataP->icolmin) * value);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
fprintf(ofP, icdataP->icformat, outValue);
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
static void
|
|
Packit |
78deda |
writeFcol(FILE * const ofP,
|
|
Packit |
78deda |
SkeletonObject * const objectP,
|
|
Packit |
78deda |
double const value) {
|
|
Packit |
78deda |
|
|
Packit |
78deda |
struct Fcdat * const fcdataP = &objectP->odata.fcolData;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
fprintf(ofP, fcdataP->fcformat,
|
|
Packit |
78deda |
(double)
|
|
Packit |
78deda |
(fcdataP->fcolmin
|
|
Packit |
78deda |
+ (fcdataP->fcolmax - fcdataP->fcolmin) * value));
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
static void
|
|
Packit |
78deda |
writeIdat(FILE * const ofP,
|
|
Packit |
78deda |
SkeletonObject * const objectP,
|
|
Packit |
78deda |
unsigned int const value) {
|
|
Packit |
78deda |
|
|
Packit |
78deda |
struct Idat * const idataP = &objectP->odata.iData;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
fprintf(ofP, idataP->iformat, value);
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
static void
|
|
Packit |
78deda |
writeText(FILE * const ofP,
|
|
Packit |
78deda |
unsigned int const nObj,
|
|
Packit |
78deda |
SkeletonObject ** const obj,
|
|
Packit |
78deda |
unsigned int const width,
|
|
Packit |
78deda |
unsigned int const height,
|
|
Packit |
78deda |
unsigned int const x,
|
|
Packit |
78deda |
unsigned int const y,
|
|
Packit |
78deda |
double const red,
|
|
Packit |
78deda |
double const green,
|
|
Packit |
78deda |
double const blue) {
|
|
Packit |
78deda |
|
|
Packit |
78deda |
unsigned int i;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
for (i = 0; i < nObj; ++i) {
|
|
Packit |
78deda |
switch (obj[i]->objType) {
|
|
Packit |
78deda |
case BDATA:
|
|
Packit |
78deda |
writeBndat(ofP, obj[i]);
|
|
Packit |
78deda |
break;
|
|
Packit |
78deda |
case IRED:
|
|
Packit |
78deda |
writeIcol(ofP, obj[i], red);
|
|
Packit |
78deda |
break;
|
|
Packit |
78deda |
case IGREEN:
|
|
Packit |
78deda |
writeIcol(ofP, obj[i], green);
|
|
Packit |
78deda |
break;
|
|
Packit |
78deda |
case IBLUE:
|
|
Packit |
78deda |
writeIcol(ofP, obj[i], blue);
|
|
Packit |
78deda |
break;
|
|
Packit |
78deda |
case ILUM:
|
|
Packit |
78deda |
writeIcol(ofP, obj[i],
|
|
Packit |
78deda |
PPM_LUMINR*red + PPM_LUMING*green + PPM_LUMINB*blue);
|
|
Packit |
78deda |
break;
|
|
Packit |
78deda |
case FRED:
|
|
Packit |
78deda |
writeFcol(ofP, obj[i], red);
|
|
Packit |
78deda |
break;
|
|
Packit |
78deda |
case FGREEN:
|
|
Packit |
78deda |
writeFcol(ofP, obj[i], green);
|
|
Packit |
78deda |
break;
|
|
Packit |
78deda |
case FBLUE:
|
|
Packit |
78deda |
writeFcol(ofP, obj[i], blue);
|
|
Packit |
78deda |
break;
|
|
Packit |
78deda |
case FLUM:
|
|
Packit |
78deda |
writeFcol(ofP, obj[i],
|
|
Packit |
78deda |
PPM_LUMINR*red + PPM_LUMING*green + PPM_LUMINB*blue);
|
|
Packit |
78deda |
break;
|
|
Packit |
78deda |
case WIDTH:
|
|
Packit |
78deda |
writeIdat(ofP, obj[i], width);
|
|
Packit |
78deda |
break;
|
|
Packit |
78deda |
case HEIGHT:
|
|
Packit |
78deda |
writeIdat(ofP, obj[i], height);
|
|
Packit |
78deda |
break;
|
|
Packit |
78deda |
case POSX:
|
|
Packit |
78deda |
writeIdat(ofP, obj[i], x);
|
|
Packit |
78deda |
break;
|
|
Packit |
78deda |
case POSY:
|
|
Packit |
78deda |
writeIdat(ofP, obj[i], y);
|
|
Packit |
78deda |
break;
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
static SkeletonObjectClass
|
|
Packit |
78deda |
objClass(SkeletonObjectType const objType) {
|
|
Packit |
78deda |
|
|
Packit |
78deda |
switch (objType) {
|
|
Packit |
78deda |
case IRED:
|
|
Packit |
78deda |
case IGREEN:
|
|
Packit |
78deda |
case IBLUE:
|
|
Packit |
78deda |
case ILUM:
|
|
Packit |
78deda |
return OBJTYP_ICOLOR;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
case FRED:
|
|
Packit |
78deda |
case FGREEN:
|
|
Packit |
78deda |
case FBLUE:
|
|
Packit |
78deda |
case FLUM:
|
|
Packit |
78deda |
return OBJTYP_FCOLOR;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
case WIDTH:
|
|
Packit |
78deda |
case HEIGHT:
|
|
Packit |
78deda |
case POSX:
|
|
Packit |
78deda |
case POSY:
|
|
Packit |
78deda |
return OBJTYP_INT;
|
|
Packit |
78deda |
case BDATA:
|
|
Packit |
78deda |
return OBJTYP_BDATA;
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
return 999; /* quiet compiler warning */
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
/*----------------------------------------------------------------------------
|
|
Packit |
78deda |
Format string validation
|
|
Packit |
78deda |
|
|
Packit |
78deda |
We validate format strings (such as "%f" "%03d") found in the skeleton files
|
|
Packit |
78deda |
for convenience, even though behavior is documented as undefined when the
|
|
Packit |
78deda |
user supplies a bogus format string. Certain strings, most notably those
|
|
Packit |
78deda |
with "%n", are especially risky; they pose a security threat.
|
|
Packit |
78deda |
|
|
Packit |
78deda |
On systems with Glibc, we check with parse_printf_format(). On other
|
|
Packit |
78deda |
systems we conduct a cursory scan of the characters in the format string,
|
|
Packit |
78deda |
looking for characters that trigger non-numeric conversions, etc.
|
|
Packit |
78deda |
|
|
Packit |
78deda |
Documentation for parse_printf_format() is usually available in texinfo
|
|
Packit |
78deda |
format on GNU/Linux systems. As of Dec. 2014 there is no official man page.
|
|
Packit |
78deda |
|
|
Packit |
78deda |
Online documentation is available from:
|
|
Packit |
78deda |
https://
|
|
Packit |
78deda |
www.gnu.org/software/libc/manual/html_node/Parsing-a-Template-String.html
|
|
Packit |
78deda |
-----------------------------------------------------------------------------*/
|
|
Packit |
78deda |
|
|
Packit |
78deda |
#if HAVE_PARSE_PRINTF_FORMAT
|
|
Packit |
78deda |
static void
|
|
Packit |
78deda |
validateParsePrintfFlag(int const printfConversion,
|
|
Packit |
78deda |
SkeletonObjectType const ctyp,
|
|
Packit |
78deda |
const char ** const errorP) {
|
|
Packit |
78deda |
/*----------------------------------------------------------------------------
|
|
Packit |
78deda |
Assuming 'printfConversion' is the value reported by parse_printf_format()
|
|
Packit |
78deda |
as the type of argument a format string requires,
|
|
Packit |
78deda |
return an explanation of how it is incompatible with 'ctyp' as
|
|
Packit |
78deda |
*errorP -- return null string if it is compatible.
|
|
Packit |
78deda |
-----------------------------------------------------------------------------*/
|
|
Packit |
78deda |
/* We first check for "%n", then the type modifiers, and finally the
|
|
Packit |
78deda |
actual conversion type (char, int, float, double, string or pointer.)
|
|
Packit |
78deda |
*/
|
|
Packit |
78deda |
switch (printfConversion & PA_FLAG_MASK) {
|
|
Packit |
78deda |
case PA_FLAG_PTR: /* This means %n */
|
|
Packit |
78deda |
pm_asprintf(errorP, "Contains a %%n conversion specifier");
|
|
Packit |
78deda |
break;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
case PA_FLAG_SHORT:
|
|
Packit |
78deda |
case PA_FLAG_LONG:
|
|
Packit |
78deda |
case PA_FLAG_LONG_LONG:
|
|
Packit |
78deda |
/* We omit PA_FLAG_LONG_DOUBLE because it is a synonym for
|
|
Packit |
78deda |
PA_FLAG_LONG_LONG: listing both causes compilation errors.
|
|
Packit |
78deda |
*/
|
|
Packit |
78deda |
pm_asprintf(errorP, "Invalid type modifier");
|
|
Packit |
78deda |
break;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
default:
|
|
Packit |
78deda |
switch (printfConversion & ~PA_FLAG_MASK) {
|
|
Packit |
78deda |
case PA_CHAR:
|
|
Packit |
78deda |
pm_message("Warning: char type conversion.");
|
|
Packit |
78deda |
case PA_INT:
|
|
Packit |
78deda |
if(objClass(ctyp) == OBJTYP_ICOLOR ||
|
|
Packit |
78deda |
objClass(ctyp) == OBJTYP_INT )
|
|
Packit |
78deda |
*errorP = NULL;
|
|
Packit |
78deda |
else
|
|
Packit |
78deda |
pm_asprintf(errorP, "Conversion specifier requires a "
|
|
Packit |
78deda |
"character or integer argument, but it is in "
|
|
Packit |
78deda |
"a replacement sequence for a different type");
|
|
Packit |
78deda |
break;
|
|
Packit |
78deda |
case PA_DOUBLE:
|
|
Packit |
78deda |
if(objClass(ctyp) == OBJTYP_FCOLOR)
|
|
Packit |
78deda |
*errorP = NULL;
|
|
Packit |
78deda |
else
|
|
Packit |
78deda |
pm_asprintf(errorP, "Conversion specifier requires a "
|
|
Packit |
78deda |
"double precision floating point argument, "
|
|
Packit |
78deda |
"but it is in "
|
|
Packit |
78deda |
"a replacement sequence for a different type");
|
|
Packit |
78deda |
break;
|
|
Packit |
78deda |
case PA_FLOAT:
|
|
Packit |
78deda |
case PA_STRING: /* %s */
|
|
Packit |
78deda |
case PA_POINTER: /* %p */
|
|
Packit |
78deda |
default:
|
|
Packit |
78deda |
pm_asprintf(errorP, "Conversion specifier requires an argument of "
|
|
Packit |
78deda |
"a type that this program never provides for "
|
|
Packit |
78deda |
"any replacement sequence");
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
#endif
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
#if HAVE_PARSE_PRINTF_FORMAT
|
|
Packit |
78deda |
static void
|
|
Packit |
78deda |
validateFormatWithPpf(const char * const format,
|
|
Packit |
78deda |
SkeletonObjectType const ctyp,
|
|
Packit |
78deda |
const char ** const errorP) {
|
|
Packit |
78deda |
/*----------------------------------------------------------------------------
|
|
Packit |
78deda |
Validate format string 'format' for use with a skeleton of type 'ctyp',
|
|
Packit |
78deda |
using the system parse_printf_format() function.
|
|
Packit |
78deda |
|
|
Packit |
78deda |
Return as *errorP an explanation of how it is invalid, or a null string
|
|
Packit |
78deda |
if it is valid.
|
|
Packit |
78deda |
-----------------------------------------------------------------------------*/
|
|
Packit |
78deda |
/* We request parse_printf_format() to report the details of the first
|
|
Packit |
78deda |
8 conversions. 8 because the maximum length of format is 16 means it
|
|
Packit |
78deda |
can have up to 8 conversions: "%d%d%d%d%d%d%d%d".
|
|
Packit |
78deda |
|
|
Packit |
78deda |
Actually this is more than necessary: we are concerned with only the
|
|
Packit |
78deda |
first conversion and whether there it is the only one.
|
|
Packit |
78deda |
*/
|
|
Packit |
78deda |
|
|
Packit |
78deda |
int printfConversion[MAXFORMAT/2] = {0, 0, 0, 0, 0, 0, 0, 0};
|
|
Packit |
78deda |
|
|
Packit |
78deda |
size_t const n =
|
|
Packit |
78deda |
parse_printf_format(format, MAXFORMAT/2, printfConversion);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
switch (n) {
|
|
Packit |
78deda |
case 0:
|
|
Packit |
78deda |
pm_asprintf(errorP, "No transformation found");
|
|
Packit |
78deda |
break;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
case 1:
|
|
Packit |
78deda |
validateParsePrintfFlag(printfConversion[0], ctyp, errorP);
|
|
Packit |
78deda |
break;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
default:
|
|
Packit |
78deda |
pm_asprintf(errorP, "Has %lu extra transformation%s ",
|
|
Packit |
78deda |
(unsigned long)n-1, n-1 > 1 ? "s" : "");
|
|
Packit |
78deda |
break;
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
#endif
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
static void
|
|
Packit |
78deda |
validateFormatOne(char const typeSpecifier,
|
|
Packit |
78deda |
bool const isLastInString,
|
|
Packit |
78deda |
SkeletonObjectType const ctyp,
|
|
Packit |
78deda |
bool * const validatedP,
|
|
Packit |
78deda |
const char ** const errorP) {
|
|
Packit |
78deda |
|
|
Packit |
78deda |
switch (typeSpecifier) {
|
|
Packit |
78deda |
/* Valid character encountered. Skip. */
|
|
Packit |
78deda |
/* ' ' (space) is listed here, but should never occur for
|
|
Packit |
78deda |
we use sscanf() to parse the fields.
|
|
Packit |
78deda |
*/
|
|
Packit |
78deda |
case ' ': case '-': case '+': case '\'': case '#': case '.':
|
|
Packit |
78deda |
case '0': case '1': case '2': case '3': case '4': case '5':
|
|
Packit |
78deda |
case '6': case '7': case '8': case '9':
|
|
Packit |
78deda |
break;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
case 'c': case 'C':
|
|
Packit |
78deda |
pm_message("Warning: char type conversion: %%%c.", typeSpecifier);
|
|
Packit |
78deda |
case 'i': case 'd': case 'u': case 'o': case 'x': case 'X':
|
|
Packit |
78deda |
if (!isLastInString)
|
|
Packit |
78deda |
pm_asprintf(errorP, "Extra characters at end");
|
|
Packit |
78deda |
else if(objClass(ctyp) != OBJTYP_ICOLOR &&
|
|
Packit |
78deda |
objClass(ctyp) != OBJTYP_INT )
|
|
Packit |
78deda |
pm_asprintf(errorP, "Conversion type mismatch");
|
|
Packit |
78deda |
else
|
|
Packit |
78deda |
*validatedP = true;
|
|
Packit |
78deda |
break;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
case 'f': case 'F': case 'g': case 'G': case 'a': case 'A':
|
|
Packit |
78deda |
if (!isLastInString)
|
|
Packit |
78deda |
pm_asprintf(errorP, "Extra characters at end");
|
|
Packit |
78deda |
else if(objClass(ctyp) != OBJTYP_FCOLOR)
|
|
Packit |
78deda |
pm_asprintf(errorP, "Conversion type mismatch");
|
|
Packit |
78deda |
else
|
|
Packit |
78deda |
*validatedP = true;
|
|
Packit |
78deda |
break;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
case '\0':
|
|
Packit |
78deda |
pm_asprintf(errorP, "No conversion specified");
|
|
Packit |
78deda |
break;
|
|
Packit |
78deda |
case '%':
|
|
Packit |
78deda |
pm_asprintf(errorP, "No more than one %% is allowed");
|
|
Packit |
78deda |
break;
|
|
Packit |
78deda |
case '$':
|
|
Packit |
78deda |
case '*':
|
|
Packit |
78deda |
pm_asprintf(errorP, "%c is not allowed", typeSpecifier);
|
|
Packit |
78deda |
break;
|
|
Packit |
78deda |
case 'h': case 'l': case 'L': case 'q': case 'j': case 'Z': case 't':
|
|
Packit |
78deda |
pm_asprintf(errorP, "Modifier %c is not allowed in format",
|
|
Packit |
78deda |
typeSpecifier);
|
|
Packit |
78deda |
break;
|
|
Packit |
78deda |
case 's': case 'S': case 'm': case 'p': case 'n':
|
|
Packit |
78deda |
pm_asprintf(errorP, "Invalid conversion type");
|
|
Packit |
78deda |
break;
|
|
Packit |
78deda |
default:
|
|
Packit |
78deda |
pm_asprintf(errorP, "Abnormal character");
|
|
Packit |
78deda |
break;
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
static void
|
|
Packit |
78deda |
validateFormatGen(const char * const format,
|
|
Packit |
78deda |
SkeletonObjectType const ctyp,
|
|
Packit |
78deda |
const char ** const errorP) {
|
|
Packit |
78deda |
/*----------------------------------------------------------------------------
|
|
Packit |
78deda |
Validate format string 'format' for use with a skeleton of type 'ctyp',
|
|
Packit |
78deda |
without using the system parse_printf_format() function.
|
|
Packit |
78deda |
|
|
Packit |
78deda |
The string must begin with "%" and end with the translation type character
|
|
Packit |
78deda |
("%d", "%x", "%f", etc.)
|
|
Packit |
78deda |
|
|
Packit |
78deda |
We check only for invalid characters. Invalid constructs, such as
|
|
Packit |
78deda |
"%00.00.00d" will pass this test.
|
|
Packit |
78deda |
|
|
Packit |
78deda |
Return as *errorP an explanation of how it is invalid, or a null string
|
|
Packit |
78deda |
if it is valid.
|
|
Packit |
78deda |
-----------------------------------------------------------------------------*/
|
|
Packit |
78deda |
if (format[0] != '%')
|
|
Packit |
78deda |
pm_asprintf(errorP, "Does not start with %%");
|
|
Packit |
78deda |
else {
|
|
Packit |
78deda |
unsigned int i;
|
|
Packit |
78deda |
bool validated;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
for (i = 1, validated = false, *errorP = NULL;
|
|
Packit |
78deda |
!validated && !*errorP;
|
|
Packit |
78deda |
++i) {
|
|
Packit |
78deda |
|
|
Packit |
78deda |
validateFormatOne(format[i], format[i+1] == '\0', ctyp,
|
|
Packit |
78deda |
&validated, errorP);
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
static void
|
|
Packit |
78deda |
validateFormat(const char * const format,
|
|
Packit |
78deda |
SkeletonObjectType const ctyp) {
|
|
Packit |
78deda |
|
|
Packit |
78deda |
const char * error;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
if (strlen(format) > MAXFORMAT)
|
|
Packit |
78deda |
pm_asprintf(&error, "Too long");
|
|
Packit |
78deda |
else {
|
|
Packit |
78deda |
#if HAVE_PARSE_PRINTF_FORMAT
|
|
Packit |
78deda |
if (true)
|
|
Packit |
78deda |
validateFormatWithPpf(format, ctyp, &error);
|
|
Packit |
78deda |
else /* Silence compiler warning about unused function */
|
|
Packit |
78deda |
validateFormatGen(format, ctyp, &error);
|
|
Packit |
78deda |
#else
|
|
Packit |
78deda |
validateFormatGen(format, ctyp, &error);
|
|
Packit |
78deda |
#endif
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
|
|
Packit |
78deda |
if (error)
|
|
Packit |
78deda |
pm_error("Invalid format string '%s'. %s", format, error);
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
static SkeletonObject *
|
|
Packit |
78deda |
newBinDataObj(unsigned int const nDat,
|
|
Packit |
78deda |
const char * const bdat) {
|
|
Packit |
78deda |
/*----------------------------------------------------------------------------
|
|
Packit |
78deda |
Create a binary data object.
|
|
Packit |
78deda |
-----------------------------------------------------------------------------*/
|
|
Packit |
78deda |
SkeletonObject * objectP;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
objectP = malloc(sizeof(*objectP) + nDat);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
if (!objectP)
|
|
Packit |
78deda |
pm_error("Failed to allocate memory for binary data object "
|
|
Packit |
78deda |
"with %u bytes", nDat);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
objectP->objType = BDATA;
|
|
Packit |
78deda |
objectP->odata.binData.ndat = nDat;
|
|
Packit |
78deda |
objectP->odata.binData.bdat = ((char *)objectP) + sizeof(SkeletonObject);
|
|
Packit |
78deda |
memcpy(objectP->odata.binData.bdat, bdat, nDat);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
return objectP;
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
static SkeletonObject *
|
|
Packit |
78deda |
newIcolDataObj(SkeletonObjectType const ctyp,
|
|
Packit |
78deda |
const char * const format,
|
|
Packit |
78deda |
unsigned int const icolmin,
|
|
Packit |
78deda |
unsigned int const icolmax) {
|
|
Packit |
78deda |
/*----------------------------------------------------------------------------
|
|
Packit |
78deda |
Create integer color data object.
|
|
Packit |
78deda |
-----------------------------------------------------------------------------*/
|
|
Packit |
78deda |
SkeletonObject * objectP;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
MALLOCVAR(objectP);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
if (!objectP)
|
|
Packit |
78deda |
pm_error("Failed to allocate memory for an integer color data "
|
|
Packit |
78deda |
"object");
|
|
Packit |
78deda |
|
|
Packit |
78deda |
objectP->objType = ctyp;
|
|
Packit |
78deda |
validateFormat(format, ctyp);
|
|
Packit |
78deda |
strcpy(objectP->odata.icolData.icformat, format);
|
|
Packit |
78deda |
objectP->odata.icolData.icolmin = icolmin;
|
|
Packit |
78deda |
objectP->odata.icolData.icolmax = icolmax;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
return objectP;
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
static SkeletonObject *
|
|
Packit |
78deda |
newFcolDataObj(SkeletonObjectType const ctyp,
|
|
Packit |
78deda |
const char * const format,
|
|
Packit |
78deda |
double const fcolmin,
|
|
Packit |
78deda |
double const fcolmax) {
|
|
Packit |
78deda |
/*----------------------------------------------------------------------------
|
|
Packit |
78deda |
Create float color data object.
|
|
Packit |
78deda |
-----------------------------------------------------------------------------*/
|
|
Packit |
78deda |
SkeletonObject * objectP;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
MALLOCVAR(objectP);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
if (!objectP)
|
|
Packit |
78deda |
pm_error("Failed to allocate memory for a float color data object");
|
|
Packit |
78deda |
|
|
Packit |
78deda |
objectP->objType = ctyp;
|
|
Packit |
78deda |
validateFormat(format, ctyp);
|
|
Packit |
78deda |
strcpy(objectP->odata.fcolData.fcformat, format);
|
|
Packit |
78deda |
objectP->odata.fcolData.fcolmin = fcolmin;
|
|
Packit |
78deda |
objectP->odata.fcolData.fcolmax = fcolmax;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
return objectP;
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
static SkeletonObject *
|
|
Packit |
78deda |
newIdataObj(SkeletonObjectType const ctyp,
|
|
Packit |
78deda |
const char * const format) {
|
|
Packit |
78deda |
/*----------------------------------------------------------------------------
|
|
Packit |
78deda |
Create universal data object.
|
|
Packit |
78deda |
-----------------------------------------------------------------------------*/
|
|
Packit |
78deda |
SkeletonObject * objectP;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
MALLOCVAR(objectP);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
if (!objectP)
|
|
Packit |
78deda |
pm_error("Failed to allocate memory for a universal data object");
|
|
Packit |
78deda |
|
|
Packit |
78deda |
objectP->objType = ctyp;
|
|
Packit |
78deda |
validateFormat(format, ctyp);
|
|
Packit |
78deda |
strcpy(objectP->odata.iData.iformat, format);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
return objectP;
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
static char const escape = '#';
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
static SkeletonObjectType
|
|
Packit |
78deda |
interpretObjType(const char * const typstr) {
|
|
Packit |
78deda |
|
|
Packit |
78deda |
SkeletonObjectType objType;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
/* handle integer colors */
|
|
Packit |
78deda |
if (streq(typstr, "ired") ) objType = IRED;
|
|
Packit |
78deda |
else if (streq(typstr, "igreen")) objType = IGREEN;
|
|
Packit |
78deda |
else if (streq(typstr, "iblue") ) objType = IBLUE;
|
|
Packit |
78deda |
else if (streq(typstr, "ilum") ) objType = ILUM;
|
|
Packit |
78deda |
/* handle real colors */
|
|
Packit |
78deda |
else if (streq(typstr, "fred") ) objType = FRED;
|
|
Packit |
78deda |
else if (streq(typstr, "fgreen")) objType = FGREEN;
|
|
Packit |
78deda |
else if (streq(typstr, "fblue") ) objType = FBLUE;
|
|
Packit |
78deda |
else if (streq(typstr, "flum") ) objType = FLUM;
|
|
Packit |
78deda |
/* handle integer data */
|
|
Packit |
78deda |
else if (streq(typstr, "width") ) objType = WIDTH;
|
|
Packit |
78deda |
else if (streq(typstr, "height")) objType = HEIGHT;
|
|
Packit |
78deda |
else if (streq(typstr, "posx") ) objType = POSX;
|
|
Packit |
78deda |
else if (streq(typstr, "posy") ) objType = POSY;
|
|
Packit |
78deda |
else objType = BDATA;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
return objType;
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
static SkeletonObject *
|
|
Packit |
78deda |
newIcSkelFromReplString(const char * const icolorObjstr,
|
|
Packit |
78deda |
SkeletonObjectType const objType) {
|
|
Packit |
78deda |
/*----------------------------------------------------------------------------
|
|
Packit |
78deda |
A new skeleton for an integer color substitution specifier (class
|
|
Packit |
78deda |
OBJTYP_ICOLOR) whose replacement string (the stuff between the parentheses
|
|
Packit |
78deda |
in #(...)) says substitution type 'objType' and the rest of the
|
|
Packit |
78deda |
replacement string is 'icolorObjstr'.
|
|
Packit |
78deda |
-----------------------------------------------------------------------------*/
|
|
Packit |
78deda |
SkeletonObject * retval;
|
|
Packit |
78deda |
unsigned int icolmin, icolmax;
|
|
Packit |
78deda |
char formstr[MAX_OBJ_BUF];
|
|
Packit |
78deda |
int nOdata;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
nOdata = sscanf(icolorObjstr, "%s%u%u", formstr, &icolmin, &icolmax);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
if (nOdata == 3)
|
|
Packit |
78deda |
retval = newIcolDataObj(objType, formstr, icolmin, icolmax);
|
|
Packit |
78deda |
else if (nOdata == EOF) {
|
|
Packit |
78deda |
/* No arguments specified. Use defaults */
|
|
Packit |
78deda |
retval = newIcolDataObj(objType, "%u", 0, 255);
|
|
Packit |
78deda |
} else
|
|
Packit |
78deda |
retval = NULL;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
return retval;
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
static SkeletonObject *
|
|
Packit |
78deda |
newFcSkelFromReplString(const char * const fcolorObjstr,
|
|
Packit |
78deda |
SkeletonObjectType const objType) {
|
|
Packit |
78deda |
/*----------------------------------------------------------------------------
|
|
Packit |
78deda |
A new skeleton for a floating point color substitution specifier (class
|
|
Packit |
78deda |
OBJTYP_FCOLOR) whose replacement string (the stuff between the parentheses
|
|
Packit |
78deda |
in #(...)) says substitution type 'objType' and the rest of the
|
|
Packit |
78deda |
replacement string is 'fcolorObjstr'.
|
|
Packit |
78deda |
-----------------------------------------------------------------------------*/
|
|
Packit |
78deda |
SkeletonObject * retval;
|
|
Packit |
78deda |
double fcolmin, fcolmax;
|
|
Packit |
78deda |
char formstr[MAX_OBJ_BUF];
|
|
Packit |
78deda |
int nOdata;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
nOdata = sscanf(fcolorObjstr, "%s%lf%lf", formstr, &fcolmin, &fcolmax);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
if (nOdata == 3)
|
|
Packit |
78deda |
retval = newFcolDataObj(objType, formstr, fcolmin, fcolmax);
|
|
Packit |
78deda |
else if (nOdata == EOF) {
|
|
Packit |
78deda |
/* No arguments specified. Use defaults */
|
|
Packit |
78deda |
retval = newFcolDataObj(objType, "%f", 0.0, 1.0);
|
|
Packit |
78deda |
} else
|
|
Packit |
78deda |
retval = NULL;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
return retval;
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
static SkeletonObject *
|
|
Packit |
78deda |
newISkelFromReplString(const char * const intObjstr,
|
|
Packit |
78deda |
SkeletonObjectType const objType) {
|
|
Packit |
78deda |
/*----------------------------------------------------------------------------
|
|
Packit |
78deda |
A new skeleton for an integer substitution specifier (class OBJTYP_INT)
|
|
Packit |
78deda |
whose replacement string (the stuff between the parentheses in #(...))
|
|
Packit |
78deda |
says substitution type 'objType' and the rest of the replacement string is
|
|
Packit |
78deda |
'intObjstr'.
|
|
Packit |
78deda |
-----------------------------------------------------------------------------*/
|
|
Packit |
78deda |
SkeletonObject * retval;
|
|
Packit |
78deda |
char formstr[MAX_OBJ_BUF];
|
|
Packit |
78deda |
int nOdata;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
nOdata = sscanf(intObjstr, "%s", formstr);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
if (nOdata == 1)
|
|
Packit |
78deda |
retval = newIdataObj(objType, formstr);
|
|
Packit |
78deda |
else if (nOdata == EOF) {
|
|
Packit |
78deda |
/* No arguments specified. Use defaults */
|
|
Packit |
78deda |
retval = newIdataObj(objType, "%u");
|
|
Packit |
78deda |
} else
|
|
Packit |
78deda |
retval = NULL;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
return retval;
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
static SkeletonObject *
|
|
Packit |
78deda |
newSkeletonFromReplString(const char * const objstr) {
|
|
Packit |
78deda |
/*----------------------------------------------------------------------------
|
|
Packit |
78deda |
A new skeleton created from the replacement string 'objstr' (the stuff
|
|
Packit |
78deda |
between the parentheses in #(...) ).
|
|
Packit |
78deda |
|
|
Packit |
78deda |
Return NULL if it isn't a valid replacement string.
|
|
Packit |
78deda |
-----------------------------------------------------------------------------*/
|
|
Packit |
78deda |
/* We use sscanf() to parse the contents of objstr, giving it a format
|
|
Packit |
78deda |
template with the largest number of fields possible plus one extra to
|
|
Packit |
78deda |
pick up and check for the existence of invalid trailing characters. We
|
|
Packit |
78deda |
read and discard fields beyond the first, if any. The appropriate
|
|
Packit |
78deda |
new**SkelFromReplString() function determines their contents with a
|
|
Packit |
78deda |
separate call to sscanf().
|
|
Packit |
78deda |
*/
|
|
Packit |
78deda |
|
|
Packit |
78deda |
SkeletonObject * retval;
|
|
Packit |
78deda |
char typstr[MAX_OBJ_BUF];
|
|
Packit |
78deda |
int typlen;
|
|
Packit |
78deda |
SkeletonObjectType objType;
|
|
Packit |
78deda |
int conversionCt;
|
|
Packit |
78deda |
char s1[MAX_OBJ_BUF]; /* Dry read. */
|
|
Packit |
78deda |
char s2[MAX_OBJ_BUF]; /* Extra tailing characters. */
|
|
Packit |
78deda |
float f1, f2; /* Dry read. */
|
|
Packit |
78deda |
|
|
Packit |
78deda |
typstr[0] = '\0'; /* initial value */
|
|
Packit |
78deda |
|
|
Packit |
78deda |
conversionCt = sscanf(objstr, "%s%n%s%f%f%s",
|
|
Packit |
78deda |
typstr, &typlen, s1, &f1, &f2, s2);
|
|
Packit |
78deda |
switch (conversionCt) {
|
|
Packit |
78deda |
case 1: case 2: case 4:
|
|
Packit |
78deda |
objType = interpretObjType(typstr);
|
|
Packit |
78deda |
break;
|
|
Packit |
78deda |
default:
|
|
Packit |
78deda |
objType = BDATA;
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
|
|
Packit |
78deda |
switch (objClass(objType)) {
|
|
Packit |
78deda |
case OBJTYP_ICOLOR:
|
|
Packit |
78deda |
retval = newIcSkelFromReplString(&objstr[typlen], objType);
|
|
Packit |
78deda |
break;
|
|
Packit |
78deda |
case OBJTYP_FCOLOR:
|
|
Packit |
78deda |
retval = newFcSkelFromReplString(&objstr[typlen], objType);
|
|
Packit |
78deda |
break;
|
|
Packit |
78deda |
case OBJTYP_INT:
|
|
Packit |
78deda |
retval = newISkelFromReplString(&objstr[typlen], objType);
|
|
Packit |
78deda |
break;
|
|
Packit |
78deda |
case OBJTYP_BDATA:
|
|
Packit |
78deda |
retval = NULL;
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
return retval;
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
static void
|
|
Packit |
78deda |
readThroughCloseParen(FILE * const ifP,
|
|
Packit |
78deda |
char * const objstr,
|
|
Packit |
78deda |
size_t const objstrSize,
|
|
Packit |
78deda |
bool * const unclosedP) {
|
|
Packit |
78deda |
/*----------------------------------------------------------------------------
|
|
Packit |
78deda |
Read *ifP up through close parenthesis ( ')' ) into 'objstr', which
|
|
Packit |
78deda |
is of size 'objstrSize'. Make it a NUL-terminated string.
|
|
Packit |
78deda |
|
|
Packit |
78deda |
Return *unclosedP true iff we run out of file or run out of objstr
|
|
Packit |
78deda |
before we see a close parenthesis. In this case, return the rest of
|
|
Packit |
78deda |
the file, or as much as fits, in 'objstr', not NUL-terminated.
|
|
Packit |
78deda |
-----------------------------------------------------------------------------*/
|
|
Packit |
78deda |
unsigned int i;
|
|
Packit |
78deda |
bool eof;
|
|
Packit |
78deda |
bool gotEscSeq;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
for (i= 0, eof = false, gotEscSeq = false;
|
|
Packit |
78deda |
i < objstrSize - 1 && !gotEscSeq && !eof;
|
|
Packit |
78deda |
++i) {
|
|
Packit |
78deda |
|
|
Packit |
78deda |
int rc;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
rc = getc(ifP);
|
|
Packit |
78deda |
if (rc == EOF)
|
|
Packit |
78deda |
eof = true;
|
|
Packit |
78deda |
else {
|
|
Packit |
78deda |
char const chr = rc;
|
|
Packit |
78deda |
if (chr == ')') {
|
|
Packit |
78deda |
gotEscSeq = true;
|
|
Packit |
78deda |
objstr[i] = '\0';
|
|
Packit |
78deda |
} else
|
|
Packit |
78deda |
objstr[i] = chr;
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
*unclosedP = !gotEscSeq;
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
typedef struct {
|
|
Packit |
78deda |
unsigned int capacity;
|
|
Packit |
78deda |
SkeletonObject ** skeletonPList;
|
|
Packit |
78deda |
unsigned int nSkeleton;
|
|
Packit |
78deda |
} SkeletonBuffer;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
static void
|
|
Packit |
78deda |
SkeletonBuffer_init(SkeletonBuffer * const bufferP,
|
|
Packit |
78deda |
unsigned int const capacity,
|
|
Packit |
78deda |
SkeletonObject ** const skeletonPList) {
|
|
Packit |
78deda |
|
|
Packit |
78deda |
bufferP->capacity = capacity;
|
|
Packit |
78deda |
bufferP->skeletonPList = skeletonPList;
|
|
Packit |
78deda |
bufferP->nSkeleton = 0;
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
static void
|
|
Packit |
78deda |
SkeletonBuffer_add(SkeletonBuffer * const bufferP,
|
|
Packit |
78deda |
SkeletonObject * const skeletonP) {
|
|
Packit |
78deda |
|
|
Packit |
78deda |
if (bufferP->nSkeleton >= bufferP->capacity)
|
|
Packit |
78deda |
pm_error("Too many skeletons. Max = %u", bufferP->capacity);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
bufferP->skeletonPList[bufferP->nSkeleton++] = skeletonP;
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
typedef struct {
|
|
Packit |
78deda |
|
|
Packit |
78deda |
char data[MAX_LINE_BUF + MAX_OBJ_BUF + 16];
|
|
Packit |
78deda |
|
|
Packit |
78deda |
unsigned int length;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
SkeletonBuffer * skeletonBufferP;
|
|
Packit |
78deda |
/* The buffer to which we flush. Flushing means turning all the
|
|
Packit |
78deda |
characters currently in our buffer into a binary skeleton object
|
|
Packit |
78deda |
here.
|
|
Packit |
78deda |
*/
|
|
Packit |
78deda |
|
|
Packit |
78deda |
} Buffer;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
static void
|
|
Packit |
78deda |
Buffer_init(Buffer * const bufferP,
|
|
Packit |
78deda |
SkeletonBuffer * const skeletonBufferP) {
|
|
Packit |
78deda |
|
|
Packit |
78deda |
bufferP->skeletonBufferP = skeletonBufferP;
|
|
Packit |
78deda |
bufferP->length = 0;
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
static void
|
|
Packit |
78deda |
Buffer_flush(Buffer * const bufferP) {
|
|
Packit |
78deda |
/*----------------------------------------------------------------------------
|
|
Packit |
78deda |
Flush the buffer out to a binary skeleton object.
|
|
Packit |
78deda |
-----------------------------------------------------------------------------*/
|
|
Packit |
78deda |
SkeletonBuffer_add(bufferP->skeletonBufferP,
|
|
Packit |
78deda |
newBinDataObj(bufferP->length, bufferP->data));
|
|
Packit |
78deda |
|
|
Packit |
78deda |
bufferP->length = 0;
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
static void
|
|
Packit |
78deda |
Buffer_add(Buffer * const bufferP,
|
|
Packit |
78deda |
char const newChar) {
|
|
Packit |
78deda |
|
|
Packit |
78deda |
if (bufferP->length >= MAX_LINE_BUF)
|
|
Packit |
78deda |
Buffer_flush(bufferP);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
assert(bufferP->length < MAX_LINE_BUF);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
bufferP->data[bufferP->length++] = newChar;
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
static void
|
|
Packit |
78deda |
Buffer_dropFinalNewline(Buffer * const bufferP) {
|
|
Packit |
78deda |
/*----------------------------------------------------------------------------
|
|
Packit |
78deda |
If the last thing in the buffer is a newline, remove it.
|
|
Packit |
78deda |
-----------------------------------------------------------------------------*/
|
|
Packit |
78deda |
if (bufferP->length >= 1 && bufferP->data[bufferP->length-1] == '\n') {
|
|
Packit |
78deda |
/* Drop finishing newline character */
|
|
Packit |
78deda |
--bufferP->length;
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
static void
|
|
Packit |
78deda |
addImpostorReplacementSeq(Buffer * const bufferP,
|
|
Packit |
78deda |
const char * const seqContents) {
|
|
Packit |
78deda |
/*----------------------------------------------------------------------------
|
|
Packit |
78deda |
Add to buffer *bufferP something that looks like a replacement sequence but
|
|
Packit |
78deda |
doesn't have the proper contents (the stuff between the parentheses) to be
|
|
Packit |
78deda |
one. For example,
|
|
Packit |
78deda |
|
|
Packit |
78deda |
"#(fread x)"
|
|
Packit |
78deda |
|
|
Packit |
78deda |
seqContents[] is the contents, NUL-terminated.
|
|
Packit |
78deda |
-----------------------------------------------------------------------------*/
|
|
Packit |
78deda |
const char * p;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
Buffer_add(bufferP, escape);
|
|
Packit |
78deda |
Buffer_add(bufferP, '(');
|
|
Packit |
78deda |
|
|
Packit |
78deda |
for (p = &seqContents[0]; *p; ++p)
|
|
Packit |
78deda |
Buffer_add(bufferP, *p);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
Buffer_add(bufferP, ')');
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
static void
|
|
Packit |
78deda |
readSkeletonFile(const char * const filename,
|
|
Packit |
78deda |
unsigned int const maxskl,
|
|
Packit |
78deda |
const char ** const errorP,
|
|
Packit |
78deda |
unsigned int * const nSkeletonP,
|
|
Packit |
78deda |
SkeletonObject ** const skeletonPList) {
|
|
Packit |
78deda |
/*----------------------------------------------------------------------------
|
|
Packit |
78deda |
-----------------------------------------------------------------------------*/
|
|
Packit |
78deda |
FILE * sklfileP;
|
|
Packit |
78deda |
SkeletonBuffer skeletonBuffer;
|
|
Packit |
78deda |
/* A buffer for accumulating skeleton objects */
|
|
Packit |
78deda |
Buffer buffer;
|
|
Packit |
78deda |
/* A buffer for accumulating binary (literal; unsubstituted) data, on
|
|
Packit |
78deda |
its way to becoming a binary skeleton object.
|
|
Packit |
78deda |
*/
|
|
Packit |
78deda |
bool eof;
|
|
Packit |
78deda |
const char * error;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
SkeletonBuffer_init(&skeletonBuffer, maxskl, skeletonPList);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
Buffer_init(&buffer, &skeletonBuffer);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
sklfileP = pm_openr(filename);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
for (eof = false, error = NULL; !eof && !error; ) {
|
|
Packit |
78deda |
|
|
Packit |
78deda |
int rc;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
rc = getc(sklfileP);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
if (rc == EOF)
|
|
Packit |
78deda |
eof = true;
|
|
Packit |
78deda |
else {
|
|
Packit |
78deda |
char const chr = rc;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
if (chr != escape) {
|
|
Packit |
78deda |
/* Not a replacement sequence; just a literal character */
|
|
Packit |
78deda |
Buffer_add(&buffer, chr);
|
|
Packit |
78deda |
} else {
|
|
Packit |
78deda |
int rc;
|
|
Packit |
78deda |
rc = getc(sklfileP);
|
|
Packit |
78deda |
if (rc == EOF) {
|
|
Packit |
78deda |
/* Not a replacement sequence, just an escape caharacter
|
|
Packit |
78deda |
at the end of the file.
|
|
Packit |
78deda |
*/
|
|
Packit |
78deda |
Buffer_add(&buffer, escape);
|
|
Packit |
78deda |
eof = true;
|
|
Packit |
78deda |
} else {
|
|
Packit |
78deda |
char const chr = rc;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
if (chr != '(') {
|
|
Packit |
78deda |
/* Not a replacement sequence, just a lone escape
|
|
Packit |
78deda |
character
|
|
Packit |
78deda |
*/
|
|
Packit |
78deda |
Buffer_add(&buffer, escape);
|
|
Packit |
78deda |
Buffer_add(&buffer, chr);
|
|
Packit |
78deda |
} else {
|
|
Packit |
78deda |
char objstr[MAX_OBJ_BUF];
|
|
Packit |
78deda |
bool unclosed;
|
|
Packit |
78deda |
readThroughCloseParen(sklfileP,
|
|
Packit |
78deda |
objstr, sizeof(objstr),
|
|
Packit |
78deda |
&unclosed);
|
|
Packit |
78deda |
if (unclosed)
|
|
Packit |
78deda |
pm_asprintf(&error, "Unclosed parentheses "
|
|
Packit |
78deda |
"in #() escape sequence");
|
|
Packit |
78deda |
else {
|
|
Packit |
78deda |
SkeletonObject * const skeletonP =
|
|
Packit |
78deda |
newSkeletonFromReplString(objstr);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
if (skeletonP) {
|
|
Packit |
78deda |
Buffer_flush(&buffer);
|
|
Packit |
78deda |
SkeletonBuffer_add(&skeletonBuffer, skeletonP);
|
|
Packit |
78deda |
} else
|
|
Packit |
78deda |
addImpostorReplacementSeq(&buffer, objstr);
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
|
|
Packit |
78deda |
if (!error) {
|
|
Packit |
78deda |
Buffer_dropFinalNewline(&buffer);
|
|
Packit |
78deda |
Buffer_flush(&buffer);
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
*errorP = error;
|
|
Packit |
78deda |
*nSkeletonP = skeletonBuffer.nSkeleton;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
fclose(sklfileP);
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
static void
|
|
Packit |
78deda |
convertIt(FILE * const ifP,
|
|
Packit |
78deda |
FILE * const ofP,
|
|
Packit |
78deda |
SkeletonObject ** const bodySkeletonPList,
|
|
Packit |
78deda |
unsigned int const bodyNskl,
|
|
Packit |
78deda |
SkeletonObject ** const headSkeletonPList,
|
|
Packit |
78deda |
unsigned int const headNskl,
|
|
Packit |
78deda |
SkeletonObject ** const tailSkeletonPList,
|
|
Packit |
78deda |
unsigned int const tailNskl) {
|
|
Packit |
78deda |
|
|
Packit |
78deda |
pixel * pixelrow;
|
|
Packit |
78deda |
pixval maxval;
|
|
Packit |
78deda |
double dmaxval;
|
|
Packit |
78deda |
int rows, cols;
|
|
Packit |
78deda |
int format;
|
|
Packit |
78deda |
unsigned int row;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
ppm_readppminit(ifP, &cols, &rows, &maxval, &format);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
pixelrow = ppm_allocrow(cols);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
dmaxval = (double)maxval;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
/* Write header */
|
|
Packit |
78deda |
writeText(ofP, headNskl, headSkeletonPList,
|
|
Packit |
78deda |
cols, rows , 0, 0, 0.0, 0.0, 0.0);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
/* Write raster */
|
|
Packit |
78deda |
for (row = 0; row < rows; ++row) {
|
|
Packit |
78deda |
unsigned int col;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
ppm_readppmrow(ifP, pixelrow, cols, maxval, format);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
for (col = 0; col < cols; ++col) {
|
|
Packit |
78deda |
pixel const thisPixel = pixelrow[col];
|
|
Packit |
78deda |
|
|
Packit |
78deda |
writeText(ofP, bodyNskl, bodySkeletonPList,
|
|
Packit |
78deda |
cols, rows, col, row,
|
|
Packit |
78deda |
PPM_GETR(thisPixel)/dmaxval,
|
|
Packit |
78deda |
PPM_GETG(thisPixel)/dmaxval,
|
|
Packit |
78deda |
PPM_GETB(thisPixel)/dmaxval);
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
|
|
Packit |
78deda |
/* Write trailer */
|
|
Packit |
78deda |
writeText(ofP, tailNskl, tailSkeletonPList,
|
|
Packit |
78deda |
cols, rows, 0, 0, 0.0, 0.0, 0.0);
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
int
|
|
Packit |
78deda |
main(int argc,
|
|
Packit |
78deda |
const char ** argv) {
|
|
Packit |
78deda |
|
|
Packit |
78deda |
struct CmdlineInfo cmdline;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
unsigned int headNskl, bodyNskl, tailNskl;
|
|
Packit |
78deda |
SkeletonObject * headSkeletonPList[MAX_SKL_HEAD_OBJ];
|
|
Packit |
78deda |
SkeletonObject * bodySkeletonPList[MAX_SKL_BODY_OBJ];
|
|
Packit |
78deda |
SkeletonObject * tailSkeletonPList[MAX_SKL_TAIL_OBJ];
|
|
Packit |
78deda |
FILE * ifP;
|
|
Packit |
78deda |
const char * error;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
pm_proginit(&argc, argv);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
parseCommandLine(argc, argv, &cmdline);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
ifP = pm_openr(cmdline.inputFileName);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
readSkeletonFile(cmdline.bodySklFileName, ARRAY_SIZE(bodySkeletonPList),
|
|
Packit |
78deda |
&error, &bodyNskl, bodySkeletonPList);
|
|
Packit |
78deda |
if (error)
|
|
Packit |
78deda |
pm_error("Invalid body skeleton file '%s'. %s",
|
|
Packit |
78deda |
cmdline.bodySklFileName, error);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
if (cmdline.hd) {
|
|
Packit |
78deda |
readSkeletonFile(cmdline.hd, ARRAY_SIZE(headSkeletonPList),
|
|
Packit |
78deda |
&error, &headNskl, headSkeletonPList);
|
|
Packit |
78deda |
if (error)
|
|
Packit |
78deda |
pm_error("Invalid head skeleton file '%s'. %s",
|
|
Packit |
78deda |
cmdline.hd, error);
|
|
Packit |
78deda |
} else
|
|
Packit |
78deda |
headNskl = 0;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
if (cmdline.tl) {
|
|
Packit |
78deda |
readSkeletonFile(cmdline.tl, ARRAY_SIZE(tailSkeletonPList),
|
|
Packit |
78deda |
&error, &tailNskl, tailSkeletonPList);
|
|
Packit |
78deda |
if (error)
|
|
Packit |
78deda |
pm_error("Invalid tail skeleton file '%s'. %s",
|
|
Packit |
78deda |
cmdline.tl, error);
|
|
Packit |
78deda |
} else
|
|
Packit |
78deda |
tailNskl = 0;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
if (cmdline.debug)
|
|
Packit |
78deda |
dumpAllSkeleton(bodySkeletonPList, bodyNskl,
|
|
Packit |
78deda |
headSkeletonPList, headNskl,
|
|
Packit |
78deda |
tailSkeletonPList, tailNskl);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
convertIt(ifP, stdout,
|
|
Packit |
78deda |
bodySkeletonPList, bodyNskl,
|
|
Packit |
78deda |
headSkeletonPList, headNskl,
|
|
Packit |
78deda |
tailSkeletonPList, tailNskl);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
pm_close(ifP);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
return 0;
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|