diff options
author | Bernie Innocenti <bernie@codewiz.org> | 2010-05-03 21:53:47 (GMT) |
---|---|---|
committer | Bernie Innocenti <bernie@codewiz.org> | 2010-05-03 21:53:47 (GMT) |
commit | 1030dc837b10a03a02a85d5504cbeec168ce49e2 (patch) | |
tree | 698eefa87ac437deaf36a4141b326f8ce7986692 /src/util |
Import XaoS r489 (trunk after version 3.5)
Diffstat (limited to 'src/util')
-rw-r--r-- | src/util/Makefile.in | 50 | ||||
-rw-r--r-- | src/util/catalog.c | 253 | ||||
-rw-r--r-- | src/util/help.c | 95 | ||||
-rw-r--r-- | src/util/png.c | 201 | ||||
-rw-r--r-- | src/util/thread.c | 221 | ||||
-rw-r--r-- | src/util/timers.c | 670 | ||||
-rw-r--r-- | src/util/util.pri | 12 | ||||
-rw-r--r-- | src/util/xerror.c | 43 | ||||
-rw-r--r-- | src/util/xldio.c | 603 | ||||
-rw-r--r-- | src/util/xmenu.c | 998 | ||||
-rw-r--r-- | src/util/xshl.c | 470 | ||||
-rw-r--r-- | src/util/xstdio.c | 488 | ||||
-rw-r--r-- | src/util/xstring.c | 141 |
13 files changed, 4245 insertions, 0 deletions
diff --git a/src/util/Makefile.in b/src/util/Makefile.in new file mode 100644 index 0000000..36aad5c --- /dev/null +++ b/src/util/Makefile.in @@ -0,0 +1,50 @@ +CC = @CC@ +CFLAGS = @CFLAGS@ +LIBS = @LIBS@ -lm +LFLAGS = @LDFLAGS@ +AR = @AR@ +RANLIB = @RANLIB@ + +SRCS = \ + png.c \ + catalog.c \ + thread.c \ + xstring.c \ + help.c \ + xerror.c \ + xshl.c \ + xldio.c \ + xstdio.c \ + xmenu.c \ + timers.c + +OBJS = $(SRCS:.c=.o) + +TLIB = ../lib/libutil.a + + +all: $(TLIB) + +$(TLIB):$(OBJS) + rm -f $@ + $(AR) rc $@ $(OBJS) + $(RANLIB) $@ + +clean: + rm -f $(TLIB) + rm -f *.[oas] + rm -f *~ + rm -f core + +distclean:clean + rm Makefile + +#dep: +# rm -f .depend +# make .depend +# +#.depend: +# echo '# Program dependencies' >.depend +# gcc -I svgalib $(DEFINES) -MM $(patsubst %.o,%.c,$(OBJS)) >>.depend +# +#include .depend diff --git a/src/util/catalog.c b/src/util/catalog.c new file mode 100644 index 0000000..76cfa69 --- /dev/null +++ b/src/util/catalog.c @@ -0,0 +1,253 @@ +#include <config.h> +#ifndef _plan9_ +#include <string.h> +#ifndef NO_MALLOC_H +#include <malloc.h> +#endif +#include <string.h> +#else +#include <u.h> +#include <libc.h> +#endif +#include <catalog.h> +#include <misc-f.h> +/* Well, just simple implementation of unbalanced trees in combination + * of small hash table. I am lazy :) but should be OK for my purposes + * + * This function is used for both-lookups and adds into table (since most of + * code is the same, depends whether newvalue is NULL. If newvalue is nonNULL, + * new variable is added into table, if name is not present here or value is + * changed othewise. + */ +static char *find_variable(catalog_t * context, CONST char *name, + CONST char *newvalue) +{ + int r = 0; + int hash = (int) strlen(name); + struct varnames *current, *last, *newp; + hash = + ((unsigned char) (name[0]) + (unsigned char) (name[hash - 1]) + + hash) % (unsigned int) CHASHMAX; + current = last = context->root[hash]; + while (current != NULL) { + last = current; + r = strcmp(current->name, name); + if (!r) { + if (newvalue != NULL) { /*overwrite value */ + free(current->value); + current->value = mystrdup(newvalue); + } + return (current->value); + } + if (r > 0) + current = current->left; + else + current = current->right; + } + /*Entry is new */ + if (newvalue == NULL) + return (NULL); + newp = (struct varnames *) calloc(1, sizeof(struct varnames)); + newp->name = mystrdup(name); + newp->value = mystrdup(newvalue); + /*FIXME. Should take a care to full memory */ + newp->left = NULL; + newp->right = NULL; + if (last == NULL) { + context->root[hash] = newp; + } else { + if (r > 0) + last->left = newp; + else + last->right = newp; + } + return (newp->value); +} + +/* + * free memory used by node and its sons + */ +static void free_node(struct varnames *node) +{ + while (node != NULL) { + struct varnames *nextnode; + free_node(node->left); + nextnode = node->right; + free(node->name); + free(node->value); + free(node); + node = nextnode; + } +} + +/* + * free catalog + */ +void free_catalog(catalog_t * context) +{ + int i; + for (i = 0; i < CHASHMAX; i++) { + free_node(context->root[i]); + context->root[i] = NULL; + } + free(context); +} + +static catalog_t *alloc_catalog(void) +{ + int i; + catalog_t *c; + c = (catalog_t *) calloc(1, sizeof(catalog_t)); + if (c == NULL) + return NULL; + for (i = 0; i < CHASHMAX; i++) + c->root[i] = NULL; + return c; +} + +/* + * Parse an catalog file and save values into memory + */ +// FIXME: this macro gives a segfault if \" is used in text. kovzol, 2009-06-29 +#define seterror(text) sprintf(errort,"line %i:%s",line,text),*error=errort +catalog_t *load_catalog(xio_file f, CONST char **error) +{ + int i; + int line = 1; + int size; + int c; + catalog_t *catalog = alloc_catalog(); + static char errort[40]; + char name[1024]; + char value[1024]; + if (catalog == NULL) { + *error = "Out of memory"; + } + if (f == NULL) { + *error = "File could not be opened"; + free_catalog(catalog); + return NULL; + } + /* Just very simple parsing loop of format + * [blanks]name[blanks]"value"[blanks] + * Blanks should be comments using # or space, newline, \r and tabulator + * Value shoud contain and \ seqences where \\ means \ and + * \[something] means something. Should be used for character " + */ + while (!xio_feof(f)) { + + do { + c = xio_getc(f); + if (c == '\n') + line++; + if (c == '#') { + while ((c = xio_getc(f)) != '\n' && c != XIO_EOF); + line++; + } + } + while (c == ' ' || c == '\n' || c == '\r' || c == '\t'); + + /*Skip blanks */ + if (c == XIO_EOF) { + if (xio_feof(f)) + break; + free_catalog(catalog); + seterror("read error"); + xio_close(f); + return NULL; + } + i = 0; + + /*read name */ + do { + name[i] = c; + i++; + c = xio_getc(f); + if (c == '\n') + line++; + if (i == 1024) { + seterror("Name is too long (>=1024 characters)"); + free_catalog(catalog); + xio_close(f); + return NULL; + } + } + + while (c != '\n' && c != ' ' && c != '\t' && c != XIO_EOF); + + /*Skip blanks */ + while (c == ' ' || c == '\n' || c == '\r' || c == '\t') { + c = xio_getc(f); + if (c == '\n') + line++; + if (c == '#') { + while ((c = xio_getc(f)) != '\n' && c != XIO_EOF); + line++; + } + } + + /*Skip blanks */ + if (c == XIO_EOF) { + if (xio_feof(f)) + seterror("Unexpected end of file after name field"); + else + seterror("read error"); + free_catalog(catalog); + xio_close(f); + return NULL; + } + + name[i] = 0; + if (c != '"') { + seterror("Begin of value field expected"); // Text modified due to segfault problem, see above (kovzol) + free_catalog(catalog); + xio_close(f); + return NULL; + } + c = xio_getc(f); + if (c == '\n') + line++; + i = 0; + + size = 0; + do { + if (c == '\\') + value[i] = xio_getc(f); + else + value[i] = c; + i++; + c = xio_getc(f); + if (c == '\n') + line++, size = 0; + if (size == 40 && c != '"') { + fprintf(stderr, "Warning - too long text at line %i\n", + line); + } + size++; + if (i == 1024) { + seterror("Value is too long (>=1024 characters)"); + free_catalog(catalog); + xio_close(f); + return NULL; + } + } + while (c != '"' && c != XIO_EOF); + + if (c == XIO_EOF) { + seterror("Unexpected EOF in value field"); + free_catalog(catalog); + xio_close(f); + return NULL; + } + + value[i] = 0; + find_variable(catalog, name, value); + } /*while */ + xio_close(f); + return (catalog); +} /*load_catalog */ + +char *find_text(catalog_t * catalog, CONST char *name) +{ + return (find_variable(catalog, name, NULL)); +} diff --git a/src/util/help.c b/src/util/help.c new file mode 100644 index 0000000..adaabb7 --- /dev/null +++ b/src/util/help.c @@ -0,0 +1,95 @@ +#ifdef _plan9_ +#include <u.h> +#include <libc.h> +#else +#include <stdlib.h> +#endif +#include <ctype.h> +#include <config.h> +#include <xio.h> +#include <xshl.h> +struct helpstatus { + int eol; + xio_file file; +}; +static int gethelp(void *userdata) +{ + struct helpstatus *s = (struct helpstatus *) userdata; + int c = xio_getc(s->file); + if (c == '\r') + return (gethelp(userdata)); + if (c < 0 || c > 255) + return 0; + if (c == '%' && s->eol) + return 0; + s->eol = (c == '\n'); + return c; +} + +struct xshl_line *help_make(CONST char *command, + int getwidth(void *, int flags, + CONST char *text), int width, + int smallheight, int bigheight) +{ + struct helpstatus *s = (struct helpstatus *) malloc(sizeof(*s)); + struct xshl_line *line; + s->file = xio_gethelp(); + if (s->file == XIO_FAILED) { + free(s); + return 0; + } + s->eol = 1; + while (1) { + int c; + c = xio_getc(s->file); + if (c == '%' && s->eol) { + c = xio_getc(s->file); + do { + int i = 0; + i = 0; + while (command[i] && c == command[i]) { + c = xio_getc(s->file); + i++; + } + if (!command[i]) { + if (isspace(c)) { + while (c != '\n' && !xio_feof(s->file)) + c = xio_getc(s->file); + line = + xshl_interpret(s, gethelp, width, getwidth, 0, + smallheight, bigheight); + xio_close(s->file); + free(s); + return (line); + } + } else { + while (c != '\n' && c != ' ' && !xio_feof(s->file)) + c = xio_getc(s->file); + if (c == ' ') + while (c == ' ') + c = xio_getc(s->file); + } + } + while (c != '\n' && !xio_feof(s->file)); + } /*c==% */ + s->eol = (c == '\n'); + if (xio_feof(s->file)) { + xio_close(s->file); + return NULL; + } + } /*while 1 */ +} + +#if _NEVER_ +void help_print(char *name, int skip, int width) +{ + struct xshl_line *l; + l = help_make(name, xshl_textlen, width, 1, 1); + if (l == NULL) { + printf("Help not available!\n"); + return; + } + xshl_print(skip, l); + xshl_free(l); +} +#endif diff --git a/src/util/png.c b/src/util/png.c new file mode 100644 index 0000000..4fb01bc --- /dev/null +++ b/src/util/png.c @@ -0,0 +1,201 @@ +#include <config.h> +#ifndef _plan9_ +#include <aconfig.h> +#ifdef USE_PNG +#include <png.h> +#endif +#include <stdlib.h> +#include <stdio.h> +#ifndef NO_MALLOC_H +#include <malloc.h> +#endif +#include <errno.h> +#else +#include <u.h> +#include <libc.h> +#include <stdio.h> +#endif +#include <filter.h> +#include <version.h> +#include <misc-f.h> +#include <xio.h> +#ifndef USE_PNG +CONST char *writepng(xio_constpath filename, CONST struct image *img) +{ + return + "XaoS can not save images because it was incorrectly compiled. Please compile it with zlib and libpng"; +} +#else + +CONST char *writepng(xio_constpath filename, CONST struct image *image) +{ + png_structp png_ptr; + png_infop info_ptr; + png_color palette[256]; + volatile unsigned short a = 255; + volatile unsigned char *b = (volatile unsigned char *) &a; +#ifdef _undefined_ + static char text[] = + "XaoS" XaoS_VERSION " - a realtime interactive fractal zoomer"; + static png_text comments[] = { + { + -1, + "Software", + text, + sizeof(text)} + }; +#endif + FILE *file = fopen(filename, "wb"); + errno = -1; + if (file == NULL) { + return strerror(errno); + } + png_ptr = + png_create_write_struct(PNG_LIBPNG_VER_STRING, (void *) NULL, + (png_error_ptr) NULL, + (png_error_ptr) NULL); + if (!png_ptr) + return "Unable to initialize pnglib"; + info_ptr = png_create_info_struct(png_ptr); + if (!info_ptr) { + png_destroy_write_struct(&png_ptr, (png_infopp) NULL); + return "No memory to create png info structure"; + } + if (setjmp(png_ptr->jmpbuf)) { + png_destroy_write_struct(&png_ptr, &info_ptr); + fclose(file); + return strerror(errno); + } + png_init_io(png_ptr, file); + png_set_filter(png_ptr, 0, + PNG_FILTER_NONE | PNG_FILTER_SUB | PNG_FILTER_PAETH | + PNG_FILTER_UP | PNG_FILTER_AVG); + /* set the zlib compression level */ + /*png_set_compression_level(png_ptr, Z_BEST_COMPRESSION); */ + png_set_compression_level(png_ptr, Z_DEFAULT_COMPRESSION); + + /* set other zlib parameters */ + png_set_compression_mem_level(png_ptr, 8); + png_set_compression_strategy(png_ptr, Z_DEFAULT_STRATEGY); + png_set_compression_window_bits(png_ptr, 15); + png_set_compression_method(png_ptr, 8); + + info_ptr->width = image->width; + info_ptr->height = image->height; + /*info_ptr->gamma=1.0; */ + info_ptr->gamma = 0.5; + info_ptr->valid |= PNG_INFO_gAMA | PNG_INFO_pHYs; + info_ptr->x_pixels_per_unit = (png_uint_32) (100 / image->pixelwidth); + info_ptr->y_pixels_per_unit = (png_uint_32) (100 / image->pixelheight); + + + switch (image->palette->type) { + case C256: + { + int i; + info_ptr->color_type = PNG_COLOR_TYPE_PALETTE; + info_ptr->bit_depth = image->bytesperpixel * 8; + info_ptr->palette = palette; + info_ptr->valid |= PNG_INFO_PLTE; + for (i = 0; i < image->palette->end; i++) + info_ptr->palette[i].red = image->palette->rgb[i][0], + info_ptr->palette[i].green = image->palette->rgb[i][1], + info_ptr->palette[i].blue = image->palette->rgb[i][2], + info_ptr->num_palette = image->palette->end; + } + break; + case SMALLITER: + case LARGEITER: + case GRAYSCALE: + info_ptr->color_type = PNG_COLOR_TYPE_GRAY; + info_ptr->bit_depth = image->bytesperpixel * 8; + break; + case TRUECOLOR: + case TRUECOLOR24: + case TRUECOLOR16: + info_ptr->color_type = PNG_COLOR_TYPE_RGB; + info_ptr->bit_depth = 8; + info_ptr->sig_bit.red = 8 - image->palette->info.truec.rprec; + info_ptr->sig_bit.green = 8 - image->palette->info.truec.gprec; + info_ptr->sig_bit.blue = 8 - image->palette->info.truec.bprec; + break; + } + info_ptr->interlace_type = 0; +#ifdef _undefined_ + png_set_text(png_ptr, info_ptr, comments, + sizeof(comments) / sizeof(png_text)); +#endif + + png_write_info(png_ptr, info_ptr); + /*png_set_filler(png_ptr,0,PNG_FILLER_AFTER); */ + png_set_packing(png_ptr); + if (image->palette->type & (TRUECOLOR | TRUECOLOR24 | TRUECOLOR16)) + png_set_shift(png_ptr, &(info_ptr->sig_bit)); + if (*b == 255) + png_set_swap(png_ptr); + png_set_bgr(png_ptr); + switch (image->palette->type) { + case C256: + case GRAYSCALE: + case SMALLITER: + case LARGEITER: +#ifdef STRUECOLOR24 + case TRUECOLOR24: + png_write_image(png_ptr, (png_bytepp) image->currlines); + break; +#endif + case TRUECOLOR: + { + int i, y; + unsigned char *r = (unsigned char *) malloc(image->width * 3); + for (i = 0; i < image->height; i++) { + for (y = 0; y < image->width; y++) + r[y * 3 + 2] = + (((pixel32_t **) (image-> + currlines))[i][y] & + image->palette->info.truec.rmask) >> image-> + palette->info.truec.rshift, r[y * 3 + 1] = + (((pixel32_t **) (image-> + currlines))[i][y] & + image->palette->info.truec.gmask) >> image-> + palette->info.truec.gshift, r[y * 3] = + (((pixel32_t **) (image-> + currlines))[i][y] & + image->palette->info.truec.bmask) >> image-> + palette->info.truec.bshift; + png_write_rows(png_ptr, (png_bytepp) & r, 1); + } + } + break; +#ifdef SUPPORT16 + case TRUECOLOR16: + { + int i, y; + unsigned char *r = (unsigned char *) malloc(image->width * 3); + for (i = 0; i < image->height; i++) { + for (y = 0; y < image->width; y++) + r[y * 3 + 2] = + (((pixel16_t **) (image-> + currlines))[i][y] & + image->palette->info.truec.rmask) >> image-> + palette->info.truec.rshift, r[y * 3 + 1] = + (((pixel16_t **) (image-> + currlines))[i][y] & + image->palette->info.truec.gmask) >> image-> + palette->info.truec.gshift, r[y * 3] = + (((pixel16_t **) (image-> + currlines))[i][y] & + image->palette->info.truec.bmask) >> image-> + palette->info.truec.bshift; + png_write_rows(png_ptr, (png_bytepp) & r, 1); + } + } + break; +#endif + } + png_write_end(png_ptr, info_ptr); + png_destroy_write_struct(&png_ptr, &info_ptr); + fclose(file); + return NULL; +} +#endif diff --git a/src/util/thread.c b/src/util/thread.c new file mode 100644 index 0000000..f3ef4a7 --- /dev/null +++ b/src/util/thread.c @@ -0,0 +1,221 @@ +#ifndef _plan9_ +#include <signal.h> +#include <stdio.h> +#endif +#include <xthread.h> +#ifndef __BEOS__ +struct taskinfo definfo = { + 0, +}; + +#ifndef nthreads + +#define getrange1(range,ncpu) ((range)*(ncpu))/nthreads +#define getrange2(range,ncpu) getrange1(range,(ncpu)+1) + +int ethreads = 0; +int nthreads = 1; + +#ifdef USE_PTHREAD + +/* Well conde follows is probably very ugly, since this is + * my absolutely first application for threads. Please let + * me know how to improvie it + */ + +static pthread_cond_t synccond, startcond; +static struct taskinfo infos[MAXTHREADS]; +static pthread_mutex_t synccondmutex, startcondmutex; +pthread_mutex_t semaphors[MAXSEMAPHORS]; +pthread_cond_t conds[MAXCONDS]; + +/*This loop is executed whole time in slave threads. + Its function is following: + 1) wait for message + 2) call function from message + 3) syncronize + 4) again + + To invoke this mechanizm main thread(#1) should call + xth_function + xth_synchronize forces forces thread to wait for others + */ + +static int nfinished; +static int npending; +static int counter; +static int bcounter; +static int bcounter1; +static int range; +static void *data; +static xfunction function; +static void *control_routine(void *i) +{ + struct taskinfo *info = i; + int mycounter = 0; + int r; + void *d; + xfunction f; + while (1) { + /* quite a lot pthread calls. Please if you are + * reading this code and crying "OH NO!" so ugly + * handling! Why so much calls? Stop crying, I am + * newbie in threads. Please rewrite my code and + * send me better and faster version. + * + * This function comunicates with pth_function from main loop + * as follows: it uses startcond to wait for order start function! + * Counter is used to ensure that main function did not give + * order whie control_routine was busy + * + * after order is received, function adress is readed from global + * variables and started. Pth_function then executes its + * own part of calculation. After that it waits counter + * nfinished to reach number of thasks-1. This is done + * using cond synccond and synccondmutex. Quite complex + * but it seems to work. Looking forward for someone, who + * should reduce number of _lock/_unlock + */ + pthread_mutex_lock(&synccondmutex); + nfinished++; + pthread_cond_signal(&synccond); + pthread_mutex_unlock(&synccondmutex); + + pthread_mutex_lock(&startcondmutex); + while (mycounter >= counter) { + if (bcounter > bcounter1) { + /*Well we are already locked using start lock..should be OK */ + mycounter--; + bcounter1++; + break; + } + pthread_cond_wait(&startcond, &startcondmutex); + } + r = range; + d = data; + f = function; + npending--; + pthread_mutex_unlock(&startcondmutex); + mycounter++; + f(d, info, getrange1(r, info->n), getrange2(r, info->n)); + } + return NULL; +} + +void pth_init(int nthreads1) +{ + int i; + pthread_attr_t attr; + if (ethreads) + return; + + if (nthreads1 == 1 || nthreads1 == 0) + return; /*use nothreads_* calls */ + if (nthreads1 > MAXTHREADS) + nthreads1 = MAXTHREADS; + nthreads = nthreads1; + + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); + + if (pthread_cond_init(&synccond, NULL)) + exit(1); + if (pthread_cond_init(&startcond, NULL)) + exit(1); + if (pthread_mutex_init(&synccondmutex, NULL)) + exit(1); + if (pthread_mutex_init(&startcondmutex, NULL)) + exit(1); + + infos[0].n = 0; + /*infos[0].id = pthread_self(); */ + + for (i = 0; i < MAXSEMAPHORS; i++) { + pthread_mutex_init(semaphors + i, NULL); + } + for (i = 0; i < MAXCONDS; i++) { + pthread_cond_init(conds + i, NULL); + } + + nfinished = 0; + for (i = 0; i < nthreads - 1; i++) { + if (pthread_create + (&infos[i + 1].id, &attr, control_routine, infos + i + 1)) { + nthreads = i + 1; + break; + } + infos[i + 1].n = i + 1; + } + if (nthreads != 1) + ethreads = 1; +} + +void pth_synchronize() +{ + /*Our job is done, synchronize now */ + if (nfinished < nthreads - 1) { + pthread_mutex_lock(&synccondmutex); + while (nfinished < nthreads - 1) { + pthread_cond_wait(&synccond, &synccondmutex); + } + pthread_mutex_unlock(&synccondmutex); + } + /*Ok job is done, lets continue :) */ +} + +void pth_bgjob(xfunction f, void *d) +{ + pthread_mutex_lock(&startcondmutex); + if (npending) { + printf("Collision!\n"); /*FIXME:remove this..I just want to know how often this happends */ + pthread_mutex_unlock(&startcondmutex); + f(d, infos, 0, 0); + } + if (bcounter < bcounter1) { + printf("Internal error\a\n"); + } + if (!nfinished) { + pthread_mutex_unlock(&startcondmutex); + /*no more CPU available :( */ + f(d, infos, 0, 0); + } + data = d; + range = 0; + function = f; + bcounter++; + nfinished--; + npending++; + pthread_cond_signal(&startcond); + pthread_mutex_unlock(&startcondmutex); +} + +void pth_function(xfunction f, void *d, int r) +{ + pth_synchronize(); + pthread_mutex_lock(&startcondmutex); + data = d; + range = r; + function = f; + /*And lets start it:) */ + nfinished = 0; + npending = nthreads - 1; + counter++; + if (nthreads == 2) + pthread_cond_signal(&startcond); + else + pthread_cond_broadcast(&startcond); + pthread_mutex_unlock(&startcondmutex); + + function(data, infos, getrange1(range, 0), getrange2(range, 0)); +} + +void pth_uninit() +{ + /*Should be empty for now since all threads will be killed after exit call */ + /*FIXME should be added something if necessary :) */ + nthreads = 1; + ethreads = 0; +} +#endif /*POSIX threads */ +#endif /*nthreads */ +#endif /*__BEOS__*/ diff --git a/src/util/timers.c b/src/util/timers.c new file mode 100644 index 0000000..13e9abe --- /dev/null +++ b/src/util/timers.c @@ -0,0 +1,670 @@ +/* + * XaoS, a fast portable realtime fractal zoomer + * Copyright (C) 1996,1997 by + * + * Jan Hubicka (hubicka@paru.cas.cz) + * Thomas Marsh (tmarsh@austin.ibm.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * All ugly architecture depended timing code is separated into this file.. + */ +#ifdef _plan9_ +#include <u.h> +#include <stdio.h> +#include <libc.h> +#else +#include <config.h> +#ifdef HAVE_GETTIMEOFDAY +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif + /*HAVE_UNISTD */ +#else +#ifdef HAVE_FTIME +#include <sys/timeb.h> +#endif + /*HAVE_FTIME */ +#endif + /*HAVE_GETTIMEOFDAY */ +#ifdef HAVE_SYS_TIME_H +#include <sys/time.h> +#else +#include <time.h> +#endif + /*HAVE_TIME_H */ +#include <aconfig.h> +#ifndef NO_MALLOC_H +#include <malloc.h> +#endif +#include <stdio.h> +#include <unistd.h> +#ifndef _MAC +#ifndef NO_MALLOC_H +#include <malloc.h> +#endif +#endif +#ifdef __BEOS__ +#include <OS.h> +#endif +#ifdef USE_ALLEGRO +#include <allegro.h> +#endif +#ifdef HAVE_SETITIMER +#include <signal.h> +#endif +#include <limits.h> +#endif +#ifndef _plan9_ +#include <assert.h> +#endif +#include "../include/timers.h" +#ifdef _WIN32 +#include <windows.h> +#endif + +#ifdef _WIN32 +#define QuadPart(x) x.QuadPart +#endif + +#ifndef SIGALRM +#undef HAVE_SETITIMER +#endif + +#define EMULDIV 1024 +struct timeemulator { + unsigned long int time; + unsigned long exact; +}; + + /* Definition of structure timer. There is lots of various formats for time + * at variious platforms. So there is quite lots of ifdefs... same is for + * saving current time and function comparing them. Rest of timer lib + * is platform independent + */ + + +struct timer { +#ifdef __BEOS__ + bigtime_t lastactivated; +#else +#ifdef _WIN32 + LARGE_INTEGER lastactivated; +#else +#ifdef USE_ALLEGRO + uclock_t lastactivated; +#else +#ifdef HAVE_UCLOCK + uclock_t lastactivated; +#else +#ifdef USE_CLOCK + int lastactivated; +#else +#ifdef HAVE_GETTIMEOFDAY + struct timeval lastactivated; +#else +#ifdef _plan9_ + int lastactivated; +#else +#ifdef HAVE_FTIME + struct timeb lastactivated; +#endif +#endif +#endif +#endif +#endif +#endif +#endif +#endif + unsigned long lastemulated; + struct timeemulator *emulator; + void (*handler) (void *); + void (*multihandler) (void *, int); + void *userdata; + struct timer *next, *previous, *group; + int interval; + int stopped; + int stoppedtime; + int slowdown; +}; + + /*Variable for saving current time */ +#ifdef __BEOS__ +bigtime_t currenttime; +#else +#ifdef _WIN32 +LARGE_INTEGER currenttime, frequency; +#else +#ifdef USE_ALLEGRO +int allegromode; +#define TICKSPERSEC 100 /*must be divisor of 1000000 */ +volatile static int counter = -1; +static int ainstalled; +#endif +#ifdef HAVE_UCLOCK +static uclock_t currenttime; +#else +#ifdef USE_CLOCK +static int currenttime; +#else +#ifdef HAVE_GETTIMEOFDAY +static struct timeval currenttime; +#ifdef AMIGA +extern long __timezone; +#define tzp __timezone +#else +static struct timezone tzp; +#endif +#else +#ifdef HAVE_FTIME +static struct timeb currenttime; +#endif +#endif +#endif +#endif +#ifdef _plan9_ +static int currenttime; +#endif +#endif +#endif + +#ifdef HAVE_SETITIMER +static int registered = 0, reghandler = 0; +static tl_group group2; +#endif +static tl_group group1; +tl_group *syncgroup = &group1, +#ifdef HAVE_SETITIMER + *asyncgroup = &group2; +#else + *asyncgroup = &group1; +#endif +#ifdef _plan9_ +#ifdef _plan9v2_ +static int plan9_msec(void) +{ /*this function was sent by Nigel Roles */ + static int fd = -1; + char buf[20]; /* ish */ + if (fd < 0) + fd = open("/dev/msec", OREAD); + else + seek(fd, 0, 0); + read(fd, buf, sizeof(buf)); + return atoi(buf); +} +#else +static int plan9_msec(void) +{ + return (int) (nsec() / 1000000); +} +#endif +#endif + +#ifndef __BEOS__ +#ifndef _WIN32 +#ifndef HAVE_GETTIMEOFDAY +#ifndef HAVE_FTIME +#ifndef _plan9_ +#ifndef _MAC +#error I am unable to get time in milisecond. Please edit timers.c and make tl_update_time and tl_lookup_timer to work for your architecture and send me then back(to hubicka@paru.cas.cz). You will need also define timers.h and change type of lasttime. +#endif +#endif +#endif +#endif +#endif +#endif + + +#ifdef USE_ALLEGRO +static void timer(void) +{ + counter++; +} + +END_OF_FUNCTION(timer); +#endif +/*following functions are architecture dependent */ +void tl_update_time(void) +{ +#ifdef __BEOS__ + currenttime = system_time(); +#else +#ifdef _WIN32 + QueryPerformanceCounter(¤ttime); +#else +#ifdef USE_ALLEGRO + if (allegromode) { + if (counter == -1) { + LOCK_VARIABLE(counter); + LOCK_FUNCTION(timer); + install_int(timer, 1000 / TICKSPERSEC); + ainstalled = 1; + counter = 0; + } + currenttime = counter; + return; + } +#endif +#ifdef HAVE_UCLOCK + currenttime = uclock(); +#else +#ifdef USE_CLOCK + currenttime = clock(); +#else +#ifdef HAVE_GETTIMEOFDAY + do { + gettimeofday(¤ttime, &tzp); + } + while (currenttime.tv_usec > 999999); +#else +#ifdef HAVE_FTIME + ftime(¤ttime); +#endif +#endif +#endif +#endif +#endif +#endif +#ifdef _plan9_ + currenttime = plan9_msec(); +#endif +} + +static INLINE int __lookup_timer(tl_timer * t) +{ +#ifdef __BEOS__ + return (currenttime - t->lastactivated); +#else +#ifdef _WIN32 + return ((QuadPart(currenttime) - + QuadPart(t->lastactivated)) * 1000000LL) / + QuadPart(frequency); +#else +#ifdef USE_ALLEGRO + if (allegromode) + return (((currenttime - + t->lastactivated) * (1000000LL / TICKSPERSEC))); +#endif +#ifdef HAVE_UCLOCK + return (((currenttime - + t->lastactivated) * 1000000LL) / UCLOCKS_PER_SEC); +#else +#ifdef USE_CLOCK + return ((currenttime - + t->lastactivated) * (1000000.0 / CLOCKS_PER_SEC)); +#else +#ifdef HAVE_GETTIMEOFDAY + return ((1000000 * + (-(int) t->lastactivated.tv_sec + (int) currenttime.tv_sec) + + (-(int) t->lastactivated.tv_usec + + (int) currenttime.tv_usec))); +#else +#ifdef HAVE_FTIME + return ((1000000 * (-t->lastactivated.time + currenttime.time) + + 1000 * (-t->lastactivated.millitm + currenttime.millitm))); +#else +#ifdef _plan9_ + return ((currenttime - t->lastactivated) * 1000); +#endif +#endif +#endif +#endif +#endif +#endif +#endif +} + +REGISTERS(3) +int tl_lookup_timer(tl_timer * t) +{ + if (t->stopped) { + return (t->stoppedtime); + } + if (t->emulator != NULL) { + return ((int) (t->emulator->time - t->lastemulated) * EMULDIV); + } + return (__lookup_timer(t) - t->slowdown); +} + +void tl_stop_timer(tl_timer * t) +{ + if (!t->stopped) { + t->stoppedtime = tl_lookup_timer(t); + t->stopped = 1; + } +} + +void tl_slowdown_timer(tl_timer * t, int time) +{ + if (!t->stopped) { + t->slowdown += time; + } else + t->stoppedtime -= time; +} + +void tl_resume_timer(tl_timer * t) +{ + if (t->stopped) { + t->stopped = 0; + t->slowdown = tl_lookup_timer(t) - t->stoppedtime; + } +} + +void tl_sleep(int time) +{ +#ifdef _WIN32 + Sleep(time / 1000); +#else +#ifdef HAVE_USLEEP + usleep(time); +#else +#ifdef __BEOS__ + snooze(time); +#else +#ifdef HAVE_SELECT + { + struct timeval tv; + tv.tv_sec = time / 1000000L; + tv.tv_usec = time % 1000000L; + (void) select(0, (void *) 0, (void *) 0, (void *) 0, &tv); + } +#else +#ifdef _plan9_ + sleep(time / 1000); +#else +/* + #warning tl_sleep function not implemented. You may ignore this warning. + #warning xaos will work correctly. But on miltitasked enviroments it is + #warning HIGHLY recomended to implement this. + */ +#endif +#endif +#endif +#endif +#endif +} + +REGISTERS(3) +void tl_reset_timer(tl_timer * t) +{ + if (t->stopped) + t->stoppedtime = 0; + else { + if (t->emulator != NULL) { + t->lastemulated = t->emulator->time; + } else + t->lastactivated = currenttime, t->slowdown = 0; + } +} + +tl_timer *tl_create_timer(void) +{ + tl_timer *timer; + timer = (tl_timer *) calloc(1, sizeof(tl_timer)); + if (timer == NULL) + return NULL; + timer->interval = -1; + timer->handler = NULL; + timer->multihandler = NULL; + timer->userdata = NULL; + timer->next = NULL; + timer->previous = NULL; + timer->group = NULL; + timer->stopped = 0; + timer->stoppedtime = 0; + timer->slowdown = 0; + timer->emulator = NULL; + tl_reset_timer(timer); +#ifdef _WIN32 + QueryPerformanceFrequency(&frequency); +#endif + return (timer); +} + +tl_group *tl_create_group(void) +{ + tl_group *timer; + timer = (tl_group *) calloc(1, sizeof(tl_group)); + if (timer == NULL) + return NULL; + timer->interval = -1; + timer->handler = NULL; + timer->multihandler = NULL; + timer->userdata = NULL; + timer->next = NULL; + timer->previous = NULL; + timer->group = timer; + tl_reset_timer(timer); + return (timer); +} + + +void tl_free_timer(tl_timer * timer) +{ + if (timer->group) + tl_remove_timer(timer); + free((void *) timer); +} + +void tl_free_group(tl_group * timer) +{ + tl_timer *next; + do { + next = timer->next; + free((void *) timer); + } + while (next != NULL); +} + +int tl_process_group(tl_group * group, int *activated) +{ + int again = 1; + tl_timer *timer, *timer1; + int minwait = INT_MAX; + tl_update_time(); + if (activated != NULL) + *activated = 0; + while (again) { + group->slowdown = 0; + again = 0; + minwait = INT_MAX; + timer = group->next; + while (timer != NULL) { + timer1 = timer->next; + if (timer->handler && timer->interval >= 0) { + int time = timer->interval - tl_lookup_timer(timer); + if (time < 500) { + if (activated != NULL) + (*activated)++; + again = 1; + tl_reset_timer(timer); + if (time < -200 * 1000000) + time = 0; /*underflow? */ + tl_slowdown_timer(timer, time); + time = timer->interval + time; + timer->handler(timer->userdata); + tl_update_time(); + } + if (time < minwait) + minwait = time; + } else if (timer->multihandler && timer->interval > 0) { + int time = timer->interval - tl_lookup_timer(timer); + if (time < 500) { + int n; + if (activated != NULL) + (*activated)++; + tl_reset_timer(timer); + if (time < -200 * 1000000) + time = 0; /*underflow? */ + n = -(time + 500) / timer->interval + 1; + time = timer->interval * n + time; + tl_slowdown_timer(timer, + time - timer->interval + + n * timer->interval); + timer->multihandler(timer->userdata, n); + tl_update_time(); + } + if (time < minwait) + minwait = time; + } + if (group->slowdown) { + again = 1; + break; + } + timer = timer1; + } + } + if (minwait != INT_MAX) { + if (minwait < 0) + return (0); + return (minwait); + } + return (-1); +} + +#ifdef HAVE_SETITIMER +static void update_async(void); +static void alarmhandler(int a) +{ + update_async(); + signal(SIGALRM, alarmhandler); +} + +static void update_async(void) +{ + int time = tl_process_group(asyncgroup, NULL); + if (time != -1) { + struct itimerval t; + t.it_interval.tv_sec = 0; + t.it_interval.tv_usec = 0; + t.it_value.tv_sec = time / 1000000; + t.it_value.tv_usec = time % 1000000; + if (!reghandler) { + signal(SIGALRM, alarmhandler), reghandler = 1; + } + setitimer(ITIMER_REAL, &t, &t); + registered = 1; + } else if (registered) { + struct itimerval t; + t.it_interval.tv_sec = 0; + t.it_interval.tv_usec = 0; + t.it_value.tv_sec = 0; + t.it_value.tv_usec = 0; + setitimer(ITIMER_REAL, &t, &t); + registered = 0; + } +} + +#else +#define update_async() +#endif +void tl_add_timer(tl_group * group, tl_timer * timer) +{ + if (timer->group) + tl_remove_timer(timer); + timer->previous = group; + timer->next = group->next; + timer->group = group; + group->next = timer; + if (timer->next != NULL) + timer->next->previous = timer; + if (timer->group == asyncgroup) + update_async(); +} + +void tl_set_interval(tl_timer * timer, int interval) +{ + if (timer->interval <= 0) { + tl_reset_timer(timer); + } + timer->interval = interval; + if (timer->group == asyncgroup) + update_async(); +} + +void tl_set_handler(tl_timer * timer, void (*handler) (void *), void *ud) +{ + timer->handler = handler; + timer->userdata = ud; + if (timer->group == asyncgroup) + update_async(); +} + +void +tl_set_multihandler(tl_timer * timer, void (*handler) (void *, int), + void *ud) +{ + timer->multihandler = handler; + timer->userdata = ud; + if (timer->group == asyncgroup) + update_async(); +} + +void tl_remove_timer(tl_timer * timer) +{ + tl_group *g = timer->group; + timer->group->slowdown = 1; + timer->previous->next = timer->next; + if (timer->next != NULL) + timer->next->previous = timer->previous; + timer->group = NULL; + if (g == asyncgroup) + update_async(); +} + +struct timeemulator *tl_create_emulator(void) +{ + return ((struct timeemulator *) + calloc(1, sizeof(struct timeemulator))); +} + +void tl_free_emulator(struct timeemulator *t) +{ + free(t); +} + +void tl_elpased(struct timeemulator *t, int elpased) +{ + t->exact += elpased; + t->time += t->exact / EMULDIV; + t->exact &= (EMULDIV - 1); +} + +void tl_emulate_timer(struct timer *t, struct timeemulator *e) +{ + int time = tl_lookup_timer(t); + t->emulator = e; + t->lastemulated = e->time; + tl_slowdown_timer(t, -time); +} + +void tl_unemulate_timer(struct timer *t) +{ + int time = tl_lookup_timer(t); + t->emulator = NULL; + tl_slowdown_timer(t, tl_lookup_timer(t) - time); +} + +#ifdef USE_ALLEGRO +void tl_allegromode(int mode) +{ + allegromode = mode; + if (!allegromode && ainstalled) { + remove_int(timer); + ainstalled = 0; + counter = -1; + } +} +#endif diff --git a/src/util/util.pri b/src/util/util.pri new file mode 100644 index 0000000..7db9d98 --- /dev/null +++ b/src/util/util.pri @@ -0,0 +1,12 @@ +SOURCES += \
+ $$PWD/png.c \
+ $$PWD/catalog.c \
+ $$PWD/thread.c \
+ $$PWD/xstring.c \
+ $$PWD/help.c \
+ $$PWD/xerror.c \
+ $$PWD/xshl.c \
+ $$PWD/xldio.c \
+ $$PWD/xstdio.c \
+ $$PWD/xmenu.c \
+ $$PWD/timers.c
diff --git a/src/util/xerror.c b/src/util/xerror.c new file mode 100644 index 0000000..f7a904f --- /dev/null +++ b/src/util/xerror.c @@ -0,0 +1,43 @@ +#ifdef _plan9_ +#include <u.h> +#include <libc.h> +#endif +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include "config.h" +#include "xerror.h" +#include "aconfig.h" +/*BeOS driver have its own routines in the C++ code */ +#ifndef BEOS_DRIVER +/*On windows we use message boxes done in the ui_win32.c code*/ +#ifndef WIN32_DRIVER +void x_message(CONST char *text, ...) +{ + va_list ap; + va_start(ap, text); + vfprintf(stdout, text, ap); + fprintf(stdout, "\n"); + va_end(ap); +} + +void x_error(CONST char *text, ...) +{ + va_list ap; + va_start(ap, text); + vfprintf(stderr, text, ap); + fprintf(stderr, "\n"); + va_end(ap); +} + +void x_fatalerror(CONST char *text, ...) +{ + va_list ap; + va_start(ap, text); + vfprintf(stderr, text, ap); + fprintf(stderr, "\n"); + va_end(ap); + exit(1); +} +#endif +#endif diff --git a/src/util/xldio.c b/src/util/xldio.c new file mode 100644 index 0000000..ab40058 --- /dev/null +++ b/src/util/xldio.c @@ -0,0 +1,603 @@ +/* This file contain long double I/O routines for Windows (because Windows API + don't support long double at all. + + They don't work on other architectures. So be curefull. */ + + +/* This source comes from the DJGPP runtime library. It has been hacked + to work with XaoS */ +/* Copyright (C) 1998 DJ Delorie, see COPYING.DJ for details */ +/* Copyright (C) 1997 DJ Delorie, see COPYING.DJ for details */ +/* Copyright (C) 1996 DJ Delorie, see COPYING.DJ for details */ +/* Copyright (C) 1994 DJ Delorie, see COPYING.DJ for details */ +#include <config.h> +#include <stdlib.h> +#include <ctype.h> +#include <xio.h> +/*#include <libc/unconst.h>*/ +#include <sys/types.h> +#include <ctype.h> +#include <string.h> +#include <stdio.h> +#include <math.h> +#include <xldio.h> +#ifdef USE_XLDIO + +static long double powten[] = { + 1e1L, 1e2L, 1e4L, 1e8L, 1e16L, 1e32L, 1e64L, 1e128L, 1e256L, + 1e512L, 1e1024L, 1e2048L, 1e4096L +}; + +long double x_strtold(CONST char *s, CONST char **sret) +{ + long double r; /* result */ + int e, ne; /* exponent */ + int sign; /* +- 1.0 */ + int esign; + int flags = 0; + int l2powm1; + + r = 0.0L; + sign = 1; + e = ne = 0; + esign = 1; + + while (*s && isspace(*s)) + s++; + + if (*s == '+') + s++; + else if (*s == '-') { + sign = -1; + s++; + } + + while ((*s >= '0') && (*s <= '9')) { + flags |= 1; + r *= 10.0L; + r += *s - '0'; + s++; + } + + if (*s == '.') { + s++; + while ((*s >= '0') && (*s <= '9')) { + flags |= 2; + r *= 10.0L; + r += *s - '0'; + s++; + ne++; + } + } + if (flags == 0) { + if (sret) + *sret = /*unconst(s, char *) */ s; + return 0.0L; + } + + if ((*s == 'e') || (*s == 'E')) { + s++; + if (*s == '+') + s++; + else if (*s == '-') { + s++; + esign = -1; + } + while ((*s >= '0') && (*s <= '9')) { + e *= 10; + e += *s - '0'; + s++; + } + } + if (esign < 0) { + esign = -esign; + e = -e; + } + e = e - ne; + if (e < -4096) { + /* possibly subnormal number, 10^e would overflow */ + r *= 1.0e-2048L; + e += 2048; + } + if (e < 0) { + e = -e; + esign = -esign; + } + if (e >= 8192) + e = 8191; + if (e) { + long double d = 1.0L; + l2powm1 = 0; + while (e) { + if (e & 1) + d *= powten[l2powm1]; + e >>= 1; + l2powm1++; + } + if (esign > 0) + r *= d; + else + r /= d; + } + if (sret) + *sret = /*unconst(s, char *) */ s; + return r * sign; +} + +#if 0 +main() +{ + printf("%E", (float) x_strtold("1.4E15", NULL)); +} +#endif + + +#define MAXEXPLD 4952 /* this includes subnormal numbers */ +static int is_nan = 0; +static char decimal = '.'; +static long double pten[] = { + 1e1L, 1e2L, 1e4L, 1e8L, 1e16L, 1e32L, 1e64L, 1e128L, 1e256L, + 1e512L, 1e1024L, 1e2048L, 1e4096L +}; + +static long double ptenneg[] = { + 1e-1L, 1e-2L, 1e-4L, 1e-8L, 1e-16L, 1e-32L, 1e-64L, 1e-128L, 1e-256L, + 1e-512L, 1e-1024L, 1e-2048L, 1e-4096L +}; + +static inline char tochar(int n) +{ + if (n >= 9) + return '9'; + if (n <= 0) + return '0'; + return n + '0'; +} + +static inline int todigit(char c) +{ + if (c <= '0') + return 0; + if (c >= '9') + return 9; + return c - '0'; +} + +#define LONGINT 0x01 /* long integer */ +#define LONGDBL 0x02 /* long double */ +#define SHORTINT 0x04 /* short integer */ +#define ALT 0x08 /* alternate form */ +#define LADJUST 0x10 /* left adjustment */ +#define ZEROPAD 0x20 /* zero (as opposed to blank) pad */ +#define HEXPREFIX 0x40 /* add 0x or 0X prefix */ + +#define MAXP 4096 +#define NP 12 +#define P (4294967296.0L * 4294967296.0L * 2.0L) /* 2^65 */ +static long double INVPREC = P; +static long double PREC = 1.0L / P; +#undef P +/* + * Defining FAST_LDOUBLE_CONVERSION results in a little bit faster + * version, which might be less accurate (about 1 bit) for long + * double. For 'normal' double it doesn't matter. + */ +/* #define FAST_LDOUBLE_CONVERSION */ +#if 1 +#define modfl mymodfl +inline long double m_floor(long double x) +{ + register long double __value; + volatile unsigned short int __cw, __cwtmp; + + asm volatile ("fnstcw %0":"=m" (__cw)); + __cwtmp = (__cw & 0xf3ff) | 0x0400; /* rounding down */ + asm volatile ("fldcw %0"::"m" (__cwtmp)); + asm volatile ("frndint":"=t" (__value):"0"(x)); + asm volatile ("fldcw %0"::"m" (__cw)); + + return __value; + +} + +static inline long double mymodfl(long double x, long double *pint) +{ + /*int p=(int) x; */ + long double p = m_floor(x); + long double frac = x - p; + if (x < 0) + p = p + 1, frac = frac - 1; + *pint = p; + return frac; +} +#endif +static char *exponentl(char *p, int expv, unsigned char fmtch) +{ + char *t; + char expbuf[MAXEXPLD]; + + *p++ = fmtch; + if (expv < 0) { + expv = -expv; + *p++ = '-'; + } else + *p++ = '+'; + t = expbuf + MAXEXPLD; + if (expv > 9) { + do { + *--t = tochar(expv % 10); + } + while ((expv /= 10) > 9); + *--t = tochar(expv); + for (; t < expbuf + MAXEXPLD; *p++ = *t++); + } else { + *p++ = '0'; + *p++ = tochar(expv); + } + return p; +} + +static int isspeciall(long double d, char *bufp) +{ + struct IEEExp { + unsigned manl:32; + unsigned manh:32; + unsigned exp:15; + unsigned sign:1; + } *ip = (struct IEEExp *) &d; + + is_nan = 0; /* don't assume the static is 0 (emacs) */ + if (ip->exp != 0x7fff) + return (0); + if ((ip->manh & 0x7fffffff) || ip->manl) { + strcpy(bufp, "NaN"); + is_nan = ip->sign ? -1 : 1; /* kludge: we don't need the sign, it's not nice + but it should work */ + } else + (void) strcpy(bufp, "Inf"); + return (3); +} + +static char *my_roundl(long double fract, int *expv, char *start, + char *end, char ch, char *signp) +{ + long double tmp; + + if (fract) { + if (fract == 0.5L) { + char *e = end; + if (*e == '.') + e--; + if (*e == '0' || *e == '2' || *e == '4' || *e == '6' + || *e == '8') { + tmp = 3.0; + goto start; + } + } + (void) modfl(fract * 10.0L, &tmp); + } else + tmp = todigit(ch); + start: + if (tmp > 4) + for (;; --end) { + if (*end == decimal) + --end; + if (++*end <= '9') + break; + *end = '0'; + if (end == start) { + if (expv) { /* e/E; increment exponent */ + *end = '1'; + ++*expv; + } else { /* f; add extra digit */ + *--end = '1'; + --start; + } + break; + } + } + /* ``"%.3f", (double)-0.0004'' gives you a negative 0. */ + else if (*signp == '-') + for (;; --end) { + if (*end == decimal) + --end; + if (*end != '0') + break; + if (end == start) + *signp = 0; + } + return start; +} + + +static int +cvtl(long double number, int prec, int flags, char *signp, + unsigned char fmtch, char *startp, char *endp) +{ + char *p, *t; + long double fract = 0; + int dotrim, expcnt, gformat; + int doextradps = 0; /* Do extra decimal places if the precision needs it */ + int doingzero = 0; /* We're displaying 0.0 */ + long double integer, tmp; + + if ((expcnt = isspeciall(number, startp))) + return (expcnt); + + dotrim = expcnt = gformat = 0; + /* fract = modfl(number, &integer); */ + integer = number; + + /* get an extra slot for rounding. */ + t = ++startp; + + p = endp - 1; + if (integer) { + int i, lp = NP, pt = MAXP; +#ifndef FAST_LDOUBLE_CONVERSION + long double oint = integer, dd = 1.0L; +#endif + if (integer > INVPREC) { + integer *= PREC; + while (lp >= 0) { + if (integer >= pten[lp]) { + expcnt += pt; + integer *= ptenneg[lp]; +#ifndef FAST_LDOUBLE_CONVERSION + dd *= pten[lp]; +#endif + } + pt >>= 1; + lp--; + } +#ifndef FAST_LDOUBLE_CONVERSION + integer = oint / dd; +#else + integer *= INVPREC; +#endif + } + /* + * Do we really need this ? + */ + for (i = 0; i < expcnt; i++) + *p-- = '0'; + } + number = integer; + fract = modfl(number, &integer); + /* If integer is zero then we need to look at where the sig figs are */ + if (integer < 1) { + /* If fract is zero the zero before the decimal point is a sig fig */ + if (fract == 0.0) + doingzero = 1; + /* If fract is non-zero all sig figs are in fractional part */ + else + doextradps = 1; + } + /* + * get integer portion of number; put into the end of the buffer; the + * .01 is added for modf(356.0 / 10, &integer) returning .59999999... + */ + for (; integer; ++expcnt) { + tmp = modfl(integer * 0.1L, &integer); + *p-- = tochar((int) ((tmp + .01L) * 10)); + } + switch (fmtch) { + case 'f': + /* reverse integer into beginning of buffer */ + if (expcnt) + for (; ++p < endp; *t++ = *p); + else + *t++ = '0'; + /* + * if precision required or alternate flag set, add in a + * decimal point. + */ + if (prec || flags & ALT) + *t++ = decimal; + /* if requires more precision and some fraction left */ + if (fract) { + if (prec) + do { + fract = modfl(fract * 10.0L, &tmp); + *t++ = tochar((int) tmp); + } + while (--prec && fract); + if (fract) + startp = my_roundl(fract, (int *) NULL, startp, + t - 1, (char) 0, signp); + } + for (; prec--; *t++ = '0'); + break; + case 'e': + case 'E': + eformat: + if (expcnt) { + *t++ = *++p; + if (prec || flags & ALT) + *t++ = decimal; + /* if requires more precision and some integer left */ + for (; prec && ++p < endp; --prec) + *t++ = *p; + /* + * if done precision and more of the integer component, + * round using it; adjust fract so we don't re-round + * later. + */ + if (!prec && ++p < endp) { + fract = 0; + startp = my_roundl((long double) 0.0L, &expcnt, + startp, t - 1, *p, signp); + } + /* adjust expcnt for digit in front of decimal */ + --expcnt; + } + /* until first fractional digit, decrement exponent */ + else if (fract) { + int lp = NP, pt = MAXP; +#ifndef FAST_LDOUBLE_CONVERSION + long double ofract = fract, dd = 1.0L; +#endif + expcnt = -1; + if (fract < PREC) { + fract *= INVPREC; + while (lp >= 0) { + if (fract <= ptenneg[lp]) { + expcnt -= pt; + fract *= pten[lp]; +#ifndef FAST_LDOUBLE_CONVERSION + dd *= pten[lp]; +#endif + } + pt >>= 1; + lp--; + } +#ifndef FAST_LDOUBLE_CONVERSION + fract = ofract * dd; +#else + fract *= PREC; +#endif + } + /* adjust expcnt for digit in front of decimal */ + for ( /* expcnt = -1 */ ;; --expcnt) { + fract = modfl(fract * 10.0L, &tmp); + if (tmp) + break; + } + *t++ = tochar((int) tmp); + if (prec || flags & ALT) + *t++ = decimal; + } else { + *t++ = '0'; + if (prec || flags & ALT) + *t++ = decimal; + } + /* if requires more precision and some fraction left */ + if (fract) { + if (prec) + do { + fract = modfl(fract * 10.0L, &tmp); + *t++ = tochar((int) tmp); + } + while (--prec && fract); + if (fract) + startp = + my_roundl(fract, &expcnt, startp, t - 1, (char) 0, + signp); + } + /* if requires more precision */ + for (; prec--; *t++ = '0'); + + /* unless alternate flag, trim any g/G format trailing 0's */ + if (gformat && !(flags & ALT)) { + while (t > startp && *--t == '0'); + if (*t == decimal) + --t; + ++t; + } + t = exponentl(t, expcnt, fmtch); + break; + case 'g': + case 'G': + if (prec) { + /* If doing zero and precision is greater than 0 count the + * 0 before the decimal place */ + if (doingzero) + --prec; + } else { + /* a precision of 0 is treated as precision of 1 unless doing zero */ + if (!doingzero) + ++prec; + } + /* + * ``The style used depends on the value converted; style e + * will be used only if the exponent resulting from the + * conversion is less than -4 or greater than the precision.'' + * -- ANSI X3J11 + */ + if (expcnt > prec || (!expcnt && fract && fract < .0001)) { + /* + * g/G format counts "significant digits, not digits of + * precision; for the e/E format, this just causes an + * off-by-one problem, i.e. g/G considers the digit + * before the decimal point significant and e/E doesn't + * count it as precision. + */ + --prec; + fmtch -= 2; /* G->E, g->e */ + gformat = 1; + goto eformat; + } + /* + * reverse integer into beginning of buffer, + * note, decrement precision + */ + if (expcnt) + for (; ++p < endp; *t++ = *p, --prec); + else + *t++ = '0'; + /* + * if precision required or alternate flag set, add in a + * decimal point. If no digits yet, add in leading 0. + */ + if (prec || flags & ALT) { + dotrim = 1; + *t++ = decimal; + } else + dotrim = 0; + /* if requires more precision and some fraction left */ + while (prec && fract) { + fract = modfl(fract * 10.0L, &tmp); + *t++ = tochar((int) tmp); + /* If we're not adding 0s + * or we are but they're sig figs: + * decrement the precision */ + if ((doextradps != 1) || ((int) tmp != 0)) { + doextradps = 0; + prec--; + } + } + if (fract) + startp = + my_roundl(fract, (int *) NULL, startp, t - 1, (char) 0, + signp); + /* alternate format, adds 0's for precision, else trim 0's */ + if (flags & ALT) + for (; prec--; *t++ = '0'); + else if (dotrim) { + while (t > startp && *--t == '0'); + if (*t != decimal) + ++t; + } + } + return t - startp; +} + +#if 0 +main() +{ + static char buf[4096]; + int i; + cvtl(0.00000000000000000005, 4, 0, &softsign, 'G', buf, + buf + sizeof(buf) - 1); + printf("%s\n", buf + 1); + printf("%.30LG\n", (long double) 234236723234234231235324.47239L); +} + +#endif +void x_ldout(long double param, int prec, xio_file stream) +{ + static char buf[4095]; + char softsign = 0; + int l; + if (param < 0) + xio_putc('-', stream), param = -param; + l = cvtl(param, prec, 0, &softsign, 'G', buf, buf + sizeof(buf)); + /*printf("a:%s %i\n",buf+1, prec); */ + buf[l + 2] = 0; + l = strlen(buf + 1); + if (buf[l] == '.') + buf[l] = 0; + /*printf("b:%s %i\n",buf+1, prec); */ + xio_puts(buf + 1, stream); +} +#endif diff --git a/src/util/xmenu.c b/src/util/xmenu.c new file mode 100644 index 0000000..8a70b5d --- /dev/null +++ b/src/util/xmenu.c @@ -0,0 +1,998 @@ +#ifdef _plan9_ +#include <u.h> +#include <libc.h> +#else +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#endif +#include <config.h> +#include <filter.h> +#include <fractal.h> +#include <ui_helper.h> +#include <xerror.h> +#include <xldio.h> +#include <misc-f.h> +#include "config.h" +#include "xmenu.h" + +#define HASHBITS 8 +#define HASHSIZE (1<<HASHBITS) +#define HASHMASK (HASHSIZE-1) +#define HASH(c,len) (((len)*32+(c)[0]+(c)[(len)-1])&HASHMASK) + +static struct queuelist { + struct queuelist *next; + struct queuelist *previous; + CONST menuitem *item; + dialogparam *d; +} *firstqueue = NULL, *lastqueue = NULL; +static struct entry { + struct entry *next; + struct entry *previous; + struct entry *nextname; + CONST menuitem *item; +} *firstitem = NULL, *lastitem = NULL; + +struct entry *namehash[HASHSIZE]; + +static void +x_menu_insert(CONST menuitem * item, struct entry *iitem, int n) +{ + int i; + int len; + int hashpos; + struct entry *list; + for (i = 0; i < n; i++) { + list = (struct entry *) calloc(1, sizeof(struct queuelist)); + if (list == NULL) { + x_error("Warning:out of memory!"); + return; + } + if (item->type != MENU_SEPARATOR) { + len = strlen(item->shortname); + hashpos = HASH(item->shortname, len); + list->nextname = namehash[hashpos]; +#ifdef DEBUG + { + struct entry *e = list->nextname; + while (e != NULL) { + if (e->item->type != MENU_SUBMENU + && e->item->type != MENU_SEPARATOR + && item->type != MENU_SEPARATOR); + if (!strcmp(e->item->shortname, item->shortname) + /*&& e->item->type != MENU_SUBMENU && item->type != MENU_SUBMENU */ + ) { + x_error + ("Menu error:Name collision %s:'%s'(%s) and '%s'(%s)", + item->shortname, item->name, item->menuname, + e->item->name, e->item->menuname); + } + e = e->nextname; + } + } +#endif + namehash[hashpos] = list; + } + list->item = item; + if (iitem == NULL) { + /*printf("ahoj\n"); */ + list->previous = lastitem; + list->next = NULL; + if (lastitem != NULL) + lastitem->next = list; + else + firstitem = list; + lastitem = list; + } else { + list->next = iitem; + list->previous = iitem->previous; + if (iitem->previous) + iitem->previous->next = list; + else + firstitem = list; + iitem->previous = list; + } + item++; + } +} + +void menu_add(CONST menuitem * item, int n) +{ + x_menu_insert(item, NULL, n); +} + +void menu_insert(CONST menuitem * item, CONST char *before, int n) +{ + struct entry *e = firstitem; + while (e != NULL) { + if (!strcmp(e->item->shortname, before)) + break; + e = e->next; + } + x_menu_insert(item, e, n); +} + +void menu_delete(CONST menuitem * items, int n) +{ + int d = 0, i; + struct entry *item = firstitem; + struct entry *pe; + int hashpos; + for (i = 0; i < n; i++) { + if (items[i].type == MENU_SEPARATOR) { + struct entry *item = firstitem; + while (item && item->item != items + i) + item = item->next; + if (!item) + abort(); + if (item->previous != NULL) + item->previous->next = item->next; + else + firstitem = item->next; + if (item->next != NULL) + item->next->previous = item->previous; + else + lastitem = item->previous; + free(item); + } else { + int len = strlen(items[i].shortname); + hashpos = HASH(items[i].shortname, len); + pe = NULL; + item = namehash[hashpos]; + while (item != NULL) { + if (items + i == item->item) { + d++; + if (pe == NULL) + namehash[hashpos] = item->nextname; + else + pe->nextname = item->nextname; + if (item->previous != NULL) + item->previous->next = item->next; + else + firstitem = item->next; + if (item->next != NULL) + item->next->previous = item->previous; + else + lastitem = item->previous; + free(item); + break; + } /*if */ + pe = item; + item = item->nextname; + } /*while */ + } +#ifdef DEBUG + if (item == NULL) + x_error("Item %s not found!", items[i].shortname); +#endif + } /*for */ +} + +void menu_addqueue(CONST menuitem * item, dialogparam * d) +{ + struct queuelist *list; + list = (struct queuelist *) calloc(1, sizeof(struct queuelist)); + if (list == NULL) { + x_error("Warning:out of memory!"); + return; + } + list->previous = lastqueue; + list->next = NULL; + list->item = item; + list->d = d; + if (lastqueue != NULL) + lastqueue->next = list; + else + firstqueue = list; + lastqueue = list; +} + +CONST menuitem *menu_delqueue(dialogparam ** d) +{ + CONST struct menuitem *item; + struct queuelist *list = firstqueue; + if (firstqueue == NULL) + return NULL; + item = firstqueue->item; + *d = firstqueue->d; + firstqueue = list->next; + if (list->next != NULL) + list->next->previous = NULL; + else + lastqueue = NULL; + free(list); + return (item); +} + +CONST static void *menu_rfind(CONST void + *(*function) (struct entry * item), + CONST char *root) +{ + struct entry *item = firstitem; + CONST void *r; + while (item != NULL) { + if (!strcmp(root, item->item->menuname)) { + if ((r = function(item)) != NULL) + return r; + if (item->item->type == MENU_SUBMENU + && (r = + menu_rfind(function, item->item->shortname)) != NULL) + return r; + } + item = item->next; + } + return NULL; +} + +CONST static char *findkey; +CONST static void *cmpfunction(struct entry *item) +{ + if (item->item->key == NULL) + return NULL; + if (!strcmp(findkey, item->item->key)) + return item->item; + return NULL; +} + +CONST menuitem *menu_findkey(CONST char *key, CONST char *root) +{ + findkey = key; + return ((CONST menuitem *) menu_rfind(cmpfunction, root)); +} + +static CONST menuitem *finditem; +CONST static void *cmpfunction2(struct entry *item) +{ + if (item->item == finditem) + return item; + return NULL; +} + +int menu_available(CONST menuitem * item, CONST char *root) +{ + finditem = item; + return (menu_rfind(cmpfunction2, root) != NULL); +} + +CONST char *menu_fullname(CONST char *menu) +{ + struct entry *item = firstitem; + while (item != NULL) { + if (item->item->type == MENU_SUBMENU + && !strcmp(menu, item->item->shortname)) { + return (item->item->name); + } + item = item->next; + } + return NULL; +} + +CONST menuitem *menu_item(CONST char *menu, int n) +{ + struct entry *item = firstitem; + while (item != NULL) { + if (!strcmp(menu, item->item->menuname)) { + if (!(item->item->flags & MENUFLAG_NOMENU)) + n--; + if (n < 0) + return (item->item); + } + item = item->next; + } + return NULL; +} + +static CONST menuitem *menu_item2(CONST char *menu, int n) +{ + struct entry *item = firstitem; + while (item != NULL) { + if (!strcmp(menu, item->item->menuname)) { + n--; + if (n < 0) + return (item->item); + } + item = item->next; + } + return NULL; +} + +int menu_havedialog(CONST menuitem * item, struct uih_context *c) +{ + if (item->type != MENU_DIALOG && item->type != MENU_CUSTOMDIALOG) + return 0; + if (!(item->type & MENUFLAG_RADIO) || c == NULL) + return 1; + if (item->flags & MENUFLAG_DIALOGATDISABLE) + return (menu_enabled(item, c)); + return (!menu_enabled(item, c)); +} + +static void menu_freeparam(dialogparam * d, CONST struct dialog *di) +{ + switch (di->type) { + case DIALOG_STRING: + case DIALOG_KEYSTRING: + case DIALOG_IFILE: + case DIALOG_OFILE: + free(d->dstring); + } +} + +void +menu_destroydialog(CONST menuitem * item, dialogparam * d, + struct uih_context *uih) +{ + int i; + CONST struct dialog *di = menu_getdialog(uih, item); + for (i = 0; di[i].question; i++) { + menu_freeparam(d + i, di + i); + } + free(d); + +} + +void +menu_activate(CONST menuitem * item, struct uih_context *c, + dialogparam * d) +{ + if (c == NULL + && (!(item->flags & MENUFLAG_ATSTARTUP) || firstqueue != NULL)) { + menu_addqueue(item, d); + return; + } else { + if (c != NULL && c->incalculation + && !(item->flags & MENUFLAG_INCALC)) { + if (c->flags & MENUFLAG_INTERRUPT) + c->interrupt = 1; + menu_addqueue(item, d); + return; + } + } + switch (item->type) { + case MENU_SEPARATOR: + x_error("separator activated!"); + break; + case MENU_SUBMENU: + x_error("submenu activated!"); + break; + case MENU_NOPARAM: + ((void (*)(struct uih_context *)) item->function) (c); + break; + case MENU_INT: + ((void (*)(struct uih_context *, int)) item->function) (c, + item-> + iparam); + break; + case MENU_STRING: + ((void (*)(struct uih_context *, CONST char *)) item->function) (c, + (CONST + char + *) + item->pparam); + break; + case MENU_DIALOG: + case MENU_CUSTOMDIALOG: + if (!menu_havedialog(item, c)) { + ((void (*)(struct uih_context * c, dialogparam *)) item-> + function) + (c, (dialogparam *) NULL); + } else { + CONST menudialog *di = menu_getdialog(c, item); + if (di[0].question == NULL) { + ((void (*)(struct uih_context * c, dialogparam *)) + item->function) (c, (dialogparam *) NULL); + break; + } else if (di[1].question == NULL) { + /*call function with right + *parameter. This avoids need to write wrappers*/ + switch (di[0].type) { + case DIALOG_INT: + case DIALOG_CHOICE: + case DIALOG_ONOFF: + ((void (*)(struct uih_context * c, int)) item-> + function) (c, d[0].dint); + break; + case DIALOG_FLOAT: + ((void (*)(struct uih_context * c, number_t)) + item->function) (c, d[0].number); + break; + case DIALOG_COORD: + ((void (*)(struct uih_context * c, number_t, number_t)) + item->function) (c, d[0].dcoord[0], d[0].dcoord[1]); + break; + case DIALOG_STRING: + case DIALOG_KEYSTRING: + ((void (*)(struct uih_context * c, char *)) item-> + function) + (c, d[0].dstring); + break; + case DIALOG_IFILE: + case DIALOG_OFILE: + ((void (*)(struct uih_context * c, xio_path)) + item->function) (c, d[0].dpath); + break; + default: + x_error("dialog:unknown type!"); + break; + } + + } else + ((void (*)(struct uih_context * c, dialogparam *)) item-> + function) + (c, d); + } + break; + default: + x_error("Menu_activate: unknown type %i!", item->type); + break; + } +} + +int menu_enabled(CONST menuitem * item, struct uih_context *c) +{ + if (item->flags & (MENUFLAG_RADIO | MENUFLAG_CHECKBOX)) + switch (item->type) { + case MENU_SEPARATOR: + return 0; + case MENU_SUBMENU: + case MENU_DIALOG: + case MENU_NOPARAM: + case MENU_CUSTOMDIALOG: + return (((int (*)(struct uih_context *)) item->control) (c)); + case MENU_INT: + return (((int (*)(struct uih_context *, int)) item-> + control) (c, item->iparam)); + case MENU_STRING: + return (((int (*)(struct uih_context *, CONST char *)) item-> + control) + (c, (CONST char *) item->pparam)); + default: + x_error("Menu_enabled: unknown type!"); + break; + } + return 0; +} + +void menu_delnumbered(int n, CONST char *name) +{ + menuitem *items; + int i; + char s[256]; + sprintf(s, "%s%i", name, 0); + items = (menuitem *) menu_findcommand(s); + menu_delete(items, n); + for (i = 0; i < n; i++) { + if (items[i].key) + free((char *) items[i].key); + free((char *) items[i].shortname); + } + free(items); +} + +CONST menuitem *menu_genernumbered(int n, CONST char *menuname, + CONST char *CONST * CONST names, + CONST char *keys, int type, int flags, + void (*function) (struct uih_context * + context, int), + int (*control) (struct uih_context * + context, int), + CONST char *prefix) +{ + int l = keys != NULL ? (int) strlen(keys) : -1; + int i; + menuitem *item = (menuitem *) malloc(sizeof(menuitem) * n); + if (item == NULL) + return NULL; + for (i = 0; i < n; i++) { + item[i].menuname = menuname; + if (i < l) { + char *key = malloc(2); + item[i].key = key; + key[0] = keys[i]; + key[1] = 0; + } else + item[i].key = 0; + item[i].type = type; + item[i].flags = flags; + item[i].iparam = i; + item[i].name = names[i]; + item[i].shortname = names[i]; + if (prefix != NULL) { + char *shortname = (char *) malloc(strlen(prefix) + 4); + item[i].shortname = shortname; + sprintf(shortname, "%s%i", prefix, i); + } + item[i].function = (void (*)(void)) function; + item[i].control = (int (*)(void)) control; + } + menu_add(item, n); + return (item); +} + +number_t menu_getfloat(CONST char *s, CONST char **error) +{ +#ifdef HAVE_LONG_DOUBLE + long double param = 0; +#else + double param = 0; +#endif +#ifdef HAVE_LONG_DOUBLE +#ifndef USE_ATOLD +#ifdef USE_XLDIO + param = x_strtold(s, NULL); + if (0) +#else + if (sscanf(s, "%LG", ¶m) == 0) +#endif +#else + param = _atold(s); + if (0) +#endif + { +#else + if (sscanf(s, "%lG", ¶m) == 0) { +#endif + *error = "Floating point number expected"; + return 0; + } + return (param); +} + +int menuparse_scheme = 0; +CONST char *menu_fillparam(struct uih_context *uih, tokenfunc f, + CONST menudialog * d, dialogparam * p) +{ + char *c = f(uih); + CONST char *error = NULL; + if (c == NULL) + return "Parameter expected"; + switch (d->type) { + case DIALOG_INT: + if (sscanf(c, "%i", &p->dint) != 1) { + return "Integer parameter expected"; + } + break; + case DIALOG_FLOAT: + p->number = menu_getfloat(c, &error); + if (error != NULL) + return (error); + break; + case DIALOG_COORD: + p->dcoord[0] = menu_getfloat(c, &error); + if (error != NULL) + return (error); + c = f(uih); + if (c == NULL) + return "Imaginary part expected"; + p->dcoord[1] = menu_getfloat(c, &error); + if (error != NULL) + return (error); + break; + case DIALOG_KEYSTRING: + if (menuparse_scheme) { + if (c[0] != '\'') + return "Key string parameter expected"; + p->dstring = mystrdup(c + 1); + } else + p->dstring = mystrdup(c); + break; + case DIALOG_STRING: + if (menuparse_scheme) { + int l = strlen(c); + if (l < 2 || c[0] != '"' || c[l - 1] != '"') + return "String parameter expected"; + p->dstring = mystrdup(c + 1); + p->dstring[l - 2] = 0; + } else + p->dstring = mystrdup(c); + break; + case DIALOG_IFILE: + case DIALOG_OFILE: + if (menuparse_scheme) { + int l = strlen(c); + if (l < 2 || c[0] != '"' || c[l - 1] != '"') + return "String parameter expected"; + p->dstring = mystrdup(c + 1); + p->dstring[l - 2] = 0; + } else + p->dstring = mystrdup(c); + break; + case DIALOG_CHOICE: + if (menuparse_scheme) { + if (c[0] != '\'') + return "Key string parameter expected"; + c++; + } + { + int i; + CONST char **keys = (CONST char **) d->defstr; + for (i = 0;; i++) { + if (keys[i] == NULL) + return "Unknown parameter"; + if (!strcmp(c, keys[i])) { + p->dint = i; + return NULL; + } + } + } + case DIALOG_ONOFF: + if (menuparse_scheme) { + if (!strcmp("#t", c)) { + p->dint = 1; + return NULL; + } + if (!strcmp("#f", c)) { + p->dint = 0; + return NULL; + } + } else { + if (!strcmp("on", c)) { + p->dint = 1; + return NULL; + } + if (!strcmp("off", c)) { + p->dint = 0; + return NULL; + } + } + default: + x_error("Unknown dialog parameter type!"); + } /*switch */ + return NULL; +} + +static char errorstr[256]; +CONST menuitem *menu_findcommand(CONST char *name) +{ + struct entry *entry; + CONST menuitem *item; + int len; + len = strlen(name); + if (len > 100) + return NULL; + entry = namehash[HASH(name, len)]; + while (entry != NULL) { + if (!strcmp(entry->item->shortname, name)) + break; + entry = entry->nextname; + } + if (entry == NULL) { + return NULL; + } + item = entry->item; + return (item); +} + +CONST char *menu_processcommand(struct uih_context *uih, tokenfunc f, + int scheme, int mask, CONST char *root) +{ + char *c = f(uih); + CONST menuitem *item; + menuparse_scheme = scheme; + if (c == NULL) { + if (!menuparse_scheme) + return "Command name expected"; + return NULL; + } + item = menu_findcommand(c); + if (item == NULL) { + sprintf(errorstr, "%s:unknown function", c); + return errorstr; + } + if (item->flags & mask) { + sprintf(errorstr, + "function '%s' not available in this context (%i, %i)", c, + mask, item->flags); + return errorstr; + } + if ((item->flags & MENUFLAG_NOPLAY) && uih != NULL) { + if (root != NULL && !menu_available(item, root)) { + sprintf(errorstr, "function '%s' is disabled", c); + return errorstr; + } + } + + if ((item->flags & MENUFLAG_CHECKBOX) && scheme) { + int w; + c = f(uih); + if (c == NULL) { + return ("Boolean parameter expected"); + } + + if (!strcmp("#t", c)) { + w = 1; + } else if (!strcmp("#f", c)) { + w = 0; + } else + return "Boolean parameter expected"; + if (w == menu_enabled(item, uih)) { + if (((w != 0) ^ ((item->flags & MENUFLAG_DIALOGATDISABLE) != + 0)) + || (item->type != MENU_DIALOG + && item->type != MENU_CUSTOMDIALOG)) { + return NULL; + } else + menu_activate(item, uih, NULL); /*disable it... */ + } + } + if (item->type != MENU_DIALOG && item->type != MENU_CUSTOMDIALOG) { + menu_activate(item, uih, NULL); + return NULL; + } + /*So we have some parameters */ + + { + dialogparam *param; + CONST menudialog *d = menu_getdialog(uih, item); + int i, n; + for (n = 0; d[n].question != NULL; n++); + param = (dialogparam *) malloc(n * sizeof(dialogparam)); + for (i = 0; i < n; i++) { + CONST char *error; + error = menu_fillparam(uih, f, d + i, param + i); + if (error != NULL) { + sprintf(errorstr, "Function '%s' parameter %i:%s", + item->shortname, i, error); + for (n = 0; n < i; n++) { + menu_freeparam(param + i, d + i); + } + free(param); + return errorstr; + } + } + menu_activate(item, uih, param); + if (uih != NULL) + menu_destroydialog(item, param, uih); + } + return NULL; +} + +static int argpos, margc; +static char **margv; +static int argposs; +static char *gettoken(struct uih_context *c) +{ + if (argpos == margc) + return NULL; + if (argpos == argposs) { + if (!margv[argpos]) + return NULL; + return (margv[argpos++] + 1); + } else + return (margv[argpos++]); +} + +int menu_processargs(int n, int argc, char **argv) +{ + CONST char *error; + argpos = n; + argposs = n; + margc = argc; + margv = argv; + error = + menu_processcommand(NULL, gettoken, 0, MENUFLAG_NOOPTION, "root"); + if (error) { + x_error("%s", error); + return -1; + } + return (argpos - 2); + +} + +void menu_printhelp(void) +{ + struct entry *e = firstitem; + while (e) { + if (e->item->type == MENU_SEPARATOR) { + e = e->next; + continue; + } + if (e->item->type == MENU_SUBMENU + && !(e->item->flags & MENUFLAG_NOOPTION)) { + struct entry *e1 = firstitem; + int n = 1; + while (e1) { + /*if (e->item->type == MENU_SEPARATOR) {printf ("\n"); e1=e1->next;continue;} */ + if (e1->item->type != MENU_SUBMENU + && e1->item->type != MENU_SEPARATOR + && !(e1->item->flags & MENUFLAG_NOOPTION) + && !strcmp(e1->item->menuname, e->item->shortname)) { + if (n) { + printf("\n%s\n\n", e->item->name); + n = 0; + } + printf(" -%-15s", e1->item->shortname); + if (menu_havedialog(e1->item, NULL)) { + CONST menudialog *d = + menu_getdialog(NULL, e1->item); + while (d->question != NULL) { + switch (d->type) { + case DIALOG_INT: + printf("integer "); + break; + case DIALOG_FLOAT: + printf("real_number "); + break; + case DIALOG_COORD: + printf("real_number real_number "); + break; + case DIALOG_KEYSTRING: + case DIALOG_STRING: + printf("string "); + break; + case DIALOG_IFILE: + printf("input_file "); + break; + case DIALOG_OFILE: + printf("output_file "); + break; + case DIALOG_CHOICE: + { + int i; + CONST char **keys = + (CONST char **) d->defstr; + for (i = 0;; i++) { + if (keys[i] == NULL) + break; + if (i != 0) + putc('|', stdout); + printf("%s", keys[i]); + } + putc(' ', stdout); + } + break; + case DIALOG_ONOFF: + printf("on|off "); + } + d++; + } + printf("\n%14s ", ""); + } + printf(" %s\n", e1->item->name); + } + e1 = e1->next; + } + } + e = e->next; + } +} + +void uih_xshlprintmenu(struct uih_context *c, CONST char *name) +{ + int i = 0; + int nexti; + CONST menuitem *item, *nextitem, *lastitem; + int comma; + printf("%%%s\n\n", name); + printf("<menuhead><head>%s</head></menuhead>\n", menu_fullname(name)); + printf("<menuitems><center>\n"); + for (i = 0; (item = menu_item2(name, i)) != NULL; i++) { + if (item->type == MENU_SEPARATOR) + printf("<p>\n"); + else if (item->type == MENU_SUBMENU) + printf("<p><submenu><a %s>%s</a>\n", item->shortname, + item->name); + else + printf("<p><a %s>%s</a>\n", item->shortname, item->name); + } + printf("</center></menuitems>\n"); + lastitem = NULL; + for (i = 0; (item = menu_item2(name, i)) != NULL; i++) { + if (item->type == MENU_SEPARATOR) + continue; + if (item->type != MENU_SUBMENU) { + for (nexti = i + 1; + (nextitem = menu_item2(name, nexti)) != NULL + && nextitem->type == MENU_SUBMENU; nexti++); + printf("<node %s, %s, %s, %s>\n", item->shortname, + (lastitem != NULL ? lastitem->shortname : ""), + nextitem != NULL ? nextitem->shortname : "", name); + printf("%%%s\n", item->shortname); + printf("<head>%s</head>\n", item->name); + if (!(item->flags & MENUFLAG_NOPLAY)) { + printf("<p><emph>Syntax</emph>:(%s", item->shortname); + if (item->flags & MENUFLAG_CHECKBOX) + printf(" bool"); + if (item->type == MENU_DIALOG + || item->type == MENU_CUSTOMDIALOG) { + int y; + CONST menudialog *di; + di = menu_getdialog(c, item); + if (item->flags & MENUFLAG_CHECKBOX) + printf(" ["); + for (y = 0; di[y].question != NULL; y++) { + switch (di[y].type) { + case DIALOG_INT: + printf(" integer"); + break; + case DIALOG_FLOAT: + printf(" float"); + break; + case DIALOG_STRING: + printf(" string"); + case DIALOG_KEYSTRING: + printf(" keyword"); + break; + case DIALOG_IFILE: + printf(" file"); + break; + case DIALOG_OFILE: + printf(" file"); + break; + case DIALOG_ONOFF: + printf(" bool"); + break; + case DIALOG_COORD: + printf(" complex"); + break; + case DIALOG_CHOICE: + printf(" keyword"); + break; + } + } + if (item->flags & MENUFLAG_CHECKBOX) + printf(" ]"); + } + printf(")\n"); + } + printf("<p>\n<emph>Available as</emph>: "); + comma = 0; + if (!(item->flags & MENUFLAG_NOMENU)) + printf("menu item"), comma = 1; + if (!(item->flags & MENUFLAG_NOOPTION)) + printf("%scommand line option", comma ? ", " : ""), comma = + 1; + if (!(item->flags & MENUFLAG_NOPLAY)) + printf("%scommand", comma ? ", " : ""), comma = 1; + printf("\n"); + printf("\n"); + lastitem = item; + } + } +} + +void uih_xshlprintmenus(struct uih_context *c) +{ + struct entry *e = firstitem; + struct entry *nexte; + struct entry *laste; + printf("%%menus\n"); + printf("<main><head>Menus</head></main>\n"); + printf("<menuitems><center>\n"); + while (e != NULL) { + if (e->item->type == MENU_SUBMENU) + printf("<p><submenu><a %s>%s</a>\n", e->item->shortname, + e->item->name); + e = e->next; + } + printf("</center></menuitems>\n"); + e = firstitem; + laste = NULL; + while (e != NULL) { + if (e->item->type == MENU_SUBMENU) { + nexte = e->next; + while (nexte != NULL && nexte->item->type != MENU_SUBMENU) + nexte = nexte->next; + printf("<node %s, %s, %s, %s>\n", e->item->shortname, + (laste != NULL ? laste->item->shortname : ""), + nexte != NULL ? nexte->item->shortname : "", "menus"); + uih_xshlprintmenu(c, e->item->shortname); + laste = e; + } + e = e->next; + } + printf("%%endmenus"); +} + +void +menu_forall(struct uih_context *c, + void (*callback) (struct uih_context * c, + CONST menuitem * item)) +{ + struct entry *e = firstitem; + while (e != NULL) { + callback(c, e->item); + e = e->next; + } +} diff --git a/src/util/xshl.c b/src/util/xshl.c new file mode 100644 index 0000000..27ab8d5 --- /dev/null +++ b/src/util/xshl.c @@ -0,0 +1,470 @@ +#ifndef _plan9_ +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <ctype.h> +#else +#include <u.h> +#include <libc.h> +#include <stdio.h> +#endif +#include <config.h> +#include <misc-f.h> +#include "xshl.h" + +#define XSHL_ENDLINE (65536) +#define XSHL_ENDPARAGRAPH (65536*2) +#define XSHL_NEWSTART (65536*4) +#define XSHL_SMALL (65536*8) +#define XSHL_SKIPBLANK (65536*16) +#define XSHL_COMMAND (65536*32) +#define XSHL_BLANK (65536*64) +#define XSHL_CLEARATLINE (65536*128) + +#define XSHL_AUTOCLEAN (XSHL_ENDLINE|XSHL_ENDPARAGRAPH|XSHL_NEWSTART|XSHL_SKIPBLANK|XSHL_COMMAND|XSHL_BLANK) + + +#define ALL (~0) +CONST static struct tag { + CONST char *name; + int andflagenable; + int orflagenable; + int andflagdisable; + int orflagdisable; +} tags[] = { + { + "p", ALL, XSHL_SKIPBLANK | XSHL_ENDPARAGRAPH, ALL, + XSHL_SKIPBLANK | XSHL_ENDPARAGRAPH} + , { + "head", ALL, + XSHL_SKIPBLANK | XSHL_BIG | XSHL_CENTERALIGN | + XSHL_ENDPARAGRAPH, ~(XSHL_BIG | XSHL_CENTERALIGN), + XSHL_SKIPBLANK | XSHL_ENDPARAGRAPH | XSHL_ENDLINE} + , { + "emph", ALL, XSHL_EMPH, ~XSHL_EMPH, 0} + , { + "br", ALL, XSHL_SKIPBLANK | XSHL_ENDLINE, ALL, 0} + , { + "white", ~XSHL_COLORMASK, XSHL_WHITE, ~XSHL_WHITE, 0} + , { + "red", ~XSHL_COLORMASK, XSHL_RED, ~XSHL_RED, 0} + , { + "black", ~XSHL_COLORMASK, XSHL_BLACK, ~XSHL_BLACK, 0} + , { + "right", ALL, XSHL_SKIPBLANK | XSHL_RIGHTALIGN | XSHL_ENDLINE, + ~XSHL_RIGHTALIGN, XSHL_SKIPBLANK | XSHL_ENDLINE} + , { + "center", ALL, XSHL_SKIPBLANK | XSHL_CENTERALIGN | XSHL_ENDLINE, + ~XSHL_CENTERALIGN, XSHL_SKIPBLANK | XSHL_ENDLINE} + , { + "tt", ALL, XSHL_MONOSPACE, ~XSHL_MONOSPACE, 0} + , { + "dl", ALL, XSHL_SKIPBLANK | XSHL_ENDLINE, + ~(XSHL_SMALL | XSHL_EMPH), XSHL_SKIPBLANK | XSHL_ENDLINE} + , { + "dt", ~XSHL_SMALL, XSHL_SKIPBLANK | XSHL_ENDLINE | XSHL_EMPH, ALL, + 0} + , { + "dd", ~XSHL_EMPH, XSHL_SKIPBLANK | XSHL_NEWSTART | XSHL_SMALL, ALL, + 0} + , { + NULL} +}; + +#define MAXINPUT 256 + +#define SMALLSKIP (4*spacewidth) + +struct boxitem { + char *text; + struct xshl_context c; + int xpos; + int width; + int height; + struct boxitem *next; +}; +static void freebox(struct boxitem *box) +{ + if (box->c.linktext != NULL) + free(box->c.linktext); + free(box->text); + free(box); +} + +static struct xshl_item *pack(struct boxitem *first, struct boxitem *last, + int *collectedflags, int width) +{ + struct xshl_item *f = NULL; + struct xshl_item *l = NULL; + struct xshl_item *item; + struct boxitem *curr = first, *ncurr; + int end = 0; + char text[256]; + int collected = 0; + while (curr != last) { + if (curr->text[0] == 0) { + ncurr = curr->next; + freebox(curr); + curr = ncurr; + continue; + } + strcpy(text, curr->text); + item = (struct xshl_item *) malloc(sizeof(struct xshl_item)); + if (item == NULL) + return NULL; + item->x = curr->xpos; + item->width = curr->width; + item->c = curr->c; + if (curr->c.linktext != NULL) + curr->c.linktext = mystrdup(curr->c.linktext); + collected |= item->c.flags; + ncurr = curr->next; + freebox(curr); + curr = ncurr; + while (curr != last && + curr->xpos == item->x + item->width && + (curr->c.flags & 0xffff) == (item->c.flags & 0xffff) + && + ((curr->c.linktext == NULL && item->c.linktext == NULL) || + (curr->c.linktext != NULL && item->c.linktext != NULL && + !strcmp(curr->c.linktext, item->c.linktext)))) + { + strcat(text, curr->text); + item->width += curr->width; + collected |= item->c.flags; + ncurr = curr->next; + freebox(curr); + curr = ncurr; + } + item->text = mystrdup(text); + item->next = NULL; + if (l != NULL) + l->next = item; + else + f = item; + l = item; + end = item->x + item->width; + } + *collectedflags = collected; + if (collected & (XSHL_CENTERALIGN | XSHL_RIGHTALIGN)) { + if (collected & XSHL_RIGHTALIGN) + end = width - end; + else + end = (width - end) / 2; + item = f; + while (item != NULL) { + item->x += end; + item = item->next; + } + } + return (f); +} + +#ifndef isspace +#define isspace(c) ((c)==' '||(c)=='\t'||(c)=='\n') +#endif +static char xshllink[32]; +static int flags; +static struct boxitem *xshl_readbox(void *data, int (*get) (void *)) +{ + char inputbuf[256]; + int c; + int i; + char command[16]; + char parameter[32]; + if (flags & XSHL_BLANK) { + struct boxitem *box = (struct boxitem *) malloc(sizeof(*box)); + box->width = 0; + box->next = NULL; + box->height = flags & XSHL_BIG ? 0 : 1; + box->text = mystrdup(" "); + box->c.flags = flags | XSHL_CLEARATLINE; + box->c.linktext = NULL; + if (xshllink[0] != 0) + box->c.linktext = mystrdup(xshllink); + flags &= ~XSHL_AUTOCLEAN; + flags |= XSHL_SKIPBLANK; + return (box); + } + if (flags & XSHL_COMMAND) { + int i = 0; + flags &= ~XSHL_COMMAND; + parameter[0] = 0; + do { + c = command[i] = get(data); + if (i < 15) + i++; + } + while (c && c != '>' && !isspace(c)); + command[i - 1] = 0; + if (c != '>' && c) { + do { + c = get(data); + } + while (c && c != '>' && isspace(c)); + if (c && c != '>') { + i = 1; + parameter[0] = c; + do { + c = parameter[i] = get(data); + if (i < 31) + i++; + } + while (c && c != '>' && !isspace(c)); + parameter[i - 1] = 0; + if (isspace(c)) { + do { + c = get(data); + } + while (c && c != '>' && isspace(c)); + } + } + } + { + int i; + int disabled = 0; + if (command[0] == '/') + disabled = 1; + for (i = 0; + tags[i].name != NULL + && strcmp(tags[i].name, command + disabled); i++); + if (tags[i].name != NULL) { + if (disabled) { + flags &= tags[i].andflagdisable; + flags |= tags[i].orflagdisable; + } else { + flags &= tags[i].andflagenable; + flags |= tags[i].orflagenable; + } + } else { + if (!strcmp(command + disabled, "a") + || !strcmp(command + disabled, "tutor")) { + if (disabled) + xshllink[0] = 0; + else + strcpy(xshllink, parameter); + } else + while (c != '>') + c = get(data); + } + } + if (c == '>') + c = get(data); + } else + c = get(data); + if (!c) { + return NULL; + } + if (flags & XSHL_SKIPBLANK) { + while (isspace(c)) { + c = get(data); + if (!c) { + return NULL; + } + } + flags &= ~XSHL_SKIPBLANK; + } + i = 0; + inputbuf[i++] = c; + while (c && c != '<' && !isspace(c)) { + c = get(data); + inputbuf[i++] = c; + if (i > 255) + i = 255; + } + inputbuf[i - 1] = 0; + if (i == 1 && !c) { + return NULL; + } + if (i == 1 && isspace(c)) { + flags |= XSHL_BLANK; + return xshl_readbox(data, get); + } + if (i == 1 && c == '<') { + flags |= XSHL_COMMAND; + return xshl_readbox(data, get); + } + { + struct boxitem *box = (struct boxitem *) malloc(sizeof(*box)); + box->width = 0; + box->next = NULL; + box->height = flags & XSHL_BIG ? 0 : 1; + box->text = mystrdup(inputbuf); + box->c.flags = flags | XSHL_CLEARATLINE; + box->c.linktext = NULL; + if (xshllink[0] != 0) + box->c.linktext = mystrdup(xshllink); + flags &= ~XSHL_AUTOCLEAN; + if (isspace(c)) + flags |= XSHL_BLANK; + if (c == '<') + flags |= XSHL_COMMAND; + return (box); + } + /*We are at the first word */ +} + +struct xshl_line *xshl_interpret(void *data, int (*get) (void *), + int width, int getwidth(void *, int flags, + CONST char *text), + int startflags, int smallheight, + int bigheight) +{ + int spacewidth = getwidth(data, 0, " "); + int cflags; + struct boxitem *first = NULL; + struct boxitem *last = NULL; + struct boxitem *item; + struct boxitem *lastword = NULL; + int maxlines = 200; + struct xshl_line *lines = + (struct xshl_line *) malloc(maxlines * sizeof(*lines)); + int nlines = 0; + int ypos = 0; + flags = startflags | XSHL_SKIPBLANK; + xshllink[0] = 0; + while ((item = xshl_readbox(data, get)) != NULL) { + if (last == NULL) { + if (item->text[0] == ' ' && !item->text[1]) { + freebox(item); + continue; + } + lastword = NULL; + first = item, item->xpos = + item->c.flags & XSHL_SMALL ? SMALLSKIP : 0; + } else { + if (item->text[0] == ' ' && !item->text[1]) { + lastword = item; + } + last->next = item, item->xpos = last->xpos + last->width; + } + last = item; + item->width = getwidth(data, item->c.flags, item->text); + if (item->c.flags & (XSHL_ENDLINE | XSHL_ENDPARAGRAPH) + || ((item->c.flags & XSHL_NEWSTART) + && item->xpos + spacewidth > SMALLSKIP)) { + if (nlines > maxlines - 1) + maxlines *= 2, lines = + (struct xshl_line *) realloc(lines, + (maxlines) * + sizeof(*lines)); + if (first != NULL) { + lines[nlines].first = pack(first, last, &cflags, width); + lines[nlines].y = ypos; + nlines++; + if (ypos & XSHL_BIG) + ypos += bigheight; + else + ypos += smallheight; + } + if (item->c.flags & (XSHL_ENDPARAGRAPH)) + ypos += smallheight; + first = last; + item->xpos = + item->c.flags & item->c.flags & XSHL_SMALL ? SMALLSKIP : 0; + lastword = NULL; + } else if (item->c.flags & XSHL_NEWSTART) + item->xpos = SMALLSKIP; + if (item->xpos + item->width > width) { + if (lastword == NULL) { + item = first; + while (item != NULL) { + struct boxitem *c = item->next; + freebox(item); + item = c; + } + first = last = NULL; + } else { + int xpos; + if (nlines > maxlines - 1) + maxlines *= 2, lines = + (struct xshl_line *) realloc(lines, + (maxlines) * + sizeof(*lines)); + lines[nlines].first = + pack(first, lastword, &cflags, width); + lines[nlines].y = ypos; + nlines++; + if (ypos & XSHL_BIG) + ypos += bigheight; + else + ypos += smallheight; + if (lastword != NULL) + first = lastword->next; + else + first = NULL; + item = first; + if (item != NULL) { + xpos = + item->c.flags & item->c. + flags & XSHL_SMALL ? SMALLSKIP : 0; + while (item != NULL) { + item->xpos = xpos; + xpos += item->width; + item = item->next; + } + } + freebox(lastword); + lastword = NULL; + if (first == NULL) + last = NULL; + } + } + } + if (last != NULL) { + lines[nlines].y = ypos; + lines[nlines].first = pack(first, last->next, &cflags, width); + } + nlines++; + lines[nlines].y = -1; + lines = + (struct xshl_line *) realloc(lines, (nlines + 2) * sizeof(*lines)); + return (lines); +} + + +int xshl_textlen(void *data, int flags, CONST char *text) +{ + return ((int) strlen(text)); +} + +void xshl_print(int startskip, struct xshl_line *lines) +{ + int i = 0; + int y = 0; + while (lines[i].y >= 0) { + int xpos = -startskip; + struct xshl_item *item; + while (y < lines[i].y) { + putc('\n', stdout), y++; + } + item = lines[i].first; + while (item) { + while (xpos < item->x) { + putc(' ', stdout), xpos++; + } + xpos += item->width; + item = item->next; + } + i++; + } +} + +void xshl_free(struct xshl_line *lines) +{ + int i = 0; + while (lines[i].y >= 0) { + struct xshl_item *item, *nextitem; + item = lines[i].first; + while (item) { + nextitem = item->next; + if (item->c.linktext != NULL) + free(item->c.linktext); + free(item->text); + free(item); + item = nextitem; + } + i++; + } + free(lines); +} diff --git a/src/util/xstdio.c b/src/util/xstdio.c new file mode 100644 index 0000000..fc7eb42 --- /dev/null +++ b/src/util/xstdio.c @@ -0,0 +1,488 @@ +#ifndef _plan9_ +#include <string.h> +#if defined(__EMX__) || defined(__APPLE__) +#include <sys/types.h> +#endif +#include <dirent.h> +#include <sys/stat.h> +#include <stdlib.h> +#include <unistd.h> +#else +#include <u.h> +#include <libc.h> +#endif +#include <config.h> +#include <filter.h> +#include <fractal.h> +#include <ui_helper.h> +#include <misc-f.h> +#ifdef _WIN32 +#define strcmp stricmp +#endif +#ifdef DJGPP +#define strcmp stricmp +#endif + +/* We reserve character 01 to application directory so we can easily refer to data files */ +char *xio_appdir; +char *xio_homedir; + +char *xio_fixpath(CONST char *c) +{ + if (c[0] == '~') { + char *c1 = (char *) malloc(strlen(c) + strlen(xio_homedir) + 5); + sprintf(c1, "%s%s", xio_homedir, c + 1); + return c1; + } + if (c[0] == '\01') { + char *c1 = (char *) malloc(strlen(c) + strlen(xio_appdir) + 5); + sprintf(c1, "%s%s", xio_appdir, c + 1); + return c1; + } + return mystrdup(c); +} + +int +xio_getfiles(xio_constpath path1, char ***names, char ***dirs, + int *nnames2, int *ndirs2) +{ +#ifdef _plan9_ + *nnames2 = *ndirs2 = 0; +#else + char *path = xio_fixpath(path1); + int maxnames = 200, maxdirs = 200; + int nnames = 0, ndirs = 0; + DIR *dir = opendir(path); + struct stat buf; + char buff[4096]; + int pathlen; + struct dirent *e; + if (dir == NULL) + return 0; + *nnames2 = 0; + *ndirs2 = 0; + e = readdir(dir); + strcpy(buff, path); + pathlen = (int) strlen(path); + if (buff[pathlen - 1] != XIO_PATHSEP) + buff[pathlen] = XIO_PATHSEP; + else + pathlen--; + *names = (char **) malloc(maxnames * sizeof(**names)); + *dirs = (char **) malloc(maxdirs * sizeof(**dirs)); + free(path); + while (e != NULL) { + char *n = mystrdup(e->d_name); + strcpy(buff + pathlen + 1, e->d_name); + stat(buff, &buf); + if (S_ISDIR(buf.st_mode)) { + if (ndirs == maxdirs) + maxdirs *= 2, *dirs = + (char **) realloc(*dirs, maxdirs * sizeof(**dirs)); + (*dirs)[ndirs] = n; + ndirs++; + } else { + if (nnames == maxnames) + maxnames *= 2, *names = + (char **) realloc(*names, maxnames * sizeof(**names)); + (*names)[nnames] = n; + nnames++; + } + e = readdir(dir); + } + if (nnames) + *names = (char **) realloc(*names, nnames * sizeof(**names)); + else + free(*names), *names = NULL; + if (ndirs) + *dirs = (char **) realloc(*dirs, ndirs * sizeof(**dirs)); + else + free(*dirs), *dirs = NULL; + *nnames2 = nnames; + *ndirs2 = ndirs; + closedir(dir); + return 1; +#endif +} + +xio_path xio_getdirectory(xio_constpath filename) +{ + int i; + xio_pathdata directory; + for (i = (int) strlen(filename); i && filename[i] != '/' && + filename[i] != '\\' && filename[i] != XIO_PATHSEP; i--); + if (filename[i] == '/' || filename[i] == '\\' + || filename[i] == XIO_PATHSEP) + i++; + directory[i] = 0; + i--; + for (; i >= 0; i--) + directory[i] = filename[i]; + return (mystrdup(directory)); +} + +xio_path xio_getfilename(CONST char *basename, CONST char *extension) +{ + static char name[40]; + int nimage = 0; +#ifdef _plan9_ +#ifdef _plan9v4_ +#define DIRLEN 116 + uchar edir[DIRLEN]; +#else + char edir[DIRLEN]; +#endif +#else + struct stat sb; +#endif + char *base = xio_fixpath(basename); + do { + sprintf(name, "%s%i%s", base, nimage++, extension); + } +#ifndef _plan9_ + while (stat(name, &sb) != -1); +#else +#ifdef _plan9v4_ + while (stat(name, edir, DIRLEN) != -1); +#else + while (stat(name, edir) != -1); +#endif +#endif + free(base); + return (name); +} + +xio_file xio_getrandomexample(xio_path name) +{ +#ifndef _plan9_ + static CONST char *CONST paths[] = { /*Where examples should be located? */ + EXAMPLESPATH, /*Data path when XaoS is propertly installed */ + "\01" XIO_PATHSEPSTR "examples", + /*XaoS was started from root of source tree */ + "\01" XIO_PATHSEPSTR ".." XIO_PATHSEPSTR "examples", + "." XIO_PATHSEPSTR "examples", + /*XaoS was started from root of source tree */ + ".." XIO_PATHSEPSTR "examples", + /*XaoS was started from bin directory in source tree */ + XIO_EMPTYPATH, /*Oops...it's not. Try curent directory */ + }; + int i = -1, p; + DIR *d = NULL; + xio_file f; + struct dirent *dir; + int n; + int max = 0; + char *realpath = NULL; + + for (p = 0; p < (int) (sizeof(paths) / sizeof(char *)) && d == NULL; + p++) { + char *pp = xio_fixpath(paths[p]); + d = opendir(pp); + free(pp); + if (d != NULL) { + realpath = xio_fixpath(paths[p]); + max = 800 - (int) strlen(realpath); + for (i = 0; (dir = readdir(d)) != NULL; i++) { + int s = (int) strlen(dir->d_name); + if (s > max || s < 4 + || strcmp(".xpf", dir->d_name + s - 4)) + i--; + /*free(dir); */ + } + if (!i) { + /*uih->errstring = "No *.xpf files found"; */ + closedir(d); + free(realpath); + d = NULL; + continue; + } + break; + } + } + if (d == NULL) { + /*uih->errstring = "Can not open examples directory"; */ + return NULL; + } + + + + rewinddir(d); + dir = NULL; + n = (int) ((number_t) i * rand() / (RAND_MAX + 1.0)); + + for (i = 0; i <= n; i++) { + int s; + do { + /*if(dir!=NULL) free(dir); */ + dir = readdir(d); + if (dir == NULL) { + /*uih->errstring = "Reading of examples directory failed"; */ + closedir(d); + free(realpath); + return NULL; + } + s = (int) strlen(dir->d_name); + } + while (s > max || s < 4 || strcmp(".xpf", dir->d_name + s - 4)); + } + if (dir == NULL) { + /*uih->errstring = "Reading of examples directory failed"; */ + closedir(d); + free(realpath); + return NULL; + } + strcpy(name, realpath); + if (name[strlen(name) - 1] != XIO_PATHSEP) + strcat(name, XIO_PATHSEPSTR); + strcat(name, dir->d_name); + closedir(d); + /*free(dir); */ + + f = xio_ropen(name); + free(realpath); + return (f); +#endif +} + +xio_file xio_getcatalog(CONST char *name) +{ + static CONST xio_constpath paths[] = { /*Where catalogs should be located? */ + CATALOGSPATH, /*Data path when XaoS is propertly installed */ +#ifndef _plan9_ + "\01" XIO_PATHSEPSTR "catalogs" XIO_PATHSEPSTR, + "\01" XIO_PATHSEPSTR ".." XIO_PATHSEPSTR "catalogs" XIO_PATHSEPSTR, + "." XIO_PATHSEPSTR "catalogs" XIO_PATHSEPSTR, + /*XaoS was started from root of source tree */ + ".." XIO_PATHSEPSTR "catalogs" XIO_PATHSEPSTR, + /*XaoS was started from bin directory in source tree */ +#else + "./catalogs/", + /*XaoS was started from root of source tree */ + "../catalogs/", + /*XaoS was started from bin directory in source tree */ +#endif + XIO_EMPTYPATH, /*Oops...it's not. Try curent directory */ + }; + int i; + xio_file f = XIO_FAILED; + xio_pathdata tmp; + for (i = 0; + i < (int) (sizeof(paths) / sizeof(char *)) && f == XIO_FAILED; + i++) { + char *p = xio_fixpath(paths[i]); + xio_addfname(tmp, p, name); + free(p); + f = xio_ropen(tmp); + if (f == XIO_FAILED) { + xio_addextension(tmp, ".cat"); + f = xio_ropen(tmp); + } + } + return (f); +} + +xio_file xio_gethelp(void) +{ + static CONST xio_constpath paths[] = { /*Where help should be located? */ + HELPPATH, /*Data path when XaoS is propertly installed */ +#ifndef _plan9_ + "\01" XIO_PATHSEPSTR "help" XIO_PATHSEPSTR "xaos.hlp", + "\01" XIO_PATHSEPSTR ".." XIO_PATHSEPSTR "help" XIO_PATHSEPSTR + "xaos.hlp", + "." XIO_PATHSEPSTR "help" XIO_PATHSEPSTR "xaos.hlp", + /*XaoS was started from root of source tree */ + ".." XIO_PATHSEPSTR "help" XIO_PATHSEPSTR "xaos.hlp", + /*XaoS was started from bin directory in source tree */ + "." XIO_PATHSEPSTR "xaos.hlp", +#else + "./help/xaos.hlp", + /*XaoS was started from root of source tree */ + "../help/xaos.hlp", + /*XaoS was started from bin directory in source tree */ + "./xaos.hlp", +#endif + /*Oops...it's not. Try curent directory */ + }; + int i; + xio_file f = XIO_FAILED; + for (i = 0; + i < (int) (sizeof(paths) / sizeof(char *)) && f == XIO_FAILED; + i++) { + char *p = xio_fixpath(paths[i]); + f = xio_ropen(p); + free(p); + } + return (f); +} + +xio_file xio_gettutorial(CONST char *name, xio_path tmp) +{ + int i; + xio_file f = XIO_FAILED; + static CONST xio_constpath paths[] = { /*Where tutorials should be located? */ + TUTORIALPATH, /*Data path when XaoS is propertly installed */ +#ifndef _plan9_ + "\01" XIO_PATHSEPSTR "tutorial" XIO_PATHSEPSTR, + "\01" XIO_PATHSEPSTR ".." XIO_PATHSEPSTR "tutorial" XIO_PATHSEPSTR, + "." XIO_PATHSEPSTR "tutorial" XIO_PATHSEPSTR, /*XaoS was started from root of source tree */ + ".." XIO_PATHSEPSTR "tutorial" XIO_PATHSEPSTR, /*XaoS was started from bin directory in source tree */ +#else + "./tutorial/", /*XaoS was started from root of source tree */ + "../tutorial/", /*XaoS was started from bin directory in source tree */ +#endif + XIO_EMPTYPATH, /*Oops...it's not. Try curent directory */ + }; + + for (i = 0; + i < (int) (sizeof(paths) / sizeof(char *)) && f == XIO_FAILED; + i++) { + char *p = xio_fixpath(paths[i]); + xio_addfname(tmp, p, name); + f = xio_ropen(tmp); + free(p); + } + return (f); +} + +int xio_exist(xio_constpath name) +{ +#ifdef _plan9_ + return (0); +#else + struct stat buf; + return (!stat(name, &buf)); +#endif +} + +static int sputc(int c, xio_file f) +{ + return putc(c, (FILE *) f->data); +} + +static int sputs(CONST char *c, xio_file f) +{ + return fputs(c, (FILE *) f->data); +} + +static int sungetc(int c, xio_file f) +{ + return ungetc(c, (FILE *) f->data); +} + +static int sgetc(xio_file f) +{ + return getc((FILE *) f->data); +} + +static int sfeof(xio_file f) +{ + return feof((FILE *) f->data); +} + +static int sflush(xio_file f) +{ + return fflush((FILE *) f->data); +} + +static int ssclose(xio_file f) +{ + int r = fclose((FILE *) f->data); + free(f); + return r; +} + +xio_file xio_ropen(CONST char *name) +{ + xio_file f = (xio_file) calloc(1, sizeof(*f)); + name = xio_fixpath(name); + f->data = (void *) fopen(name, "rt"); + /*free (name); */ + if (!f->data) { + free(f); + return 0; + } + f->fclose = ssclose; + f->xeof = sfeof; + f->fgetc = sgetc; + f->fungetc = sungetc; + return f; +} + +xio_file xio_wopen(CONST char *name) +{ + xio_file f = (xio_file) calloc(1, sizeof(*f)); + name = xio_fixpath(name); + f->data = (void *) fopen(name, "wt"); + /*free (name); */ + if (!f->data) { + free(f); + return 0; + } + f->fputc = sputc; + f->fputs = sputs; + f->fclose = ssclose; + f->flush = sflush; + return f; +} + +#ifdef DJGPP +#define DRIVES +#endif +#ifdef _WIN32 +#define DRIVES +#endif +void xio_init(CONST char *name) +{ + if (getenv("HOME")) + xio_homedir = mystrdup(getenv("HOME")); + else + xio_homedir = mystrdup("./"); + if ( +#ifdef DRIVES + (((name[0] >= 'a' && name[0] <= 'z') + || (name[0] >= 'A' && name[0] <= 'Z')) && name[1] == ':' + && (name[2] == '\\' || name[2] == '/')) || +#endif + name[0] == '/' || name[0] == '\\' || name[0] == XIO_PATHSEP + || name[0] == '~') { + char *c = mystrdup(name); + int i; + int pos = 0; + for (i = 0; i < (int) strlen(c); i++) + if (name[i] == '/' || name[i] == '\\' + || name[i] == XIO_PATHSEP) + pos = i; + c[pos] = 0; + xio_appdir = xio_fixpath(c); + free(c); + } else { + char buf[4096]; + buf[0] = '.'; + buf[1] = 0; +#ifndef _plan9_ + getcwd(buf, sizeof(buf)); +#endif + xio_appdir = mystrdup(buf); + { + char *c = mystrdup(name), *c1; + int i; + int pos = 0; + for (i = 0; i < (int) strlen(c); i++) + if (name[i] == '/' || name[i] == '\\' + || name[i] == XIO_PATHSEP) + pos = i; + c[pos] = 0; + c1 = (char *) malloc(strlen(c) + strlen(xio_appdir) + 2); + sprintf(c1, "%s%s%s", xio_appdir, XIO_PATHSEPSTR, c); + free(c); + free(xio_appdir); + xio_appdir = c1; + } + } +} + +void xio_uninit() +{ + free(xio_appdir); + free(xio_homedir); +} diff --git a/src/util/xstring.c b/src/util/xstring.c new file mode 100644 index 0000000..02959f6 --- /dev/null +++ b/src/util/xstring.c @@ -0,0 +1,141 @@ +#ifndef _plan9_ +#include <string.h> +#include <stdlib.h> +#else +#include <u.h> +#include <libc.h> +#endif + +#include <xio.h> +#include <misc-f.h> +struct fr { + char *string; + int pos; + int allocedsize; + int stringsize; +}; + +char *mystrdup(const char *c) +{ + int l = strlen(c); + char *d = malloc(l + 1); + if (!d) + return NULL; + memcpy(d, c, l + 1); + return d; +} + +static int sputc(int c, xio_file s) +{ + struct fr *f = (struct fr *) s->data; + if (f->pos >= f->allocedsize - 1) { + char *c = (char *) realloc(f->string, f->allocedsize * 2); + if (!c) + return XIO_EOF; + f->string = c; + f->allocedsize *= 2; + } + f->string[f->pos++] = c; + if (f->pos >= f->stringsize) + f->string[f->pos] = 0, f->stringsize = f->pos; + return 0; +} + +static int sputs(CONST char *c, xio_file s) +{ + int l = strlen(c); + struct fr *f = (struct fr *) s->data; + while (f->pos + l >= f->allocedsize - 1) { + char *c = (char *) realloc(f->string, f->allocedsize * 2); + if (!c) + return XIO_EOF; + f->string = c; + f->allocedsize *= 2; + } + memcpy(f->string + f->pos, c, l); + f->pos += l; + if (f->pos >= f->stringsize) + f->string[f->pos] = 0, f->stringsize = f->pos; + return 0; +} + +static int sungetc(int c, xio_file s) +{ + struct fr *f = (struct fr *) s->data; + f->pos--; + /*f->string[f->pos]=c; */ + return 0; +} + +static int sgetc(xio_file s) +{ + struct fr *f = (struct fr *) s->data; + if (f->pos == f->stringsize) + return XIO_EOF; + return f->string[f->pos++]; +} + +static int sfeof(xio_file s) +{ + struct fr *f = (struct fr *) s->data; + return (f->pos == f->stringsize); +} + +static int srclose(xio_file s) +{ + struct fr *f = (struct fr *) s->data; + free(f->string); + free(f); + free(s); + return 0; +} + +static int swclose(xio_file s) +{ + struct fr *f = (struct fr *) s->data; + f->string = (char *) realloc(f->string, f->stringsize + 1); + /*free(s); + free(f); */ + return 0; +} + +char *xio_getstring(xio_file s) +{ + struct fr *f = (struct fr *) s->data; + char *c = f->string; + free(f); + free(s); + return c; +} + +xio_file xio_strropen(CONST char *string) +{ + xio_file s = (xio_file) calloc(1, sizeof(*s)); + struct fr *f = (struct fr *) calloc(1, sizeof(*f)); + s->data = f; + f->pos = 0; + f->string = (char *) string; + f->stringsize = strlen(string); + s->fclose = srclose; + s->xeof = sfeof; + s->fgetc = sgetc; + s->fungetc = sungetc; + return s; +} + +#define PAGE 4096 +xio_file xio_strwopen(void) +{ + xio_file s = (xio_file) calloc(1, sizeof(*s)); + struct fr *f = (struct fr *) calloc(1, sizeof(*f)); + s->data = f; + f->pos = 0; + f->string = (char *) malloc(PAGE); + f->allocedsize = PAGE; + f->stringsize = 0; + s->fputc = sputc; + s->fputs = sputs; + s->fclose = swclose; + s->flush = NULL; + return s; +} |