Skip to content
Fetching contributors…
Cannot retrieve contributors at this time
10420 lines (9499 sloc) 307 KB
/* Copyright (C) 2002-2012 by George Williams */
/*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/* Yet another interpreter */
#include "fontforge.h"
#include <gfile.h>
#include <utype.h>
#include <ustring.h>
#include <ffglib.h>
#include <chardata.h>
#include <unistd.h>
#include <math.h>
#include <setjmp.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <time.h>
#include <locale.h>
#ifdef HAVE_IEEEFP_H
# include <ieeefp.h> /* Solaris defines isnan in ieeefp rather than math.h */
#endif
#ifndef _NO_LIBREADLINE
# include <readline/readline.h>
# include <readline/history.h>
#endif
#include "ttf.h"
#include "plugins.h"
#include "scripting.h"
#include "scriptfuncs.h"
#include "flaglist.h"
#include "gutils/prefs.h"
#include "gutils/unicodelibinfo.h"
#include "xvasprintf.h"
int no_windowing_ui = false;
int running_script = false;
int use_utf8_in_script = true;
extern int prefRevisionsToRetain; /* sfd.c */
#ifndef _NO_FFSCRIPT
static int verbose = -1;
static struct dictionary globals;
struct keywords { enum token_type tok; const char *name; } keywords[] = {
{ tt_if, "if" },
{ tt_else, "else" },
{ tt_elseif, "elseif" },
{ tt_endif, "endif" },
{ tt_while, "while" },
{ tt_foreach, "foreach" },
{ tt_endloop, "endloop" },
{ tt_shift, "shift" },
{ tt_return, "return" },
{ tt_break, "break" },
{ 0, NULL }
};
static const char *toknames[] = {
"name", "string", "number", "unicode id", "real number",
"lparen", "rparen", "comma", "end of ff_statement",
"lbracket", "rbracket",
"minus", "plus", "logical not", "bitwise not", "colon",
"multiply", "divide", "mod", "logical and", "logical or", "bitwise and", "bitwise or", "bitwise xor",
"equal to", "not equal to", "greater than", "less than", "greater than or equal to", "less than or equal to",
"assignment", "plus equals", "minus equals", "mul equals", "div equals", "mod equals",
"increment", "decrement",
"if", "else", "elseif", "endif", "while", "foreach", "endloop",
"shift", "return",
"End Of File",
NULL };
char *utf82script_copy(const char *ustr) {
return( use_utf8_in_script ? copy(ustr) : utf8_2_latin1_copy(ustr));
}
char *script2utf8_copy(const char *str) {
return( use_utf8_in_script ? copy(str) : latin1_2_utf8_copy(str));
}
static char *script2latin1_copy(const char *str) {
if ( !use_utf8_in_script )
return( copy(str));
else {
unichar_t *t = utf82u_copy(str);
char *ret = cu_copy(t);
free(t);
return( ret );
}
}
#endif /* _NO_FFSCRIPT */
void arrayfree(Array *a) {
int i;
for ( i=0; i<a->argc; ++i ) {
if ( a->vals[i].type==v_str )
free(a->vals[i].u.sval);
else if ( a->vals[i].type==v_arr )
arrayfree(a->vals[i].u.aval);
}
free(a->vals);
free(a);
}
static Array *arraycopy(Array *a) {
int i;
Array *c;
c = malloc(sizeof(Array));
c->argc = a->argc;
c->vals = malloc(c->argc*sizeof(Val));
memcpy(c->vals,a->vals,c->argc*sizeof(Val));
for ( i=0; i<a->argc; ++i ) {
if ( a->vals[i].type==v_str )
c->vals[i].u.sval = copy(a->vals[i].u.sval);
else if ( a->vals[i].type==v_arr )
c->vals[i].u.aval = arraycopy(a->vals[i].u.aval);
}
return( c );
}
#ifndef _NO_FFSCRIPT
static void array_copy_into(Array *dest,int offset,Array *src) {
int i;
memcpy(dest->vals+offset,src->vals,src->argc*sizeof(Val));
for ( i=0; i<src->argc; ++i ) {
if ( src->vals[i].type==v_str )
dest->vals[i+offset].u.sval = copy(src->vals[i].u.sval);
else if ( src->vals[i].type==v_arr )
dest->vals[i+offset].u.aval = arraycopy(src->vals[i].u.aval);
}
}
void DictionaryFree(struct dictionary *dica) {
int i;
if ( dica==NULL )
return;
for ( i=0; i<dica->cnt; ++i ) {
free(dica->entries[i].name );
if ( dica->entries[i].val.type == v_str )
free( dica->entries[i].val.u.sval );
if ( dica->entries[i].val.type == v_arr )
arrayfree( dica->entries[i].val.u.aval );
}
free( dica->entries );
dica->entries = NULL;
}
static int DicaLookup(struct dictionary *dica,char *name,Val *val) {
int i;
if ( dica!=NULL && dica->entries!=NULL ) {
for ( i=0; i<dica->cnt; ++i )
if ( strcmp(dica->entries[i].name,name)==0 ) {
val->type = v_lval;
val->u.lval = &dica->entries[i].val;
return( true );
}
}
return( false );
}
static void DicaNewEntry(struct dictionary *dica,char *name,Val *val) {
if ( dica->entries==NULL ) {
dica->max = 10;
dica->entries = malloc(dica->max*sizeof(struct dictentry));
} else if ( dica->cnt>=dica->max ) {
dica->max += 10;
dica->entries = realloc(dica->entries,dica->max*sizeof(struct dictentry));
}
dica->entries[dica->cnt].name = copy(name);
dica->entries[dica->cnt].val.type = v_void;
val->type = v_lval;
val->u.lval = &dica->entries[dica->cnt].val;
++dica->cnt;
}
static void calldatafree(Context *c) {
int i;
/* child may have freed some args itself by shifting,
but argc will reflect the proper values none the less */
for ( i=1; i<c->a.argc; ++i ) {
if ( c->a.vals[i].type == v_str ) {
free( c->a.vals[i].u.sval );
c->a.vals[i].u.sval = NULL;
}
if ( c->a.vals[i].type == v_arrfree || (c->a.vals[i].type == v_arr && c->dontfree[i]!=c->a.vals[i].u.aval )) {
arrayfree( c->a.vals[i].u.aval );
c->a.vals[i].u.aval = NULL;
}
c->a.vals[i].type = v_void;
}
DictionaryFree(&c->locals);
if ( c->script!=NULL ) {
fclose(c->script);
c->script = NULL;
}
}
/* coverity[+kill] */
static void traceback(Context *c) {
int cnt = 0;
while ( c!=NULL ) {
if (c->interactive) {
if ( c->err_env!=NULL ) {
longjmp(*c->err_env,1);
}
c->error = ce_true;
return;
}
if ( cnt==1 ) LogError( _("Called from...\n") );
if ( cnt>0 ) LogError( _(" %s: line %d\n"), c->filename, c->lineno );
calldatafree(c);
if ( c->err_env!=NULL )
longjmp(*c->err_env,1);
c = c->caller;
++cnt;
}
exit(1);
}
static void showtoken(Context *c,enum token_type got) {
if ( got==tt_name || got==tt_string )
LogError( " \"%s\"\n", c->tok_text );
else if ( got==tt_number )
LogError( " %d (0x%x)\n", c->tok_val.u.ival, c->tok_val.u.ival );
else if ( got==tt_unicode )
LogError( " 0u%x\n", c->tok_val.u.ival );
else if ( got==tt_real )
LogError( " %g\n", c->tok_val.u.fval );
else
LogError( "\n" );
traceback(c);
}
static void expect(Context *c,enum token_type expected, enum token_type got) {
if ( got!=expected ) {
if ( verbose>0 )
fflush(stdout);
if (c->interactive)
LogError( _("Error: Expected %s, got %s"),
toknames[expected], toknames[got] );
else
LogError( _("%s: %d Expected %s, got %s"),
c->filename, c->lineno, toknames[expected], toknames[got] );
if ( !no_windowing_ui ) {
ff_post_error(NULL,_("%1$s: %2$d. Expected %3$s got %4$s"),
c->filename, c->lineno, toknames[expected], toknames[got] );
}
showtoken(c,got);
}
}
static void unexpected(Context *c,enum token_type got) {
if ( verbose>0 )
fflush(stdout);
if (c->interactive)
LogError( _("Error: Unexpected %s found"), toknames[got] );
else
LogError( _("%s: %d Unexpected %s found"),
c->filename, c->lineno, toknames[got] );
if ( !no_windowing_ui ) {
ff_post_error(NULL,"%1$s: %2$d Unexpected %3$",
c->filename, c->lineno, toknames[got] );
}
showtoken(c,got);
}
void ScriptError( Context *c, const char *msg ) {
char *t1 = script2utf8_copy(msg);
char *ufile = def2utf8_copy(c->filename);
/* All of fontforge's internal errors are in ASCII where there is */
/* no difference between latin1 and utf8. User errors are a different */
/* matter */
if ( verbose>0 )
fflush(stdout);
if ( c->interactive )
LogError( "Error: %s\n", t1 );
else if ( c->lineno!=0 )
LogError( _("%s line: %d %s\n"), ufile, c->lineno, t1 );
else
LogError( "%s: %s\n", ufile, t1 );
if ( !no_windowing_ui ) {
ff_post_error(NULL,"%s: %d %s",ufile, c->lineno, t1 );
}
free(ufile); free(t1);
traceback(c);
}
void ScriptErrorString( Context *c, const char *msg, const char *name) {
char *t1 = script2utf8_copy(msg);
char *t2 = script2utf8_copy(name);
char *ufile = def2utf8_copy(c->filename);
if ( verbose>0 )
fflush(stdout);
if ( c->interactive )
LogError( "Error: %s: %s\n", t1, t2 );
else if ( c->lineno!=0 )
LogError( _("%s line: %d %s: %s\n"), ufile, c->lineno, t1, t2 );
else
LogError( "%s: %s: %s\n", ufile, t1, t2 );
if ( !no_windowing_ui ) {
ff_post_error(NULL,"%s: %d %s: %s",ufile, c->lineno, t1, t2 );
}
free(ufile); free(t1); free(t2);
traceback(c);
}
void ScriptErrorF( Context *c, const char *format, ... ) {
char *ufile = def2utf8_copy(c->filename);
/* All string arguments here assumed to be utf8 */
char errbuf[400];
va_list ap;
va_start(ap,format);
vsnprintf(errbuf,sizeof(errbuf),format,ap);
va_end(ap);
if ( verbose>0 )
fflush(stdout);
if (c->interactive)
LogError( _("Error: %s\n"), errbuf );
else if ( c->lineno!=0 )
LogError( _("%s line: %d %s\n"), ufile, c->lineno, errbuf );
else
LogError( "%s: %s\n", ufile, errbuf );
if ( !no_windowing_ui ) {
ff_post_error(NULL,"%s: %d %s",ufile, c->lineno, errbuf );
}
free(ufile);
traceback(c);
}
static char *forcePSName_copy(Context *c,char *str) {
char *pt;
for ( pt=str; *pt; ++pt ) {
if ( *pt<=' ' || *pt>=0x7f ||
*pt=='(' || *pt==')' ||
*pt=='[' || *pt==']' ||
*pt=='{' || *pt=='}' ||
*pt=='<' || *pt=='>' ||
*pt=='%' || *pt=='/' )
ScriptErrorString(c,"Invalid character in PostScript name token (probably fontname): ", str );
}
return( copy( str ));
}
static char *forceASCIIcopy(Context *c,char *str) {
char *pt;
for ( pt=str; *pt; ++pt ) {
if ( *pt<' ' || *pt>=0x7f )
ScriptErrorString(c,"Invalid ASCII character in: ", str );
}
return( copy( str ));
}
static void dereflvalif(Val *val) {
if ( val->type == v_lval ) {
*val = *val->u.lval;
if ( val->type==v_str )
val->u.sval = copy(val->u.sval);
}
}
/* *************************** Built in Functions *************************** */
static void PrintVal(Val *val) {
int j;
if ( val->type==v_str ) {
char *t1 = script2utf8_copy(val->u.sval);
char *loc = utf82def_copy(t1);
printf( "%s", loc );
free(loc); free(t1);
} else if ( val->type==v_arr || val->type==v_arrfree ) {
putchar( '[' );
if ( val->u.aval->argc>0 ) {
PrintVal(&val->u.aval->vals[0]);
for ( j=1; j<val->u.aval->argc; ++j ) {
putchar(',');
if ( val->u.aval->vals[j-1].type==v_arr || val->u.aval->vals[j-1].type==v_arrfree )
putchar('\n');
PrintVal(&val->u.aval->vals[j]);
}
}
putchar( ']' );
} else if ( val->type==v_int )
printf( "%d", val->u.ival );
else if ( val->type==v_unicode )
printf( "0u%04X", val->u.ival );
else if ( val->type==v_real )
printf( "%g", (double) val->u.fval );
else if ( val->type==v_void )
printf( "<void>");
else
printf( "<" "???" ">");
}
static void bPrint(Context *c) {
int i;
for ( i=1; i<c->a.argc; ++i )
PrintVal(&c->a.vals[i] );
printf( "\n" );
fflush(stdout);
}
static void bError(Context *c) {
ScriptError( c, c->a.vals[1].u.sval );
c->error = ce_silent;
}
static void bPostNotice(Context *c) {
char *t1;
char *loc;
loc = c->a.vals[1].u.sval;
if ( !no_windowing_ui ) {
if ( !use_utf8_in_script ) {
unichar_t *t1 = uc_copy(loc);
loc = u2utf8_copy(t1);
free(t1);
}
ff_post_notice(_("Attention"), "%.200s", loc );
if ( loc != c->a.vals[1].u.sval )
free(loc);
} else
{
t1 = script2utf8_copy(loc);
loc = utf82def_copy(t1);
fprintf(stderr,"%s\n", loc );
free(loc); free(t1);
}
}
static void bAskUser(Context *c) {
char *quest;
const char *def="";
if ( c->a.argc!=2 && c->a.argc!=3 ) {
c->error = ce_wrongnumarg;
return;
} else if ( c->a.vals[1].type!=v_str || ( c->a.argc==3 && c->a.vals[2].type!=v_str) ) {
c->error = ce_expectstr;
return;
}
quest = c->a.vals[1].u.sval;
if ( c->a.argc==3 )
def = c->a.vals[2].u.sval;
if ( no_windowing_ui ) {
char buffer[300];
char *t1 = script2utf8_copy(quest);
char *loc = utf82def_copy(t1);
printf( "%s", loc );
free(t1); free(loc);
buffer[0] = '\0';
c->return_val.type = v_str;
if ( fgets(buffer,sizeof(buffer),stdin)==NULL ) {
clearerr(stdin);
c->return_val.u.sval = copy("");
} else if ( buffer[0]=='\0' || buffer[0]=='\n' || buffer[0]=='\r' )
c->return_val.u.sval = copy(def);
else {
t1 = def2utf8_copy(buffer);
c->return_val.u.sval = utf82script_copy(t1);
free(t1);
}
} else {
char *t1, *t2, *ret;
if ( use_utf8_in_script ) {
ret = ff_ask_string(quest,def,"%s", quest);
} else {
t1 = latin1_2_utf8_copy(quest);
ret = ff_ask_string(t1,t2=latin1_2_utf8_copy(def),"%s", t1);
free(t1); free(t2);
}
c->return_val.type = v_str;
c->return_val.u.sval = utf82script_copy(ret);
if ( ret==NULL )
c->return_val.u.sval = copy("");
else
free(ret);
}
}
static void bArray(Context *c) {
int i;
if ( c->a.vals[1].u.ival<=0 )
ScriptError( c, "Argument must be positive" );
c->return_val.type = v_arrfree;
c->return_val.u.aval = malloc(sizeof(Array));
c->return_val.u.aval->argc = c->a.vals[1].u.ival;
c->return_val.u.aval->vals = malloc(c->a.vals[1].u.ival*sizeof(Val));
for ( i=0; i<c->a.vals[1].u.ival; ++i )
c->return_val.u.aval->vals[i].type = v_void;
}
static void bSizeOf(Context *c) {
if ( c->a.vals[1].type!=v_arr && c->a.vals[1].type!=v_arrfree )
ScriptError( c, "Expected array argument" );
c->return_val.type = v_int;
c->return_val.u.ival = c->a.vals[1].u.aval->argc;
}
static void bTypeOf(Context *c) {
static const char *typenames[] = { "Integer", "Real", "String", "Unicode", "LValue",
"Array", "Array", "LValue", "LValue", "LValue", "Void" };
c->return_val.type = v_str;
c->return_val.u.sval = copy( typenames[c->a.vals[1].type] );
}
static void bStrlen(Context *c) {
c->return_val.type = v_int;
c->return_val.u.ival = strlen( c->a.vals[1].u.sval );
}
static void bStrstr(Context *c) {
char *pt;
c->return_val.type = v_int;
pt = strstr(c->a.vals[1].u.sval,c->a.vals[2].u.sval);
c->return_val.u.ival = pt==NULL ? -1 : pt-c->a.vals[1].u.sval;
}
static void bStrSplit(Context *c) {
char *pt, *pt2, *str1, *str2;
int max=-1, len2, cnt, k;
if ( c->a.argc!=3 && c->a.argc!=4 ) {
c->error = ce_wrongnumarg;
return;
} else if ( c->a.vals[1].type!=v_str || c->a.vals[2].type!=v_str ) {
c->error = ce_badargtype;
return;
} else if ( c->a.argc==4 ) {
if ( c->a.vals[3].type!=v_int ) {
c->error = ce_badargtype;
return;
}
max = c->a.vals[3].u.ival;
}
str1 = c->a.vals[1].u.sval;
str2 = c->a.vals[2].u.sval;
len2 = strlen( str2 );
for ( k=0; k<2; ++k ) {
cnt = 0;
pt = str1;
while ( (pt2 = strstr(pt,str2))!=NULL ) {
if ( k ) {
if ( max!=-1 && cnt>=max )
break;
c->return_val.u.aval->vals[cnt].type = v_str;
c->return_val.u.aval->vals[cnt].u.sval = copyn(pt,pt2-pt);
}
++cnt;
pt = pt2+len2;
}
if ( !k ) {
if ( *pt!='\0' )
++cnt;
if ( max!=-1 && cnt>max )
cnt = max;
c->return_val.type = v_arrfree;
c->return_val.u.aval = malloc(sizeof(Array));
c->return_val.u.aval->argc = cnt;
c->return_val.u.aval->vals = malloc(cnt*sizeof(Val));
} else {
if ((*pt!='\0') && ((max==-1) || (cnt<max))) {
c->return_val.u.aval->vals[cnt].type = v_str;
c->return_val.u.aval->vals[cnt].u.sval = copy(pt);
}
}
}
}
static void bStrJoin(Context *c) {
char *str2;
int len, len2, k, i;
Array *arr;
if ( (c->a.vals[1].type!=v_arr && c->a.vals[1].type!=v_arrfree) ||
c->a.vals[2].type!=v_str ) {
c->error = ce_badargtype;
return;
}
arr = c->a.vals[1].u.aval;
str2 = c->a.vals[2].u.sval;
len2 = strlen( str2 );
for ( k=0; k<2; ++k ) {
len = 0;
for ( i=0; i<arr->argc; ++i ) {
if ( arr->vals[i].type!=v_str )
ScriptError( c, "Bad type for array element" );
if ( k ) {
strcpy(c->return_val.u.sval+len,arr->vals[i].u.sval);
strcat(c->return_val.u.sval+len,str2);
}
len += strlen(arr->vals[i].u.sval) + len2;
}
if ( !k ) {
c->return_val.type = v_str;
c->return_val.u.sval = malloc(len+1);
}
}
}
static void bStrcasestr(Context *c) {
char *pt;
c->return_val.type = v_int;
pt = strstrmatch(c->a.vals[1].u.sval,c->a.vals[2].u.sval);
c->return_val.u.ival = pt==NULL ? -1 : pt-c->a.vals[1].u.sval;
}
static void bStrrstr(Context *c) {
char *pt;
char *haystack, *needle;
int nlen;
c->return_val.type = v_int;
haystack = c->a.vals[1].u.sval; needle = c->a.vals[2].u.sval;
nlen = strlen( needle );
for ( pt=haystack+strlen(haystack)-nlen; pt>=haystack; --pt )
if ( strncmp(pt,needle,nlen)==0 )
break;
c->return_val.u.ival = pt-haystack;
}
static void bStrsub(Context *c) {
int start, end;
char *str;
if ( c->a.argc!=3 && c->a.argc!=4 ) {
c->error = ce_wrongnumarg;
return;
} else if ( c->a.vals[1].type!=v_str || c->a.vals[2].type!=v_int || \
(c->a.argc==4 && c->a.vals[3].type!=v_int) ) {
c->error = ce_badargtype;
return;
}
str = c->a.vals[1].u.sval;
start = c->a.vals[2].u.ival;
end = c->a.argc==4? c->a.vals[3].u.ival : (int)strlen(str);
if ( start<0 || start>(int)strlen(str) || end<start || end>(int)strlen(str) )
ScriptError( c, "Arguments out of bounds" );
c->return_val.type = v_str;
c->return_val.u.sval = copyn(str+start,end-start);
}
static void bStrcasecmp(Context *c) {
c->return_val.type = v_int;
c->return_val.u.ival = strmatch(c->a.vals[1].u.sval,c->a.vals[2].u.sval);
}
static void bStrtol(Context *c) {
int base = 10;
if ( c->a.argc!=2 && c->a.argc!=3 ) {
c->error = ce_wrongnumarg;
return;
} else if ( c->a.vals[1].type!=v_str || (c->a.argc==3 && c->a.vals[2].type!=v_int) ) {
c->error = ce_badargtype;
return;
} else if ( c->a.argc==3 ) {
base = c->a.vals[2].u.ival;
if ( base<0 || base==1 || base>36 )
ScriptError( c, "Argument out of bounds" );
}
c->return_val.type = v_int;
c->return_val.u.ival = strtol(c->a.vals[1].u.sval,NULL,base);
}
static void bStrtod(Context *c) {
c->return_val.type = v_real;
c->return_val.u.fval = (float)strtod(c->a.vals[1].u.sval,NULL);
}
static void bStrskipint(Context *c) {
int base = 10;
char *end;
if ( c->a.argc!=2 && c->a.argc!=3 ) {
c->error = ce_wrongnumarg;
return;
} else if ( c->a.vals[1].type!=v_str || (c->a.argc==3 && c->a.vals[2].type!=v_int) ) {
c->error = ce_badargtype;
return;
} else if ( c->a.argc==3 ) {
base = c->a.vals[2].u.ival;
if ( base<0 || base==1 || base>36 )
ScriptError( c, "Argument out of bounds" );
}
c->return_val.type = v_int;
strtol(c->a.vals[1].u.sval,&end,base);
c->return_val.u.ival = end-c->a.vals[1].u.sval;
}
static void bStrftime(Context *c) {
int isgmt=1;
char *oldloc = NULL;
char buffer[300];
struct tm *tm;
time_t now;
if ( c->a.argc<2 || c->a.argc>4 ) {
c->error = ce_wrongnumarg;
return;
} else if ( c->a.vals[1].type!=v_str ||
(c->a.argc>=3 && c->a.vals[2].type!=v_int) ||
(c->a.argc>=4 && c->a.vals[3].type!=v_str) ) {
c->error = ce_badargtype;
return;
}
if ( c->a.argc>=3 )
isgmt = c->a.vals[2].u.ival;
if ( c->a.argc>=4 )
oldloc = setlocale(LC_TIME, c->a.vals[3].u.sval); // TODO
time(&now);
if ( isgmt )
tm = gmtime(&now);
else
tm = localtime(&now);
strftime(buffer,sizeof(buffer),c->a.vals[1].u.sval,tm);
if ( oldloc!=NULL )
(void) setlocale(LC_TIME, oldloc);
c->return_val.type = v_str;
c->return_val.u.sval = copy(buffer);
}
static void bisupper(Context *c) {
const char *pt;
long ch;
c->return_val.type = v_int;
if ( c->a.vals[1].type==v_str ) {
pt = c->a.vals[1].u.sval;
ch = utf8_ildb(&pt);
c->return_val.u.ival = ch>=0 && ch<0x10000?isupper(ch):0;
} else if ( c->a.vals[1].type==v_int || c->a.vals[1].type==v_unicode )
c->return_val.u.ival = isupper(c->a.vals[1].u.ival);
else
c->error = ce_badargtype;
}
static void bislower(Context *c) {
const char *pt;
long ch;
c->return_val.type = v_int;
if ( c->a.vals[1].type==v_str ) {
pt = c->a.vals[1].u.sval;
ch = utf8_ildb(&pt);
c->return_val.u.ival = ch>=0 && ch<0x10000?islower(ch):0;
} else if ( c->a.vals[1].type==v_int || c->a.vals[1].type==v_unicode )
c->return_val.u.ival = islower(c->a.vals[1].u.ival);
else
c->error = ce_badargtype;
}
static void bisdigit(Context *c) {
const char *pt;
long ch;
c->return_val.type = v_int;
if ( c->a.vals[1].type==v_str ) {
pt = c->a.vals[1].u.sval;
ch = utf8_ildb(&pt);
c->return_val.u.ival = ch>=0 && ch<0x10000?isdigit(ch):0;
} else if ( c->a.vals[1].type==v_int || c->a.vals[1].type==v_unicode )
c->return_val.u.ival = isdigit(c->a.vals[1].u.ival);
else
c->error = ce_badargtype;
}
static void bishexdigit(Context *c) {
const char *pt;
long ch;
c->return_val.type = v_int;
if ( c->a.vals[1].type==v_str ) {
pt = c->a.vals[1].u.sval;
ch = utf8_ildb(&pt);
c->return_val.u.ival = ch>=0 && ch<0x10000?ishexdigit(ch):0;
} else if ( c->a.vals[1].type==v_int || c->a.vals[1].type==v_unicode )
c->return_val.u.ival = ishexdigit(c->a.vals[1].u.ival);
else
c->error = ce_badargtype;
}
static void bisalpha(Context *c) {
const char *pt;
long ch;
c->return_val.type = v_int;
if ( c->a.vals[1].type==v_str ) {
pt = c->a.vals[1].u.sval;
ch = utf8_ildb(&pt);
c->return_val.u.ival = ch>=0 && ch<0x10000?isalpha(ch):0;
} else if ( c->a.vals[1].type==v_int || c->a.vals[1].type==v_unicode )
c->return_val.u.ival = isalpha(c->a.vals[1].u.ival);
else
c->error = ce_badargtype;
}
static void bisalnum(Context *c) {
const char *pt;
long ch;
c->return_val.type = v_int;
if ( c->a.vals[1].type==v_str ) {
pt = c->a.vals[1].u.sval;
ch = utf8_ildb(&pt);
c->return_val.u.ival = ch>=0 && ch<0x10000?isalnum(ch):0;
} else if ( c->a.vals[1].type==v_int || c->a.vals[1].type==v_unicode )
c->return_val.u.ival = isalnum(c->a.vals[1].u.ival);
else
c->error = ce_badargtype;
}
static void bisspace(Context *c) {
const char *pt;
long ch;
c->return_val.type = v_int;
if ( c->a.vals[1].type==v_str ) {
pt = c->a.vals[1].u.sval;
ch = utf8_ildb(&pt);
c->return_val.u.ival = ch>=0 && ch<0x10000?isspace(ch):0;
} else if ( c->a.vals[1].type==v_int || c->a.vals[1].type==v_unicode )
c->return_val.u.ival = isspace(c->a.vals[1].u.ival);
else
c->error = ce_badargtype;
}
static void btoupper(Context *c) {
char *pt; const char *ipt;
long ch;
if ( c->a.vals[1].type==v_str ) {
c->return_val.type = v_str;
c->return_val.u.sval = pt = copy(ipt = c->a.vals[1].u.sval);
while ( *ipt ) {
ch = utf8_ildb(&ipt);
if ( ch==-1 )
break;
if ( ch<0x10000 ) ch = toupper(ch);
pt = utf8_idpb(pt,ch,UTF8IDPB_NOZERO);
}
*pt = '\0';
} else if ( c->a.vals[1].type==v_int || c->a.vals[1].type==v_unicode ) {
c->return_val.type = v_int;
c->return_val.u.ival = c->a.vals[1].u.ival<0x10000?toupper(c->a.vals[1].u.ival): c->a.vals[1].u.ival;
} else
c->error = ce_badargtype;
}
static void btolower(Context *c) {
char *pt; const char *ipt;
long ch;
if ( c->a.vals[1].type==v_str ) {
c->return_val.type = v_str;
c->return_val.u.sval = pt = copy(ipt = c->a.vals[1].u.sval);
while ( *ipt ) {
ch = utf8_ildb(&ipt);
if ( ch==-1 )
break;
if ( ch<0x10000 ) ch = tolower(ch);
pt = utf8_idpb(pt,ch,UTF8IDPB_NOZERO);
}
*pt = '\0';
} else if ( c->a.vals[1].type==v_int || c->a.vals[1].type==v_unicode ) {
c->return_val.type = v_int;
c->return_val.u.ival = c->a.vals[1].u.ival<0x10000?tolower(c->a.vals[1].u.ival): c->a.vals[1].u.ival;
} else
c->error = ce_badargtype;
}
static void btomirror(Context *c) {
char *pt; const char *ipt;
long ch;
if ( c->a.vals[1].type==v_str ) {
c->return_val.type = v_str;
c->return_val.u.sval = pt = copy(ipt = c->a.vals[1].u.sval);
while ( *ipt ) {
ch = utf8_ildb(&ipt);
if ( ch==-1 )
break;
if ( ch<0x10000 ) ch = tomirror(ch);
pt = utf8_idpb(pt,ch,UTF8IDPB_NOZERO);
}
*pt = '\0';
} else if ( c->a.vals[1].type==v_int || c->a.vals[1].type==v_unicode ) {
c->return_val.type = v_int;
c->return_val.u.ival = c->a.vals[1].u.ival<0x10000?tomirror(c->a.vals[1].u.ival): c->a.vals[1].u.ival;
} else
c->error = ce_badargtype;
}
static void bLoadPrefs(Context *c) {
LoadPrefs();
}
static void bSavePrefs(Context *c) {
SavePrefs(false);
DumpPfaEditEncodings();
}
static void bGetPrefs(Context *c) {
if ( !GetPrefs(c->a.vals[1].u.sval,&c->return_val) )
ScriptErrorString( c, "Unknown Preference variable", c->a.vals[1].u.sval );
}
static void bSetPrefs(Context *c) {
int ret;
if ( c->a.argc!=3 && c->a.argc!=4 )
c->error = ce_wrongnumarg;
else if ( c->a.vals[1].type!=v_str && (c->a.argc==4 && c->a.vals[3].type!=v_int) )
c->error = ce_badargtype;
else if ( (ret=SetPrefs(c->a.vals[1].u.sval,&c->a.vals[2],c->a.argc==4?&c->a.vals[3]:NULL))==0 )
ScriptErrorString( c, "Unknown Preference variable", c->a.vals[1].u.sval );
else if ( ret==-1 )
ScriptErrorString( c, "Bad type for preference variable", c->a.vals[1].u.sval);
}
static void bDefaultOtherSubrs(Context *c) {
DefaultOtherSubrs();
}
static void bReadOtherSubrsFile(Context *c) {
if ( ReadOtherSubrsFile(c->a.vals[1].u.sval)<=0 )
ScriptErrorString( c,"Failed to read OtherSubrs from %s", c->a.vals[1].u.sval );
}
static void bGetEnv(Context *c) {
char *env;
if ( (env = getenv(c->a.vals[1].u.sval))==NULL )
ScriptErrorString( c, "Unknown Preference variable", c->a.vals[1].u.sval );
c->return_val.type = v_str;
c->return_val.u.sval = strdup(env);
}
static void bHasSpiro(Context *c) {
c->return_val.type=v_int;
c->return_val.u.ival=hasspiro();
}
static void bSpiroVersion(Context *c) {
/* Return libspiro Version number */
c->return_val.type = v_str;
c->return_val.u.sval = libspiro_version();
}
static void bUnicodeFromName(Context *c) {
c->return_val.type = v_int;
c->return_val.u.ival = UniFromName(c->a.vals[1].u.sval,ui_none,&custom);
}
static void bNameFromUnicode(Context *c) {
char buffer[400];
int uniinterp;
NameList *for_new_glyphs;
if ( c->a.argc!=2 && c->a.argc!=3 ) {
c->error = ce_wrongnumarg;
return;
} else if ( c->a.vals[1].type!=v_int && c->a.vals[1].type!=v_unicode ) {
c->error = ce_badargtype;
return;
} else if ( c->a.argc==3 && c->a.vals[2].type!=v_str ) {
c->error = ce_badargtype;
return;
}
if ( c->a.argc==3 ) {
uniinterp = ui_none;
for_new_glyphs = NameListByName(c->a.vals[2].u.sval);
if ( for_new_glyphs == NULL )
ScriptErrorString( c, "Could not find namelist", c->a.vals[2].u.sval);
} else if (c->curfv == NULL) {
uniinterp = ui_none;
for_new_glyphs = NameListByName("AGL with PUA");
} else {
uniinterp = c->curfv->sf->uni_interp;
for_new_glyphs = c->curfv->sf->for_new_glyphs;
}
c->return_val.type = v_str;
c->return_val.u.sval = copy(StdGlyphName(buffer,c->a.vals[1].u.ival,uniinterp,for_new_glyphs));
}
static void bUnicodeBlockCountFromLib(Context *c) {
/* If the library is available, then return the number of name blocks */
c->return_val.type=v_int;
c->return_val.u.ival=unicode_block_count();
}
static void bUnicodeBlockEndFromLib(Context *c) {
/* If the library is available, then get the official Nth block end */
if ( c->a.vals[1].type!=v_int && c->a.vals[1].type!=v_unicode ) {
c->error = ce_badargtype;
return;
}
c->return_val.type=v_int;
c->return_val.u.ival=unicode_block_end(c->a.vals[1].u.ival);
}
static void bUnicodeBlockNameFromLib(Context *c) {
/* If the library is available, then get the official Nth block name */
char *temp;
if ( c->a.vals[1].type!=v_int && c->a.vals[1].type!=v_unicode ) {
c->error = ce_badargtype;
return;
}
c->return_val.type = v_str;
if ( (temp=unicode_block_name(c->a.vals[1].u.ival))==NULL ) {
temp=malloc(1*sizeof(char)); *temp='\0';
}
c->return_val.u.sval=temp;
}
static void bUnicodeBlockStartFromLib(Context *c) {
/* If the library is available, then get the official Nth block start */
if ( c->a.vals[1].type!=v_int && c->a.vals[1].type!=v_unicode ) {
c->error = ce_badargtype;
return;
}
c->return_val.type=v_int;
c->return_val.u.ival=unicode_block_start(c->a.vals[1].u.ival);
}
static void bUnicodeNameFromLib(Context *c) {
/* If the library is available, then get the official name for this unicode value */
char *temp;
if ( c->a.vals[1].type!=v_int && c->a.vals[1].type!=v_unicode ) {
c->error = ce_badargtype;
return;
}
c->return_val.type = v_str;
if ( (temp=unicode_name(c->a.vals[1].u.ival))==NULL ) {
temp=malloc(1*sizeof(char)); *temp='\0';
}
c->return_val.u.sval = temp;
}
static void bUnicodeAnnotationFromLib(Context *c) {
char *temp;
if ( c->a.vals[1].type!=v_int && c->a.vals[1].type!=v_unicode ) {
c->error = ce_badargtype;
return;
}
c->return_val.type = v_str;
if ( (temp=unicode_annot(c->a.vals[1].u.ival))==NULL ) {
temp=malloc(1*sizeof(char)); *temp='\0';
}
c->return_val.u.sval = temp;
}
static void bUnicodeNamesListVersion(Context *c) {
/* If the library is available, then return the Nameslist Version */
char *temp;
if ( (temp=unicode_library_version())==NULL ) {
temp=malloc(1*sizeof(char)); *temp='\0';
}
c->return_val.type = v_str;
c->return_val.u.sval = temp;
}
static void bChr(Context *c) {
char buf[2];
char *temp;
int i;
if ( c->a.argc!=2 )
ScriptError( c, "Wrong number of arguments" );
else if ( c->a.vals[1].type==v_int ) {
if ( c->a.vals[1].u.ival<-128 || c->a.vals[1].u.ival>255 )
ScriptError( c, "Bad value for argument" );
buf[0] = c->a.vals[1].u.ival; buf[1] = 0;
c->return_val.type = v_str;
c->return_val.u.sval = copy(buf);
} else if ( c->a.vals[1].type==v_arr || c->a.vals[1].type==v_arrfree ) {
Array *arr = c->a.vals[1].u.aval;
temp = malloc((arr->argc+1)*sizeof(char));
for ( i=0; i<arr->argc; ++i ) {
if ( arr->vals[i].type!=v_int )
ScriptError( c, "Bad type for argument" );
else if ( arr->vals[i].u.ival<-128 || arr->vals[i].u.ival>255 )
ScriptError( c, "Bad value for argument" );
temp[i] = arr->vals[i].u.ival;
}
temp[i] = 0;
c->return_val.type = v_str;
c->return_val.u.sval = temp;
} else
ScriptError( c, "Bad type for argument" );
}
static void bUtf8(Context *c) {
uint32 buf[2];
int i;
uint32 *temp;
if ( c->a.vals[1].type==v_int ) {
if ( c->a.vals[1].u.ival<0 || c->a.vals[1].u.ival>0x10ffff ) {
c->error = ce_badargtype;
return;
}
buf[0] = c->a.vals[1].u.ival; buf[1] = 0;
c->return_val.type = v_str;
c->return_val.u.sval = u2utf8_copy(buf);
} else if ( c->a.vals[1].type==v_arr || c->a.vals[1].type==v_arrfree ) {
Array *arr = c->a.vals[1].u.aval;
temp = malloc((arr->argc+1)*sizeof(int32));
for ( i=0; i<arr->argc; ++i ) {
if ( arr->vals[i].type!=v_int ) {
c->error = ce_badargtype;
free(temp);
return;
} else if ( arr->vals[i].u.ival<0 || arr->vals[i].u.ival>0x10ffff ){
c->error = ce_badargtype;
return;
}
temp[i] = arr->vals[i].u.ival;
}
temp[i] = 0;
c->return_val.type = v_str;
c->return_val.u.sval = u2utf8_copy(temp);
free(temp);
} else
c->error = ce_badargtype;
}
static void bUCS4(Context *c) {
if ( c->a.vals[1].type==v_str ) {
/* TODO: see if more than v_str method, or simplify this in builtins */
const char *pt = c->a.vals[1].u.sval;
int i, len = g_utf8_strlen( pt, -1 );
c->return_val.type = v_arrfree;
c->return_val.u.aval = malloc(sizeof(Array));
c->return_val.u.aval->argc = len;
c->return_val.u.aval->vals = malloc(len*sizeof(Val));
for ( i=0; i<len; ++i ) {
c->return_val.u.aval->vals[i].type = v_int;
c->return_val.u.aval->vals[i].u.ival = utf8_ildb(&pt);
}
} else
c->error = ce_badargtype;
}
static void bOrd(Context *c) {
if ( c->a.argc!=2 && c->a.argc!=3 ) {
c->error = ce_wrongnumarg;
return;
} else if ( c->a.vals[1].type!=v_str || (c->a.argc==3 && c->a.vals[2].type!=v_int) ) {
c->error = ce_badargtype;
return;
}
if ( c->a.argc==3 ) {
if ( c->a.vals[2].u.ival<0 || c->a.vals[2].u.ival>(int)strlen( c->a.vals[1].u.sval) ) {
c->error = ce_badargtype;
return;
}
c->return_val.type = v_int;
c->return_val.u.ival = (uint8) c->a.vals[1].u.sval[c->a.vals[2].u.ival];
} else {
int i, len = strlen(c->a.vals[1].u.sval);
c->return_val.type = v_arrfree;
c->return_val.u.aval = malloc(sizeof(Array));
c->return_val.u.aval->argc = len;
c->return_val.u.aval->vals = malloc(len*sizeof(Val));
for ( i=0; i<len; ++i ) {
c->return_val.u.aval->vals[i].type = v_int;
c->return_val.u.aval->vals[i].u.ival = (uint8) c->a.vals[1].u.sval[i];
}
}
}
static void bReal(Context *c) {
if ( c->a.vals[1].type!=v_int && c->a.vals[1].type!=v_unicode ) {
c->error = ce_badargtype;
return;
}
c->return_val.type = v_real;
c->return_val.u.fval = (float) c->a.vals[1].u.ival;
}
static void bUCodePoint(Context *c) {
if ( c->a.vals[1].type==v_real )
c->return_val.u.ival = c->a.vals[1].u.fval;
else if ( c->a.vals[1].type==v_unicode || c->a.vals[1].type==v_int )
c->return_val.u.ival = c->a.vals[1].u.ival;
else {
c->error = ce_badargtype;
return;
}
c->return_val.type = v_unicode;
}
static void bInt(Context *c) {
if ( c->a.vals[1].type==v_real )
c->return_val.u.ival = c->a.vals[1].u.fval;
else if ( c->a.vals[1].type==v_unicode || c->a.vals[1].type==v_int )
c->return_val.u.ival = c->a.vals[1].u.ival;
else {
c->error = ce_badargtype;
return;
}
c->return_val.type = v_int;
}
static void bFloor(Context *c) {
c->return_val.type = v_int;
c->return_val.u.ival = floor( c->a.vals[1].u.fval );
}
static void bCeil(Context *c) {
c->return_val.type = v_int;
c->return_val.u.ival = ceil( c->a.vals[1].u.fval );
}
static void bRound(Context *c) {
c->return_val.type = v_int;
c->return_val.u.ival = rint( c->a.vals[1].u.fval );
}
static void bIsNan(Context *c) {
c->return_val.type = v_int;
c->return_val.u.ival = isnan( c->a.vals[1].u.fval );
}
static void bIsFinite(Context *c) {
c->return_val.type = v_int;
c->return_val.u.ival = finite( c->a.vals[1].u.fval );
}
static char *ToString(Val *val) {
int j;
char buffer[40];
if ( val->type==v_str ) {
return( copy(val->u.sval) );
} else if ( val->type==v_arr || val->type==v_arrfree ) {
char **results, *ret, *pt;
int len;
results = malloc(val->u.aval->argc*sizeof(char *));
len = 0;
for ( j=0; j<val->u.aval->argc; ++j ) {
results[j] = ToString(&val->u.aval->vals[j]);
len += strlen(results[j])+2;
}
ret = pt = malloc(len+20);
*pt++ = '[';
if ( val->u.aval->argc>0 ) {
strcpy(pt,results[0]); pt += strlen(pt);
free(results[0]);
for ( j=1; j<val->u.aval->argc; ++j ) {
*pt++ = ',';
if ( val->u.aval->vals[j-1].type==v_arr || val->u.aval->vals[j-1].type==v_arrfree )
*pt++ = '\n';
strcpy(pt,results[j]); pt += strlen(pt);
free(results[j]);
}
}
*pt++ = ']'; *pt = '\0';
free(results);
return( ret );
} else if ( val->type==v_int )
sprintf( buffer, "%d", val->u.ival );
else if ( val->type==v_unicode )
sprintf( buffer, "0u%04X", val->u.ival );
else if ( val->type==v_real )
sprintf( buffer, "%g", (double) val->u.fval );
else if ( val->type==v_void )
sprintf( buffer, "<void>");
else
sprintf( buffer, "<" "???" ">");
return( copy( buffer ));
}
static void bToString(Context *c) {
c->return_val.type = v_str;
c->return_val.u.sval = ToString( &c->a.vals[1] );
}
static void bSqrt(Context *c) {
double val;
if ( c->a.vals[1].type==v_real )
val = c->a.vals[1].u.fval;
else if ( c->a.vals[1].type==v_int )
val = c->a.vals[1].u.ival;
else {
c->error = ce_badargtype;
return;
}
c->return_val.type = v_real;
c->return_val.u.fval = sqrt( val );
}
static void bExp(Context *c) {
double val;
if ( c->a.vals[1].type==v_real )
val = c->a.vals[1].u.fval;
else if ( c->a.vals[1].type==v_int )
val = c->a.vals[1].u.ival;
else {
c->error = ce_badargtype;
return;
}
c->return_val.type = v_real;
c->return_val.u.fval = exp( val );
}
static void bLog(Context *c) {
double val;
if ( c->a.vals[1].type==v_real )
val = c->a.vals[1].u.fval;
else if ( c->a.vals[1].type==v_int )
val = c->a.vals[1].u.ival;
else {
c->error = ce_badargtype;
return;
}
c->return_val.type = v_real;
c->return_val.u.fval = log( val );
}
static void bPow(Context *c) {
double val1, val2;
if ( c->a.vals[1].type==v_real )
val1 = c->a.vals[1].u.fval;
else if ( c->a.vals[1].type==v_int )
val1 = c->a.vals[1].u.ival;
else {
c->error = ce_badargtype;
return;
}
if ( c->a.vals[2].type==v_real )
val2 = c->a.vals[2].u.fval;
else if ( c->a.vals[2].type==v_int )
val2 = c->a.vals[2].u.ival;
else {
c->error = ce_badargtype;
return;
}
c->return_val.type = v_real;
c->return_val.u.fval = pow( val1, val2 );
}
static void bSin(Context *c) {
double val;
if ( c->a.vals[1].type==v_real )
val = c->a.vals[1].u.fval;
else if ( c->a.vals[1].type==v_int )
val = c->a.vals[1].u.ival;
else {
c->error = ce_badargtype;
return;
}
c->return_val.type = v_real;
c->return_val.u.fval = sin( val );
}
static void bCos(Context *c) {
double val;
if ( c->a.vals[1].type==v_real )
val = c->a.vals[1].u.fval;
else if ( c->a.vals[1].type==v_int )
val = c->a.vals[1].u.ival;
else {
c->error = ce_badargtype;
return;
}
c->return_val.type = v_real;
c->return_val.u.fval = cos( val );
}
static void bTan(Context *c) {
double val;
if ( c->a.vals[1].type==v_real )
val = c->a.vals[1].u.fval;
else if ( c->a.vals[1].type==v_int )
val = c->a.vals[1].u.ival;
else {
c->error = ce_badargtype;
return;
}
c->return_val.type = v_real;
c->return_val.u.fval = tan( val );
}
static void bATan2(Context *c) {
double val1, val2;
if ( c->a.vals[1].type==v_real )
val1 = c->a.vals[1].u.fval;
else if ( c->a.vals[1].type==v_int )
val1 = c->a.vals[1].u.ival;
else {
c->error = ce_badargtype;
return;
}
if ( c->a.vals[2].type==v_real )
val2 = c->a.vals[2].u.fval;
else if ( c->a.vals[2].type==v_int )
val2 = c->a.vals[2].u.ival;
else {
c->error = ce_badargtype;
return;
}
c->return_val.type = v_real;
c->return_val.u.fval = atan2( val1, val2 );
}
static void bRand(Context *c) {
c->return_val.type = v_int;
c->return_val.u.ival = rand();
}
static void bFileAccess(Context *c) {
if ( c->a.argc!=3 && c->a.argc!=2 ) {
c->error = ce_wrongnumarg;
return;
} else if ( c->a.vals[1].type!=v_str || (c->a.argc==3 && c->a.vals[2].type!=v_int) ) {
c->error = ce_badargtype;
return;
}
c->return_val.type = v_int;
c->return_val.u.ival = access(c->a.vals[1].u.sval,c->a.argc==3 ? c->a.vals[2].u.ival : R_OK );
}
static void bLoadFileToString(Context *c) {
FILE *f;
int len;
char *name, *_name;
c->return_val.type = v_str;
_name = script2utf8_copy(c->a.vals[1].u.sval);
name = utf82def_copy(_name); free(_name);
f = fopen(name,"rb");
free(name);
if ( f==NULL )
c->return_val.u.sval = copy("");
else {
fseek(f,0,SEEK_END);
len = ftell(f);
rewind(f);
c->return_val.u.sval = malloc(len+1);
len = fread(c->return_val.u.sval,1,len,f);
c->return_val.u.sval[len]='\0';
fclose(f);
}
}
static void bWriteStringToFile(Context *c) {
FILE *f;
int append = 0;
char *name, *_name;
if ( c->a.argc!=3 && c->a.argc!=4 ) {
c->error = ce_wrongnumarg;
return;
} else if ( c->a.vals[1].type!=v_str && c->a.vals[2].type!=v_str ) {
c->error = ce_badargtype;
return;
} else if ( c->a.argc==4 ) {
if ( c->a.vals[3].type!=v_int ) {
c->error = ce_badargtype;
return;
}
append = c->a.vals[3].u.ival;
}
_name = script2utf8_copy(c->a.vals[2].u.sval);
name = utf82def_copy(_name); free(_name);
f = fopen(name,append?"ab":"wb");
free(name);
c->return_val.type = v_int;
if ( f==NULL )
c->return_val.u.ival = -1;
else {
c->return_val.u.ival = fwrite(c->a.vals[1].u.sval,1,strlen(c->a.vals[1].u.sval),f);
fclose(f);
}
}
static void bLoadPlugin(Context *c) {
char *name, *_name;
_name = script2utf8_copy(c->a.vals[1].u.sval);
name = utf82def_copy(_name); free(_name);
LoadPlugin(name);
free(name);
}
static void bLoadPluginDir(Context *c) {
char *dir=NULL, *_dir;
if ( c->a.argc>2 ) {
c->error = ce_wrongnumarg;
return;
} else if ( c->a.argc==2 ) {
if ( c->a.vals[1].type!=v_str ) {
c->error = ce_badargtype;
return;
}
_dir = script2utf8_copy(c->a.vals[1].u.sval);
dir = utf82def_copy(_dir); free(_dir);
}
LoadPluginDir(dir);
free(dir);
}
static void bLoadNamelist(Context *c) {
char *name, *_name;
_name = script2utf8_copy(c->a.vals[1].u.sval);
name = utf82def_copy(_name); free(_name);
LoadNamelist(name);
free(name);
}
static void bLoadNamelistDir(Context *c) {
char *dir=NULL, *_dir;
if ( c->a.argc>2 ) {
c->error = ce_wrongnumarg;
return;
} else if ( c->a.argc==2 ) {
if ( c->a.vals[1].type!=v_str ) {
c->error = ce_expectstr;
return;
}
_dir = script2utf8_copy(c->a.vals[1].u.sval);
dir = utf82def_copy(_dir); free(_dir);
}
LoadNamelistDir(dir);
free(dir);
}
/* **** File menu **** */
static void bQuit(Context *c) {
c->error = ce_quit;
if ( verbose>0 ) putchar('\n');
if ( c->a.argc>2 ) {
c->error = ce_wrongnumarg;
return;
}
if ( c->a.argc==2 ) {
if ( c->a.vals[1].type!=v_int ) {
c->error = ce_expectint;
return;
} else
c->return_val.u.ival=c->a.vals[1].u.ival;
} else
c->return_val.u.ival=0;
c->return_val.type=v_int;
}
#endif /* _NO_FFSCRIPT */
char **GetFontNames(char *filename, int do_slow) {
FILE *foo;
char **ret = NULL;
if ( GFileIsDir(filename)) {
char *temp = malloc(strlen(filename)+strlen("/glyphs/contents.plist")+1);
strcpy(temp,filename);
strcat(temp,"/glyphs/contents.plist");
if ( GFileExists(temp))
ret = NamesReadUFO(filename);
else {
strcpy(temp,filename);
strcat(temp,"/font.props");
if ( GFileExists(temp))
ret = NamesReadSFD(temp);
/* The fonts.prop file will look just like an sfd file as far */
/* as fontnames are concerned, we don't need a separate routine*/
}
free(temp);
} else {
foo = fopen(filename,"rb");
if ( foo!=NULL ) {
/* Try to guess the file type from the first few characters... */
int ch1 = getc(foo);
int ch2 = getc(foo);
int ch3 = getc(foo);
int ch4 = getc(foo);
fseek(foo, 98, SEEK_SET);
/* ch5 */ (void)getc(foo);
/* ch6 */ (void)getc(foo);
fclose(foo);
if (( ch1==0 && ch2==1 && ch3==0 && ch4==0 ) ||
(ch1=='O' && ch2=='T' && ch3=='T' && ch4=='O') ||
(ch1=='t' && ch2=='r' && ch3=='u' && ch4=='e') ||
(ch1=='t' && ch2=='t' && ch3=='c' && ch4=='f') ) {
ret = NamesReadTTF(filename);
} else if (( ch1=='%' && ch2=='!' ) ||
( ch1==0x80 && ch2=='\01' ) ) { /* PFB header */
ret = NamesReadPostScript(filename);
} else if ( ch1=='%' && ch2=='P' && ch3=='D' && ch4=='F' && do_slow ) {
// We are disabling scanning for P. D. F. until we can address the performance issues.
ret = NamesReadPDF(filename);
} else if ( ch1=='<' && ch2=='?' && (ch3=='x'||ch3=='X') && (ch4=='m'||ch4=='M') ) {
ret = NamesReadSVG(filename);
} else if ( ch1=='S' && ch2=='p' && ch3=='l' && ch4=='i' ) {
ret = NamesReadSFD(filename);
} else if ( ch1==1 && ch2==0 && ch3==4 ) {
ret = NamesReadCFF(filename);
} else /* Too hard to figure out a valid mark for a mac resource file */
ret = NamesReadMacBinary(filename);
}
}
return( ret );
}
#ifndef _NO_FFSCRIPT
static void bFontsInFile(Context *c) {
char **ret;
int cnt;
char *t;
char *locfilename;
t = script2utf8_copy(c->a.vals[1].u.sval);
locfilename = utf82def_copy(t);
ret = GetFontNames(locfilename, 1);
free(t); free(locfilename);
cnt = 0;
if ( ret!=NULL ) for ( cnt=0; ret[cnt]!=NULL; ++cnt );
c->return_val.type = v_arrfree;
c->return_val.u.aval = malloc(sizeof(Array));
c->return_val.u.aval->argc = cnt;
c->return_val.u.aval->vals = malloc((cnt==0?1:cnt)*sizeof(Val));
if ( ret!=NULL ) for ( cnt=0; ret[cnt]!=NULL; ++cnt ) {
c->return_val.u.aval->vals[cnt].type = v_str;
c->return_val.u.aval->vals[cnt].u.sval = ret[cnt];
}
free(ret);
}
static void bOpen(Context *c) {
SplineFont *sf;
int openflags=0;
char *t;
char *locfilename;
if ( c->a.argc!=2 && c->a.argc!=3 ) {
c->error = ce_wrongnumarg;
return;
} else if ( c->a.vals[1].type!=v_str )
ScriptError( c, "Open expects a filename" );
else if ( c->a.argc==3 ) {
if ( c->a.vals[2].type!=v_int )
ScriptError( c, "Open expects an integer for second argument" );
openflags = c->a.vals[2].u.ival;
}
t = script2utf8_copy(c->a.vals[1].u.sval);
locfilename = utf82def_copy(t);
sf = LoadSplineFont(locfilename,openflags);
free(t); free(locfilename);
if ( sf==NULL )
ScriptErrorString(c, "Failed to open", c->a.vals[1].u.sval);
else {
if ( sf->fv!=NULL )
/* All done */;
else if ( !no_windowing_ui )
FontViewCreate(sf,openflags&of_hidewindow);
else
FVAppend(_FontViewCreate(sf));
c->curfv = sf->fv;
}
}
static void bSelectBitmap(Context *c) {
BDFFont *bdf;
int depth, size;
size = c->a.vals[2].u.ival;
if ( size==-1 )
c->curfv->active_bitmap = NULL;
else {
depth = size>>16;
if ( depth==0 ) depth = 1;
size = size&0xffff;
for ( bdf = c->curfv->sf->bitmaps; bdf!=NULL; bdf=bdf->next )
if ( size==bdf->pixelsize && depth==BDFDepth(bdf))
break;
ScriptError(c,"No matching bitmap");
c->curfv->active_bitmap = bdf;
}
}
static void bNew(Context *c) {
if ( !no_windowing_ui )
c->curfv = FontViewCreate(SplineFontNew(),false);
else
c->curfv = FVAppend(_FontViewCreate(SplineFontNew()));
}
static void bClose(Context *c) {
FontViewClose(c->curfv);
c->curfv = NULL;
}
static void bRevert(Context *c) {
FVRevert(c->curfv);
}
static void bRevertToBackup(Context *c) {
FVRevertBackup(c->curfv);
}
static void bSave(Context *c) {
SplineFont *sf = c->curfv->sf;
char *t, *pt;
char *locfilename;
int s2d = false;
int localRevisionsToRetain = -1;
if ( c->a.argc>3 ) {
c->error = ce_wrongnumarg;
return;
}
// Grab the optional number of backups that are desired argument
if ( c->a.argc==3 ) {
/**
* A call Save( wheretosave, revisioncount )
*/
if ( c->a.vals[2].type!=v_int )
ScriptError(c,"The second argument to Save() must be a number of revisions to keep (integer)");
localRevisionsToRetain = c->a.vals[2].u.ival;
}
if ( c->a.argc>=2 )
{
if ( c->a.vals[1].type!=v_str )
ScriptError(c,"If an argument is given to Save it must be a filename");
t = script2utf8_copy(c->a.vals[1].u.sval);
locfilename = utf82def_copy(t);
pt = strrchr(locfilename,'.');
if ( pt!=NULL && strmatch(pt,".sfdir")==0 )
s2d = true;
int rc = SFDWriteBakExtended( locfilename,
sf,c->curfv->map,c->curfv->normal,s2d,
localRevisionsToRetain );
if ( !rc )
ScriptError(c,"Save failed" );
/* Hmmm. We don't set the filename, nor the save_to_dir bit */
free(t); free(locfilename);
}
else
{
if ( sf->filename==NULL )
ScriptError(c,"This font has no associated sfd file yet, you must specify a filename" );
/**
* If there are no existing backup files, don't start creating them here.
* Otherwise, save as many as the user wants.
*/
int s2d = false;
int rc = SFDWriteBakExtended( sf->filename,
sf,c->curfv->map,c->curfv->normal,s2d,
localRevisionsToRetain );
if ( !rc )
ScriptError(c,"Save failed" );
}
}
static void bGenerate(Context *c) {
SplineFont *sf = c->curfv->sf;
const char *bitmaptype = "";
int fmflags = -1;
int res = -1;
char *subfontdirectory = NULL;
char *t;
char *locfilename;
NameList *rename_to = NULL;
if ( c->a.argc<2 || c->a.argc>7 ) {
c->error = ce_wrongnumarg;
return;
} else if ( c->a.vals[1].type!=v_str ||
(c->a.argc>=3 && c->a.vals[2].type!=v_str ) ||
(c->a.argc>=4 && c->a.vals[3].type!=v_int ) ||
(c->a.argc>=5 && c->a.vals[4].type!=v_int ) ||
(c->a.argc>=6 && c->a.vals[5].type!=v_str ) ||
(c->a.argc>=7 && c->a.vals[5].type!=v_str ) ) {
c->error = ce_badargtype;
return;
}
if ( c->a.argc>=3 )
bitmaptype = c->a.vals[2].u.sval;
if ( c->a.argc>=4 )
fmflags = c->a.vals[3].u.ival;
if ( c->a.argc>=5 )
res = c->a.vals[4].u.ival;
if ( c->a.argc>=6 )
subfontdirectory = c->a.vals[5].u.sval;
if ( c->a.argc>=7 ) {
rename_to = NameListByName(c->a.vals[6].u.sval);
if ( rename_to==NULL )
ScriptErrorString( c, "Could not find namelist: ", c->a.vals[6].u.sval);
}
t = script2utf8_copy(c->a.vals[1].u.sval);
locfilename = utf82def_copy(t);
if ( !GenerateScript(sf,locfilename,bitmaptype,fmflags,res,subfontdirectory,
NULL,c->curfv->normal==NULL?c->curfv->map:c->curfv->normal,rename_to,
ly_fore) )
ScriptError(c,"Save failed");
free(t); free(locfilename);
}
static int strtailcmp(char *needle, char *haystack) {
int nlen = strlen(needle), hlen = strlen(haystack);
if ( nlen>hlen )
return( -1 );
if ( *needle=='/' )
return( strcmp(needle,haystack));
return( strcmp(needle,haystack+hlen-nlen));
}
typedef SplineFont *SFArray[48];
static void bGenerateFamily(Context *c) {
SplineFont *sf = NULL;
const char *bitmaptype = "";
int fmflags = -1;
struct sflist *sfs, *cur, *lastsfs;
Array *fonts;
FontViewBase *fv;
int i, j, fc, added;
uint16 psstyle;
int fondcnt = 0, fondmax = 10;
SFArray *familysfs=NULL;
char *t;
char *locfilename;
familysfs = malloc((fondmax=10)*sizeof(SFArray));
if ( c->a.vals[1].type!=v_str || c->a.vals[2].type!=v_str ||
c->a.vals[3].type!=v_int ||
c->a.vals[4].type!=v_arr ) {
c->error = ce_badargtype;
return;
}
bitmaptype = c->a.vals[2].u.sval;
fmflags = c->a.vals[3].u.ival;
fonts = c->a.vals[4].u.aval;
for ( i=0; i<fonts->argc; ++i ) {
if ( fonts->vals[i].type!=v_str )
ScriptError(c,"Values in the fontname array must be strings");
for ( fv=FontViewFirst(); fv!=NULL; fv=fv->next ) if ( fv->sf!=sf )
if ( strtailcmp(fonts->vals[i].u.sval,fv->sf->origname)==0 ||
(fv->sf->filename!=NULL && strtailcmp(fonts->vals[i].u.sval,fv->sf->origname)==0 ))
break;
if ( fv==NULL )
for ( fv=FontViewFirst(); fv!=NULL; fv=fv->next ) if ( fv->sf!=sf )
if ( strcmp(fonts->vals[i].u.sval,fv->sf->fontname)==0 )
break;
if ( fv==NULL ) {
LogError( "%s\n", fonts->vals[i].u.sval );
ScriptError( c, "The above font is not loaded" );
}
if ( sf==NULL )
sf = fv->sf;
if ( strcmp(fv->sf->familyname,sf->familyname)!=0 )
LogError( _("Warning: %s has a different family name than does %s (GenerateFamily)\n"),
fv->sf->fontname, sf->fontname );
MacStyleCode(fv->sf,&psstyle);
if ( psstyle>=48 ) {
LogError( "%s(%s)\n", fv->sf->origname, fv->sf->fontname );
ScriptError( c, "A font can't be both Condensed and Expanded" );
}
added = false;
if ( fv->sf->fondname==NULL ) {
if ( fondcnt>0 ) {
for ( j=0; j<48; ++j )
if ( familysfs[0][j]!=NULL )
break;
if ( familysfs[0][j]->fondname==NULL ) {
if ( familysfs[0][psstyle]==NULL || familysfs[0][psstyle]==fv->sf ) {
familysfs[0][psstyle] = fv->sf;
fv->sf->map = fv->map;
added = true;
}
}
}
} else {
for ( fc=0; fc<fondcnt; ++fc ) {
for ( j=0; j<48; ++j )
if ( familysfs[fc][j]!=NULL )
break;
if ( familysfs[fc][j]->fondname!=NULL &&
strcmp(familysfs[fc][j]->fondname,fv->sf->fondname)==0 ) {
if ( familysfs[fc][psstyle]==NULL || familysfs[fc][psstyle]==fv->sf ) {
familysfs[fc][psstyle] = fv->sf;
added = true;
} else {
LogError( _("%s(%s) and %s(%s) 0x%x in FOND %s\n"),
familysfs[fc][psstyle]->origname, familysfs[fc][psstyle]->fontname,
fv->sf->origname, fv->sf->fontname,
psstyle, fv->sf->fondname );
ScriptError( c, "Two array entries given with the same style (in the Mac's postscript style set)" );
}
}
}
}
if ( !added ) {
if ( fondcnt>=fondmax )
familysfs = realloc(familysfs,(fondmax+=10)*sizeof(SFArray));
memset(familysfs[fondcnt],0,sizeof(SFArray));
familysfs[fondcnt++][psstyle] = fv->sf;
}
}
if ( familysfs[0][0]==NULL ) {
if ( MacStyleCode(c->curfv->sf,NULL)==0 && strcmp(c->curfv->sf->familyname,sf->familyname)!=0 )
familysfs[0][0] = c->curfv->sf;
if ( familysfs[0][0]==NULL )
ScriptError(c,"At least one of the specified fonts must have a plain style");
}
sfs = lastsfs = NULL;
for ( fc=0; fc<fondcnt; ++fc ) {
for ( j=0; j<48; ++j ) if ( familysfs[fc][j]!=NULL ) {
cur = chunkalloc(sizeof(struct sflist));
if ( sfs==NULL ) sfs = cur;
else lastsfs->next = cur;
lastsfs = cur;
cur->sf = familysfs[fc][j];
cur->map = cur->sf->map;
}
}
free(familysfs);
t = script2utf8_copy(c->a.vals[1].u.sval);
locfilename = utf82def_copy(t);
if ( !GenerateScript(sf,locfilename,bitmaptype,fmflags,-1,NULL,sfs,
c->curfv->normal==NULL?c->curfv->map:c->curfv->normal,NULL,
ly_fore) )
ScriptError(c,"Save failed");
free(t); free(locfilename);
for ( cur=sfs; cur!=NULL; cur=sfs ) {
sfs = cur->next;
/* free(cur->sizes); */ /* Done inside GenerateScript */
chunkfree(cur,sizeof(struct sflist));
}
}
static void bGenerateFeatureFile(Context *c) {
SplineFont *sf = c->curfv->sf;
char *t;
char *locfilename;
OTLookup *otl = NULL;
FILE *out;
int err;
if ( c->a.argc!=2 && c->a.argc!=3 ) {
c->error = ce_wrongnumarg;
return;
}
if ( c->a.vals[1].type!=v_str || (c->a.argc==3 && c->a.vals[2].type!=v_str) ) {
c->error = ce_badargtype;
return;
}
if ( c->a.argc==3 ) {
otl = SFFindLookup(sf,c->a.vals[2].u.sval);
if ( otl==NULL )
ScriptError(c,"Unknown lookup");
}
t = script2utf8_copy(c->a.vals[1].u.sval);
locfilename = utf82def_copy(t);
out = fopen(locfilename,"w");
if ( out==NULL )
ScriptError(c,"Failed to open output file");
if ( otl!=NULL )
FeatDumpOneLookup(out,sf,otl);
else
FeatDumpFontLookups(out,sf);
err = ferror(out);
if ( fclose(out)!=0 || err )
ScriptError(c,"IO Error");
free(t); free(locfilename);
}
static void bControlAfmLigatureOutput(Context *c) {
ScriptError(c,"This scripting function no longer works.");
}
static void Bitmapper(Context *c,int isavail) {
int32 *sizes;
int i;
int rasterize = true;
if ( c->a.argc!=2 && (!isavail || c->a.argc!=3)) {
c->error = ce_wrongnumarg;
return;
}
if ( c->a.vals[1].type!=v_arr ) {
c->error = ce_badargtype;
return;
}
for ( i=0; i<c->a.vals[1].u.aval->argc; ++i )
if ( c->a.vals[1].u.aval->vals[i].type!=v_int ||
c->a.vals[1].u.aval->vals[i].u.ival<=2 )
ScriptError( c, "Bad type of array component");
if ( c->a.argc==3 ) {
if ( c->a.vals[2].type!=v_int ) {
c->error = ce_badargtype;
return;
}
rasterize = c->a.vals[2].u.ival;
}
sizes = malloc((c->a.vals[1].u.aval->argc+1)*sizeof(int32));
for ( i=0; i<c->a.vals[1].u.aval->argc; ++i ) {
sizes[i] = c->a.vals[1].u.aval->vals[i].u.ival;
if ( (sizes[i]>>16)==0 )
sizes[i] |= 0x10000;
}
sizes[i] = 0;
if ( !BitmapControl(c->curfv,sizes,isavail,rasterize) )
ScriptError(c,"Bitmap operation failed"); /* Storage leak here longjmp avoids free */
free(sizes);
}
static void bBitmapsAvail(Context *c) {
int shows_bitmap = false;
BDFFont *bdf;
if ( c->curfv->active_bitmap!=NULL ) {
for ( bdf=c->curfv->sf->bitmaps; bdf!=NULL; bdf = bdf->next )
if ( bdf==c->curfv->active_bitmap )
break;
shows_bitmap = bdf!=NULL;
}
Bitmapper(c,true);
if ( shows_bitmap && c->curfv->active_bitmap!=NULL ) {
BDFFont *bdf;
for ( bdf=c->curfv->sf->bitmaps; bdf!=NULL; bdf = bdf->next )
if ( bdf==c->curfv->active_bitmap )
break;
if ( bdf==NULL )
c->curfv->active_bitmap = c->curfv->sf->bitmaps;
}
}
static void bBitmapsRegen(Context *c) {
Bitmapper(c,false);
}
static void bImport(Context *c) {
char *ext, *filename;
int format, back, ok, flags;
char *t; char *locfilename;
if ( c->a.argc<2 || c->a.argc>4 ) {
c->error = ce_wrongnumarg;
return;
}
if ( c->a.vals[1].type!=v_str || \
(c->a.argc>=3 && c->a.vals[2].type!=v_int) || \
(c->a.argc==4 && c->a.vals[3].type!=v_int) ) {
c->error = ce_badargtype;
return;
}
t = script2utf8_copy(c->a.vals[1].u.sval);
locfilename = utf82def_copy(t);
filename = GFileMakeAbsoluteName(locfilename);
free(locfilename); free(t);
ext = strrchr(filename,'.');
if ( ext==NULL ) {
int len = strlen(filename);
ext = filename+len-2;
if ( ext[0]!='p' || ext[1]!='k' )
ScriptErrorString( c, "No extension in", filename);
}
back = 0; flags = -1;
if ( strmatch(ext,".bdf")==0 || strmatch(ext-4,".bdf.gz")==0 )
format = fv_bdf;
else if ( strmatch(ext,".pcf")==0 || strmatch(ext-4,".pcf.gz")==0 )
format = fv_pcf;
else if ( strmatch(ext,".ttf")==0 || strmatch(ext,".otf")==0 || strmatch(ext,".otb")==0 )
format = fv_ttf;
else if ( strmatch(ext,"pk")==0 || strmatch(ext,".pk")==0 ) {
format = fv_pk;
back = true;
} else if ( strmatch(ext,".eps")==0 || strmatch(ext,".ps")==0 ||
strmatch(ext,".art")==0 ) {
if ( strchr(filename,'*')!=NULL )
format = fv_epstemplate;
else
format = fv_eps;
} else if ( strmatch(ext,".pdf")==0 ) {
if ( strchr(filename,'*')!=NULL )
format = fv_pdftemplate;
else
format = fv_pdf;
} else if ( strmatch(ext,".svg")==0 ) {
if ( strchr(filename,'*')!=NULL )
format = fv_svgtemplate;
else
format = fv_svg;
} else {
if ( strchr(filename,'*')!=NULL )
format = fv_imgtemplate;
else
format = fv_image;
back = true;
}
if ( c->a.argc>=3 )
back = c->a.vals[2].u.ival;
if ( c->a.argc>=4 )
flags = c->a.vals[3].u.ival;
if ( format==fv_bdf )
ok = FVImportBDF(c->curfv,filename,false, back);
else if ( format==fv_pcf )
ok = FVImportBDF(c->curfv,filename,2, back);
else if ( format==fv_ttf )
ok = FVImportMult(c->curfv,filename, back, bf_ttf);
else if ( format==fv_pk )
ok = FVImportBDF(c->curfv,filename,true, back);
else if ( format==fv_image || format==fv_eps || format==fv_svg || format==fv_pdf )
ok = FVImportImages(c->curfv,filename,format,back,flags);
else
ok = FVImportImageTemplate(c->curfv,filename,format,back,flags);
free(filename);
if ( !ok )
ScriptError(c,"Import failed" );
}
#ifdef FONTFORGE_CONFIG_WRITE_PFM
static void bWritePfm(Context *c) {
SplineFont *sf = c->curfv->sf;
char *t; char *locfilename;
t = script2utf8_copy(c->a.vals[1].u.sval);
locfilename = utf82def_copy(t);
if ( !WritePfmFile(c->a.vals[1].u.sval,sf,0,c->curfv->map) )
ScriptError(c,"Save failed");
free(locfilename); free(t);
}
#endif
static void bExport(Context *c) {
int format,i, gid ;
BDFFont *bdf;
char *pt, *format_spec;
char buffer[20];
char *t;
if ( c->a.argc!=2 && c->a.argc!=3 ) {
c->error = ce_wrongnumarg;
return;
}
if ( c->a.vals[1].type!=v_str || (c->a.argc==3 && c->a.vals[2].type!=v_int) ) {
c->error = ce_badargtype;
return;
}
t = script2utf8_copy(c->a.vals[1].u.sval);
pt = utf82def_copy(t); free(t);
sprintf( buffer, "%%n_%%f.%.4s", pt);
format_spec = buffer;
if ( strrchr(pt,'.')!=NULL ) {
format_spec = pt;
pt = strrchr(pt,'.')+1;
}
if ( strmatch(pt,"eps")==0 )
format = 0;
else if ( strmatch(pt,"fig")==0 )
format = 1;
else if ( strmatch(pt,"svg")==0 )
format = 2;
else if ( strmatch(pt,"glif")==0 )
format = 3;
else if ( strmatch(pt,"pdf")==0 )
format = 4;
else if ( strmatch(pt,"plate")==0 )
format = 5;
else if ( strmatch(pt,"xbm")==0 )
format = 6;
else if ( strmatch(pt,"bmp")==0 )
format = 7;
#ifndef _NO_LIBPNG
else if ( strmatch(pt,"png")==0 )
format = 8;
else
ScriptError( c, "Bad format (first arg must be eps/fig/xbm/bmp/png)");
#else
else
ScriptError( c, "Bad format (first arg must be eps/fig/xbm/bmp)");
#endif
if (( format>=4 && c->a.argc!=3 ) || (format<4 && c->a.argc==3 )) {
c->error = ce_wrongnumarg;
return;
}
bdf=NULL;
if ( format>4 ) {
for ( bdf = c->curfv->sf->bitmaps; bdf!=NULL; bdf=bdf->next )
if (( BDFDepth(bdf)==1 && bdf->pixelsize==c->a.vals[2].u.ival) ||
(bdf->pixelsize!=(c->a.vals[2].u.ival&0xffff) &&
BDFDepth(bdf)==(c->a.vals[2].u.ival>>16)) )
break;
if ( bdf==NULL )
ScriptError(c, "No bitmap font matches the specified size");
}
for ( i=0; i<c->curfv->map->enccount; ++i )
if ( c->curfv->selected[i] && (gid=c->curfv->map->map[i])!=-1 &&
SCWorthOutputting(c->curfv->sf->glyphs[gid]) )
ScriptExport(c->curfv->sf,bdf,format,gid,format_spec,c->curfv->map);
if ( format_spec!=buffer )
free(format_spec);
}
/* FontImage("Outputfilename",array of [pointsize,string][,width[,height]]) */
static void bFontImage(Context *c) {
int i ;
char *pt, *t;
int width = -1, height = -1;
Array *arr;
if ( c->a.argc<3 || c->a.argc>5 ) {
c->error = ce_wrongnumarg;
return;
} else if ( c->a.vals[1].type!=v_str ||
(c->a.vals[2].type!=v_arr && c->a.vals[2].type!=v_arrfree) ||
(c->a.argc>=4 && c->a.vals[3].type!=v_int ) ||
(c->a.argc>=5 && c->a.vals[4].type!=v_int ) ) {
c->error = ce_badargtype;
return;
}
t = script2utf8_copy(c->a.vals[1].u.sval);
pt = strrchr(t,'.');
if ( pt==NULL || (strmatch(pt,".bmp")!=0
#ifndef _NO_LIBPNG
&& strmatch(pt,".png")!=0
#endif
))
ScriptError( c, "Unsupported image format");
if ( c->a.argc>=4 )
width = c->a.vals[3].u.ival;
if ( c->a.argc>=5 )
height = c->a.vals[4].u.ival;
arr = c->a.vals[2].u.aval;
if ( (arr->argc&1) && arr->argc>=2 )
ScriptError(c, "Second argument must be an array with an even number of entries");
if ( arr->argc==1 ) {
if ( arr->vals[0].type != v_int )
ScriptError( c, "Second argument must be an array where each even numbered entry is an integer pixelsize" );
} else for ( i=0; i<arr->argc; i+=2 ) {
if ( arr->vals[i].type != v_int )
ScriptError( c, "Second argument must be an array where each even numbered entry is an integer pixelsize" );
if ( arr->vals[i+1].type != v_str )
ScriptError( c, "Second argument must be an array where each odd numbered entry is a string" );
}
FontImage(c->curfv->sf,t,arr,width,height);
free(t);
}
static void bMergeKern(Context *c) {
char *t; char *locfilename;
t = script2utf8_copy(c->a.vals[1].u.sval);
locfilename = utf82def_copy(t);
if ( !LoadKerningDataFromMetricsFile(c->curfv->sf,locfilename,c->curfv->map))
ScriptError( c, "Failed to find kern info in file" );
free(locfilename); free(t);
}
static void bPrintSetup(Context *c) {
if ( c->a.argc!=2 && c->a.argc!=3 && c->a.argc!=5 ) {
c->error = ce_wrongnumarg;
return;
}
if ( c->a.vals[1].type!=v_int )
ScriptError( c, "Bad type for first argument");
if ( c->a.argc>=3 && c->a.vals[2].type!=v_str )
ScriptError( c, "Bad type for second argument");
if ( c->a.argc==5 ) {
if ( c->a.vals[3].type!=v_int )
ScriptError( c, "Bad type for third argument");
if ( c->a.vals[4].type!=v_int )
ScriptError( c, "Bad type for fourth argument");
pagewidth = c->a.vals[3].u.ival;
pageheight = c->a.vals[4].u.ival;
}
if ( c->a.vals[1].u.ival<0 || c->a.vals[1].u.ival>5 )
ScriptError( c, "First argument out of range [0,5]");
printtype = c->a.vals[1].u.ival;
if ( c->a.argc>=3 && printtype==4 )
printcommand = copy(c->a.vals[2].u.sval);
else if ( c->a.argc>=3 && (printtype==0 || printtype==1) )
printlazyprinter = copy(c->a.vals[2].u.sval);
}
static void bPrintFont(Context *c) {
int type, i, inlinesample = false;
int32 *pointsizes=NULL;
char *samplefile=NULL, *output=NULL;
unichar_t *sample=NULL;
char *t; char *locfilename=NULL;
if ( c->a.argc<2 || c->a.argc>5 ) {
c->error = ce_wrongnumarg;
return;
}
type = c->a.vals[1].u.ival;
if ( c->a.vals[1].type!=v_int || type<0 || type>4 )
ScriptError( c, "Bad type for first argument");
if ( type==4 ) {
type=3;
inlinesample = true;
}
if ( c->a.argc>=3 ) {
if ( c->a.vals[2].type==v_int ) {
if ( c->a.vals[2].u.ival>0 ) {
pointsizes = calloc(2,sizeof(int32));
pointsizes[0] = c->a.vals[2].u.ival;
}
} else if ( c->a.vals[2].type==v_arr ) {
Array *a = c->a.vals[2].u.aval;
pointsizes = malloc((a->argc+1)*sizeof(int32));
for ( i=0; i<a->argc; ++i ) {
if ( a->vals[i].type!=v_int )
ScriptError( c, "Bad type for array contents");
pointsizes[i] = a->vals[i].u.ival;
}
pointsizes[i] = 0;
} else
ScriptError( c, "Bad type for second argument");
}
if ( c->a.argc>=4 ) {
if ( c->a.vals[3].type!=v_str )
ScriptError( c, "Bad type for third argument");
else if ( *c->a.vals[3].u.sval!='\0' ) {
samplefile = c->a.vals[3].u.sval;
if ( inlinesample ) {
sample = utf82u_copy(samplefile);
samplefile = NULL;
} else {
t = script2utf8_copy(samplefile);
samplefile = locfilename = utf82def_copy(t); free(t);
}
}
}
if ( c->a.argc>=5 ) {
if ( c->a.vals[4].type!=v_str )
ScriptError( c, "Bad type for fourth argument");
else if ( *c->a.vals[4].u.sval!='\0' )
output = c->a.vals[4].u.sval;
}
ScriptPrint(c->curfv,type,pointsizes,samplefile,sample,output);
free(pointsizes);
free(locfilename);
/* ScriptPrint frees sample for us */
}
/* **** Edit menu **** */
static void bCut(Context *c) {
FVCopy(c->curfv,ct_fullcopy);
FVClear(c->curfv);
}
static void bCopy(Context *c) {
FVCopy(c->curfv,ct_fullcopy);
}
static void bCopyReference(Context *c) {
FVCopy(c->curfv,ct_reference);
}
static void bCopyUnlinked(Context *c) {
FVCopy(c->curfv,ct_unlinkrefs);
}
static void bCopyWidth(Context *c) {
FVCopy(c->curfv,ut_width);
}
static void bCopyVWidth(Context *c) {
if ( c->curfv!=NULL && !c->curfv->sf->hasvmetrics )
ScriptError(c,"Vertical metrics not enabled in this font");
FVCopy(c->curfv,ut_vwidth);
}
static void bCopyLBearing(Context *c) {
FVCopy(c->curfv,ut_lbearing);
}
static void bCopyRBearing(Context *c) {
FVCopy(c->curfv,ut_rbearing);
}
static void bCopyAnchors(Context *c) {
FVCopyAnchors(c->curfv);
}
static int GetOneSelCharIndex(Context *c) {
FontViewBase *fv = c->curfv;
EncMap *map = fv->map;
int i, found = -1;
for ( i=0; i<map->enccount; ++i ) if ( fv->selected[i] ) {
if ( found==-1 )
found = i;
else
ScriptError(c,"More than one character selected" );
}
if ( found==-1 )
ScriptError(c,"No characters selected" );
return( found );
}
static SplineChar *GetOneSelChar(Context *c) {
int found = GetOneSelCharIndex(c);
return( SFMakeChar(c->curfv->sf,c->curfv->map,found));
}
static void bCopyGlyphFeatures(Context *c) {
ScriptError(c,"This scripting function no longer works.");
}
static void bPaste(Context *c) {
PasteIntoFV(c->curfv,false,NULL);
}
static void bPasteInto(Context *c) {
PasteIntoFV(c->curfv,true,NULL);
}
static void bPasteWithOffset(Context *c) {
real trans[6];
memset(trans,0,sizeof(trans));
trans[0] = trans[3] = 1;
if ( c->a.vals[1].type==v_int )
trans[4] = c->a.vals[1].u.ival;
else if ( c->a.vals[1].type==v_real )
trans[4] = c->a.vals[1].u.fval;
else {
c->error = ce_badargtype;
return;
}
if ( c->a.vals[2].type==v_int )
trans[5] = c->a.vals[2].u.ival;
else if ( c->a.vals[2].type==v_real )
trans[5] = c->a.vals[2].u.fval;
else {
c->error = ce_badargtype;
return;
}
PasteIntoFV(c->curfv,3,trans);
}
static void bClear(Context *c) {
FVClear( c->curfv );
}
static void bClearBackground(Context *c) {
FVClearBackground( c->curfv );
}
static void bCopyFgToBg(Context *c) {
FVCopyFgtoBg(c->curfv);
}
static void bUnlinkReference(Context *c) {
FVUnlinkRef(c->curfv);
}
static void bJoin(Context *c) {
FVJoin(c->curfv);
}
static void bSameGlyphAs(Context *c) {
FVSameGlyphAs(c->curfv);
}
static void bMultipleEncodingsToReferences(Context *c) {
int i, gid;
FontViewBase *fv = c->curfv;
SplineFont *sf = fv->sf;
EncMap *map = fv->map;
SplineChar *sc, *orig;
struct altuni *alt, *next, *prev;
int uni, enc;
for ( i=0; i<map->enccount; ++i ) {
if ( (gid=map->map[i])!=-1 && fv->selected[i] &&
(orig = sf->glyphs[gid])!=NULL && orig->altuni!=NULL ) {
prev = NULL;
for ( alt = orig->altuni; alt!=NULL; alt=next ) {
if ( alt->vs==-1 ) {
next = alt->next;
uni = alt->unienc;
orig->altuni = next;
AltUniFree(alt);
if ( prev==NULL )
orig->altuni = next;
else
prev->next = next;
enc = EncFromUni(uni,map->enc);
if ( enc!=-1 ) {
map->map[enc] = -1;
sc = SFMakeChar(sf,map,enc);
SCAddRef(sc,orig,ly_fore,0,0);
}
} else
prev = alt;
}
}
}
/* Now suppose we had a duplicate encoding of a glyph with no unicode */
/* so there will be no altuni to mark it */
for ( gid=0; gid<sf->glyphcnt; ++gid ) {
for ( i=0; i<map->enccount; ++i ) {
if ( map->map[i]==gid && map->backmap[gid]!=i &&
(fv->selected[i] || (map->backmap[gid]!=-1 && fv->selected[map->backmap[gid]]))) {
map->map[i] = -1;
sc = SFMakeChar(sf,map,i);
SCAddRef(sc,orig,ly_fore,0,0);
sc->width = orig->width;
sc->vwidth = orig->vwidth;
}
}
}
}
static void bSelectAll(Context *c) {
memset(c->curfv->selected,1,c->curfv->map->enccount);
}
static void bSelectNone(Context *c) {
memset(c->curfv->selected,0,c->curfv->map->enccount);
}
static void bSelectInvert(Context *c) {
int i;
for ( i=0; i<c->curfv->map->enccount; ++i )
c->curfv->selected[i] = !c->curfv->selected[i];
}
static int ParseCharIdent(Context *c, Val *val, int signal_error) {
SplineFont *sf = c->curfv->sf;
EncMap *map = c->curfv->map;
int bottom = -1;
if ( val->type==v_int )
bottom = val->u.ival;
else if ( val->type==v_unicode || val->type==v_str ) {
if ( val->type==v_unicode )
bottom = SFFindSlot(sf,map,val->u.ival,NULL);
else {
bottom = SFFindSlot(sf,map,-1,val->u.sval);
}
} else {
if ( signal_error )
ScriptError( c, "Bad type for argument");
else
return( -1 );
}
if ( bottom<0 || bottom>=map->enccount ) {
if ( signal_error ) {
char buffer[40], *name = buffer;
if ( val->type==v_int )
sprintf( buffer, "%d", val->u.ival );
else if ( val->type == v_unicode )
sprintf( buffer, "U+%04X", val->u.ival );
else
name = val->u.sval;
if ( bottom==-1 )
ScriptErrorString( c, "Character not found", name );
else
ScriptErrorString( c, "Character is not in font", name );
}
return( -1 );
}
return( bottom );
}
static int bDoSelect(Context *c, int signal_error, int select, int by_ranges) {
int top, bottom, i,j;
int any = false;
if ( c->a.argc==2 && (c->a.vals[1].type==v_arr || c->a.vals[1].type==v_arrfree)) {
struct array *arr = c->a.vals[1].u.aval;
for ( i=0; i<arr->argc && i<c->curfv->map->enccount; ++i ) {
if ( arr->vals[i].type!=v_int ) {
if ( signal_error )
ScriptError(c,"Bad type within selection array");
else
return( any ? -1 : -2 );
} else {
c->curfv->selected[i] = (arr->vals[i].u.ival!=0);
++any;
}
}
return( any );
}
for ( i=1; i<c->a.argc; i+=1+by_ranges ) {
bottom = ParseCharIdent(c,&c->a.vals[i],signal_error);
if ( i+1==c->a.argc || !by_ranges )
top = bottom;
else {
top = ParseCharIdent(c,&c->a.vals[i+1],signal_error);
}
if ( bottom==-1 || top==-1 ) /* an error occurred in parsing */
return( any ? -1 : -2 );
if ( top<bottom ) { j=top; top=bottom; bottom = j; }
for ( j=bottom; j<=top; ++j ) {
c->curfv->selected[j] = select;
++any;
}
}
return( any );
}
static void bSelectMore(Context *c) {
if ( c->a.argc==1 )
ScriptError( c, "SelectMore needs at least one argument");
bDoSelect(c,true,true,true);
}
static void bSelectFewer(Context *c) {
if ( c->a.argc==1 )
ScriptError( c, "SelectFewer needs at least one argument");
bDoSelect(c,true,false,true);
}
static void bSelect(Context *c) {
memset(c->curfv->selected,0,c->curfv->map->enccount);
bDoSelect(c,true,true,true);
}
static void bSelectMoreIf(Context *c) {
if ( c->a.argc==1 )
ScriptError( c, "SelectMore needs at least one argument");
c->return_val.type = v_int;
c->return_val.u.ival = bDoSelect(c,false,true,true);
}
static void bSelectMoreSingletons(Context *c) {
if ( c->a.argc==1 )
ScriptError( c, "SelectMore needs at least one argument");
bDoSelect(c,true,true,false);
}
static void bSelectMoreSingletonsIf(Context *c) {
if ( c->a.argc==1 )
ScriptError( c, "SelectMore needs at least one argument");
c->return_val.type = v_int;
c->return_val.u.ival = bDoSelect(c,false,true,false);
}
static void bSelectFewerSingletons(Context *c) {
if ( c->a.argc==1 )
ScriptError( c, "SelectFewer needs at least one argument");
bDoSelect(c,true,false,false);
}
static void bSelectSingletons(Context *c) {
memset(c->curfv->selected,0,c->curfv->map->enccount);
bDoSelect(c,true,true,false);
}
static void bSelectSingletonsIf(Context *c) {
memset(c->curfv->selected,0,c->curfv->map->enccount);
c->return_val.type = v_int;
c->return_val.u.ival = bDoSelect(c,false,true,false);
}
static void bSelectAllInstancesOf(Context *c) {
int i,j,gid;
SplineChar *sc;
FontViewBase *fv = c->curfv;
EncMap *map = fv->map;
SplineFont *sf = fv->sf;
struct altuni *alt;
memset(fv->selected,0,map->enccount);
for ( i=1; i<c->a.argc; ++i ) {
if ( c->a.vals[i].type==v_unicode ) {
int uni = c->a.vals[i].u.ival;
for ( j=0; j<map->enccount; ++j ) if ( (gid=map->map[j])!=-1 && (sc=sf->glyphs[gid])!=NULL ) {
for ( alt=sc->altuni; alt!=NULL && alt->unienc!=uni; alt=alt->next );
if ( sc->unicodeenc == uni || alt!=NULL )
fv->selected[j] = true;
}
} else if ( c->a.vals[i].type==v_str ) {
char *name = c->a.vals[i].u.sval;
for ( j=0; j<map->enccount; ++j ) if ( (gid=map->map[j])!=-1 && (sc=sf->glyphs[gid])!=NULL ) {
if ( strcmp(sc->name,name)==0 )
fv->selected[j] = true;
}
} else {
c->error = ce_badargtype;
return;
}
}
}
static void bSelectIf(Context *c) {
memset(c->curfv->selected,0,c->curfv->map->enccount);
c->return_val.type = v_int;
c->return_val.u.ival = bDoSelect(c,false,true,true);
}
static void bSelectChanged(Context *c) {
int i, gid;
FontViewBase *fv = c->curfv;
EncMap *map = fv->map;
SplineFont *sf = fv->sf;
int add = 0;
if ( c->a.argc!=1 && c->a.argc!=2 )
ScriptError( c, "Too many arguments");
if ( c->a.argc==2 ) {
if ( c->a.vals[1].type!=v_int ) {
c->error = ce_badargtype;
return;
}
add = c->a.vals[1].u.ival;
}
if ( add ) {
for ( i=0; i< map->enccount; ++i )
fv->selected[i] |= ( (gid=map->map[i])!=-1 && sf->glyphs[gid]!=NULL && sf->glyphs[gid]->changed );
} else {
for ( i=0; i< map->enccount; ++i )
fv->selected[i] = ( (gid=map->map[i])!=-1 && sf->glyphs[gid]!=NULL && sf->glyphs[gid]->changed );
}
}
static void bSelectHintingNeeded(Context *c) {
int i, gid;
FontViewBase *fv = c->curfv;
EncMap *map = fv->map;
SplineFont *sf = fv->sf;
int add = 0;
int order2 = sf->layers[ly_fore].order2;
if ( c->a.argc!=1 && c->a.argc!=2 )
ScriptError( c, "Too many arguments");
if ( c->a.argc==2 ) {
if ( c->a.vals[1].type!=v_int ) {
c->error = ce_badargtype;
return;
}
add = c->a.vals[1].u.ival;
}
if ( add ) {
for ( i=0; i< map->enccount; ++i )
fv->selected[i] |= ( (gid=map->map[i])!=-1 && sf->glyphs[gid]!=NULL &&
((!order2 && sf->glyphs[gid]->changedsincelasthinted ) ||
( order2 && sf->glyphs[gid]->layers[ly_fore].splines!=NULL &&
sf->glyphs[gid]->ttf_instrs_len<=0 )) );
} else {
for ( i=0; i< map->enccount; ++i )
fv->selected[i] = ( (gid=map->map[i])!=-1 && sf->glyphs[gid]!=NULL &&
((!order2 && sf->glyphs[gid]->changedsincelasthinted ) ||
( order2 && sf->glyphs[gid]->layers[ly_fore].splines!=NULL &&
sf->glyphs[gid]->ttf_instrs_len<=0 )) );
}
}
static void bSelectWorthOutputting(Context *c) {
int i, gid;
FontViewBase *fv = c->curfv;
EncMap *map = fv->map;
SplineFont *sf = fv->sf;
int add = 0;
if ( c->a.argc!=1 && c->a.argc!=2 )
ScriptError( c, "Too many arguments");
if ( c->a.argc==2 ) {
if ( c->a.vals[1].type!=v_int ) {
c->error = ce_badargtype;
return;
}
add = c->a.vals[1].u.ival;
}
if ( add ) {
for ( i=0; i< map->enccount; ++i )
fv->selected[i] |= ( (gid=map->map[i])!=-1 && sf->glyphs[gid]!=NULL &&
SCWorthOutputting(sf->glyphs[gid]) );
} else {
for ( i=0; i< map->enccount; ++i )
fv->selected[i] = ( (gid=map->map[i])!=-1 && sf->glyphs[gid]!=NULL &&
SCWorthOutputting(sf->glyphs[gid]) );
}
}
static void bSelectGlyphsSplines(Context *c) {
FontViewBase *fv = c->curfv;
int i, gid;
EncMap *map = fv->map;
SplineFont *sf = fv->sf;
int layer = fv->active_layer;
int add = 0;
if ( c->a.argc!=1 && c->a.argc!=2 )
ScriptError( c, "Too many arguments");
if ( c->a.argc==2 ) {
if ( c->a.vals[1].type!=v_int ) {
c->error = ce_badargtype;
return;
}
add = c->a.vals[1].u.ival;
}
if ( add ) {
for ( i=0; i< map->enccount; ++i )
fv->selected[i] |= ( (gid=map->map[i])!=-1 && sf->glyphs[gid]!=NULL &&
sf->glyphs[gid]->layers[layer].splines!=NULL );
} else {
for ( i=0; i< map->enccount; ++i )
fv->selected[i] = ( (gid=map->map[i])!=-1 && sf->glyphs[gid]!=NULL &&
sf->glyphs[gid]->layers[layer].splines!=NULL );
}
}
static void bSelectGlyphsReferences(Context *c) {
FontViewBase *fv = c->curfv;
int i, gid;
EncMap *map = fv->map;
SplineFont *sf = fv->sf;
int layer = fv->active_layer;
int add = 0;
if ( c->a.argc!=1 && c->a.argc!=2 )
ScriptError( c, "Too many arguments");
if ( c->a.argc==2 ) {
if ( c->a.vals[1].type!=v_int ) {
c->error = ce_badargtype;
return;
}
add = c->a.vals[1].u.ival;
}
if ( add ) {
for ( i=0; i< map->enccount; ++i )
fv->selected[i] |= ( (gid=map->map[i])!=-1 && sf->glyphs[gid]!=NULL &&
sf->glyphs[gid]->layers[layer].refs!=NULL );
} else {
for ( i=0; i< map->enccount; ++i )
fv->selected[i] = ( (gid=map->map[i])!=-1 && sf->glyphs[gid]!=NULL &&
sf->glyphs[gid]->layers[layer].refs!=NULL);
}
}
static void bSelectGlyphsBoth(Context *c) {
FontViewBase *fv = c->curfv;
int i, gid;
EncMap *map = fv->map;
SplineFont *sf = fv->sf;
int layer = fv->active_layer;
int add = 0;
if ( c->a.argc!=1 && c->a.argc!=2 )
ScriptError( c, "Too many arguments");
if ( c->a.argc==2 ) {
if ( c->a.vals[1].type!=v_int ) {
c->error = ce_badargtype;
return;
}
add = c->a.vals[1].u.ival;
}
if ( add ) {
for ( i=0; i< map->enccount; ++i )
fv->selected[i] |= ( (gid=map->map[i])!=-1 && sf->glyphs[gid]!=NULL &&
sf->glyphs[gid]->layers[layer].refs!=NULL &&
sf->glyphs[gid]->layers[layer].splines!=NULL );
} else {
for ( i=0; i< map->enccount; ++i )
fv->selected[i] = ( (gid=map->map[i])!=-1 && sf->glyphs[gid]!=NULL &&
sf->glyphs[gid]->layers[layer].refs!=NULL &&
sf->glyphs[gid]->layers[layer].splines!=NULL );
}
}
static void bSelectByATT(Context *c) {
ScriptError(c,"This scripting function no longer works. It has been replace by SelectByPosSub");
}
static void bSelectByPosSub(Context *c) {
struct lookup_subtable *sub;
if ( c->a.vals[1].type!=v_str || c->a.vals[2].type!=v_int ) {
c->error = ce_badargtype;
return;
} else if ( c->a.vals[2].u.ival<1 || c->a.vals[2].u.ival>3 ) {
c->error = ce_badargtype;
return;
}
sub = SFFindLookupSubtable(c->curfv->sf,c->a.vals[1].u.sval);
if ( sub==NULL )
ScriptErrorString(c,"Unknown lookup subtable",c->a.vals[1].u.sval);
c->return_val.type = v_int;
c->return_val.u.ival = FVBParseSelectByPST(c->curfv,sub,c->a.vals[2].u.ival);
}
static void bSelectByColor(Context *c) {
int col, sccol;
int i;
EncMap *map = c->curfv->map;
SplineFont *sf = c->curfv->sf;
if ( c->a.vals[1].type!=v_str && c->a.vals[1].type!=v_int ) {
c->error = ce_badargtype;
return;
}
if ( c->a.vals[1].type==v_int )
col = c->a.vals[1].u.ival;
else {
if ( strmatch(c->a.vals[1].u.sval,"Red")==0 )
col = 0xff0000;
else if ( strmatch(c->a.vals[1].u.sval,"Green")==0 )
col = 0x00ff00;
else if ( strmatch(c->a.vals[1].u.sval,"Blue")==0 )
col = 0x0000ff;
else if ( strmatch(c->a.vals[1].u.sval,"Magenta")==0 )
col = 0xff00ff;
else if ( strmatch(c->a.vals[1].u.sval,"Cyan")==0 )
col = 0x00ffff;
else if ( strmatch(c->a.vals[1].u.sval,"Yellow")==0 )
col = 0xffff00;
else if ( strmatch(c->a.vals[1].u.sval,"White")==0 )
col = 0xffffff;
else if ( strmatch(c->a.vals[1].u.sval,"none")==0 ||
strmatch(c->a.vals[1].u.sval,"Default")==0 )
col = COLOR_DEFAULT;
else
ScriptErrorString(c,"Unknown color", c->a.vals[1].u.sval);
}
for ( i=0; i<map->enccount; ++i ) {
int gid = map->map[i];
if ( gid!=-1 ) {
sccol = ( sf->glyphs[gid]==NULL ) ? COLOR_DEFAULT : sf->glyphs[gid]->color;
if ( c->curfv->selected[i]!=(sccol==col) )
c->curfv->selected[i] = !c->curfv->selected[i];
}
}
}
/* **** Element Menu **** */
static void bReencode(Context *c) {
Encoding *new_enc;
int force = 0;
int ret;
if ( c->a.argc!=2 && c->a.argc!=3 ) {
c->error = ce_wrongnumarg;
return;
} else if ( c->a.vals[1].type!=v_str || \
(c->a.argc==3 && c->a.vals[2].type!=v_int) ) {
c->error = ce_badargtype;
return;
}
if ( c->a.argc==3 )
force = c->a.vals[2].u.ival;
ret = SFReencode(c->curfv->sf, c->a.vals[1].u.sval, force);
if ( ret==-1 )
ScriptErrorString(c,"Unknown encoding", c->a.vals[1].u.sval);
}
static void bRenameGlyphs(Context *c) {
NameList *nl;
nl = NameListByName(c->a.vals[1].u.sval);
if ( nl==NULL )
ScriptErrorString(c,"Unknown namelist", c->a.vals[1].u.sval);
SFRenameGlyphsToNamelist(c->curfv->sf,nl);
}
static void bSetCharCnt(Context *c) {
EncMap *map = c->curfv->map;
int newcnt;
if ( c->a.vals[1].u.ival<=0 || c->a.vals[1].u.ival>10*65536 )
ScriptError(c,"Argument out of bounds");
newcnt = c->a.vals[1].u.ival;
if ( map->enccount==newcnt )
return;
if ( newcnt<map->enc->char_cnt ) {
map->enc = &custom;
if ( !no_windowing_ui )
FVSetTitles(c->curfv->sf);
} else {
c->curfv->selected = realloc(c->curfv->selected,newcnt);
if ( newcnt>map->encmax ) {
memset(c->curfv->selected+map->enccount,0,newcnt-map->enccount);
map->map = realloc(map->map,(map->encmax=newcnt+10)*sizeof(int32));
memset(map->map+map->enccount,-1,(newcnt-map->enccount)*sizeof(int32));
}
}
map->enccount = newcnt;
if ( !no_windowing_ui )
FontViewReformatOne(c->curfv);
c->curfv->sf->changed = true;
c->curfv->sf->changed_since_autosave = true;
c->curfv->sf->changed_since_xuidchanged = true;
}
static void bDetachGlyphs(Context *c) {
FontViewBase *fv = c->curfv;
FVDetachGlyphs(fv);
}
static void bDetachAndRemoveGlyphs(Context *c) {
FontViewBase *fv = c->curfv;
FVDetachAndRemoveGlyphs( fv);
}
static void bRemoveDetachedGlyphs(Context *c) {
FontViewBase *fv = c->curfv;
int i, gid;
EncMap *map = fv->map;
SplineFont *sf = fv->sf;
SplineChar *sc;
int changed = false;
for ( gid=0; gid<sf->glyphcnt; ++gid ) if ( sf->glyphs[gid]!=NULL )
sf->glyphs[gid]->ticked = false;
for ( i=0; i<map->enccount; ++i ) if ( (gid=map->map[i])!=-1 )
sf->glyphs[gid]->ticked = true;
for ( gid=0; gid<sf->glyphcnt; ++gid ) if ( (sc=sf->glyphs[gid])!=NULL && !sc->ticked ) {
SFRemoveGlyph(sf,sc);
changed = true;
}
if ( changed && !sf->changed ) {
fv->sf->changed = true;
}
}
static void bLoadTableFromFile(Context *c) {
SplineFont *sf = c->curfv->sf;
uint32 tag;
char *tstr, *end;
struct ttf_table *tab;
FILE *file;
struct stat statb;
char *t; char *locfilename;
tstr = c->a.vals[1].u.sval;
end = tstr+strlen(tstr);
if ( *tstr=='\0' || end-tstr>4 )
ScriptError(c, "Bad tag");
tag = *tstr<<24;
tag |= (tstr+1<end ? tstr[1] : ' ')<<16;
tag |= (tstr+2<end ? tstr[2] : ' ')<<8 ;
tag |= (tstr+3<end ? tstr[3] : ' ') ;
t = script2utf8_copy(c->a.vals[2].u.sval);
locfilename = utf82def_copy(t);
file = fopen(locfilename,"rb");
free(locfilename); free(t);
if ( file==NULL )
ScriptErrorString(c,"Could not open file: ", c->a.vals[2].u.sval );
if ( fstat(fileno(file),&statb)==-1 )
ScriptErrorString(c,"fstat() failed on: ", c->a.vals[2].u.sval );
for ( tab=sf->ttf_tab_saved; tab!=NULL && tab->tag!=tag; tab=tab->next );
if ( tab==NULL ) {
tab = chunkalloc(sizeof(struct ttf_table));
tab->tag = tag;
tab->next = sf->ttf_tab_saved;
sf->ttf_tab_saved = tab;
} else
free(tab->data);
tab->data = malloc(statb.st_size);
tab->len = fread(tab->data,1,statb.st_size,file);
fclose(file);
}
static void bSaveTableToFile(Context *c) {
SplineFont *sf = c->curfv->sf;
uint32 tag;
char *tstr, *end;
struct ttf_table *tab;
FILE *file;
char *t; char *locfilename;
tstr = c->a.vals[1].u.sval;
end = tstr+strlen(tstr);
if ( *tstr=='\0' || end-tstr>4 )
ScriptError(c, "Bad tag");
tag = *tstr<<24;
tag |= (tstr+1<end ? tstr[1] : ' ')<<16;
tag |= (tstr+2<end ? tstr[2] : ' ')<<8 ;
tag |= (tstr+3<end ? tstr[3] : ' ') ;
t = script2utf8_copy(c->a.vals[2].u.sval);
locfilename = utf82def_copy(t);
file = fopen(locfilename,"wb");
free(locfilename); free(t);
if ( file==NULL )
ScriptErrorString(c,"Could not open file: ", c->a.vals[2].u.sval );
for ( tab=sf->ttf_tab_saved; tab!=NULL && tab->tag!=tag; tab=tab->next );
if ( tab==NULL )
ScriptErrorString(c,"No preserved table matches tag: ", tstr );
fwrite(tab->data,1,tab->len,file);
fclose(file);
}
static void bRemovePreservedTable(Context *c) {
SplineFont *sf = c->curfv->sf;
uint32 tag;
char *tstr, *end;
struct ttf_table *tab, *prev;
tstr = c->a.vals[1].u.sval;
end = tstr+strlen(tstr);
if ( *tstr=='\0' || end-tstr>4 )
ScriptError(c, "Bad tag");
tag = *tstr<<24;
tag |= (tstr+1<end ? tstr[1] : ' ')<<16;
tag |= (tstr+2<end ? tstr[2] : ' ')<<8 ;
tag |= (tstr+3<end ? tstr[3] : ' ') ;
for ( tab=sf->ttf_tab_saved, prev=NULL; tab!=NULL && tab->tag!=tag; prev=tab, tab=tab->next );
if ( tab==NULL )
ScriptErrorString(c,"No preserved table matches tag: ", tstr );
if ( prev==NULL )
sf->ttf_tab_saved = tab->next;
else
prev->next = tab->next;
free(tab->data);
chunkfree(tab,sizeof(*tab));
}
static void bHasPreservedTable(Context *c) {
SplineFont *sf = c->curfv->sf;
uint32 tag;
char *tstr, *end;
struct ttf_table *tab;
tstr = c->a.vals[1].u.sval;
end = tstr+strlen(tstr);
if ( *tstr=='\0' || end-tstr>4 )
ScriptError(c, "Bad tag");
tag = *tstr<<24;
tag |= (tstr+1<end ? tstr[1] : ' ')<<16;
tag |= (tstr+2<end ? tstr[2] : ' ')<<8 ;
tag |= (tstr+3<end ? tstr[3] : ' ') ;
for ( tab=sf->ttf_tab_saved; tab!=NULL && tab->tag!=tag; tab=tab->next );
c->return_val.type = v_int;
c->return_val.u.ival = (tab!=NULL);
}
static void bLoadEncodingFile(Context *c) {
char *t; char *locfilename;
if ( c->a.argc != 2 && c->a.argc != 3 ) {
c->error = ce_wrongnumarg;
return;
} else if ( (c->a.vals[1].type!=v_str) || \
(c->a.argc >= 3 && c->a.vals[2].type !=v_str) ) {
c->error = ce_badargtype;
return;
}
t = script2utf8_copy(c->a.vals[1].u.sval);
locfilename = utf82def_copy(t);
ParseEncodingFile(locfilename, (c->a.argc>=3 ? c->a.vals[2].u.sval : NULL));
free(locfilename); free(t);
/*DumpPfaEditEncodings();*/
}
static void bSetFontOrder(Context *c) {
if ( c->a.vals[1].u.ival!=2 && c->a.vals[1].u.ival!=3 )
ScriptError(c,"Order must be 2 or 3");
c->return_val.type = v_int;
c->return_val.u.ival = c->curfv->sf->layers[ly_fore].order2?2:3;
if ( c->a.vals[1].u.ival==(c->curfv->sf->layers[ly_fore].order2?2:3))
/* No Op */;
else {
if ( c->a.vals[1].u.ival==2 ) {
SFCloseAllInstrs(c->curfv->sf);
SFConvertToOrder2(c->curfv->sf);
} else
SFConvertToOrder3(c->curfv->sf);
}
}
static void bSetFontHasVerticalMetrics(Context *c) {
c->return_val.type = v_int;
c->return_val.u.ival = c->curfv->sf->hasvmetrics;
c->curfv->sf->hasvmetrics = (c->a.vals[1].u.ival!=0);
}
static void bSetGasp(Context *c) {
int i, base;
struct array *arr;
SplineFont *sf = c->curfv->sf;
if ( c->a.argc==2 && (c->a.vals[1].type==v_arr || c->a.vals[1].type==v_arrfree)) {
arr = c->a.vals[1].u.aval;
if ( arr->argc&1 )
ScriptError( c, "Bad array size");
base = 0;
} else if ( (c->a.argc&1)==0 ) {
c->error = ce_wrongnumarg;
return;
} else {
arr = &c->a;
base = 1;
}
for ( i=base; i<arr->argc; i += 2 ) {
if ( arr->vals[i].type!=v_int || arr->vals[i+1].type!=v_int ) {
c->error = ce_badargtype;
return;
}
if ( arr->vals[i].u.ival<=0 || arr->vals[i].u.ival>65535 )
ScriptError(c,"'gasp' Pixel size out of range");
if ( i!=base && arr->vals[i].u.ival<=arr->vals[i-2].u.ival )
ScriptError(c,"'gasp' Pixel size out of order");
if ( arr->vals[i+1].u.ival<0 || arr->vals[i+1].u.ival>15 )
ScriptError(c,"'gasp' flag out of range");
if ( arr->vals[i+1].u.ival>3 )
sf->gasp_version=1;
}
if ( arr->argc>=2 && arr->vals[arr->argc-2].u.ival!=65535 )
ScriptError(c,"'gasp' Final pixel size must be 65535");
free(sf->gasp);
sf->gasp_cnt = (arr->argc-base)/2;
if ( sf->gasp_cnt!=0 ) {
sf->gasp = calloc(sf->gasp_cnt,sizeof(struct gasp));
for ( i=base; i<arr->argc; i += 2 ) {
int g = (i-base)/2;
sf->gasp[g].ppem = arr->vals[i].u.ival;
sf->gasp[g].flags = arr->vals[i+1].u.ival;
}
} else
sf->gasp = NULL;
}
static void _SetFontNames(Context *c,SplineFont *sf) {
int i;
if ( c->a.argc==1 || c->a.argc>7 ) {
c->error = ce_wrongnumarg;
return;
}
for ( i=1; i<c->a.argc; ++i )
if ( c->a.vals[i].type!=v_str ) {
c->error = ce_badargtype;
return;
}
if ( *c->a.vals[1].u.sval!='\0' ) {
free(sf->fontname);
sf->fontname = forcePSName_copy(c,c->a.vals[1].u.sval);
}
if ( c->a.argc>2 && *c->a.vals[2].u.sval!='\0' ) {
free(sf->familyname);
sf->familyname = script2latin1_copy(c->a.vals[2].u.sval);
}
if ( c->a.argc>3 && *c->a.vals[3].u.sval!='\0' ) {
free(sf->fullname);
sf->fullname = script2latin1_copy(c->a.vals[3].u.sval);
}
if ( c->a.argc>4 && *c->a.vals[4].u.sval!='\0' ) {
free(sf->weight);
sf->weight = script2latin1_copy(c->a.vals[4].u.sval);
}
if ( c->a.argc>5 && *c->a.vals[5].u.sval!='\0' ) {
free(sf->copyright);
sf->copyright = script2latin1_copy(c->a.vals[5].u.sval);
}
if ( c->a.argc>6 && *c->a.vals[6].u.sval!='\0' ) {
free(sf->version);
sf->version = script2latin1_copy(c->a.vals[6].u.sval);
}
SFReplaceFontnameBDFProps(c->curfv->sf);
}
static void bSetFontNames(Context *c) {
SplineFont *sf = c->curfv->sf;
_SetFontNames(c,sf);
}
static void bSetFondName(Context *c) {
SplineFont *sf = c->curfv->sf;
if ( *c->a.vals[1].u.sval!='\0' ) {
free(sf->fondname);
sf->fondname = forceASCIIcopy(c,c->a.vals[1].u.sval);
}
}
static void bSetTTFName(Context *c) {
SplineFont *sf = c->curfv->sf;
char *u;
int lang, strid;
struct ttflangname *prev, *ln;
if ( sf->cidmaster!=NULL ) sf = sf->cidmaster;
if ( c->a.vals[1].type!=v_int || c->a.vals[2].type!=v_int ||
c->a.vals[3].type!=v_str ) {
c->error = ce_badargtype;
return;
}
lang = c->a.vals[1].u.ival;
strid = c->a.vals[2].u.ival;
if ( lang<0 || lang>0xffff )
ScriptError(c,"Bad value for language");
else if ( strid<0 || strid>=ttf_namemax )
ScriptError(c,"Bad value for string id");
u = copy(c->a.vals[3].u.sval);
if ( *u=='\0' ) {
free(u);
u = NULL;
}
for ( ln = sf->names; ln!=NULL && ln->lang!=lang; ln = ln->next );
if ( ln==NULL ) {
if ( u==NULL )
return;
for ( prev = NULL, ln = sf->names; ln!=NULL && ln->lang<lang; prev = ln, ln = ln->next );
ln = chunkalloc(sizeof(struct ttflangname));
ln->lang = lang;
if ( prev==NULL ) { ln->next = sf->names; sf->names = ln; }
else { ln->next = prev->next; prev->next = ln; }
}
free(ln->names[strid]);
ln->names[strid] = u;
}
static void bGetTTFName(Context *c) {
SplineFont *sf = c->curfv->sf;
int lang, strid;
struct ttflangname *ln;
if ( sf->cidmaster!=NULL ) sf = sf->cidmaster;
lang = c->a.vals[1].u.ival;
strid = c->a.vals[2].u.ival;
if ( lang<0 || lang>0xffff )
ScriptError(c,"Bad value for language");
else if ( strid<0 || strid>=ttf_namemax )
ScriptError(c,"Bad value for string id");
c->return_val.type = v_str;
for ( ln = sf->names; ln!=NULL && ln->lang!=lang; ln = ln->next );
if ( ln==NULL || ln->names[strid]==NULL )
c->return_val.u.sval = copy("");
else
c->return_val.u.sval = copy(ln->names[strid]);
}
static void bSetItalicAngle(Context *c) {
double denom=1;
double num;
if ( c->a.argc!=2 && c->a.argc!=3 ) {
c->error = ce_wrongnumarg;
return;
}
if ( c->a.argc==3 ) {
if ( c->a.vals[2].type!=v_int || c->a.vals[2].u.ival==0 ) {
c->error = ce_badargtype;
return;
}
denom=c->a.vals[2].u.ival;
}
if ( c->a.vals[1].type==v_real )
num = c->a.vals[1].u.fval;
else if ( c->a.vals[1].type==v_int )
num = c->a.vals[1].u.ival;
else {
c->error = ce_badargtype;
return;
}
c->curfv->sf->italicangle = num / denom;
}
static void bSetMacStyle(Context *c) {
if ( c->a.argc!=2 ) {
c->error = ce_wrongnumarg;
return;
}
if ( c->a.vals[1].type==v_int )
c->curfv->sf->macstyle = c->a.vals[1].u.ival;
else if ( c->a.vals[1].type==v_str )
c->curfv->sf->macstyle = _MacStyleCode(c->a.vals[1].u.sval,NULL,NULL);
else {
c->error = ce_badargtype;
return;
}
}
static void bSetPanose(Context *c) {
int i;
if ( c->a.argc!=2 && c->a.argc!=3 ) {
c->error = ce_wrongnumarg;
return;
}
if ( c->a.argc==2 ) {
if ( c->a.vals[1].type!=v_arr && c->a.vals[1].type!=v_arrfree ) {
c->error = ce_badargtype;
return;
}
if ( c->a.vals[1].u.aval->argc!=10 )
ScriptError(c,"Wrong size of array");
if ( c->a.vals[1].u.aval->vals[0].type!=v_int )
ScriptError(c,"Bad argument sub-type");
SFDefaultOS2Info(&c->curfv->sf->pfminfo,c->curfv->sf,c->curfv->sf->fontname);
for ( i=0; i<10; ++i ) {
if ( c->a.vals[1].u.aval->vals[i].type!=v_int )
ScriptError(c,"Bad argument sub-type");
c->curfv->sf->pfminfo.panose[i] = c->a.vals[1].u.aval->vals[i].u.ival;
}
} else if ( c->a.argc==3 ) {
if ( c->a.vals[1].type!=v_int || c->a.vals[2].type!=v_int) {
c->error = ce_expectint;
return;
}
if ( c->a.vals[1].u.ival<0 || c->a.vals[1].u.ival>=10 )
ScriptError(c,"Bad argument value must be between [0,9]");
SFDefaultOS2Info(&c->curfv->sf->pfminfo,c->curfv->sf,c->curfv->sf->fontname);
c->curfv->sf->pfminfo.panose[c->a.vals[1].u.ival] = c->a.vals[2].u.ival;
}
c->curfv->sf->pfminfo.pfmset = true;
c->curfv->sf->pfminfo.panose_set = true;
c->curfv->sf->changed = true;
}
static void setint16(int16 *val,Context *c) {
if ( c->a.vals[2].type!=v_int )
c->error = ce_badargtype;
else
*val = c->a.vals[2].u.ival;
}
static void setss16(int16 *val,SplineFont *sf,Context *c) {
if ( c->a.vals[2].type!=v_int ) {
c->error = ce_badargtype;
return;
}
*val = c->a.vals[2].u.ival;
sf->pfminfo.subsuper_set = true;
}
static void bSetOS2Value(Context *c) {
int i;
SplineFont *sf = c->curfv->sf;
if ( c->a.vals[1].type!=v_str ) {
c->error = ce_expectstr;
return;
}
SFDefaultOS2Info(&sf->pfminfo,sf,sf->fontname);
if ( strmatch(c->a.vals[1].u.sval,"Weight")==0 ) {
setint16(&sf->pfminfo.weight,c);
} else if ( strmatch(c->a.vals[1].u.sval,"Width")==0 ) {
setint16(&sf->pfminfo.width,c);
} else if ( strmatch(c->a.vals[1].u.sval,"FSType")==0 ) {
setint16(&sf->pfminfo.fstype,c);
} else if ( strmatch(c->a.vals[1].u.sval,"IBMFamily")==0 ) {
setint16(&sf->pfminfo.os2_family_class,c);
} else if ( strmatch(c->a.vals[1].u.sval,"VendorID")==0 ) {
char *pt1, *pt2;
if ( c->a.vals[2].type!=v_str )
ScriptError(c,"Bad argument type");
else if ( strlen(c->a.vals[2].u.sval)>4 )
ScriptError(c,"VendorID string limited to 4 (ASCII) characters");
pt1 = c->a.vals[2].u.sval;
pt2 = sf->pfminfo.os2_vendor;
memset(pt2,' ',4);
while ( *pt1!='\0' )
*pt2++ = *pt1++;
} else if ( strmatch(c->a.vals[1].u.sval,"WinAscent")==0 ) {
setint16(&sf->pfminfo.os2_winascent,c);
} else if ( strmatch(c->a.vals[1].u.sval,"WinAscentIsOffset")==0 ) {
if ( c->a.vals[2].type!=v_int )
ScriptError(c,"Bad argument type");
sf->pfminfo.winascent_add = c->a.vals[2].u.ival;
} else if ( strmatch(c->a.vals[1].u.sval,"WinDescent")==0 ) {
setint16(&sf->pfminfo.os2_windescent,c);
} else if ( strmatch(c->a.vals[1].u.sval,"WinDescentIsOffset")==0 ) {
if ( c->a.vals[2].type!=v_int )
ScriptError(c,"Bad argument type");
sf->pfminfo.windescent_add = c->a.vals[2].u.ival;
} else if ( strmatch(c->a.vals[1].u.sval,"typoAscent")==0 ) {
setint16(&sf->pfminfo.os2_typoascent,c);
} else if ( strmatch(c->a.vals[1].u.sval,"typoAscentIsOffset")==0 ) {
if ( c->a.vals[2].type!=v_int )
ScriptError(c,"Bad argument type");
sf->pfminfo.typoascent_add = c->a.vals[2].u.ival;
} else if ( strmatch(c->a.vals[1].u.sval,"typoDescent")==0 ) {
setint16(&sf->pfminfo.os2_typodescent,c);
} else if ( strmatch(c->a.vals[1].u.sval,"typoDescentIsOffset")==0 ) {
if ( c->a.vals[2].type!=v_int )
ScriptError(c,"Bad argument type");
sf->pfminfo.typodescent_add = c->a.vals[2].u.ival;
} else if ( strmatch(c->a.vals[1].u.sval,"typoLineGap")==0 ) {
setint16(&sf->pfminfo.os2_typolinegap,c);
} else if ( strmatch(c->a.vals[1].u.sval,"hheadAscent")==0 ) {
setint16(&sf->pfminfo.hhead_ascent,c);
} else if ( strmatch(c->a.vals[1].u.sval,"hheadAscentIsOffset")==0 ) {
if ( c->a.vals[2].type!=v_int )
ScriptError(c,"Bad argument type");
sf->pfminfo.hheadascent_add = c->a.vals[2].u.ival;
} else if ( strmatch(c->a.vals[1].u.sval,"hheadDescent")==0 ) {
setint16(&sf->pfminfo.hhead_descent,c);
} else if ( strmatch(c->a.vals[1].u.sval,"hheadDescentIsOffset")==0 ) {
if ( c->a.vals[2].type!=v_int )
ScriptError(c,"Bad argument type");
sf->pfminfo.hheaddescent_add = c->a.vals[2].u.ival;
} else if ( strmatch(c->a.vals[1].u.sval,"LineGap")==0 || strmatch(c->a.vals[1].u.sval,"HHeadLineGap")==0 ) {
setint16(&sf->pfminfo.linegap,c);
} else if ( strmatch(c->a.vals[1].u.sval,"VLineGap")==0 || strmatch(c->a.vals[1].u.sval,"VHeadLineGap")==0 ) {
setint16(&sf->pfminfo.vlinegap,c);
} else if ( strmatch(c->a.vals[1].u.sval,"Panose")==0 ) {
if ( c->a.vals[2].type!=v_arr && c->a.vals[2].type!=v_arrfree )
ScriptError(c,"Bad argument type");
if ( c->a.vals[2].u.aval->argc!=10 )
ScriptError(c,"Wrong size of array");
if ( c->a.vals[2].u.aval->vals[0].type!=v_int )
ScriptError(c,"Bad argument sub-type");
for ( i=0; i<10; ++i ) {
if ( c->a.vals[2].u.aval->vals[i].type!=v_int )
ScriptError(c,"Bad argument sub-type");
sf->pfminfo.panose[i] = c->a.vals[2].u.aval->vals[i].u.ival;
}
sf->pfminfo.panose_set =