#include "fontmisc.h"
#ifndef FONTMODULE
#include <string.h>
#include <ctype.h>
#include <math.h>
#else
#include "Xmd.h"
#include "Xdefs.h"
#include "xf86_ansic.h"
#endif
#ifndef True
#define True (-1)
#endif
#ifndef False
#define False (0)
#endif
#include "xttcap.h"
#if 0
#if (defined(sun) && !(defined(SVR4) || defined(__SVR4)))
double strtod(char *str, char **ptr);
double strtol(char *str, char **ptr, int base);
#endif
#endif
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]);
#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 = xalloc(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:
xfree(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
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 (!mystrcasecmp(validRecords[i].strRecordName, strName)) {
result = True;
*refRefRecord = &validRecords[i];
break;
}
}
return result;
}
Bool
SPropRecValList_new(SDynPropRecValList *pThisList)
{
Bool result = False;
pThisList->headNode = NULL;
return result;
}
Bool
SPropRecValList_delete(SDynPropRecValList *pThisList)
{
Bool result = False;
SPropRecValListNodeP *p, *np;
for (p=pThisList->headNode; NULL!=p; p=np) {
np = p->nextNode;
switch (p->containerE.refRecordType->recordType) {
case eRecTypeInteger:
break;
case eRecTypeDouble:
break;
case eRecTypeBool:
break;
case eRecTypeString:
if (SPropContainer_value_str(&p->containerE))
xfree((void*)SPropContainer_value_str(&p->containerE));
break;
case eRecTypeVoid:
break;
}
xfree(p);
}
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
extern 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 (!mystrcasecmp(strValue, "yes"))
val = True;
else if (!mystrcasecmp(strValue, "y"))
val = True;
else if (!mystrcasecmp(strValue, "on"))
val = True;
else if (!mystrcasecmp(strValue, "true"))
val = True;
else if (!mystrcasecmp(strValue, "t"))
val = True;
else if (!mystrcasecmp(strValue, "ok"))
val = True;
else if (!mystrcasecmp(strValue, "no"))
val = False;
else if (!mystrcasecmp(strValue, "n"))
val = False;
else if (!mystrcasecmp(strValue, "off"))
val = False;
else if (!mystrcasecmp(strValue, "false"))
val = False;
else if (!mystrcasecmp(strValue, "f"))
val = False;
else if (!mystrcasecmp(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 = (char *)xalloc(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 =
(SPropRecValListNodeP *)xalloc(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;
}
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 (!mystrcasecmp(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=(char *)xalloc(len+1);
memcpy(value, p+1, len);
value[len]='\0';
SPropRecValList_add_record(pThisList,
"FaceNumber",
value);
xfree(value);
term=p;
}
break;
}
if ( !isdigit(*p) )
break;
}
}
while (strCapHead<term) {
int i;
char const *nextColon = strchr(strCapHead, ':');
if (0<nextColon-strCapHead) {
char *duplicated = (char *)xalloc((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 (!mystrcasecmp(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:
;
}
xfree(duplicated);
}
strCapHead = nextColon+1;
}
abort:
return result;
}
Bool
mystrcasecmp(char const *s1, char const *s2)
{
Bool result = True;
#if (defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) ||\
defined(__bsdi__)) && !defined(FONTMODULE)
result = strcasecmp(s1, s2) != 0;
#else
{
unsigned int len1 = strlen(s1);
if (len1 == strlen(s2)) {
int i;
for (i=0; i<len1; i++) {
if (toupper(*s1++) != toupper(*s2++))
goto quit;
}
result = False;
} else
;
}
quit:
;
#endif
return result;
}
char *
XttXstrdup(char const *str)
{
char *result;
result = (char *)xalloc(strlen(str)+1);
if (result)
strcpy(result, str);
return result;
}
#if 0
int main()
{
SDynPropRecValList list;
SPropRecValList_new(&list);
SPropRecValList_read_prop_file(&list, "-");
SPropRecValList_dump(&list);
SPropRecValList_delete(&list);
return 0;
}
#endif