Tailorization of trunk

Tue, 15 Feb 2005 18:57:52 +0100

author
tailor@f281.ttorni.ton.tut.fi
date
Tue, 15 Feb 2005 18:57:52 +0100
changeset 0
86b7f6f9c5c0
child 1
6e704fc09528

Tailorization of trunk
Import of the upstream sources from the repository

http://tao.uab.es/ion/svn/libtu/trunk

as of revision 2

LICENSE file | annotate | diff | comparison | revisions
Makefile file | annotate | diff | comparison | revisions
README file | annotate | diff | comparison | revisions
include/misc.h file | annotate | diff | comparison | revisions
include/optparser.h file | annotate | diff | comparison | revisions
include/output.h file | annotate | diff | comparison | revisions
include/parser.h file | annotate | diff | comparison | revisions
include/tokenizer.h file | annotate | diff | comparison | revisions
include/types.h file | annotate | diff | comparison | revisions
include/util.h file | annotate | diff | comparison | revisions
misc.c file | annotate | diff | comparison | revisions
np-conv.h file | annotate | diff | comparison | revisions
numparser2.h file | annotate | diff | comparison | revisions
optparser.c file | annotate | diff | comparison | revisions
output.c file | annotate | diff | comparison | revisions
parser.c file | annotate | diff | comparison | revisions
tester.c file | annotate | diff | comparison | revisions
tester2.c file | annotate | diff | comparison | revisions
tester3.c file | annotate | diff | comparison | revisions
tokenizer.c file | annotate | diff | comparison | revisions
util.c file | annotate | diff | comparison | revisions
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/LICENSE	Tue Feb 15 18:57:52 2005 +0100
@@ -0,0 +1,125 @@
+                      The "Artistic License"
+
+                             Preamble
+
+The intent of this document is to state the conditions under which a
+Package may be copied, such that the Copyright Holder maintains some
+semblance of artistic control over the development of the Package,
+while giving the users of the package the right to use and distribute
+the Package in a more-or-less customary fashion, plus the right to make
+reasonable modifications.
+
+It also grants you the rights to reuse parts of a Package in your own
+programs without transferring this License to those programs, provided
+that you meet some reasonable requirements.
+
+Definitions:
+
+        "Package" refers to the collection of files distributed by the
+        Copyright Holder, and derivatives of that collection of files
+        created through textual modification.
+
+        "Standard Version" refers to such a Package if it has not been
+        modified, or has been modified in accordance with the wishes
+        of the Copyright Holder as specified below.
+
+        "Copyright Holder" is whoever is named in the copyright or
+        copyrights for the package.
+
+        "You" is you, if you're thinking about copying or distributing
+        this Package.
+
+        "Reasonable copying fee" is whatever you can justify on the
+        basis of media cost, duplication charges, time of people involved,
+        and so on.  (You will not be required to justify it to the
+        Copyright Holder, but only to the computing community at large
+        as a market that must bear the fee.)
+
+        "Freely Available" means that no fee is charged for the item
+        itself, though there may be fees involved in handling the item.
+        It also means that recipients of the item may redistribute it
+        under the same conditions they received it.
+
+1. You may make and give away verbatim copies of the source form of the
+Standard Version of this Package without restriction, provided that you
+duplicate all of the original copyright notices and associated disclaimers.
+
+2. You may apply bug fixes, portability fixes and other modifications
+derived from the Public Domain or from the Copyright Holder.  A Package
+modified in such a way shall still be considered the Standard Version.
+
+3. You may otherwise modify your copy of this Package in any way, provided
+that you insert a prominent notice in each changed file stating how and
+when you changed that file, and provided that you do at least ONE of the
+following:
+
+    a) place your modifications in the Public Domain or otherwise make them
+    Freely Available, such as by posting said modifications to Usenet or
+    an equivalent medium, or placing the modifications on a major archive
+    site such as uunet.uu.net, or by allowing the Copyright Holder to include
+    your modifications in the Standard Version of the Package.
+
+    b) use the modified Package only within your corporation or organization.
+
+    c) rename any non-standard executables so the names do not conflict
+    with standard executables, which must also be provided, and provide
+    a separate manual page for each non-standard executable that clearly
+    documents how it differs from the Standard Version.
+
+    d) make other distribution arrangements with the Copyright Holder.
+
+4. You may distribute the programs of this Package in object code or
+executable form, provided that you do at least ONE of the following:
+
+    a) distribute a Standard Version of the executables and library files,
+    together with instructions (in the manual page or equivalent) on where
+    to get the Standard Version.
+
+    b) accompany the distribution with the machine-readable source of
+    the Package with your modifications.
+
+    c) give non-standard executables non-standard names, and clearly
+    document the differences in manual pages (or equivalent), together
+    with instructions on where to get the Standard Version.
+
+    d) make other distribution arrangements with the Copyright Holder.
+
+5. You may charge a reasonable copying fee for any distribution of this
+Package.  You may charge any fee you choose for support of this
+Package.  You may not charge a fee for this Package itself.  However,
+you may distribute this Package in aggregate with other (possibly
+commercial) programs as part of a larger (possibly commercial) software
+distribution provided that you do not advertise this Package as a
+product of your own.
+
+6. The scripts and library files supplied as input to or produced as
+output from the programs of this Package do not automatically fall
+under the copyright of this Package, but belong to whomever generated
+them, and may be sold commercially, and may be aggregated with this
+Package.  If such scripts or library files are aggregated with this
+Package via the so-called "undump" or "unexec" methods of producing a
+binary executable image, then distribution of such an image shall
+neither be construed as a distribution of this Package nor shall it
+fall under the restrictions of Paragraphs 3 and 4, provided that you do
+not represent such an executable image as a Standard Version of this
+Package.
+
+7. You may reuse parts of this Package in your own programs, provided that
+you explicitly state where you got them from, in the source code (and, left
+to your courtesy, in the documentation), duplicating all the associated
+copyright notices and disclaimers. Besides your changes, if any, must be
+clearly marked as such. Parts reused that way will no longer fall under this
+license if, and only if, the name of your program(s) have no immediate
+connection with the name of the Package itself or its associated programs.
+You may then apply whatever restrictions you wish on the reused parts or
+choose to place them in the Public Domain--this will apply only within the
+context of your package.
+
+8. The name of the Copyright Holder may not be used to endorse or promote
+products derived from this software without specific prior written permission.
+
+9. THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+
+                                The End
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Makefile	Tue Feb 15 18:57:52 2005 +0100
@@ -0,0 +1,75 @@
+#
+# libtu Makefile
+#
+
+# Where to install? ($PREFIX/lib/libtu.a, $PREFIX/include/libtu/)
+#
+PREFIX=/usr/local
+
+# Any extra defines needed
+#
+#DEFINES=
+
+# Any extra include paths needed
+#
+#INCLUDES=
+
+######################################
+
+WARN=	-W -Wimplicit -Wreturn-type -Wswitch -Wcomment \
+	-Wtrigraphs -Wformat -Wchar-subscripts -Wuninitialized \
+	-Wparentheses -pedantic-errors
+
+CC_FLAGS=-g -O2 -ansi $(DEFINES) $(INCLUDES) $(WARN)
+CC=gcc
+AR=ar
+AR_FLAGS=crs
+
+INSTALL=install
+MODE=644
+
+######################################
+
+OBJS= misc.o output.o util.o optparser.o parser.o tokenizer.o
+	
+DEPEND= .depend
+
+LIBDIR=$(PREFIX)/lib
+INCDIR=$(PREFIX)/include/libtu
+
+TARGETS=libtu.a
+TESTERS=tester tester2 tester3
+
+######################################
+
+all: $(TARGETS)
+
+testers: $(TESTERS)
+
+libtu.a: $(OBJS)
+	$(AR) $(AR_FLAGS) $@ $+
+
+%: %.c
+	$(CC) $(CC_FLAGS) $+ -L. -ltu -lm -o $@
+
+%.o: %.c
+	$(CC) $(CC_FLAGS) -c $< -o $@
+
+clean:
+	rm -f $(OBJS) $(DEPEND)
+
+realclean: clean
+	rm -f $(TARGETS)
+
+depend:
+	$(CC) -M $(CC_FLAGS) *.c > $(DEPEND)
+
+install:
+	$(INSTALL) -d $(LIBDIR)
+	$(INSTALL) -d $(INCDIR)
+	$(INSTALL) -m $(MODE) libtu.a $(LIBDIR)
+	$(INSTALL) -m $(MODE) include/* $(INCDIR)
+
+ifeq ($(DEPEND),$(wildcard $(DEPEND)))
+include $(DEPEND)
+endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/README	Tue Feb 15 18:57:52 2005 +0100
@@ -0,0 +1,22 @@
+
+
+                                    libtu
+				 
+		   Copyright (c) Tuomo Valkonen 1999-2000.
+		    
+                             <tuomov@cc.tut.fi>
+		  
+		  
+
+Libtu is a small utility library for programs written in C. Naturally,
+libtu is free software under the "Artistic License". See the file
+LICENSE for details.
+
+To build the library, first edit Makefile to customize it for your
+system if necessary. Then 'make depend && make'.
+To install it run 'make install' (perhaps as root depending on
+where you are installing it).
+
+If you want to use it in your programs, you may try to figure out how
+by reading the header files (include/*.h) and test programs (tester*.c).
+Or you could try urging me to write some sort of a manual.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/include/misc.h	Tue Feb 15 18:57:52 2005 +0100
@@ -0,0 +1,41 @@
+/*
+ * libtu/misc.h
+ *
+ * Copyright (c) Tuomo Valkonen 1999-2000.
+ * 
+ * This file is distributed under the terms of the "Artistic License".
+ * See the included file LICENSE for details.
+ */
+
+#ifndef __LIBTU_MISC_H
+#define __LIBTU_MISC_H
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <malloc.h>
+#include <assert.h>
+#include "types.h"
+
+#define TR(X) X
+#define DUMMY_TR(X) X
+
+#define ALLOC(X) (X*)malloczero(sizeof(X))
+#define ALLOC_N(X, N) (X*)malloczero(sizeof(X)*(N))
+#define REALLOC_N(PTR, X, S, N) (X*)remalloczero(PTR, sizeof(X)*(S), sizeof(X)*(N))
+
+#define FREE(X) ({if(X!=NULL) free(X);})
+
+extern void* malloczero(int size);
+extern void* remalloczero(void *ptr, int oldsize, int newsize);
+
+extern char* scopy(const char *p);
+extern char* scat(const char *p1, const char *p2);
+extern char* scat3(const char *p1, const char *p2, const char *p3);
+
+extern const char* simple_basename(const char *name);
+
+/* I dislike fread and fwrite... */
+extern bool readf(FILE *fd, void *buf, size_t n);
+extern bool writef(FILE *fd, const void *buf, size_t n);
+
+#endif /* __LIBTU_MISC_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/include/optparser.h	Tue Feb 15 18:57:52 2005 +0100
@@ -0,0 +1,56 @@
+/*
+ * libtu/optparser.h
+ *
+ * Copyright (c) Tuomo Valkonen 1999-2000.
+ * 
+ * This file is distributed under the terms of the "Artistic License".
+ * See the included file LICENSE for details.
+ */
+
+#ifndef __LIBTU_OPTPARSER_H
+#define __LIBTU_OPTPARSER_H
+
+#include "types.h"
+
+
+#define OPT_ID(X)			((X)|0x10000)
+#define OPT_ID_RESERVED(X)	((X)|0x20000)
+
+enum{
+	OPT__IMM_ARG=0x0100,
+	OPT_IMM_ARG=0x0101,			/* may have immediate argument (-fblaah) 	*/
+	OPT_CHAINABLE=0x0200,		/* chainable (-xzf)							*/
+	OPT_NO_DASH=0x0400,			/* dash not necessary (xzf)					*/
+	OPT_MIDLONG=0x0800,			/* have midlong opt (-help)					*/
+	OPT_NO_LONG=0x1000,			/* no long opt (--help)						*/
+	OPT_ARG=1,					/* option has an argument					*/
+	OPT_OPT_ARG=3				/* option may have an argument				*/
+};
+
+
+typedef struct{
+	int optid;
+	const char *longopt;
+	int	flags;
+} OptParserOpt;
+
+
+enum{
+	OPT_ID_END=0,
+	OPT_ID_ARGUMENT=1,
+
+	E_OPT_INVALID_OPTION=-1,
+	E_OPT_INVALID_CHAIN_OPTION=-2,
+	E_OPT_SYNTAX_ERROR=-3,
+	E_OPT_MISSING_ARGUMENT=-4,
+	E_OPT_UNEXPECTED_ARGUMENT=-5
+};
+
+
+extern void optparser_init(int argc, char *const argv[],
+						   const OptParserOpt *opts);
+extern int  optparser_get_opt();
+extern const char* optparser_get_arg();
+extern void optparser_print_error();
+
+#endif /* __LIBTU_OPTPARSER_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/include/output.h	Tue Feb 15 18:57:52 2005 +0100
@@ -0,0 +1,50 @@
+/*
+ * libtu/output.h
+ *
+ * Copyright (c) Tuomo Valkonen 1999-2000.
+ * 
+ * This file is distributed under the terms of the "Artistic License".
+ * See the included file LICENSE for details.
+ */
+
+#ifndef __LIBTU_OUTPUT_H
+#define __LIBTU_OUTPUT_H
+
+#include <stdarg.h>
+
+#include "types.h"
+
+
+extern void verbose(const char *p, ...);
+extern void verbose_v(const char *p, va_list args);
+extern void verbose_enable(bool enable);
+extern int verbose_indent(int depth);
+
+extern void warn_progname_enable(bool enable);
+
+extern void die(const char *p, ...);
+extern void die_v(const char *p, va_list args);
+
+extern void die_obj(const char *obj, const char *p, ...);
+extern void die_obj_v(const char *obj, const char *p, va_list args);
+extern void die_obj_line(const char *obj, int line, const char *p, ...);
+extern void die_obj_line_v(const char *obj, int line, const char *p, va_list args);
+
+extern void die_err();
+extern void die_err_obj(const char *obj);
+extern void die_err_obj_line(const char *obj, int line);
+
+
+extern void warn(const char *p, ...);
+extern void warn_v(const char *p, va_list args);
+
+extern void warn_obj(const char *obj, const char *p, ...);
+extern void warn_obj_v(const char *obj, const char *p, va_list args);
+extern void warn_obj_line(const char *obj, int line, const char *p, ...);
+extern void warn_obj_line_v(const char *obj, int line, const char *p, va_list args);
+
+extern void warn_err();
+extern void warn_err_obj(const char *obj);
+extern void warn_err_obj_line(const char *obj, int line);
+
+#endif /* __LIBTU_OUTPUT_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/include/parser.h	Tue Feb 15 18:57:52 2005 +0100
@@ -0,0 +1,45 @@
+/*
+ * libtu/parser.h
+ *
+ * Copyright (c) Tuomo Valkonen 1999-2000.
+ * 
+ * This file is distributed under the terms of the "Artistic License".
+ * See the included file LICENSE for details.
+ */
+
+#ifndef __LIBTU_PARSER_H
+#define __LIBTU_PARSER_H
+
+#include "tokenizer.h"
+
+/*
+ * format:
+ * 	l = long
+ *	d = double
+ * 	i = identifier
+ * 	s = string
+ * 	c = char
+ *  . = 1 times any     ("l.d")
+ *  * = 0 or more times any (must be the last, "sd*")
+ * 	? = optional		("?c")
+ * 	: = conditional		(":c:s")
+ * 
+ * special entries:
+ * 
+ * "#end" 		call this handler at the end of section.
+ * "#cancel" 	call this handler when recovering from error
+ */
+
+typedef struct _ConfOpt{
+	const char *optname;
+	const char *argfmt;
+	bool (*fn)(Tokenizer *tokz, int n, Token *toks);
+	struct _ConfOpt *opts;
+} ConfOpt;
+
+
+extern bool parse_config_tokz(Tokenizer *tokz, const ConfOpt *options);
+extern bool parse_config(const char *fname, const ConfOpt *options);
+extern bool parse_config_file(FILE *file, const ConfOpt *options);
+
+#endif /* __LIBTU_PARSER_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/include/tokenizer.h	Tue Feb 15 18:57:52 2005 +0100
@@ -0,0 +1,170 @@
+/*
+ * libtu/tokenizer.h
+ *
+ * Copyright (c) Tuomo Valkonen 1999-2000.
+ * 
+ * This file is distributed under the terms of the "Artistic License".
+ * See the included file LICENSE for details.
+ */
+
+#ifndef __LIBTU_TOKENIZER_H
+#define __LIBTU_TOKENIZER_H
+
+#include <stdio.h>
+#include "types.h"
+
+
+#define TOK_SET_LONG(TOK, VAL) 		{(TOK)->type=TOK_LONG; (TOK)->u.lval=VAL;}
+#define TOK_SET_DOUBLE(TOK, VAL) 	{(TOK)->type=TOK_DOUBLE; (TOK)->u.dval=VAL;}
+#define TOK_SET_CHAR(TOK, VAL) 		{(TOK)->type=TOK_CHAR; (TOK)->u.cval=VAL;}
+#define TOK_SET_STRING(TOK, VAL) 	{(TOK)->type=TOK_STRING; (TOK)->u.sval=VAL;}
+#define TOK_SET_IDENT(TOK, VAL) 	{(TOK)->type=TOK_IDENT; (TOK)->u.sval=VAL;}
+#define TOK_SET_COMMENT(TOK, VAL) 	{(TOK)->type=TOK_COMMENT; (TOK)->u.sval=VAL;}
+#define TOK_SET_OP(TOK, VAL) 		{(TOK)->type=TOK_OP; (TOK)->u.opval=VAL;}
+
+#define TOK_TYPE(TOK)				((TOK)->type)
+#define TOK_LONG_VAL(TOK)			((TOK)->u.lval)
+#define TOK_DOUBLE_VAL(TOK)			((TOK)->u.dval)
+#define TOK_CHAR_VAL(TOK)			((TOK)->u.cval)
+#define TOK_STRING_VAL(TOK)			((TOK)->u.sval)
+#define TOK_IDENT_VAL(TOK)			((TOK)->u.sval)
+#define TOK_COMMENT_VAL(TOK)		((TOK)->u.sval)
+#define TOK_OP_VAL(TOK)				((TOK)->u.opval)
+
+#define TOK_IS_LONG(TOK)			((TOK)->type==TOK_LONG)
+#define TOK_IS_DOUBLE(TOK)			((TOK)->type==TOK_DOUBLE)
+#define TOK_IS_CHAR(TOK)			((TOK)->type==TOK_CHAR)
+#define TOK_IS_STRING(TOK)			((TOK)->type==TOK_STRING)
+#define TOK_IS_IDENT(TOK)			((TOK)->type==TOK_IDENT)
+#define TOK_IS_COMMENT(TOK)			((TOK)->type==TOK_COMMENT)
+#define TOK_IS_OP(TOK)				((TOK)->type==TOK_OP)
+
+#define TOK_OP_IS(TOK, OP)			((TOK)->type==TOK_OP && (TOK)->u.opval==(OP))
+
+#define TOK_TAKE_STRING_VAL(TOK)	((TOK)->type=TOK_INVALID, (TOK)->u.sval)
+#define TOK_TAKE_IDENT_VAL(TOK)		((TOK)->type=TOK_INVALID, (TOK)->u.sval)
+#define TOK_TAKE_COMMENT_VAL(TOK)	((TOK)->type=TOK_INVALID, (TOK)->u.sval)
+
+
+enum{
+	TOK_INVALID=0,
+	TOK_LONG,
+	TOK_DOUBLE,
+	TOK_CHAR,
+	TOK_STRING,
+	TOK_IDENT,
+	TOK_COMMENT,
+	TOK_OP
+};
+
+
+enum{
+#define OP2(X,Y)   ((X)|((Y)<<8))
+#define OP3(X,Y,Z) ((X)|((Y)<<8)|((Z)<<16))
+
+	OP_L_PAR=	'(', OP_R_PAR=	')', OP_L_BRK=	'[', OP_R_BRK=	']',
+	OP_L_BRC=	'{', OP_R_BRC=	'}', OP_COMMA=	',', OP_SCOLON=	';',
+
+	OP_PLUS=	'+', OP_MINUS=	'-', OP_MUL=	'*', OP_DIV=	'/',
+	OP_MOD=		'%', OP_POW=	'^', OP_OR= 	'|', OP_AND=	'&',
+	/*OP_NOT=	'~',*/ OP_NOT=	'!', OP_ASGN=	'=', OP_LT=		'<',
+	OP_GT=		'>', OP_DOT=	'.', OP_COLON=	':', OP_QMARK=	'?',
+	OP_AT=		'@',
+	OP_NEXTLINE='\n',OP_EOF=	-1,
+	
+	OP_INC=		OP2('+','+'),		 OP_DEC=	OP2('-','-'),
+	OP_LSHIFT=	OP2('<','<'), 		 OP_RSHIFT=	OP2('>','>'),
+	OP_AS_INC=	OP2('+','='), 		 OP_AS_DEC= OP2('-','='),
+	OP_AS_MUL=	OP2('*','='), 		 OP_AS_DIV= OP2('/','='),
+	OP_AS_MOD=	OP2('%','='), 		 OP_AS_POW= OP2('^','='),
+
+/*	AS_OR=		OP2('|','='),		 AS_AND=	OP2('&','='), */
+	OP_EQ=		OP2('=','='), 		 OP_NE=		OP2('!','='),
+	OP_LE=		OP2('<','='), 		 OP_GE=		OP2('>','=')
+	
+/*	L_AND=		OP2('&','&'), L_OR=		OP2('|','|'),
+	L_XOR=		OP2('^','^'), */
+
+/*	AsLShift=	OP3('<','<','='),
+	AsRShift=	OP3('>','>','='), */
+		
+#undef OP2
+#undef OP3
+};
+
+
+typedef struct{
+	int type;
+	int line;
+	union{
+		long lval;
+		double dval;
+		char cval;
+		char *sval;
+		int opval;
+	} u;
+} Token;
+
+#define TOK_INIT {0, 0, {0}}
+
+
+extern void tok_free(Token*tok);
+extern void tok_init(Token*tok);
+
+
+/* */
+
+
+enum{
+	TOKZ_IGNORE_NEXTLINE=0x1,
+	TOKZ_READ_COMMENTS=0x2,
+	TOKZ_PARSER_INDENT_MODE=0x4
+};
+
+
+enum{
+	E_TOKZ_UNEXPECTED_EOF=1,
+	E_TOKZ_UNEXPECTED_EOL,
+	E_TOKZ_EOL_EXPECTED,
+	E_TOKZ_INVALID_CHAR,
+	E_TOKZ_TOOBIG,
+	E_TOKZ_NUMFMT,
+	E_TOKZ_NUM_JUNK,
+	E_TOKZ_NOTINT,
+	E_TOKZ_RANGE,
+	E_TOKZ_MULTICHAR,
+	
+	E_TOKZ_TOKEN_LIMIT,
+	E_TOKZ_UNKNOWN_OPTION,
+	E_TOKZ_SYNTAX,
+	E_TOKZ_INVALID_ARGUMENT,
+	E_TOKZ_EOS_EXPECTED,
+	E_TOKZ_TOO_FEW_ARGS,
+	E_TOKZ_TOO_MANY_ARGS,
+	E_TOKZ_MAX_NEST,
+	E_TOKZ_UNEXPECTED_EOS,
+	E_TOKZ_IDENTIFIER_EXPECTED
+};
+
+
+struct _ConfOpt;
+
+typedef struct{
+	FILE *file;
+	const char *name;
+	int flags;
+	int line;
+	int ungetc;
+	const struct _ConfOpt **optstack;
+	int nest_lvl;
+	void *user_data;
+} Tokenizer;
+
+
+extern Tokenizer *tokz_open(const char *fname);
+extern Tokenizer *tokz_open_file(FILE *file);
+extern void tokz_close(Tokenizer *tokz);
+extern bool tokz_get_token(Tokenizer *tokz, Token *tok);
+extern void tokz_warn_error(const Tokenizer *tokz, int line, int e);
+
+#endif /* __LIBTU_TOKENIZER_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/include/types.h	Tue Feb 15 18:57:52 2005 +0100
@@ -0,0 +1,80 @@
+/*
+ * libtu/types.h
+ *
+ * Copyright (c) Tuomo Valkonen 1999-2000.
+ * 
+ * This file is distributed under the terms of the "Artistic License".
+ * See the included file LICENSE for details.
+ */
+
+#ifndef __LIBTU_TYPES_H
+#define __LIBTU_TYPES_H
+
+#include <sys/types.h>
+
+#ifndef TRUE
+ #define TRUE 1
+#endif
+
+#ifndef FALSE
+ #define FALSE 0
+#endif
+
+#ifndef NULL
+ #define NULL ((void*)0)
+#endif
+
+#ifndef LIBTU_TYPEDEF_UXXX
+
+ /* All systems seem to define these whichever way they want to
+  * despite -D_*_SOURCE etc. so there is no easy way to know whether
+  * they can be typedef'd or not. Unless you want to go through using
+  * autoconf or similar methods. ==> Just stick to #define. :-(
+  */
+  
+ #ifndef uchar
+  #define uchar	unsigned char
+ #endif
+ #ifndef ushort
+  #define ushort unsigned short
+ #endif
+ #ifndef uint
+  #define uint unsigned int
+ #endif
+ #ifndef ulong
+  #define ulong	unsigned long
+ #endif
+
+#else /* LIBTU_TYPEDEF_UXXX */
+
+ #ifndef uchar
+  typedef unsigned char uchar;
+ #endif
+ #ifndef ushort
+  typedef unsigned short ushort;
+ #endif
+ #ifndef uint
+  typedef unsigned int uint;
+ #endif
+ #ifndef ulong
+  typedef unsigned long ulong;
+ #endif
+ 
+#endif /* LIBTU_TYPEDEF_UXXX */
+
+
+#ifndef LIBTU_TYPEDEF_BOOL
+
+ #ifndef bool
+  #define bool int
+ #endif
+ 
+#else /* LIBTU_TYPEDEF_BOOL */
+
+ #ifndef bool
+  typedef int bool;
+ #endif
+ 
+#endif /* LIBTU_TYPEDEF_BOOL */
+
+#endif /* __LIBTU_TYPES_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/include/util.h	Tue Feb 15 18:57:52 2005 +0100
@@ -0,0 +1,40 @@
+/*
+ * libtu/util.h
+ *
+ * Copyright (c) Tuomo Valkonen 1999-2000.
+ * 
+ * This file is distributed under the terms of the "Artistic License".
+ * See the included file LICENSE for details.
+ */
+
+#ifndef __LIBTU_UTIL_H
+#define __LIBTU_UTIL_H
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "types.h"
+
+
+typedef struct{
+	const char *name;
+	const char *version;
+	const char *authors;
+	const char *license;
+	const char *usage;
+} ProgInfo;
+
+
+extern void libtu_init_argv0(const char *argv0, const ProgInfo *info);
+extern void libtu_init(int *argc, char *argv[], const ProgInfo *info);
+
+extern const char *prog_execname();
+extern const ProgInfo *prog_info();
+extern const char *prog_name();
+extern const char *prog_version();
+extern const char *prog_authors();
+extern const char *prog_license();
+extern const char *prog_usage();
+
+#endif /* __LIBTU_UTIL_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/misc.c	Tue Feb 15 18:57:52 2005 +0100
@@ -0,0 +1,149 @@
+/*
+ * libtu/misc.c
+ *
+ * Copyright (c) Tuomo Valkonen 1999-2000.
+ * 
+ * This file is distributed under the terms of the "Artistic License".
+ * See the included file LICENSE for details.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <malloc.h>
+
+#include "include/misc.h"
+
+
+void *malloczero(int size)
+{
+	void *p=malloc(size);
+	
+	if(p!=NULL)
+		memset(p, 0, size);
+	
+	return p;
+}
+
+
+void *remalloczero(void *ptr, int oldsize, int newsize)
+{
+	void *p=NULL;
+	
+	if(newsize!=0){
+		p=malloc(newsize);
+	
+		if(p==NULL)
+			return NULL;
+	
+		memset(p, 0, newsize);
+	
+		if(ptr!=NULL && oldsize<newsize)
+			memcpy(p, ptr, oldsize);
+	}
+	
+	if(ptr!=NULL)
+		free(ptr);
+
+	return p;
+}
+
+
+char *scopy(const char *p)
+{
+	char*pn;
+	size_t l=strlen(p);
+	
+	pn=(char*)malloc(l+1);
+	
+	if(pn==NULL)
+		return NULL;
+	
+	memcpy(pn, p, l+1);
+	
+	return pn;
+}
+	
+	
+char *scat(const char *p1, const char *p2)
+{
+	size_t l1, l2;
+	char*pn;
+	
+	l1=strlen(p1);
+	l2=strlen(p2);
+	
+	pn=(char*)malloc(l1+l2+1);
+	
+	if(pn==NULL)
+		return NULL;
+	
+	memcpy(pn, p1, l1);
+	memcpy(pn+l1, p2, l2+1);
+	
+	return pn;
+}
+
+
+char *scat3(const char *p1, const char *p2, const char *p3)
+{
+	size_t l1, l2, l3;
+	char *pn;
+	
+	l1=strlen(p1);
+	l2=strlen(p2);
+	l3=strlen(p3);
+	
+	pn=(char*)malloc(l1+l2+l3+1);
+	
+	if(pn==NULL)
+		return NULL;
+	
+	memcpy(pn, p1, l1);
+	memcpy(pn+l1, p2, l2);
+	memcpy(pn+l1+l2, p3, l3+1);
+	
+	return pn;
+}
+
+
+/* */
+
+
+const char *simple_basename(const char *name)
+{
+	const char *p;
+	
+	p=name+strlen(name)-1;
+	
+	/* Skip any trailing slashes */
+	while(*p=='/'){
+		/* root? */
+		if(p==name)
+			return name;
+		p--;
+	}
+	
+	while(p!=name){
+		if(*p=='/')
+			return p+1;
+		p--;
+	}
+	
+	return name;
+}
+
+
+/* */
+
+
+bool readf(FILE *f, void *buf, size_t n)
+{
+	return fread(buf, 1, n, f)!=1;
+}
+
+
+bool writef(FILE *f, const void *buf, size_t n)
+{
+	return fwrite(buf, 1, n, f)!=1;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/np-conv.h	Tue Feb 15 18:57:52 2005 +0100
@@ -0,0 +1,73 @@
+/*
+ * libtu/np-conv.h
+ *
+ * Copyright (c) Tuomo Valkonen 1999-2000.
+ * 
+ * This file is distributed under the terms of the "Artistic License".
+ * See the included file LICENSE for details.
+ */
+
+#include <math.h>
+
+
+#define FN_NUM_TO_SIGNED(T, UMAX, MAX, MIN)                          \
+ static int num_to_##T(T *ret, const NPNum *num, bool allow_uns_big) \
+ {                                                                   \
+	if(num->exponent)                                                \
+		return E_TOKZ_NOTINT;                                        \
+	if(num->nmantissa>0)                                             \
+		return E_TOKZ_RANGE;                                         \
+                                                                     \
+	if(!num->negative){                                              \
+		*ret=num->mantissa[0];                                       \
+		if(allow_uns_big?num->mantissa[0]>UMAX:num->mantissa[0]>MAX) \
+			return E_TOKZ_RANGE;                                     \
+	}else{                                                           \
+		*ret=-num->mantissa[0];                                      \
+		if(num->mantissa[0]>-(ulong)MIN)                             \
+			return E_TOKZ_RANGE;                                     \
+	}                                                                \
+	return 0;                                                        \
+}
+
+#define FN_NUM_TO_UNSIGNED(T, UMAX, MIN)                         \
+ static int num_to_##T(T *ret, const NPNum *num, bool allow_neg) \
+ {                                                               \
+	if(num->exponent)                                            \
+		return E_TOKZ_NOTINT;                                    \
+	if(num->nmantissa>0)                                         \
+		return E_TOKZ_RANGE;                                     \
+                                                                 \
+	if(!num->negative){                                          \
+		*ret=num->mantissa[0];                                   \
+		if(num->mantissa[0]>UMAX)                                \
+			return E_TOKZ_RANGE;                                 \
+	}else{                                                       \
+		*ret=-num->mantissa[0];                                  \
+		if(!allow_neg || num->mantissa[0]>(ulong)-MIN)           \
+			return E_TOKZ_RANGE;                                 \
+	}                                                            \
+	return 0;                                                    \
+}
+
+
+#define FN_NUM_TO_FLOAT(T, POW)                  \
+ static int num_to_##T(T *ret, const NPNum *num) \
+ {                                               \
+	T d=0;                                       \
+	int i;                                       \
+	                                             \
+	for(i=num->nmantissa;i>=0;i--)               \
+		d=d*(T)(ULONG_MAX+1.0)+num->mantissa[i]; \
+                                                 \
+	d*=POW(10, num->exponent);                   \
+	*ret=d;                                      \
+	                                             \
+	return 0;                                    \
+ }
+
+FN_NUM_TO_SIGNED(long, ULONG_MAX, LONG_MAX, LONG_MIN)
+FN_NUM_TO_SIGNED(char, UCHAR_MAX, CHAR_MAX, CHAR_MIN)
+FN_NUM_TO_FLOAT(double, pow)
+
+#undef NEG
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/numparser2.h	Tue Feb 15 18:57:52 2005 +0100
@@ -0,0 +1,220 @@
+/*
+ * libtu/numparser2.h
+ *
+ * Copyright (c) Tuomo Valkonen 1999-2000.
+ * 
+ * This file is distributed under the terms of the "Artistic License".
+ * See the included file LICENSE for details.
+ */
+
+#define MAX_MANTISSA 10  /* should be enough for our needs */
+#define ULONG_SIZE (sizeof(ulong)*8)
+
+/*
+ * Can handle quite big numbers (depends on MAX_MANTISSA). This is really
+ * a crappy little hack (especially the generic (non-i386asm) mulby10
+ * algorithm... hopefully it works...) but this'll do for now.
+ */
+
+enum{
+	NPNUM_INT,
+	NPNUM_FLOAT
+};
+
+typedef struct _NPNum{
+	unsigned char nmantissa;
+	int type;
+	int base;
+ 	bool negative;
+	ulong mantissa[MAX_MANTISSA];
+	long exponent;
+} NPNum;
+
+#define NUM_INIT {0, 0, 0, 0, {0,}, 0}
+
+#define ADD_EXP(NUM, X) (NUM)->exponent+=(X);
+
+#if defined(__GNUG__) && defined(i386) && !defined(LIBTU_NP_NO_I386_ASM)
+ #define LIBTU_NP_I386_ASM
+#endif
+
+static int npnum_mulbase_add(NPNum *num, long base, long v)
+{
+	long i, j;
+	ulong overflow;
+#ifndef LIBTU_NP_I386_ASM
+	ulong val;
+#endif
+	
+	for(i=num->nmantissa;i>=0;i--){
+#ifdef LIBTU_NP_I386_ASM
+		__asm__("mul %4\n"
+				: "=a" (num->mantissa[i]), "=d" (overflow)
+				: "0" (num->mantissa[i]), "1" (0), "q" (base)
+				: "eax", "edx");
+#else
+		overflow=0;
+		val=num->mantissa[i];
+		
+		if(val<ULONG_MAX/base){
+			val*=base;
+		}else if(val){
+			ulong tmp=val;
+			ulong old=val;
+			for(j=0; j<base; j++){
+				val+=tmp;
+				if(val<=old)
+					overflow++;
+				old=val;
+			}
+		}
+		num->mantissa[i]=val;
+#endif
+		if(overflow){
+			if(i==num->nmantissa){
+				if(num->nmantissa==MAX_MANTISSA)
+					return E_TOKZ_TOOBIG;
+				num->nmantissa++;
+			}
+			num->mantissa[i+1]+=overflow;
+		}
+	}
+	num->mantissa[0]+=v;
+	
+	return 0;
+}
+
+#undef LIBTU_NP_I386_ASM
+
+
+/* */
+
+
+static bool is_end(int c)
+{
+	return ((c!='.' && ispunct(c)) || isspace(c) || iscntrl(c));
+}
+
+
+/* */
+
+
+static int parse_exponent(NPNum *num, Tokenizer *tokz, int c)
+{
+	long exp=0;
+	bool neg=FALSE;
+	int err=0;
+	
+	c=GETCH();
+	
+	if(c=='-' || c=='+'){
+		if(c=='-')
+			neg=TRUE;
+		c=GETCH();
+	}
+	
+	for(; 1; c=GETCH()){
+		if(isdigit(c)){
+			exp*=10;
+			exp+=c-'0';
+		}else if(is_end(c)){
+			UNGETCH(c);
+			break;
+		}else{
+			err=E_TOKZ_NUMFMT;
+		}
+	}
+
+	if(neg)
+		exp*=-1;
+	
+	ADD_EXP(num, exp);
+	
+	return err;
+}
+
+
+static int parse_number(NPNum *num, Tokenizer *tokz, int c)
+{
+	int base=10;
+	int dm=1;
+	int err=0;
+	int tmp;
+	
+	if(c=='-' || c=='+'){
+		if(c=='-')
+			num->negative=TRUE;
+		c=GETCH();
+		if(!isdigit(c))
+			err=E_TOKZ_NUMFMT;
+	}else if(c=='0'){
+		dm=0;
+		c=GETCH();
+		if(c=='x' || c=='X'){
+			base=16;
+			c=GETCH();
+		}else if(c=='b' || c=='B'){
+			base=2;
+			c=GETCH();
+		}else if('0'<=c && c<='7'){
+			base=7;
+		}else{
+			dm=2;
+		}
+	}
+	
+	num->base=base;
+	
+	for(; 1; c=GETCH()){
+		if((c=='e' || c=='E') && dm!=0){
+			if(dm<2){
+				err=E_TOKZ_NUMFMT;
+				continue;
+			}
+			tmp=parse_exponent(num, tokz, c);
+			if(err==0)
+				err=tmp;
+			break;
+		}
+		
+		if(isxdigit(c)){
+			if('0'<=c && c<='9')
+				c-='0';
+			else if(isupper(c))
+				c-='A'-10;
+			else
+				c-='a'-10;
+			
+			if(c>=base)
+				err=E_TOKZ_NUMFMT;
+			
+			npnum_mulbase_add(num, base, c);
+			
+			if(dm==1)
+				dm=2;
+			else if(dm==3)
+				ADD_EXP(num, -1);
+			
+			continue;
+		}
+		
+		if(c=='.'){
+			if(dm!=2)
+				err=E_TOKZ_NUMFMT;
+			else
+				dm=3;
+			continue;
+		}
+		
+		if(is_end(c)){
+			UNGETCH(c);
+			break;
+		}
+		
+		err=E_TOKZ_NUMFMT;
+	}
+	
+	num->type=(num->exponent==0 ? NPNUM_INT : NPNUM_FLOAT);
+	
+	return err;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/optparser.c	Tue Feb 15 18:57:52 2005 +0100
@@ -0,0 +1,308 @@
+/*
+ * libtu/optparser.c
+ *
+ * Copyright (c) Tuomo Valkonen 1999-2000.
+ * 
+ * This file is distributed under the terms of the "Artistic License".
+ * See the included file LICENSE for details.
+ */
+
+#include <string.h>
+#include <stdlib.h>
+
+#include "include/util.h"
+#include "include/misc.h"
+#include "include/optparser.h"
+#include "include/output.h"
+
+
+#define O_CHAINABLE(o)	(o->flags&OPT_CHAINABLE)
+#define O_IMM_ARG(o)	(o->flags&OPT__IMM_ARG)
+#define O_NO_DASH(o)	(o->flags&OPT_NO_DASH)
+#define O_MIDLONG(o)	(o->flags&OPT_MIDLONG)
+#define O_NO_LONG(o)	(o->flags&OPT_NO_LONG)
+#define O_ARGS(o)		(o->flags&OPT_OPT_ARG)
+#define O_ARG(o)		(o->flasg&OPT_ARG)
+#define O_OPT_ARG(o)	(O_ARGS(o)==OPT_OPT_ARG)
+#define O_ID(o)			(o->optid)
+
+
+static const OptParserOpt *o_opts=NULL;
+static char *const *o_current=NULL;
+static int o_left=0;
+static const char* o_chain_ptr=NULL;
+static int o_args_left=0;
+static const char*o_tmp=NULL;
+static int o_error=0;
+
+
+/* */
+
+
+void optparser_init(int argc, char *const argv[], const OptParserOpt *opts)
+{
+	o_opts=opts;
+	o_current=argv+1;
+	o_left=argc-1;
+	o_chain_ptr=NULL;
+	o_args_left=0;
+	o_tmp=NULL;
+}
+
+
+/* */
+
+
+static const OptParserOpt *find_chain_opt(char p, const OptParserOpt *o)
+{
+	for(;O_ID(o);o++){
+		if(O_CHAINABLE(o) && O_ID(o)==p)
+			return o;
+	}
+	return NULL;
+}
+
+
+static bool valid_chain(const char *p, const OptParserOpt *o)
+{
+	while(*p!='\0'){
+		if(!find_chain_opt(*p, o))
+			return FALSE;
+		p++;
+	}
+	return TRUE;
+}
+	
+
+static bool is_option(const char *p)
+{
+	 if(p==NULL)
+		  return FALSE;
+	 if(*p++!='-')
+		  return FALSE;
+	 if(*p++!='-')
+		  return FALSE;
+	 if(*p=='\0')
+		  return FALSE;
+	 return TRUE;
+}
+	
+
+/* */
+
+
+int optparser_get_opt()
+{
+#define RET(X) return o_tmp=p, o_error=X
+	const char *p, *p2=NULL;
+	bool lo=FALSE, dash=TRUE;
+	const OptParserOpt *o;
+	int l;
+
+	while(o_args_left)
+		optparser_get_arg();
+
+	o_tmp=NULL;
+
+	/* Are we doing a chain (i.e. opt. of style 'tar xzf') ? */
+	if(o_chain_ptr!=NULL){
+		p=o_chain_ptr++;
+		if(!*o_chain_ptr)
+			o_chain_ptr=NULL;
+
+		o=find_chain_opt(*p, o_opts);
+		
+		if(o==NULL)
+			RET(E_OPT_INVALID_CHAIN_OPTION);
+
+		goto do_arg;
+	}
+	
+	if(o_left<1)
+		return OPT_ID_END;
+
+	o_left--;
+	p=*o_current++;
+	
+	if(*p!='-'){
+		/* foo */
+		dash=FALSE;
+	}else if(*(p+1)=='-'){
+		/* --foo */
+		if(*(p+2)=='\0'){
+			/* -- */
+			o_args_left=o_left;
+			RET(OPT_ID_ARGUMENT);
+		}
+		lo=TRUE;
+		p2=p+2;
+	}else{
+		/* -foo */
+		if(*(p+1)=='\0'){
+			/* - */
+			o_args_left=1;
+			RET(OPT_ID_ARGUMENT);
+		}
+		p2=p+1;
+	}
+
+	o=o_opts;
+
+again:
+	for(;O_ID(o);o++){
+		if(lo){
+			/* Do long option (--foo=bar) */
+			if(o->longopt==NULL)
+				continue;
+			l=strlen(o->longopt);
+			if(strncmp(p2, o->longopt, l)!=0)
+				continue;
+			
+			if(O_NO_LONG(o))
+				RET(E_OPT_INVALID_OPTION);
+
+			if(p2[l]=='\0'){
+				if(O_ARGS(o)==OPT_ARG)
+					 RET(E_OPT_MISSING_ARGUMENT);
+				return O_ID(o);
+			}else if(p2[l]=='='){
+				if(!O_ARGS(o))
+					 RET(E_OPT_UNEXPECTED_ARGUMENT);
+				if(p2[l+1]=='\0')
+					 RET(E_OPT_MISSING_ARGUMENT);
+				o_tmp=p2+l+1;
+				o_args_left=1;
+				return O_ID(o);
+			}
+		}else{
+			/* Do midlong option (-foobar) */
+			if(dash && o->longopt!=NULL && strcmp(p2, o->longopt)==0){
+				if(!O_MIDLONG(o))
+					 RET(E_OPT_INVALID_OPTION);
+				goto do_arg;
+			}
+	
+			/* Do short option (-f) */
+			if((!dash && !O_NO_DASH(o)) || *p2!=O_ID(o))
+				continue;
+			   
+			if(*(p2+1)!='\0'){
+				if(O_CHAINABLE(o) && valid_chain(p2+1, o_opts)){
+					 o_chain_ptr=p2+1;
+				}else if(O_IMM_ARG(o)){
+					 o_tmp=p2+1;
+					 o_args_left=1;
+					 return O_ID(o);
+				}else{
+					 continue;
+				}
+			}
+do_arg:
+			if(!O_ARGS(o))
+				return O_ID(o);
+			   
+			if(O_ARGS(o)==OPT_ARG){
+				if(o_left==0)
+					 RET(E_OPT_MISSING_ARGUMENT);
+			}else{
+				if(!o_left || is_option(*o_current))
+					 return O_ID(o);
+			}
+
+			o_args_left=1;
+			return O_ID(o);
+		}
+	}
+
+	if(dash)
+		RET(E_OPT_INVALID_OPTION);
+	
+	RET(OPT_ID_ARGUMENT);
+#undef RET
+}
+
+
+/* */
+
+
+const char* optparser_get_arg()
+{
+	const char *p;
+	
+	if(o_tmp!=NULL){
+		/* If o_args_left==0, then were returning an invalid option
+		 * otherwise an immediate argument (e.g. -funsigned-char
+		 * where '-f' is the option and 'unsigned-char' the argument)
+		 */
+		if(o_args_left>0)
+			o_args_left--;
+		p=o_tmp;
+		o_tmp=NULL;
+		return p;
+	}
+		
+	if(o_args_left<1 || o_left<1)
+		return NULL;
+
+	o_left--;
+	o_args_left--;
+	return *o_current++;
+}
+
+
+/* */
+
+static void warn_arg(const char *e)
+{
+	const char*p=optparser_get_arg();
+	
+	if(p==NULL)
+		warn("%s (null)", e);
+	else
+		warn("%s \'%s\'", e, p);
+}
+
+
+static void warn_opt(const char *e)
+{
+	if(o_chain_ptr!=NULL && o_tmp!=NULL)
+		warn("%s \'-%c\'", e, *o_tmp);
+	else
+		warn_arg(e);
+}
+
+
+void optparser_print_error()
+{
+	switch(o_error){
+	case E_OPT_INVALID_OPTION:
+		warn_opt(TR("Invalid option"));
+		break;
+
+	case E_OPT_INVALID_CHAIN_OPTION:
+		warn_opt(TR("Invalid option in chain (this cannot happen)"));
+		break;		
+
+	case E_OPT_SYNTAX_ERROR:
+		warn_arg(TR("Syntax error while parsing"));
+		break;
+				 
+	case E_OPT_MISSING_ARGUMENT:
+		warn_opt(TR("Missing argument to"));
+		break;
+
+	case E_OPT_UNEXPECTED_ARGUMENT:
+		warn_opt(TR("No argument expected to"));
+		break;
+		
+	case OPT_ID_ARGUMENT:
+		warn(TR("Unexpected argument"));
+		break;
+
+	default:
+		warn(TR("(unknown error)"));
+	}
+	
+	o_tmp=NULL;
+	o_error=0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/output.c	Tue Feb 15 18:57:52 2005 +0100
@@ -0,0 +1,282 @@
+/*
+ * libtu/output.c
+ *
+ * Copyright (c) Tuomo Valkonen 1999-2000.
+ * 
+ * This file is distributed under the terms of the "Artistic License".
+ * See the included file LICENSE for details.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <strings.h>
+#include <string.h>
+
+#include "include/misc.h"
+#include "include/output.h"
+#include "include/util.h"
+
+
+/* verbose
+ */
+
+static bool verbose_mode=FALSE;
+static int verbose_indent_lvl=0;
+static bool progname_enable=TRUE;
+
+#define INDENTATOR_LENGTH 4
+
+static char indentator[]={' ', ' ', ' ', ' '};
+
+
+void verbose(const char *p, ...)
+{
+	va_list args;
+	
+	va_start(args, p);
+	
+	verbose_v(p, args);
+	
+	va_end(args);
+}
+		   
+
+void verbose_v(const char *p, va_list args)
+{
+	int i;
+	
+	if(verbose_mode){
+		for(i=0; i<verbose_indent_lvl; i++)
+			writef(stdout, indentator, INDENTATOR_LENGTH);
+		
+		vprintf(p, args);
+		fflush(stdout);
+	}
+}
+
+
+void verbose_enable(bool enable)
+{
+	verbose_mode=enable;
+}
+
+
+int verbose_indent(int depth)
+{
+	int old=verbose_indent_lvl;
+	
+	if(depth>=0)
+		verbose_indent_lvl=depth;
+	
+	return old;
+}
+		
+
+/* warn
+ */
+
+void warn_progname_enable(bool enable)
+{
+	progname_enable=enable;
+}
+
+
+static void put_prog_name()
+{
+	const char*progname;
+	
+	if(!progname_enable)
+		return;
+	
+	progname=prog_execname();
+	
+	if(progname==NULL)
+		return;
+	
+	fprintf(stderr, "%s: ", (char*)progname);
+}
+
+
+void warn(const char *p, ...)
+{
+	va_list args;
+	
+	va_start(args, p);
+	
+	warn_v(p, args);
+	
+	va_end(args);
+}
+
+
+void warn_v(const char *p, va_list args)
+{
+	put_prog_name();
+	vfprintf(stderr, p, args);
+	putc('\n', stderr);
+}
+
+
+void warn_obj(const char *obj, const char *p, ...)
+{
+	va_list args;
+	
+	va_start(args, p);
+	
+	warn_obj_v(obj, p, args);
+	
+	va_end(args);
+}
+
+
+void warn_obj_line(const char *obj, int line, const char *p, ...)
+{
+	va_list args;
+	
+	va_start(args, p);
+	
+	warn_obj_line_v(obj, line, p, args);
+	
+	va_end(args);
+}
+
+
+void warn_obj_v(const char *obj, const char *p, va_list args)
+{
+	put_prog_name();
+	if(obj!=NULL)
+		fprintf(stderr,"%s: ", obj);
+	vfprintf(stderr, p, args);
+	putc('\n', stderr);
+}
+
+
+void warn_obj_line_v(const char *obj, int line, const char *p, va_list args)
+{
+	put_prog_name();
+	if(obj!=NULL){
+		if(line>0)
+			fprintf(stderr, TR("%s:%d: "), obj, line);
+		else		
+			fprintf(stderr, "%s: ", obj);
+	}else{
+		if(line>0)
+			fprintf(stderr, TR("%d: "), line);
+	}
+	vfprintf(stderr, p, args);
+	putc('\n', stderr);
+}
+
+
+void warn_err()
+{
+	put_prog_name();
+	fprintf(stderr, "%s\n", strerror(errno));
+}
+
+
+void warn_err_obj(const char *obj)
+{
+	put_prog_name();
+	if(obj!=NULL)
+		fprintf(stderr, "%s: %s\n", obj, strerror(errno));
+	else
+		fprintf(stderr, "%s\n", strerror(errno));
+
+}
+
+
+void warn_err_obj_line(const char *obj, int line)
+{
+	put_prog_name();
+	if(obj!=NULL){
+		if(line>0)
+			fprintf(stderr, TR("%s:%d: %s\n"), obj, line, strerror(errno));
+		else
+			fprintf(stderr, "%s: %s\n", obj, strerror(errno));
+	}else{
+		if(line>0)
+			fprintf(stderr, TR("%d: %s\n"), line, strerror(errno));
+		else
+			fprintf(stderr, TR("%s\n"), strerror(errno));
+	}
+
+}
+
+
+/* die
+ */
+
+void die(const char *p, ...)
+{
+	va_list args;
+	
+	va_start(args, p);
+	
+	die_v(p, args);
+	
+	va_end(args);
+}
+
+
+void die_v(const char *p, va_list args)
+{
+	warn_v(p, args);
+	exit(EXIT_FAILURE);
+}
+
+
+void die_obj(const char *obj, const char *p, ...)
+{
+	va_list args;
+	
+	va_start(args, p);
+	die_obj_v(obj, p, args);
+	va_end(args);
+}
+
+
+void die_obj_line(const char *obj, int line, const char *p, ...)
+{
+	va_list args;
+	
+	va_start(args, p);
+	die_obj_line_v(obj, line, p, args);
+	va_end(args);
+}
+
+
+void die_obj_v(const char *obj, const char *p, va_list args)
+{
+	warn_obj_v(obj, p, args);
+	exit(EXIT_FAILURE);
+}
+
+
+void die_obj_line_v(const char *obj, int line, const char *p, va_list args)
+{
+	warn_obj_line_v(obj, line, p, args);
+	exit(EXIT_FAILURE);
+}
+
+
+void die_err()
+{
+	warn_err();
+	exit(EXIT_FAILURE);
+}
+
+
+void die_err_obj(const char *obj)
+{
+	warn_err_obj(obj);
+	exit(EXIT_FAILURE);
+}
+
+
+void die_err_obj_line(const char *obj, int line)
+{
+	warn_err_obj_line(obj, line);
+	exit(EXIT_FAILURE);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/parser.c	Tue Feb 15 18:57:52 2005 +0100
@@ -0,0 +1,518 @@
+/*
+ * libtu/parser.c
+ *
+ * Copyright (c) Tuomo Valkonen 1999-2000.
+ * 
+ * This file is distributed under the terms of the "Artistic License".
+ * See the included file LICENSE for details.
+ */
+
+#include <string.h>
+
+#include "include/parser.h"
+#include "include/misc.h"
+#include "include/output.h"
+
+#define MAX_TOKENS 	32
+#define MAX_NEST	16
+
+
+enum{
+	P_EOF,
+	P_OK,
+	P_ERROR,
+	P_BEG_SECT,
+	P_END_SECT
+};
+
+
+static bool check_args(const Tokenizer *tokz, Token *tokens, int ntokens,
+					   const char *fmt);
+
+
+/* */
+
+
+static int read_statement(const ConfOpt **opt_ret, Token *tokens,
+						  int *ntok_ret, Tokenizer *tokz,
+						  const ConfOpt *options)
+{
+	int ntokens=0;
+	Token *tok=NULL;
+	const ConfOpt *opt=NULL;
+	int had_comma=0;
+	int retval=P_OK;
+	int e=0;
+	int e_line=0;
+
+	while(1){
+		if(ntokens==MAX_TOKENS-1){
+			e=E_TOKZ_TOKEN_LIMIT;
+			goto ret_err;
+		}
+		
+		tok=&tokens[ntokens];
+		
+		if(!tokz_get_token(tokz, tok))
+			goto ret_err;
+		
+		ntokens++;
+		
+		if(!TOK_IS_OP(tok)){
+			if(ntokens==1 && !had_comma){
+				if(!TOK_IS_IDENT(tok)){
+					e=E_TOKZ_IDENTIFIER_EXPECTED;
+					goto ret_err;
+				}
+		
+				/* find the option */
+				for(opt=options; opt->optname; opt++){
+					if(strcmp(opt->optname, TOK_IDENT_VAL(tok))==0)
+						break;
+				}
+				
+				if(!opt->optname){
+					e=E_TOKZ_UNKNOWN_OPTION;
+					e_line=tok->line;
+					retval=P_ERROR;
+				}
+
+				had_comma=2;
+			}else{
+				if(!had_comma){
+					e=E_TOKZ_SYNTAX;
+					goto ret_err;
+				}
+			
+				had_comma=0;
+			}
+			continue;
+		}
+		
+		/* It is an operator */
+		
+		switch(TOK_OP_VAL(tok)){
+		case OP_SCOLON:
+			if(opt){
+				if(had_comma || opt->opts){
+					e=E_TOKZ_SYNTAX;
+					goto ret_err;
+				}
+				goto ret_success;
+			}
+			break;
+			
+		case OP_NEXTLINE:
+			if(had_comma==1){
+				e=E_TOKZ_SYNTAX;
+				e_line=tok->line-1;
+				goto ret_err2;
+			}
+			
+			if(opt && !opt->opts)
+				goto ret_success;
+			break;
+			
+		case OP_EOF:
+			if(had_comma==1){
+				e=E_TOKZ_UNEXPECTED_EOF;
+				goto ret_err;
+			}
+			
+			if(opt && opt->opts){
+				e=E_TOKZ_UNEXPECTED_EOF;
+				goto ret_err;
+			}
+			
+			retval=P_EOF;
+			goto ret_success;
+			
+		case OP_R_BRC:
+			if(had_comma==1){
+				e=E_TOKZ_SYNTAX;
+				goto ret_err;
+			}
+			
+			if(opt && opt->opts){
+				e=E_TOKZ_SYNTAX;
+				goto ret_err;
+			}
+			
+			retval=P_END_SECT;
+			goto ret_success;
+			
+		case OP_L_BRC:
+			if(had_comma==1 || !opt || !opt->opts){
+				e=E_TOKZ_SYNTAX;
+				goto ret_err;
+			}
+			
+			retval=P_BEG_SECT;
+			goto ret_success;
+			
+		case OP_COMMA:
+			if(had_comma){
+				e=E_TOKZ_SYNTAX;
+				goto ret_err;
+			}
+			had_comma=1;
+			break;
+			
+		default:
+			e=E_TOKZ_SYNTAX;
+			goto ret_err;
+		}
+		
+		ntokens--;
+	}
+
+ret_err:
+	e_line=tok->line;
+ret_err2:
+	retval=P_ERROR;
+
+ret_success:
+	if(retval==P_ERROR && e!=0)
+		tokz_warn_error(tokz, e_line, e);
+	
+ 	*opt_ret=opt;
+	*ntok_ret=ntokens;
+	
+	return retval;
+}
+
+
+/* */
+
+
+static bool call_end_sect(Tokenizer *tokz, const ConfOpt *options)
+{	
+	bool retval=TRUE;
+	
+	while(options->optname){
+		if(strcmp(options->optname, "#end")==0){
+			retval=options->fn(tokz, 0, NULL);
+			break;
+		}
+		options++;
+	}
+	
+	return retval;
+}
+
+
+static void call_cancel_sect(Tokenizer *tokz, const ConfOpt *options)
+{	
+	while(options->optname){
+		if(strcmp(options->optname, "#cancel")==0){
+			options->fn(tokz, 0, NULL);
+			break;
+		}
+		options++;
+	}
+}
+			
+
+/* */
+
+
+/* Does the parsing work
+ */
+bool parse_config_tokz(Tokenizer *tokz, const ConfOpt *options)
+{
+	Token tokens[MAX_TOKENS];
+	bool alloced_optstack=FALSE;
+	int i, t, ntokens;
+	int init_nest_lvl;
+	bool had_error=FALSE;
+
+	/* Allocate tokz->optstack if it does not yet exist (if it does,
+	 * we have been called from an option handler)
+	 */
+	if(!tokz->optstack){
+		tokz->optstack=ALLOC_N(const ConfOpt*, MAX_NEST);
+		if(!tokz->optstack){
+			warn_err();
+			return FALSE;
+		}
+		
+		memset(tokz->optstack, 0, sizeof(ConfOpt*)*MAX_NEST);
+		init_nest_lvl=tokz->nest_lvl=0;
+		alloced_optstack=TRUE;
+	}else{
+		init_nest_lvl=tokz->nest_lvl;
+	}
+	
+	tokz->optstack[init_nest_lvl]=options;
+	
+	for(i=0;i<MAX_TOKENS;i++)
+		tok_init(&tokens[i]);
+
+	
+	/* The loop
+	 */
+	while(1){
+		t=read_statement(&options, tokens, &ntokens,
+						 tokz, tokz->optstack[tokz->nest_lvl]);
+		
+		had_error=(t==P_ERROR);
+		
+		/* Check that arguments are ok */
+		if(!had_error && options)
+			had_error=!check_args(tokz, tokens, ntokens, options->argfmt);
+
+		if(tokz->flags&TOKZ_PARSER_INDENT_MODE)
+			verbose_indent(tokz->nest_lvl);
+		
+		/* New section? */
+		if(t==P_BEG_SECT){
+			if(tokz->nest_lvl==MAX_NEST-1){
+				tokz_warn_error(tokz, tokz->line, E_TOKZ_MAX_NEST);
+				had_error=TRUE;
+				while(ntokens--)
+					tok_free(&tokens[ntokens]);
+				break;
+			}else{
+				tokz->optstack[++tokz->nest_lvl]=options->opts;
+			}
+		}
+		
+		/* call the handler */
+		if(!had_error && options && options->fn)
+			had_error=!options->fn(tokz, ntokens-1, tokens);
+		
+		/* free the tokens */
+		while(ntokens--)
+			tok_free(&tokens[ntokens]);
+		
+		switch(t){		
+		case P_BEG_SECT:
+			if(!had_error)
+				continue;
+			/* #cancel handler should not be called when
+			 * error occured in section begin handler */
+			tokz->nest_lvl--;
+			break;
+
+		case P_EOF:
+			if(tokz->nest_lvl>0){
+				tokz_warn_error(tokz, 0, E_TOKZ_UNEXPECTED_EOF);
+				had_error=TRUE;
+			}else if(!had_error){
+				had_error=!call_end_sect(tokz, tokz->optstack[0]);
+			}
+			break;
+							
+		case P_END_SECT:
+			if(tokz->nest_lvl==0){
+				tokz_warn_error(tokz, tokz->line, E_TOKZ_SYNTAX);
+				had_error=TRUE;
+				break;
+			}
+			
+			if(!had_error)
+				had_error=!call_end_sect(tokz, tokz->optstack[tokz->nest_lvl]);
+
+			tokz->nest_lvl--;
+			
+			if(tokz->nest_lvl<init_nest_lvl)
+				break;
+			   
+			/* fall thru */
+
+		default:
+			if(!had_error)
+				continue;			
+		}
+		break;
+	}
+	
+	/* On error, call all the #cancel-handlers */
+	while(had_error && tokz->nest_lvl>=init_nest_lvl){
+		call_cancel_sect(tokz, tokz->optstack[tokz->nest_lvl]);
+		tokz->nest_lvl--;
+	}
+	
+	/* Free optstack if it was alloced by this call */
+	if(alloced_optstack){
+		free(tokz->optstack);
+		tokz->optstack=NULL;
+		tokz->nest_lvl=0;
+	}
+	
+	if(tokz->flags&TOKZ_PARSER_INDENT_MODE)
+		verbose_indent(init_nest_lvl);
+	
+	return !had_error;
+}
+
+
+/* */
+
+
+bool parse_config(const char *fname, const ConfOpt *options)
+{
+	Tokenizer *tokz;
+	bool ret;
+	
+	tokz=tokz_open(fname);
+	
+	if(tokz==NULL)
+		return FALSE;
+	
+	ret=parse_config_tokz(tokz, options);
+	
+	tokz_close(tokz);
+	
+	return ret;
+}
+
+
+bool parse_config_file(FILE *file, const ConfOpt *options)
+{
+	Tokenizer *tokz;
+	bool ret;
+	
+	tokz=tokz_open_file(file);
+	
+	if(tokz==NULL)
+		return FALSE;
+	
+	ret=parse_config_tokz(tokz, options);
+	
+	tokz_close(tokz);
+	
+	return ret;
+}
+
+
+/*
+ * Argument validity checking stuff
+ */
+
+
+static bool arg_match(Token *tok, char c)
+{
+	static const char chs[]={0, 'l', 'd', 'c', 's', 'i', 0, 0};
+	char c2;
+	
+	if(c=='.' || c=='*')
+		return TRUE;
+	
+	c2=chs[tok->type];
+	
+	if(c2==c)
+		return TRUE;
+	
+	if(c2=='c' && c=='l'){
+		TOK_SET_LONG(tok, TOK_CHAR_VAL(tok));
+		return TRUE;
+	}
+	
+	if(c2=='l' && c=='c'){
+		TOK_SET_CHAR(tok, TOK_LONG_VAL(tok));
+		return TRUE;
+	}
+	
+	if(c2=='l' && c=='d'){
+		TOK_SET_DOUBLE(tok, TOK_LONG_VAL(tok));
+		return TRUE;
+	}
+	   
+	return FALSE;
+}
+
+
+static bool check_argument(const char **pret, Token *tok, const char *p)
+{
+	int mode=0;
+
+	if(*p=='*'){
+		*pret=p;
+		return TRUE;
+	}else if(*p=='?'){
+		mode=1;
+		p++;
+	}else if(*p==':'){
+		mode=2;
+		p++;
+	}else if(*p=='+'){
+		*pret=p;
+		return arg_match(tok, *(p-1));
+	}
+	
+	while(*p!='\0'){
+		if(arg_match(tok, *p)){
+			p++;
+			while(mode==2 && *p==':'){
+				if(*++p=='\0')
+					break; /* invalid argument format string it is... */
+				p++;
+			}
+			*pret=p;
+			return TRUE;
+		}
+		
+		if(mode==0)
+			break;
+		
+		p++;
+		
+		if(mode==1){
+			*pret=p;
+			return TRUE;
+		}
+		
+		if(*p!=':')
+			break;
+		p++;
+	}
+	
+	*pret=p;
+	return FALSE;
+}
+
+						   
+static bool args_at_end(const char *p)
+{
+	if(p==NULL)
+		return TRUE;
+	
+	while(*p!='\0'){
+		if(*p=='*' || *p=='+')
+			p++;
+		else if(*p=='?')
+			p+=2;
+		else
+			return FALSE;
+	}
+	
+	return TRUE;
+}
+
+
+static bool check_args(const Tokenizer *tokz, Token *tokens, int ntokens,
+					   const char *fmt)
+{
+	int i;
+		
+	if(fmt==NULL)
+		return ntokens==2;
+
+	for(i=1; i<ntokens-1; i++){
+		if(!check_argument(&fmt, &tokens[i], fmt)){
+			tokz_warn_error(tokz, tokens[i].line,
+							*fmt!='\0' ? E_TOKZ_INVALID_ARGUMENT 
+									   : E_TOKZ_TOO_MANY_ARGS);
+			return FALSE;
+		}
+	}
+
+	if(!args_at_end(fmt)){
+		tokz_warn_error(tokz, tokens[i].line, E_TOKZ_TOO_FEW_ARGS);
+		return FALSE;
+	}
+	
+	return TRUE;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tester.c	Tue Feb 15 18:57:52 2005 +0100
@@ -0,0 +1,51 @@
+/*
+ * libtu/tester.c
+ *
+ * Copyright (c) Tuomo Valkonen 1999-2000.
+ * 
+ * This file is distributed under the terms of the "Artistic License".
+ * See the included file LICENSE for details.
+ */
+
+#include <stdio.h>
+#include "include/misc.h"
+#include "include/tokenizer.h"
+
+
+int main(void)
+{
+	Tokenizer*tokz;
+	Token tok=TOK_INIT;
+	
+	if(!(tokz=tokz_open_file(stdin)))
+		return EXIT_FAILURE;
+
+	while(tokz_get_token(tokz, &tok)){
+		switch(tok.type){
+		case TOK_LONG:
+			printf("long - %ld\n", TOK_LONG_VAL(&tok));
+			break;
+		case TOK_DOUBLE:
+			printf("double - %g\n", TOK_DOUBLE_VAL(&tok));
+			break;
+		case TOK_CHAR:
+			printf("char - '%c'\n", TOK_CHAR_VAL(&tok));
+			break;
+		case TOK_STRING:
+			printf("string - \"%s\"\n", TOK_STRING_VAL(&tok));
+			break;
+		case TOK_IDENT:
+			printf("ident - %s\n", TOK_IDENT_VAL(&tok));
+			break;
+		case TOK_COMMENT:
+			printf("comment - %s\n", TOK_COMMENT_VAL(&tok));
+			break;
+		case TOK_OP:
+			printf("operator - %03x\n", TOK_OP_VAL(&tok));
+			break;
+		}
+	}
+	   
+	return EXIT_SUCCESS;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tester2.c	Tue Feb 15 18:57:52 2005 +0100
@@ -0,0 +1,68 @@
+/*
+ * libtu/tester2.c
+ *
+ * Copyright (c) Tuomo Valkonen 1999-2000.
+ * 
+ * This file is distributed under the terms of the "Artistic License".
+ * See the included file LICENSE for details.
+ */
+
+#include <stdio.h>
+#include "include/misc.h"
+#include "include/tokenizer.h"
+#include "include/parser.h"
+#include "include/util.h"
+
+
+static bool test_fn(Tokenizer *tokz, int n, Token *toks)
+{
+	printf("test_fn() %d %s\n", n, TOK_IDENT_VAL(toks)); 
+	
+	return TRUE;
+}
+
+
+
+static bool sect_fn(Tokenizer *tokz, int n, Token *toks)
+{
+	printf("sect_fn() %d %s\n", n, TOK_IDENT_VAL(toks+1));
+	
+	return TRUE;
+}
+
+
+static bool test2_fn(Tokenizer *tokz, int n, Token *toks)
+{
+	printf("test2_fn() %d %ld %f\n", n, TOK_LONG_VAL(toks+1), TOK_DOUBLE_VAL(toks+2));
+
+	return TRUE;
+}
+
+static bool test3_fn(Tokenizer *tokz, int n, Token *toks)
+{
+	if(n==1)
+		printf("test3_fn() \"%s\"\n", TOK_STRING_VAL(toks+1));
+	else
+		printf("test3_fn() \"%s\" %ld\n", TOK_STRING_VAL(toks+1), TOK_LONG_VAL(toks+2));
+
+	return TRUE;
+}
+	
+	
+static ConfOpt opts[]={
+	{"test", NULL, test_fn, NULL},
+	{"t2", "ld", test2_fn, NULL},
+	{"foo", "s?l", test3_fn, NULL},
+	{"sect", "s", sect_fn, opts},
+	{NULL, NULL, NULL, NULL}
+};
+
+			 
+int main(int argc, char *argv[])
+{
+	libtu_init_argv0(argv[0], NULL);
+	parse_config_file(stdin, opts);
+	
+	return EXIT_SUCCESS;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tester3.c	Tue Feb 15 18:57:52 2005 +0100
@@ -0,0 +1,77 @@
+/*
+ * libtu/tester3.c
+ *
+ * Copyright (c) Tuomo Valkonen 1999-2000.
+ * 
+ * This file is distributed under the terms of the "Artistic License".
+ * See the included file LICENSE for details.
+ */
+
+#include <stdio.h>
+#include "include/util.h"
+#include "include/misc.h"
+#include "include/optparser.h"
+
+
+static const char usage[]=
+	"$u [options]\n"
+	"\n"
+	"Where options are:\n"
+	"\n"
+	"  -o, -f, -v, -z, -x\n"
+	"$c                   \n"
+	"\n";
+	
+
+static ProgInfo proginfo={
+	"Tester III",
+	"0.1",
+	"foo",
+	"bar",
+	usage
+};
+
+
+static OptParserOpt opts[]={
+	{'o',	"opt",		OPT_IMM_ARG},
+	{'f',	"file",		OPT_CHAINABLE|OPT_NO_DASH|OPT_ARG},
+	{'v',	"view",		OPT_CHAINABLE|OPT_NO_DASH},
+	{'z',	"zip",		OPT_CHAINABLE|OPT_NO_DASH},
+	{'x',	"extract",	OPT_CHAINABLE|OPT_NO_DASH},
+	{0, NULL, 0}
+};
+	
+
+int main(int argc, char *argv[])
+{
+	int opt;
+	
+	libtu_init(&argc, argv, &proginfo);
+	
+	optparser_init(argc, argv, opts);
+	
+	while((opt=optparser_get_opt())){
+		switch(opt){
+		case 'o':
+			printf("opt: %s\n", optparser_get_arg());
+			break;
+		case 'f':
+			printf("file: %s\n", optparser_get_arg());
+			break;
+		case 'v':
+			printf("view\n");
+			break;
+		case 'z':
+			printf("zip\n");
+			break;
+		case 'x':
+			printf("extract\n");
+			break;
+		default:
+			optparser_print_error();
+			return 1;
+		}
+	}
+	return 0;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tokenizer.c	Tue Feb 15 18:57:52 2005 +0100
@@ -0,0 +1,756 @@
+/*
+ * libtu/tokenizer.c
+ *
+ * Copyright (c) Tuomo Valkonen 1999-2000.
+ * 
+ * This file is distributed under the terms of the "Artistic License".
+ * See the included file LICENSE for details.
+ */
+
+#include <errno.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <malloc.h>
+#include <limits.h>
+#include <assert.h>
+#include <math.h>
+#include <string.h>
+
+#include "include/tokenizer.h"
+#include "include/misc.h"
+#include "include/output.h"
+
+
+static const char *errors[]={
+	DUMMY_TR("(no error)"),
+	DUMMY_TR("Unexpected end of file"),				/* E_TOKZ_UNEXPECTED_EOF */
+	DUMMY_TR("Unexpected end of line"),				/* E_TOKZ_UNEXPECTED_EOL */
+	DUMMY_TR("End of line expected"),				/* E_TOKZ_EOL_EXPECTED */
+	DUMMY_TR("Invalid character"),					/* E_TOKZ_INVALID_CHAR*/
+	DUMMY_TR("Numeric constant too big"),			/* E_TOKZ_TOOBIG */
+	DUMMY_TR("Invalid numberic format"),			/* E_TOKZ_NUMFMT */
+	DUMMY_TR("Junk after numeric constant"),		/* E_TOKZ_NUM_JUNK */
+	DUMMY_TR("Not an integer"),						/* E_TOKZ_NOTINT */
+	DUMMY_TR("Numeric constant out of range"),		/* E_TOKZ_RANGE */
+	DUMMY_TR("Multi-character character constant"),	/* E_TOKZ_MULTICHAR */
+	DUMMY_TR("Token/statement limit reached"),		/* E_TOKZ_TOKEN_LIMIT */
+	DUMMY_TR("Unknown option"),						/* E_TOKZ_UNKONWN_OPTION */
+	DUMMY_TR("Syntax error"),						/* E_TOKZ_SYNTAX */
+	DUMMY_TR("Invalid argument"),					/* E_TOKZ_INVALID_ARGUMENT */
+	DUMMY_TR("End of statement expected"),			/* E_TOKZ_EOS_EXPECTED */
+	DUMMY_TR("Too few arguments"),					/* E_TOKZ_TOO_FEW_ARGS */
+	DUMMY_TR("Too many arguments"),					/* E_TOKZ_TOO_MANY_ARGS */
+	DUMMY_TR("Maximum section nestin level exceeded"), /* E_TOK_Z_MAX_NEST */
+	DUMMY_TR("Unexpected end of statement"),		/* E_TOKZ_UNEXPECTED_EOS */
+	DUMMY_TR("Identifier expected"),				/* E_TOKZ_IDENTIFIER_EXPECTED */
+};
+
+
+/* */
+
+#define STRBLEN 32
+
+#define STRING_DECL(X) char* X=NULL; char X##_tmp[STRBLEN]; int X##_tmpl=0
+#define STRING_DECL_P(X, P) char* X=NULL; char X##_tmp[STRBLEN]=P; int X##_tmpl=sizeof(P)-1
+#define STRING_APPEND(X, C) {if(!_string_append(&X, X##_tmp, &X##_tmpl, c)) return -ENOMEM;}
+#define STRING_FREE(X) if(X!=NULL) free(X)
+#define STRING_FINISH(X) {if(!_string_finish(&X, X##_tmp, X##_tmpl)) return -ENOMEM;}
+
+
+static bool _string_append(char **p, char *tmp, int *tmplen, char c)
+{
+	char *tmp2;
+	
+	if(*tmplen==STRBLEN-1){
+		tmp[STRBLEN-1]='\0';
+		if(*p!=NULL){
+			tmp2=scat(*p, tmp);
+			free(*p);
+			*p=tmp2;
+		}else{
+			*p=scopy(tmp);
+		}
+		*tmplen=1;
+		tmp[0]=c;
+		return *p!=NULL;
+	}else{
+		tmp[(*tmplen)++]=c;
+		return TRUE;
+	}
+}
+
+
+static bool _string_finish(char **p, char *tmp, int tmplen)
+{
+	char *tmp2;
+	
+	if(tmplen==0){
+		if(*p==NULL)
+			*p=scopy("");
+	}else{
+		tmp[tmplen]='\0';
+		if(*p!=NULL){
+			tmp2=scat(*p, tmp);
+			free(*p);
+			*p=tmp2;
+		}else{
+			*p=scopy(tmp);
+		}
+	}
+	return *p!=NULL;
+}
+
+
+/* */
+
+
+#define INC_LINE() tokz->line++
+#define GETCH() _getch(tokz)
+#define UNGETCH(C) _ungetch(tokz, C)
+
+static int _getch(Tokenizer *tokz)
+{
+	int c;
+	
+	if(tokz->ungetc!=-1){
+		c=tokz->ungetc;
+		tokz->ungetc=-1;
+	}else{
+		c=getc(tokz->file);
+	}
+/*	if(c=='\n')
+		tokz->line++;*/
+	
+	return c;
+}
+
+
+static void _ungetch(Tokenizer *tokz, int c)
+{
+/*	if(c=='\n')
+		tokz->line--;*/
+	tokz->ungetc=c;
+	/*ungetc(c, tokz->file);*/
+}
+
+
+/* */
+
+
+static int scan_line_comment(Token *tok, Tokenizer *tokz)
+{
+	STRING_DECL_P(s, "#");
+	int c;
+
+	c=GETCH();
+				
+	while(c!='\n' && c!=EOF){
+		STRING_APPEND(s, c);
+		c=GETCH();
+	}
+
+	UNGETCH(c);
+
+	STRING_FINISH(s);
+	
+	TOK_SET_COMMENT(tok, s);
+	
+	return 0;
+}
+
+
+static int skip_line_comment(Tokenizer *tokz)
+{
+	int c;
+	
+	do{
+		c=GETCH();
+	}while(c!='\n' && c!=EOF);
+
+	UNGETCH(c);
+		
+	return 0;
+}
+
+
+/* */
+
+
+static int scan_c_comment(Token *tok, Tokenizer *tokz)
+{
+	STRING_DECL_P(s, "/*");
+	int c;
+	int st=0;
+	
+	while(1){
+		c=GETCH();
+		
+		if(c==EOF){
+			STRING_FREE(s);
+			return E_TOKZ_UNEXPECTED_EOF;
+		}
+		
+		STRING_APPEND(s, c);
+		
+		if(c=='\n'){
+			INC_LINE();
+		}else if(st==0 && c=='*'){
+			st=1;
+		}else if(st==1){
+			if(c=='/')
+				break;
+			st=0;
+		}
+	}
+
+	STRING_FINISH(s);
+
+	TOK_SET_COMMENT(tok, s);
+
+	return 0;
+}
+
+
+static int skip_c_comment(Tokenizer *tokz)
+{
+	int c;
+	int st=0;
+	
+	while(1){
+		c=GETCH();
+		
+		if(c==EOF)
+			return E_TOKZ_UNEXPECTED_EOF;
+		
+		if(c=='\n')
+			INC_LINE();
+		else if(st==0 && c=='*')
+			st=1;
+		else if(st==1){
+			if(c=='/')
+				break;
+			st=0;
+		}
+	}
+	
+	return 0;
+}
+
+
+/* */
+
+
+static int scan_char_escape(Tokenizer *tokz)
+{
+	static char* special_chars="nrtbae";
+	static char* specials="\n\r\t\b\a\033";
+	int base, max;
+	int i ,c;
+	
+	c=GETCH();
+	
+	for(i=0;special_chars[i];i++){
+		if(special_chars[i]==c)
+			return specials[c];
+	}
+	
+	if(c=='x' || c=='X'){
+		base=16;max=2;i=0;
+	}else if(c=='d' || c=='D'){
+		base=10;max=3;i=0;
+	}else if(c=='8' || c=='9'){
+		base=10;max=2;i=c-'0';
+	}else if('0'<=c && c<='7'){
+		base=8;max=2;i=c-'0';
+	}else if(c=='\n'){
+		UNGETCH(c);
+		return -2;
+	}else{
+		return c;
+	}
+	
+		
+	while(--max>=0){
+		c=GETCH();
+		
+		if(c==EOF)
+			return EOF;
+		
+		if(c=='\n'){
+			UNGETCH(c);
+			return -2;
+		}
+		
+		if(base==16){
+			if(!isxdigit(c))
+				break;
+			
+			i<<=4;
+			
+			if(isdigit(c))
+				i+=c-'0';
+			else if(i>='a')
+				i+=0xa+c-'a';
+			else
+				i+=0xa+c-'a';
+			
+		}else if(base==10){
+			if(!isdigit(c))
+				break;
+			i*=10;
+			i+=c-'0';
+		}else{
+			if(c<'0' || c>'7')
+				break;
+			i<<=3;
+			i+=c-'0';
+		}
+	}
+	
+	if(max>=0)
+		UNGETCH(c);
+
+	return i;
+}
+
+
+/* */
+
+
+static int scan_string(Token *tok, Tokenizer *tokz, bool escapes)
+{
+	STRING_DECL(s);
+	int c;
+
+	while(1){	
+		c=GETCH();
+		
+		if(c=='"')
+			break;
+		
+		if(c=='\n'){
+			UNGETCH(c);
+			STRING_FREE(s);
+			return E_TOKZ_UNEXPECTED_EOL;
+		}
+		
+		if(c=='\\' && escapes){
+			c=scan_char_escape(tokz);
+			if(c==-2){
+				STRING_FREE(s);
+				return E_TOKZ_UNEXPECTED_EOL;
+			}
+		}
+		
+		if(c==EOF){
+			STRING_FREE(s);
+			return E_TOKZ_UNEXPECTED_EOF;
+		}
+		
+		STRING_APPEND(s, c);
+	}
+	
+	STRING_FINISH(s);
+	
+	TOK_SET_STRING(tok, s);
+
+	return 0;
+}
+
+
+/* */
+
+
+static int scan_char(Token *tok, Tokenizer *tokz)
+{
+	int c, c2;
+	
+	c=GETCH();
+	
+	if(c==EOF)
+		return E_TOKZ_UNEXPECTED_EOF;
+	
+	if(c=='\n')
+		return E_TOKZ_UNEXPECTED_EOL;
+
+	if(c=='\\'){
+		c=scan_char_escape(tokz);	
+		
+		if(c==EOF)
+			return E_TOKZ_UNEXPECTED_EOF;
+		
+		if(c==-2)
+			return E_TOKZ_UNEXPECTED_EOL;
+	}
+	
+	c2=GETCH();
+	
+	if(c2!='\'')
+		return E_TOKZ_MULTICHAR;
+	
+	TOK_SET_CHAR(tok, c);
+	
+	return 0;
+}
+
+
+/* */
+
+
+#define START_IDENT(X) (isalpha(X) || X=='_' || X=='$')
+
+
+static int scan_identifier(Token *tok, Tokenizer *tokz, int c)
+{
+	STRING_DECL(s);
+	
+	do{
+		STRING_APPEND(s, c);
+		c=GETCH();
+	}while(isalnum(c) || c=='_' || c=='$');
+	
+	UNGETCH(c);
+	
+	STRING_FINISH(s);
+	
+	TOK_SET_IDENT(tok, s);
+
+	return 0;
+}
+
+
+#include "numparser2.h"
+#include "np-conv.h"
+
+
+static int scan_number(Token *tok, Tokenizer *tokz, int c)
+{
+	NPNum num=NUM_INIT;
+	int e;
+	
+	if((e=parse_number(&num, tokz, c)))
+		return e;
+	
+	if(num.type==NPNUM_INT){
+		long l;
+		if((e=num_to_long(&l, &num, TRUE)))
+			return e;
+	
+		TOK_SET_LONG(tok, l);
+	}else if(num.type==NPNUM_FLOAT){
+  		double d;
+  		if((e=num_to_double(&d, &num)))
+	  		return e;
+			
+		TOK_SET_DOUBLE(tok, d);
+	}else{
+		return E_TOKZ_NUMFMT;
+	}
+
+	return 0;
+}
+
+
+/* */
+
+
+static uchar op_map[]={
+	0x00,		/* ________ 0-7     */
+	0x00,		/* ________ 8-15    */
+	0x00,		/* ________ 16-23   */
+	0x00,		/* ________ 24-31   */
+	0x62,		/* _!___%&_ 32-39   */
+	0xff,		/* ()*+,-./ 40-47   */
+	0x00,		/* ________ 48-55   */
+	0xfc,		/* __:;<=>? 56-63   */
+	0x01,		/* @_______ 64-71   */
+	0x00,		/* ________ 72-79   */
+	0x00,		/* ________ 80-87   */
+	0x78,		/* ___[_]^_ 88-95   */
+	0x00,		/* ________ 96-103  */
+	0x00,		/* ________ 104-111 */
+	0x00,		/* ________ 112-119 */
+	0x38		/* ___{|}__ 120-127 */
+};
+
+
+static bool map_isset(uchar *map, uint ch)
+{
+	if(ch>127)
+		return FALSE;
+
+	return map[ch>>3]&(1<<(ch&7));
+}
+
+
+static bool is_opch(uint ch)
+{
+	return map_isset(op_map, ch);
+}
+
+
+static int scan_op(Token *tok, Tokenizer *tokz,  int c)
+{
+	int c2;
+	int op=-1;
+	
+	/* Quickly check it is an operator character */
+	if(!is_opch(c))
+		return E_TOKZ_INVALID_CHAR;
+
+	switch(c){
+	case '+':
+	case '-':
+	case '*':
+/*	case '/':	 Checked elsewhere */
+	case '%':
+	case '^':
+	case '!':
+	case '=':
+	case '<':
+	case '>':
+		c2=GETCH();
+		if(c2=='='){
+			op=c|(c2<<8);
+		}else if(c2==c && (c2!='%' && c2!='!' && c2!='*')){
+			if(c=='<' || c=='>'){
+				int c3=GETCH();
+				if(c3=='='){
+					op=c|(c2<<8)|(c3<<16);
+				}else{
+					UNGETCH(c3);
+					op=c|(c2<<8);
+				}
+			}else{
+				op=c|(c2<<8);
+			}
+		}else{
+			UNGETCH(c2);
+			op=c;
+		}
+		break;
+		
+	/* It is already known that it is a operator so these are not needed
+	case ':':
+	case '~':
+	case '?':
+	case '.':
+	case ';';
+	case '{':
+	case '}':
+	case '@':		
+	case '|':
+	case '&':
+	*/
+	default:
+		op=c;
+	}
+	
+	TOK_SET_OP(tok, op);
+
+	return 0;
+}
+
+
+/* */
+
+
+void tokz_warn_error(const Tokenizer *tokz, int line, int e)
+{
+	if(e==E_TOKZ_UNEXPECTED_EOF)
+		line=0;
+	
+	if(e<0)
+		warn_obj_line(tokz->name, line, "%s", strerror(-e));
+	else
+		warn_obj_line(tokz->name, line, "%s", TR(errors[e]));
+}
+
+
+bool tokz_get_token(Tokenizer *tokz, Token *tok)
+{
+	int c, c2, e;
+	
+	assert(tokz->file);
+	
+	tok_free(tok);
+	
+	while(1){
+	
+		e=0;
+		
+		do{
+			c=GETCH();
+		}while(c!='\n' && c!=EOF && isspace(c));
+	
+		tok->line=tokz->line;
+	
+		switch(c){
+		case EOF:
+			TOK_SET_OP(tok, OP_EOF);
+			return TRUE;
+			
+		case '\n':
+			INC_LINE();
+			
+			if(tokz->flags&TOKZ_IGNORE_NEXTLINE)
+				continue;
+			
+			TOK_SET_OP(tok, OP_NEXTLINE);
+			
+			return TRUE;
+			
+		case '\\':
+			do{
+				c=GETCH();
+				if(c==EOF){
+					TOK_SET_OP(tok, OP_EOF);
+					return FALSE;
+				}
+				if(!isspace(c)){
+					tokz_warn_error(tokz, tokz->line, E_TOKZ_EOL_EXPECTED);
+					return FALSE;
+				}
+			}while(c!='\n');
+			
+			INC_LINE();
+			continue;
+
+		case '#':
+			if(tokz->flags&TOKZ_READ_COMMENTS){
+				e=scan_line_comment(tok, tokz);
+				break;
+			}else if((e=skip_line_comment(tokz))){
+				break;
+			}
+			
+			continue;
+			
+		case '/':
+			{
+				c2=GETCH();
+				
+				if(c2=='='){
+					TOK_SET_OP(tok, OP_AS_DIV);
+					return TRUE;
+				}
+				
+				if(c2!='*'){
+					UNGETCH(c2);
+					TOK_SET_OP(tok, OP_DIV);
+					return TRUE;
+				}
+
+				if(tokz->flags&TOKZ_READ_COMMENTS){
+					e=scan_c_comment(tok, tokz);
+					break;
+				}else if((e=skip_c_comment(tokz))){
+					break;
+				}
+				
+				continue;
+			}
+			
+		case '\"':
+			e=scan_string(tok, tokz, TRUE);
+			break;
+
+		case '\'':
+			e=scan_char(tok, tokz);
+			break;
+
+		default: 
+			if(('0'<=c && c<='9') || c=='-' || c=='+'){
+				e=scan_number(tok, tokz, c);
+				break;
+			}
+
+		 	if(START_IDENT(c))
+				e=scan_identifier(tok, tokz, c);
+			else
+				e=scan_op(tok, tokz, c);
+		}
+		
+		if(!e)
+			return TRUE;
+		
+		tokz_warn_error(tokz, tokz->line, e);
+		return FALSE;
+	}
+}
+
+
+Tokenizer *tokz_open(const char *fname)
+{ 
+	Tokenizer*tokz;
+	FILE*file;
+	
+	file=fopen(fname, "r");
+	
+	if(file==NULL){
+		warn_err_obj(fname);
+		return NULL;
+	}
+	
+	tokz=tokz_open_file(file);
+	
+	if(tokz==NULL)
+		fclose(file);
+	else
+		tokz->name=fname;
+	
+	return tokz;
+}
+
+
+Tokenizer *tokz_open_file(FILE *file)
+{
+	Tokenizer*tokz;
+	
+	tokz=ALLOC(Tokenizer);
+	
+	if(tokz==NULL){
+		warn_err();
+		return NULL;
+	}
+	
+	tokz->file=file;
+	tokz->name=NULL;
+	tokz->line=1;
+	tokz->ungetc=-1;
+	tokz->flags=0;
+	tokz->optstack=NULL;
+	tokz->nest_lvl=0;
+	
+	return tokz;
+}
+
+
+void tokz_close(Tokenizer *tokz)
+{
+	if(tokz->file!=NULL)
+		fclose(tokz->file);
+
+	free(tokz);
+}
+
+
+/* */
+
+
+void tok_free(Token *tok)
+{
+	if(TOK_IS_STRING(tok))
+		free(TOK_STRING_VAL(tok));
+	
+	tok->type=TOK_INVALID;
+}
+
+
+void tok_init(Token *tok)
+{
+	static Token dummy=TOK_INIT;
+	
+	memcpy(tok, &dummy, sizeof(*tok));
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/util.c	Tue Feb 15 18:57:52 2005 +0100
@@ -0,0 +1,227 @@
+/*
+ * libtu/util.c
+ *
+ * Copyright (c) Tuomo Valkonen 1999-2000.
+ * 
+ * This file is distributed under the terms of the "Artistic License".
+ * See the included file LICENSE for details.
+ */
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef CONFIG_LOCALE
+#include <libintl.h>
+#endif
+
+#include "include/util.h"
+#include "include/misc.h"
+
+
+static const ProgInfo *proginfo=NULL;
+static const char *progname=NULL;
+
+static void common_opts(int *argc, char *argv[]);
+
+
+void libtu_init_argv0(const char *argv0, const ProgInfo *info)
+{
+	progname=argv0;
+	proginfo=info;
+	
+#ifdef CONFIG_LOCALE
+	textdomain(simple_basename(argv0));
+#endif
+}
+
+
+void libtu_init(int *argc, char *argv[], const ProgInfo *info)
+{
+	libtu_init_argv0(argv[0], info);
+	
+	common_opts(argc, argv);
+}
+
+
+const char *prog_execname()
+{
+	return progname;
+}
+
+
+const ProgInfo *prog_info()
+{
+	return proginfo;
+}
+
+
+const char *prog_name()
+{
+	return proginfo ? proginfo->name : NULL;
+}
+
+
+const char *prog_version()
+{
+	return proginfo ? proginfo->version : NULL;
+}
+
+
+const char *prog_authors()
+{
+	return proginfo ? proginfo->authors : NULL;
+}
+
+
+const char *prog_license()
+{
+	return proginfo ? proginfo->license : NULL;
+}
+
+
+const char *prog_usage()
+{
+	return proginfo ? proginfo->usage : NULL;
+}
+
+
+/* */
+
+
+static char *usages[][2]={
+	{"--help",		"Show this help\n"},
+	{"--version",	"Show program version\n"},
+	{"--authors",	"Show program authors\n"},
+	{"--license",	"Show program license\n"},
+	{"--proginfo",	"Show program info\n"},
+	{NULL,}
+};
+
+
+static void common_usage(size_t start, size_t len)
+{
+	size_t l;
+	int i;
+	
+	for(i=0; usages[i][0]!=NULL; i++){
+	
+		for(l=0; l<start; l++){
+			putc(' ', stdout);
+		};
+		
+		l=strlen(usages[i][0]);
+		writef(stdout, usages[i][0], l);
+		
+		do{
+			putc(' ', stdout);
+		}while(++l<len-start);
+		
+		writef(stdout, usages[i][1], strlen(usages[i][1]));
+	}
+}
+
+
+static void show_usage(const char *p)
+{
+	const char *tmp;
+	size_t len;
+	size_t start;
+	
+	do{
+		tmp=strchr(p, '\n');
+
+		if(tmp==NULL){
+			len=strlen(p);
+			if(len==0)
+				break;
+		}else{
+			len=tmp-p;
+		}
+		
+		start=strspn(p, " ");
+		
+		if(p[start]=='$' && p[start+1]=='u'){
+			tmp=prog_execname();
+			if(start!=0)
+				writef(stdout, p, start);
+			printf(TR("Usage: %s"), tmp);
+			writef(stdout, p+start+2, len-start-2);
+			putc('\n', stdout);
+		}else if(p[start]=='$' && p[start+1]=='c'){
+			common_usage(start, len);
+		}else{
+			writef(stdout, p, len);
+			putc('\n', stdout);
+		}
+		
+		p+=len+1;
+	}while(*(p-1)!='\0');
+	
+}
+
+
+static void common_opts(int *argcp, char *argv[])
+{
+	int argc=*argcp;
+	const char *p, *p2;
+
+	argc--;
+	argv++;
+	
+	for(; argc>0; argc--, argv++){
+		if(strcmp(*argv, "--help")==0){
+			p=prog_usage();
+			if(p==NULL){
+				printf(TR("Usage: %s [options]\n"
+						  "Where options are:\n\n"), prog_execname());
+				common_usage(5, 20);
+				printf("\n");
+			}else{
+				show_usage(p);
+			}
+		}else if(strcmp(*argv, "--version")==0){
+			p=prog_version();
+			if(p==NULL)
+				printf(TR("No version available\n"));
+			else
+				printf("%s\n", p);
+		}else if(strcmp(*argv, "--authors")==0){
+			p=prog_authors();
+			if(p==NULL)
+				printf(TR("No author(s) info available\n"));
+			else
+				printf("%s\n", p);
+		}else if(strcmp(*argv, "--license")==0){
+			p=prog_license();
+			if(p==NULL)
+				printf(TR("No license available\n"));
+			else
+				printf("%s", TR(p));
+		}else if(strcmp(*argv, "--proginfo")==0){
+			p2=prog_version();
+			p=prog_name();
+			
+			if(p==NULL){
+				p=prog_execname();
+			
+				if(p==NULL){
+					printf(TR("No name available\n"));
+					break;
+				}
+			}
+			
+			if(p2)
+				printf("%s v%s\n", p, p2);
+			else
+				printf("%s\n", p);
+		}else if(strcmp(*argv, "--")){
+			break;
+		}else{
+			continue;
+		}
+			
+		exit(EXIT_SUCCESS);
+	}
+}

mercurial