summaryrefslogtreecommitdiff
path: root/Build/source/texk/web2c/luatexdir/luafontloader/fontforge/Unicode/usprintf.c
diff options
context:
space:
mode:
Diffstat (limited to 'Build/source/texk/web2c/luatexdir/luafontloader/fontforge/Unicode/usprintf.c')
-rw-r--r--Build/source/texk/web2c/luatexdir/luafontloader/fontforge/Unicode/usprintf.c435
1 files changed, 435 insertions, 0 deletions
diff --git a/Build/source/texk/web2c/luatexdir/luafontloader/fontforge/Unicode/usprintf.c b/Build/source/texk/web2c/luatexdir/luafontloader/fontforge/Unicode/usprintf.c
new file mode 100644
index 00000000000..90ddbad38fe
--- /dev/null
+++ b/Build/source/texk/web2c/luatexdir/luafontloader/fontforge/Unicode/usprintf.c
@@ -0,0 +1,435 @@
+/* Copyright (C) 2001-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.
+ */
+#include <stddef.h>
+#include <stdarg.h>
+#include "ustring.h"
+#include "utype.h"
+
+/* unicode printf. Expect arguments to be given using <num>$ notation */
+/* But there's no way I'm going to implement all of printf now. I'll do what I */
+/* think is important and leave the rest for later. Maybe */
+/* args begin with 1 */
+
+enum arg_type { at_int, at_double, at_ustr, at_astr, at_iptr };
+
+struct args {
+ unsigned int is_alt:1; /* # flag */
+ unsigned int is_zeropad:1; /* 0 flag */
+ unsigned int is_leftadj:1; /* - flag */
+ unsigned int is_blank:1; /* " " flag */
+ unsigned int is_signed:1; /* + flag */
+ unsigned int is_thousand:1; /* ' flag */
+ unsigned int is_short:1; /* h */
+ unsigned int is_long:1; /* l */
+ unsigned int hasformat:1; /* else it's a precision/fieldwidth */
+ char format;
+ int fieldwidth, precision;
+ enum arg_type arg_type;
+ long ival;
+ const unichar_t *uval;
+ double dval;
+};
+
+struct state {
+ int argmax;
+ struct args *args;
+ unichar_t *opt, *end;
+ int cnt;
+};
+
+#define addchar(state,ch) (++((state)->cnt),(state)->opt<(state)->end?*((state)->opt)++ = (ch): 0)
+
+static int isspec(int ch) {
+ char *str = "%npSscaAgGfFeEouxXdi";
+
+ while ( *str && *str!=ch ) ++str;
+return( *str==ch );
+}
+
+static void padvalue(struct state *state,int arg,unichar_t *txt,int fieldwidth) {
+ int len=0, padc;
+
+ padc = state->args[arg].is_zeropad?'0':' ';
+ if ( fieldwidth>0 ) {
+ len = u_strlen(txt);
+ if ( !state->args[arg].is_leftadj ) {
+ while ( len<fieldwidth ) {
+ addchar(state,padc);
+ ++len;
+ }
+ }
+ }
+ while ( *txt ) {
+ addchar(state,*txt);
+ ++txt;
+ }
+ while ( len<fieldwidth ) {
+ addchar(state,padc);
+ ++len;
+ }
+}
+
+static void padstr(struct state *state,int arg,const unichar_t *txt,int fieldwidth, int precision) {
+ int len=0, padc,i;
+
+ if ( fieldwidth>0 ) {
+ len = precision>0?precision:u_strlen(txt);
+ padc = state->args[arg].is_zeropad?'0':' ';
+ if ( !state->args[arg].is_leftadj ) {
+ while ( len<fieldwidth ) {
+ addchar(state,padc);
+ ++len;
+ }
+ }
+ }
+ for ( i=0; *txt && (precision==0 || i<precision); ++i, ++txt )
+ addchar(state,*txt);
+ while ( len<fieldwidth ) {
+ addchar(state,padc);
+ ++len;
+ }
+}
+
+static void formatarg(struct state *state,int arg) {
+ static char *hex = "0123456789abcdef", *HEX="0123456789ABCDEF";
+ char *trans;
+ int radix, neg; unsigned long val;
+ unichar_t buf[20], *pt;
+ char cbuf[20];
+ int i, precision, fieldwidth;
+
+ if ( arg<0 || arg>=state->argmax )
+return;
+ if (( precision = state->args[arg].precision )<0 )
+ precision = state->args[-state->args[arg].precision-1].ival;
+ if (( fieldwidth = state->args[arg].fieldwidth )<0 )
+ fieldwidth = state->args[-state->args[arg].fieldwidth-1].ival;
+ if ( fieldwidth<0 ) {
+ fieldwidth = -fieldwidth;
+ state->args[arg].is_leftadj = true;
+ }
+
+ switch ( state->args[arg].format ) {
+ case 'n':
+ *((int *) (state->args[arg].uval)) = state->cnt;
+ break;
+ case 'c':
+ buf[0] = state->args[arg].ival;
+ buf[1] = '\0';
+ padvalue(state,arg,buf,fieldwidth);
+ break;
+ case 'd': case 'i': case 'o': case 'x': case 'X': case 'u':
+ trans = state->args[arg].format=='X'?HEX:hex;
+ pt = buf+sizeof(buf)/sizeof(buf[0])-1;
+ *pt-- = '\0';
+ neg = false;
+ radix = state->args[arg].format=='d' || state->args[arg].format=='i' ||
+ state->args[arg].format=='u'?10:
+ state->args[arg].format=='o'?8:16;
+ val = state->args[arg].ival;
+ if ( state->args[arg].ival<0 &&
+ (state->args[arg].format=='d' || state->args[arg].format=='i')) {
+ neg = true;
+ val = -val;
+ }
+ for ( i=0; val!=0 || i<precision; ++i ) {
+ if ( radix==10 && state->args[arg].is_thousand && i!=0 && i%3==0 )
+ *pt-- = ','; /* !!!!! locale !!!!! */
+ *pt-- = trans[val%radix];
+ val /= radix;
+ }
+ if ( state->args[arg].is_alt ) {
+ if ( radix==8 && pt[1]!='0' )
+ *pt-- = '0';
+ else if ( radix==16 && state->args[arg].ival!=0 ) {
+ *pt-- = state->args[arg].format;
+ *pt-- = '0';
+ }
+ }
+ if ( state->args[arg].format=='d' || state->args[arg].format=='i' ) {
+ if ( neg )
+ *pt-- = '-';
+ else if ( state->args[arg].is_signed )
+ *pt-- = '+';
+ else if ( state->args[arg].is_blank )
+ *pt-- = ' ';
+ }
+ padvalue(state,arg,pt+1,fieldwidth);
+ break;
+ case 's':
+ if ( state->args[arg].uval == NULL ) {
+ static unichar_t null[] = { '<','n','u','l','l','>', '\0' };
+ padstr(state,arg,null,fieldwidth,precision);
+ } else if ( state->args[arg].is_short ) {
+ unichar_t *temp = def2u_copy((char *) (state->args[arg].uval));
+ padstr(state,arg,temp,fieldwidth,precision);
+ free(temp);
+ } else
+ padstr(state,arg,state->args[arg].uval,fieldwidth,precision);
+ break;
+ case 'e': case 'E': case 'f': case 'F': case 'g': case 'G': case 'a': case 'A':
+ /* This doesn't really do a good job!!!! */
+ switch ( state->args[arg].format ) {
+ case 'e': case 'E':
+ sprintf(cbuf,"%e",state->args[arg].dval);
+ break;
+ case 'f': case 'F':
+ sprintf(cbuf,"%f",state->args[arg].dval);
+ break;
+ case 'g': case 'G':
+ sprintf(cbuf,"%g",state->args[arg].dval);
+ break;
+ case 'a': case 'A':
+ sprintf(cbuf,"%a",state->args[arg].dval);
+ break;
+ }
+ uc_strcpy(buf,cbuf);
+ padvalue(state,arg,buf,fieldwidth);
+ break;
+ /* a 'p' conversion is converted into the equivalent 'x' conversion earlier */
+ }
+}
+
+int u_vsnprintf(unichar_t *str, int len, const unichar_t *format, va_list ap ) {
+ struct state state;
+ struct args args[20], temp;
+ const unichar_t *pt;
+ int argmax = 0, arg, ac, val, hadarg;
+
+ memset(&state,'\0',sizeof(state));
+ memset(args,'\0',sizeof(args));
+ ac = 0;
+ for ( pt=format; *pt; ) {
+ if ( *pt!='%' )
+ ++pt;
+ else if ( pt[1]=='%' )
+ pt += 2;
+ else {
+ for ( ++pt, arg=0; isdigit(*pt); ++pt )
+ arg = 10*arg + tovalue(*pt);
+ ++ac;
+ if ( *pt=='$' ) {
+ if ( arg>argmax ) argmax = arg;
+ } else {
+ if ( ac>argmax ) argmax = ac;
+ }
+ while ( *pt && !isspec(*pt)) {
+ if ( *pt=='*' ) {
+ ++ac;
+ ++pt;
+ for ( ++pt, arg=0; isdigit(*pt); ++pt )
+ arg = 10*arg + tovalue(*pt);
+ if ( *pt=='$' ) {
+ if ( arg>argmax ) argmax = arg;
+ } else {
+ if ( ac>argmax ) argmax = ac;
+ }
+ }
+ ++pt;
+ }
+ }
+ }
+ state.argmax = argmax;
+ if ( argmax>sizeof(args)/sizeof(args[0]) )
+ state.args = (struct args *) gcalloc(argmax,sizeof(struct args));
+ else
+ state.args = args;
+ state.opt = str; state.end = str+len;
+
+ ac = 1;
+ for ( pt=format; *pt; ) {
+ if ( *pt!='%' )
+ ++pt;
+ else if ( pt[1]=='%' )
+ pt+=2;
+ else {
+ ++pt;
+ memset(&temp,'\0',sizeof(temp));
+ hadarg = 0;
+ if ( isdigit(*pt)) {
+ for ( arg=0; isdigit(*pt); ++pt )
+ arg = 10*arg + tovalue(*pt);
+ if ( *pt=='$' ) {
+ hadarg = true;
+ ++pt;
+ } else
+ temp.fieldwidth = arg;
+ }
+ while ( 1 ) {
+ if ( *pt=='#' ) temp.is_alt=true;
+ else if ( *pt=='0' ) temp.is_zeropad=true;
+ else if ( *pt=='-' ) temp.is_leftadj=true;
+ else if ( *pt==' ' ) temp.is_blank=true;
+ else if ( *pt=='+' ) temp.is_signed=true;
+ else if ( *pt=='\'' ) temp.is_thousand=true;
+ else
+ break;
+ ++pt;
+ }
+ if ( *pt=='*' ) {
+ temp.fieldwidth = -ac++;
+ for ( ++pt, val=0; isdigit(*pt); ++pt )
+ val = 10*val + tovalue(*pt);
+ if ( *pt=='$' ) temp.fieldwidth = -val;
+ } else if ( isdigit(*pt)) {
+ while ( isdigit(*pt)) {
+ temp.fieldwidth = 10*temp.fieldwidth + tovalue(*pt);
+ ++pt;
+ }
+ }
+ temp.precision = 0x800000;
+ if ( *pt=='.' ) {
+ ++pt;
+ if ( *pt=='*' ) {
+ temp.precision = -ac++;
+ for ( ++pt, val=0; isdigit(*pt); ++pt )
+ val = 10*val + tovalue(*pt);
+ if ( *pt=='$' ) temp.precision = -val;
+ } else if ( isdigit(*pt)) {
+ temp.precision = 0;
+ while ( isdigit(*pt)) {
+ temp.precision = 10*temp.precision + tovalue(*pt);
+ ++pt;
+ }
+ }
+ }
+ if ( *pt=='h' ) { temp.is_short=true; ++pt; }
+ else if ( *pt=='l' ) { temp.is_long=true; ++pt; }
+ if ( temp.fieldwidth<0 )
+ state.args[-temp.fieldwidth-1].arg_type = at_int;
+ if ( temp.precision<0 )
+ state.args[-temp.precision-1].arg_type = at_int;
+ temp.format = *pt++;
+ temp.hasformat = true;
+ if ( temp.format=='d' || temp.format=='i' || temp.format=='o' ||
+ temp.format=='u' || temp.format=='x' || temp.format=='X' ||
+ temp.format=='c' ) {
+ temp.arg_type = at_int;
+ if ( temp.precision == (int) 0x800000 ) temp.precision = 1;
+ } else if ( temp.format=='e' || temp.format=='E' || temp.format=='f' ||
+ temp.format=='F' || temp.format=='g' || temp.format=='G' ) {
+ temp.arg_type = at_double;
+ if ( temp.precision == (int) 0x800000 ) temp.precision = 6;
+ } else if ( temp.format=='a' || temp.format=='A' ) {
+ /* aA hex conversion of double */
+ temp.arg_type = at_double;
+ if ( temp.precision == (int) 0x800000 ) temp.precision = 2*sizeof(double)-2;
+ } else if ( temp.format=='s' && temp.is_short )
+ temp.arg_type = at_astr;
+ else if ( temp.format=='s' )
+ temp.arg_type = at_ustr;
+ else if ( temp.format=='p' ) {
+ temp.arg_type = at_int;
+ temp.format = 'x';
+ temp.is_alt = true;
+ if ( sizeof(int) < sizeof( void * ) )
+ temp.is_long = true;
+ } else if ( temp.format=='n' )
+ temp.arg_type = at_iptr;
+ if ( !hadarg ) arg = ac;
+ ++ac;
+ state.args[arg-1] = temp;
+ }
+ }
+
+ /* Now read the args in order */
+ for ( arg=0; arg<argmax; ++arg ) {
+ switch ( state.args[arg].arg_type ) {
+ case at_int:
+ if ( state.args[arg].is_long )
+ state.args[arg].ival = va_arg(ap,long);
+ else
+ state.args[arg].ival = va_arg(ap,int);
+ break;
+ case at_double:
+ state.args[arg].dval = va_arg(ap,double);
+ break;
+ case at_ustr:
+ state.args[arg].uval = va_arg(ap,unichar_t *);
+ break;
+ case at_astr:
+ state.args[arg].uval = (unichar_t *) va_arg(ap,char *);
+ break;
+ case at_iptr:
+ state.args[arg].uval = (unichar_t *) va_arg(ap,int *);
+ break;
+ default:
+ /* Shouldn't get here, if we do, skip one arg */
+ (void) va_arg(ap,int);
+ break;
+ }
+ }
+
+ ac = 1;
+ for ( pt=format; *pt; ) {
+ if ( *pt!='%' ) {
+ addchar(&state,*pt);
+ ++pt;
+ } else if ( pt[1]=='%' ) {
+ addchar(&state,'%');
+ pt+=2;
+ } else {
+ for ( ++pt, arg=0; isdigit(*pt); ++pt )
+ arg = 10*arg + tovalue(*pt);
+ if ( *pt!='$' ) {
+ arg = ac;
+ if ( !state.args[arg-1].hasformat ) ++arg;
+ if ( !state.args[arg-1].hasformat ) ++arg;
+ }
+ if ( state.args[arg-1].fieldwidth<0 ) ++ac;
+ if ( state.args[arg-1].precision<0 && state.args[arg-1].precision!= (int) 0x800000)
+ ++ac;
+ ++ac;
+ while ( *pt && !isspec(*pt)) ++pt;
+ formatarg(&state,arg-1);
+ ++pt;
+ }
+ }
+ addchar(&state,'\0');
+ if ( state.args!=args ) free(state.args);
+return( state.cnt-1 ); /* don't include trailing nul */
+}
+
+int u_snprintf(unichar_t *str, int len, const unichar_t *format, ... ) {
+ va_list ap;
+ int ret;
+
+ va_start(ap,format);
+ ret = u_vsnprintf(str,len,format,ap);
+ va_end(ap);
+return( ret );
+}
+
+int u_sprintf(unichar_t *str, const unichar_t *format, ... ) {
+ va_list ap;
+ int ret;
+
+ va_start(ap,format);
+ ret = u_vsnprintf(str,0x10000,format,ap);
+ va_end(ap);
+return( ret );
+}