#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <X11/fonts/fontmisc.h>
#include <string.h>
#include <ctype.h>
#include <math.h>
#ifndef True
#define True (-1)
#endif
#ifndef False
#define False (0)
#endif
#include "xttcap.h"
typedef struct TagSPropRecValListNodeP
{
SPropRecValContainerEntityP containerE;
struct TagSPropRecValListNodeP *nextNode;
} SPropRecValListNodeP;
static SPropertyRecord const validRecords[] =
{
{ "FontFile", eRecTypeString },
{ "FaceNumber", eRecTypeString },
{ "AutoItalic", eRecTypeDouble },
{ "DoubleStrike", eRecTypeString },
{ "FontProperties", eRecTypeBool },
{ "ForceSpacing", eRecTypeString },
{ "ScaleBBoxWidth", eRecTypeString },
{ "ScaleWidth", eRecTypeDouble },
{ "EncodingOptions", eRecTypeString },
{ "Hinting", eRecTypeBool },
{ "VeryLazyMetrics", eRecTypeBool },
{ "CodeRange", eRecTypeString },
{ "EmbeddedBitmap", eRecTypeString },
{ "VeryLazyBitmapWidthScale", eRecTypeDouble },
{ "ForceConstantSpacingCodeRange", eRecTypeString },
{ "ForceConstantSpacingMetrics", eRecTypeString },
{ "Dummy", eRecTypeVoid }
};
static int const
numOfValidRecords = sizeof(validRecords)/sizeof(validRecords[0]);
static struct {
char const * capVariable;
char const * recordName;
} const correspondRelations[] = {
{ "fn", "FaceNumber" },
{ "ai", "AutoItalic" },
{ "ds", "DoubleStrike" },
{ "fp", "FontProperties" },
{ "fs", "ForceSpacing" },
{ "bw", "ScaleBBoxWidth" },
{ "sw", "ScaleWidth" },
{ "eo", "EncodingOptions" },
{ "vl", "VeryLazyMetrics" },
{ "bs", "VeryLazyBitmapWidthScale" },
{ "cr", "CodeRange" },
{ "eb", "EmbeddedBitmap" },
{ "hi", "Hinting" },
{ "fc", "ForceConstantSpacingCodeRange" },
{ "fm", "ForceConstantSpacingMetrics" }
};
static int const
numOfCorrespondRelations
= sizeof(correspondRelations)/sizeof(correspondRelations[0]);
static Bool
get_record_type_by_name(SPropertyRecord const ** const refRefRecord,
char const *strName)
{
Bool result = False;
int i;
*refRefRecord = NULL;
for (i=0; i<numOfValidRecords; i++) {
if (!strcasecmp(validRecords[i].strRecordName, strName)) {
result = True;
*refRefRecord = &validRecords[i];
break;
}
}
return result;
}
static Bool
SPropRecValList_add_record(SDynPropRecValList *pThisList,
char const * const recordName,
char const * const strValue)
{
Bool result = False;
SPropRecValContainerEntityP tmpContainerE;
if (get_record_type_by_name(&tmpContainerE.refRecordType, recordName)) {
switch (tmpContainerE.refRecordType->recordType) {
case eRecTypeInteger:
{
int val;
char *endPtr;
val = strtol(strValue, &endPtr, 0);
if ('\0' != *endPtr) {
fprintf(stderr,
"truetype font property : "
"%s record needs integer value.\n",
recordName);
result = True;
goto quit;
}
SPropContainer_value_int(&tmpContainerE) = val;
}
break;
case eRecTypeDouble:
{
double val;
char *endPtr;
val = strtod(strValue, &endPtr);
if ('\0' != *endPtr) {
fprintf(stderr,
"truetype font property : "
"%s record needs floating point value.\n",
recordName);
result = True;
goto quit;
}
SPropContainer_value_dbl(&tmpContainerE) = val;
}
break;
case eRecTypeBool:
{
Bool val;
if (!strcasecmp(strValue, "yes"))
val = True;
else if (!strcasecmp(strValue, "y"))
val = True;
else if (!strcasecmp(strValue, "on"))
val = True;
else if (!strcasecmp(strValue, "true"))
val = True;
else if (!strcasecmp(strValue, "t"))
val = True;
else if (!strcasecmp(strValue, "ok"))
val = True;
else if (!strcasecmp(strValue, "no"))
val = False;
else if (!strcasecmp(strValue, "n"))
val = False;
else if (!strcasecmp(strValue, "off"))
val = False;
else if (!strcasecmp(strValue, "false"))
val = False;
else if (!strcasecmp(strValue, "f"))
val = False;
else if (!strcasecmp(strValue, "bad"))
val = False;
else {
fprintf(stderr,
"truetype font property : "
"%s record needs boolean value.\n",
recordName);
result = True;
goto quit;
}
SPropContainer_value_bool(&tmpContainerE) = val;
}
break;
case eRecTypeString:
{
char *p;
if (NULL == (p = malloc(strlen(strValue)+1))) {
fprintf(stderr,
"truetype font property : "
"cannot allocate memory.\n");
result = True;
goto quit;
}
strcpy(p, strValue);
SPropContainer_value_str(&tmpContainerE) = p;
}
break;
case eRecTypeVoid:
if ('\0' != *strValue) {
fprintf(stderr,
"truetype font property : "
"%s record needs void.\n", recordName);
result = True;
}
break;
}
{
SPropRecValListNodeP *newNode;
if (NULL == (newNode = malloc(sizeof(*newNode)))) {
fprintf(stderr,
"truetype font property : "
"cannot allocate memory.\n");
result = True;
goto quit;
}
newNode->nextNode = pThisList->headNode;
newNode->containerE = tmpContainerE;
tmpContainerE.refRecordType = NULL;
pThisList->headNode = newNode;
}
} else {
fprintf(stderr,
"truetype font : "
"invalid record name \"%s.\"\n", recordName);
result = True;
}
quit:
return result;
}
#ifdef USE_TTP_FILE
#ifndef LEN_LINEBUF
#define LEN_LINEBUF 2048
#endif
static Bool
get_one_line(FILE *is, char *buf)
{
Bool result = False;
int count = 0;
Bool flHead = True;
Bool flSpace = False;
Bool flInSingleQuote = False;
Bool flInDoubleQuote = False;
Bool flBackSlash = False;
Bool flFirstElement = True;
*buf = '\0';
for (;;) {
int c = fgetc(is);
if (ferror(is)) {
fprintf(stderr, "truetype font property file : read error.\n");
result = True;
break;
}
if (EOF == c) {
if (flInSingleQuote || flInDoubleQuote) {
fprintf(stderr,
"truetype font property file : unmatched quote.\n");
result = True;
}
break;
}
if (flInSingleQuote) {
if ('\'' == c) {
flInSingleQuote = False;
c = -1;
} else
;
goto trans;
}
if (flBackSlash) {
flBackSlash = False;
if ('n' == c)
c = '\n';
if ('\n' == c)
c = -1;
else
;
goto trans;
}
if ('\\' == c) {
flBackSlash = True;
c = -1;
goto trans;
}
if (flInDoubleQuote) {
if ('"' == c) {
flInDoubleQuote = False;
c = -1;
} else
;
goto trans;
}
if ('#' == c) {
while ('\n' != c) {
c = fgetc(is);
if (ferror(is)) {
fprintf(stderr,
"truetype font property file : read error.\n");
result = True;
break;
}
if (EOF == c) {
break;
}
}
break;
}
if ('\'' == c) {
flInSingleQuote = True;
c = -1;
goto trans;
}
if ('"' == c) {
flInDoubleQuote = True;
c = -1;
goto trans;
}
if ('\n' == c)
break;
if (isspace(c)) {
if (!flHead)
flSpace = True;
continue;
}
trans:
flHead = False;
do {
if (count>=LEN_LINEBUF-1) {
fprintf(stderr,
"truetype font property file : too long line.\n");
result = True;
goto quit;
}
if (flSpace) {
if (flFirstElement) {
flFirstElement = False;
*buf = (char)0xff;
} else
*buf = ' ';
flSpace = False;
} else
if (-1 != c) {
*buf = c;
c = -1;
} else
buf--;
buf++;
} while (-1 != c);
}
*buf = '\0';
quit:
return result;
}
static Bool
parse_one_line(SDynPropRecValList *pThisList, FILE *is)
{
Bool result = False;
char *buf = NULL;
char *recordHead, *valueHead = NULL;
if (NULL == (buf = malloc(LEN_LINEBUF))) {
fprintf(stderr,
"truetype font property file : cannot allocate memory.\n");
result = True;
goto abort;
}
{
recordHead = buf;
do {
if (get_one_line(is, buf)) {
result = True;
goto quit;
}
if (feof(is)) {
if ('\0' == *buf)
goto quit;
break;
}
} while ('\0' == *buf);
if (NULL != (valueHead = strchr(buf, 0xff))) {
*valueHead = '\0';
valueHead++;
} else
valueHead = buf+strlen(buf);
#if 0
fprintf(stderr,
"truetype font property file : \n"
"recName:\"%s\"\nvalue:\"%s\"\n",
recordHead, valueHead);
#endif
result = SPropRecValList_add_record(pThisList, recordHead, valueHead);
}
quit:
free(buf);
abort:
return result;
}
Bool
SPropRecValList_read_prop_file(SDynPropRecValList *pThisList,
char const * const strFileName)
{
Bool result = False;
FILE *is;
#if 1
if (!strcmp(strFileName, "-"))
is = stdin;
else
#endif
is = fopen(strFileName, "r");
if (NULL == is) {
fprintf(stderr, "truetype font property : cannot open file %s.\n",
strFileName);
result = True;
goto abort;
}
{
for (;;) {
if (False != (result = parse_one_line(pThisList, is)))
goto quit;
if (feof(is))
break;
}
}
quit:
#if 1
if (strcmp(strFileName, "-"))
#endif
fclose(is);
abort:
return result;
}
#endif
Bool
SPropRecValList_new(SDynPropRecValList *pThisList)
{
Bool result = False;
pThisList->headNode = NULL;
return result;
}
#ifdef DUMP
void
SPropRecValList_dump(SRefPropRecValList *pThisList)
{
SPropRecValListNodeP *p;
for (p=pThisList->headNode; NULL!=p; p=p->nextNode) {
switch (p->containerE.refRecordType->recordType) {
case eRecTypeInteger:
fprintf(stderr, "%s = %d\n",
p->containerE.refRecordType->strRecordName,
p->containerE.uValue.integerValue);
break;
case eRecTypeDouble:
fprintf(stderr, "%s = %f\n",
p->containerE.refRecordType->strRecordName,
p->containerE.uValue.doubleValue);
break;
case eRecTypeBool:
fprintf(stderr, "%s = %s\n",
p->containerE.refRecordType->strRecordName,
p->containerE.uValue.boolValue
? "True":"False");
break;
case eRecTypeString:
fprintf(stderr, "%s = \"%s\"\n",
p->containerE.refRecordType->strRecordName,
p->containerE.uValue.dynStringValue);
break;
case eRecTypeVoid:
fprintf(stderr, "%s = void\n",
p->containerE.refRecordType->strRecordName);
break;
}
}
}
#endif
Bool
SPropRecValList_search_record(SRefPropRecValList *pThisList,
SPropRecValContainer *refRecValue,
char const * const recordName)
{
Bool result = False;
SPropRecValListNodeP *p;
*refRecValue = NULL;
for (p=pThisList->headNode; NULL!=p; p=p->nextNode) {
if (!strcasecmp(p->containerE.refRecordType->strRecordName,
recordName)) {
*refRecValue = &p->containerE;
result = True;
break;
}
}
return result;
}
Bool
SPropRecValList_add_by_font_cap(SDynPropRecValList *pThisList,
char const *strCapHead)
{
Bool result = False;
char const *term;
if (NULL == (term = strrchr(strCapHead, ':')))
goto abort;
{
char const *p;
for (p=term-1; p>=strCapHead; p--) {
if ( ':'==*p ) {
if ( p!=term ) {
int len = term-p-1;
char *value;
len = term-p-1;
value=malloc(len+1);
memcpy(value, p+1, len);
value[len]='\0';
SPropRecValList_add_record(pThisList,
"FaceNumber",
value);
free(value);
term=p;
}
break;
}
if ( !isdigit(*p) )
break;
}
}
while (strCapHead<term) {
int i;
char const *nextColon = strchr(strCapHead, ':');
if (0<nextColon-strCapHead) {
char *duplicated = malloc((nextColon-strCapHead)+1);
{
char *value;
memcpy(duplicated, strCapHead, nextColon-strCapHead);
duplicated[nextColon-strCapHead] = '\0';
if (NULL != (value=strchr(duplicated, '='))) {
*value = '\0';
value++;
} else
value = &duplicated[nextColon-strCapHead];
for (i=0; i<numOfCorrespondRelations; i++) {
if (!strcasecmp(correspondRelations[i].capVariable,
duplicated)) {
if (SPropRecValList_add_record(pThisList,
correspondRelations[i]
.recordName,
value))
break;
goto next;
}
}
fprintf(stderr, "truetype font : Illegal Font Cap.\n");
result = True;
break;
next:
;
}
free(duplicated);
}
strCapHead = nextColon+1;
}
abort:
return result;
}
char *
XttXstrdup(char const *str)
{
char *result;
result = malloc(strlen(str)+1);
if (result)
strcpy(result, str);
return result;
}