Tue, 15 Feb 2005 18:57:52 +0100
Tailorization of trunk
Import of the upstream sources from the repository
http://tao.uab.es/ion/svn/libtu/trunk
as of revision 2
--- /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); + } +}