diff options
-rw-r--r-- | e-util/ChangeLog | 12 | ||||
-rw-r--r-- | e-util/Makefile.am | 12 | ||||
-rw-r--r-- | e-util/e-config.h | 2 | ||||
-rw-r--r-- | e-util/e-event.h | 2 | ||||
-rw-r--r-- | e-util/e-host-utils.c | 391 | ||||
-rw-r--r-- | e-util/e-host-utils.h | 38 | ||||
-rw-r--r-- | e-util/e-memory.c | 1312 | ||||
-rw-r--r-- | e-util/e-memory.h | 74 | ||||
-rw-r--r-- | e-util/e-menu.h | 2 | ||||
-rw-r--r-- | e-util/e-msgport.c | 1250 | ||||
-rw-r--r-- | e-util/e-msgport.h | 111 | ||||
-rw-r--r-- | e-util/e-passwords.c | 2 | ||||
-rw-r--r-- | e-util/e-path.c | 255 | ||||
-rw-r--r-- | e-util/e-path.h | 39 | ||||
-rw-r--r-- | e-util/e-plugin.c | 2 | ||||
-rw-r--r-- | e-util/e-popup.h | 2 | ||||
-rw-r--r-- | e-util/e-sexp.c | 1381 | ||||
-rw-r--r-- | e-util/e-sexp.h | 172 | ||||
-rw-r--r-- | e-util/e-trie.c | 345 | ||||
-rw-r--r-- | e-util/e-trie.h | 47 |
20 files changed, 18 insertions, 5433 deletions
diff --git a/e-util/ChangeLog b/e-util/ChangeLog index 8a8697baa3..ed3a9db1aa 100644 --- a/e-util/ChangeLog +++ b/e-util/ChangeLog @@ -45,6 +45,18 @@ (epl_construct): if we're enabled, and load-on-startup is set, load the module right away. Not to be abused! +2004-11-16 Not Zed <NotZed@Ximian.com> + + * e-host-utils.[ch]: removed, code moved into + camel-net-utils.[ch]. + +2004-11-15 Not Zed <NotZed@Ximian.com> + + * e-trie.[ch], e-memory.[ch], e-sexp.[ch], e-msgport.[ch]: Moved + to eds/libedataserver. + + * e-path.[ch]: removed & deleted. + 2004-11-03 Not Zed <NotZed@Ximian.com> * e-plugin.c (e_plugin_list_plugins): added helper api to list all diff --git a/e-util/Makefile.am b/e-util/Makefile.am index 6f7923d86d..656b68d378 100644 --- a/e-util/Makefile.am +++ b/e-util/Makefile.am @@ -35,26 +35,20 @@ eutilinclude_HEADERS = \ e-fsutils.h \ e-gtk-utils.h \ e-gui-utils.h \ - e-host-utils.h \ e-html-utils.h \ e-icon-factory.h \ e-iterator.h \ e-list-iterator.h \ e-list.h \ - e-memory.h \ e-menu.h \ e-mktemp.h \ - e-msgport.h \ e-passwords.h \ - e-path.h \ e-plugin.h \ e-popup.h \ e-request.h \ - e-sexp.h \ e-signature.h \ e-signature-list.h \ e-time-utils.h \ - e-trie.h \ e-uid.h \ e-url.h \ md5-utils.h \ @@ -79,26 +73,20 @@ libeutil_la_SOURCES = \ e-fsutils.c \ e-gtk-utils.c \ e-gui-utils.c \ - e-host-utils.c \ e-html-utils.c \ e-icon-factory.c \ e-iterator.c \ e-list-iterator.c \ e-list.c \ - e-memory.c \ e-menu.c \ e-mktemp.c \ - e-msgport.c \ e-passwords.c \ - e-path.c \ e-plugin.c \ e-popup.c \ e-request.c \ - e-sexp.c \ e-signature.c \ e-signature-list.c \ e-time-utils.c \ - e-trie.c \ e-uid.c \ e-url.c \ eggtrayicon.c \ diff --git a/e-util/e-config.h b/e-util/e-config.h index b05990f625..db8d437bdd 100644 --- a/e-util/e-config.h +++ b/e-util/e-config.h @@ -24,7 +24,7 @@ #define __E_CONFIG_H__ #include <glib-object.h> -#include "e-util/e-msgport.h" +#include "libedataserver/e-msgport.h" #ifdef __cplusplus extern "C" { diff --git a/e-util/e-event.h b/e-util/e-event.h index 0a26b66b09..f73f0444db 100644 --- a/e-util/e-event.h +++ b/e-util/e-event.h @@ -28,7 +28,7 @@ #define __E_EVENT_H__ #include <glib-object.h> -#include "e-util/e-msgport.h" +#include "libedataserver/e-msgport.h" #ifdef __cplusplus extern "C" { diff --git a/e-util/e-host-utils.c b/e-util/e-host-utils.c deleted file mode 100644 index bab6486e0c..0000000000 --- a/e-util/e-host-utils.c +++ /dev/null @@ -1,391 +0,0 @@ -/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ -/* e-host-utils.c - * - * Copyright (C) 2001 Ximian, Inc. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General Public - * License as published by the Free Software Foundation. - * - * 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., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - * - * Author: Chris Toshok, Jeffrey Stedfast - */ - - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include <glib.h> - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <sys/types.h> -#include <sys/socket.h> -#include <netinet/in.h> -#include <arpa/inet.h> -#include <errno.h> - -#include "e-host-utils.h" - - -#if !defined (HAVE_GETHOSTBYNAME_R) || !defined (HAVE_GETHOSTBYADDR_R) -G_LOCK_DEFINE_STATIC (gethost_mutex); -#endif - - -#define ALIGN(x) (((x) + (sizeof (char *) - 1)) & ~(sizeof (char *) - 1)) - -#define GETHOST_PROCESS(h, host, buf, buflen, herr) G_STMT_START { \ - int num_aliases = 0, num_addrs = 0; \ - int req_length; \ - char *p; \ - int i; \ - \ - /* check to make sure we have enough room in our buffer */ \ - req_length = 0; \ - if (h->h_aliases) { \ - for (i = 0; h->h_aliases[i]; i++) \ - req_length += strlen (h->h_aliases[i]) + 1; \ - num_aliases = i; \ - } \ - \ - if (h->h_addr_list) { \ - for (i = 0; h->h_addr_list[i]; i++) \ - req_length += h->h_length; \ - num_addrs = i; \ - } \ - \ - req_length += sizeof (char *) * (num_aliases + 1); \ - req_length += sizeof (char *) * (num_addrs + 1); \ - req_length += strlen (h->h_name) + 1; \ - \ - if (buflen < req_length) { \ - *herr = ERANGE; \ - G_UNLOCK (gethost_mutex); \ - return ERANGE; \ - } \ - \ - /* we store the alias/addr pointers in the buffer */ \ - /* their addresses here. */ \ - p = buf; \ - if (num_aliases) { \ - host->h_aliases = (char **) p; \ - p += sizeof (char *) * (num_aliases + 1); \ - } else \ - host->h_aliases = NULL; \ - \ - if (num_addrs) { \ - host->h_addr_list = (char **) p; \ - p += sizeof (char *) * (num_addrs + 1); \ - } else \ - host->h_addr_list = NULL; \ - \ - /* copy the host name into the buffer */ \ - host->h_name = p; \ - strcpy (p, h->h_name); \ - p += strlen (h->h_name) + 1; \ - host->h_addrtype = h->h_addrtype; \ - host->h_length = h->h_length; \ - \ - /* copy the aliases/addresses into the buffer */ \ - /* and assign pointers into the hostent */ \ - *p = 0; \ - if (num_aliases) { \ - for (i = 0; i < num_aliases; i++) { \ - strcpy (p, h->h_aliases[i]); \ - host->h_aliases[i] = p; \ - p += strlen (h->h_aliases[i]); \ - } \ - host->h_aliases[num_aliases] = NULL; \ - } \ - \ - if (num_addrs) { \ - for (i = 0; i < num_addrs; i++) { \ - memcpy (p, h->h_addr_list[i], h->h_length); \ - host->h_addr_list[i] = p; \ - p += h->h_length; \ - } \ - host->h_addr_list[num_addrs] = NULL; \ - } \ -} G_STMT_END - - -#ifdef ENABLE_IPv6 -/* some helpful utils for IPv6 lookups */ -#define IPv6_BUFLEN_MIN (sizeof (char *) * 3) - -static int -ai_to_herr (int error) -{ - switch (error) { - case EAI_NONAME: - case EAI_FAIL: - return HOST_NOT_FOUND; - break; - case EAI_SERVICE: - return NO_DATA; - break; - case EAI_ADDRFAMILY: - return NO_ADDRESS; - break; - case EAI_NODATA: - return NO_DATA; - break; - case EAI_MEMORY: - return ENOMEM; - break; - case EAI_AGAIN: - return TRY_AGAIN; - break; - case EAI_SYSTEM: - return errno; - break; - default: - return NO_RECOVERY; - break; - } -} - -#endif /* ENABLE_IPv6 */ - -/** - * e_gethostbyname_r: - * @name: the host to resolve - * @host: a buffer pointing to a struct hostent to use for storage - * @buf: a buffer to use for hostname storage - * @buflen: the size of @buf - * @herr: a pointer to a variable to store an error code in - * - * Resolves the hostname @name, in a hopefully-reentrant fashion. - * - * Return value: 0 on success, ERANGE if @buflen is too small, - * "something else" otherwise (in which case *@herr will be set to - * one of the gethostbyname() error codes). - **/ -int -e_gethostbyname_r (const char *name, struct hostent *host, - char *buf, size_t buflen, int *herr) -{ -#ifdef ENABLE_IPv6 - struct addrinfo hints, *res; - int retval, len; - char *addr; - - memset (&hints, 0, sizeof (struct addrinfo)); -#ifdef HAVE_AI_ADDRCONFIG - hints.ai_flags = AI_CANONNAME | AI_ADDRCONFIG; -#else - hints.ai_flags = AI_CANONNAME; -#endif - hints.ai_family = PF_UNSPEC; - hints.ai_socktype = SOCK_STREAM; - hints.ai_protocol = IPPROTO_TCP; - - if ((retval = getaddrinfo (name, NULL, &hints, &res)) != 0) { - *herr = ai_to_herr (retval); - return -1; - } - - len = ALIGN (strlen (res->ai_canonname) + 1); - if (buflen < IPv6_BUFLEN_MIN + len + res->ai_addrlen + sizeof (char *)) - return ERANGE; - - /* h_name */ - strcpy (buf, res->ai_canonname); - host->h_name = buf; - buf += len; - - /* h_aliases */ - ((char **) buf)[0] = NULL; - host->h_aliases = (char **) buf; - buf += sizeof (char *); - - /* h_addrtype and h_length */ - host->h_length = res->ai_addrlen; - if (res->ai_family == PF_INET6) { - host->h_addrtype = AF_INET6; - - addr = (char *) &((struct sockaddr_in6 *) res->ai_addr)->sin6_addr; - } else { - host->h_addrtype = AF_INET; - - addr = (char *) &((struct sockaddr_in *) res->ai_addr)->sin_addr; - } - - memcpy (buf, addr, host->h_length); - addr = buf; - buf += ALIGN (host->h_length); - - /* h_addr_list */ - ((char **) buf)[0] = addr; - ((char **) buf)[1] = NULL; - host->h_addr_list = (char **) buf; - - freeaddrinfo (res); - - return 0; -#else /* No support for IPv6 addresses */ -#ifdef HAVE_GETHOSTBYNAME_R -#ifdef GETHOSTBYNAME_R_FIVE_ARGS - if (gethostbyname_r (name, host, buf, buflen, herr)) - return 0; - else - return errno; -#else - struct hostent *hp; - int retval; - - retval = gethostbyname_r (name, host, buf, buflen, &hp, herr); - if (hp != NULL) { - *herr = 0; - } else if (retval == 0) { - /* glibc 2.3.2 workaround - it seems that - * gethostbyname_r will sometimes return 0 on fail and - * not set the hostent values (hence the crash in bug - * #56337). Hopefully we can depend on @hp being NULL - * in this error case like we do with - * gethostbyaddr_r(). - */ - retval = -1; - } - - return retval; -#endif -#else /* No support for gethostbyname_r */ - struct hostent *h; - - G_LOCK (gethost_mutex); - - h = gethostbyname (name); - - if (!h) { - *herr = h_errno; - G_UNLOCK (gethost_mutex); - return -1; - } - - GETHOST_PROCESS (h, host, buf, buflen, herr); - - G_UNLOCK (gethost_mutex); - - return 0; -#endif /* HAVE_GETHOSTBYNAME_R */ -#endif /* ENABLE_IPv6 */ -} - - -/** - * e_gethostbyaddr_r: - * @addr: the addr to resolve - * @addrlen: address length - * @type: AF type - * @host: a buffer pointing to a struct hostent to use for storage - * @buf: a buffer to use for hostname storage - * @buflen: the size of @buf - * @herr: a pointer to a variable to store an error code in - * - * Resolves the address @addr, in a hopefully-reentrant fashion. - * - * Return value: 0 on success, ERANGE if @buflen is too small, - * "something else" otherwise (in which case *@herr will be set to - * one of the gethostbyaddr() error codes). - **/ -int -e_gethostbyaddr_r (const char *addr, int addrlen, int type, struct hostent *host, - char *buf, size_t buflen, int *herr) -{ -#ifdef ENABLE_IPv6 - int retval, len; - - if ((retval = getnameinfo (addr, addrlen, buf, buflen, NULL, 0, NI_NAMEREQD)) != 0) { - *herr = ai_to_herr (retval); - return -1; - } - - len = ALIGN (strlen (buf) + 1); - if (buflen < IPv6_BUFLEN_MIN + len + addrlen + sizeof (char *)) - return ERANGE; - - /* h_name */ - host->h_name = buf; - buf += len; - - /* h_aliases */ - ((char **) buf)[0] = NULL; - host->h_aliases = (char **) buf; - buf += sizeof (char *); - - /* h_addrtype and h_length */ - host->h_length = addrlen; - host->h_addrtype = type; - - memcpy (buf, addr, host->h_length); - addr = buf; - buf += ALIGN (host->h_length); - - /* h_addr_list */ - ((char **) buf)[0] = addr; - ((char **) buf)[1] = NULL; - host->h_addr_list = (char **) buf; - - return 0; -#else /* No support for IPv6 addresses */ -#ifdef HAVE_GETHOSTBYADDR_R -#ifdef GETHOSTBYADDR_R_SEVEN_ARGS - if (gethostbyaddr_r (addr, addrlen, type, host, buf, buflen, herr)) - return 0; - else - return errno; -#else - struct hostent *hp; - int retval; - - retval = gethostbyaddr_r (addr, addrlen, type, host, buf, buflen, &hp, herr); - if (hp != NULL) { - *herr = 0; - retval = 0; - } else if (retval == 0) { - /* glibc 2.3.2 workaround - it seems that - * gethostbyaddr_r will sometimes return 0 on fail and - * fill @host with garbage strings from /etc/hosts - * (failure to parse the file? who knows). Luckily, it - * seems that we can rely on @hp being NULL on - * fail. - */ - retval = -1; - } - - return retval; -#endif -#else /* No support for gethostbyaddr_r */ - struct hostent *h; - - G_LOCK (gethost_mutex); - - h = gethostbyaddr (addr, addrlen, type); - - if (!h) { - *herr = h_errno; - G_UNLOCK (gethost_mutex); - return -1; - } - - GETHOST_PROCESS (h, host, buf, buflen, herr); - - G_UNLOCK (gethost_mutex); - - return 0; -#endif /* HAVE_GETHOSTBYADDR_R */ -#endif /* ENABLE_IPv6 */ -} diff --git a/e-util/e-host-utils.h b/e-util/e-host-utils.h deleted file mode 100644 index 543a9d3cc2..0000000000 --- a/e-util/e-host-utils.h +++ /dev/null @@ -1,38 +0,0 @@ -/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ -/* e-host-utils.h - * - * Copyright (C) 2001 Ximian, Inc. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General Public - * License as published by the Free Software Foundation. - * - * 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., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - * - * Authors: Chris Toshok, Jeffrey Stedfast - */ - -#ifndef E_HOST_UTILS_H -#define E_HOST_UTILS_H - -#include <sys/types.h> -#include <netdb.h> - -/* gethostbyname_r implementation that works for systems without a - native gethostbyname_r. if you use this, you must make sure to - *only* use this - it can't even coexist with naked calls to - gethostbyname (even if they exist in libraries.) yes, this loses - in many ways. blame your local OS developer. */ -int e_gethostbyname_r (const char *name, struct hostent *host, char *buf, size_t buflen, int *herr); - -int e_gethostbyaddr_r (const char *addr, int len, int type, struct hostent *host, char *buf, size_t buflen, int *herr); - -#endif /* E_HOST_UTILS_H */ diff --git a/e-util/e-memory.c b/e-util/e-memory.c deleted file mode 100644 index 455e2637ff..0000000000 --- a/e-util/e-memory.c +++ /dev/null @@ -1,1312 +0,0 @@ -/* - * Copyright (c) 2000, 2001 Ximian Inc. - * - * Authors: Michael Zucchi <notzed@ximian.com> - * Jacob Berkman <jacob@ximian.com> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General Public - * License as published by the Free Software Foundation. - * - * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - * USA - -*/ - -#include "e-memory.h" - -#include <string.h> /* memset() */ -#include <stdlib.h> /* alloca() */ -#include <glib.h> - -#define s(x) /* strv debug */ -#define p(x) /* poolv debug */ -#define p2(x) /* poolv assertion checking */ - -/*#define MALLOC_CHECK*/ - -/*#define PROFILE_POOLV*/ - -#ifdef PROFILE_POOLV -#include <time.h> -#define pp(x) x -#else -#define pp(x) -#endif - -/*#define TIMEIT*/ - -#ifdef TIMEIT -#include <sys/time.h> -#include <unistd.h> - -struct timeval timeit_start; - -static time_start(const char *desc) -{ - gettimeofday(&timeit_start, NULL); - printf("starting: %s\n", desc); -} - -static time_end(const char *desc) -{ - unsigned long diff; - struct timeval end; - - gettimeofday(&end, NULL); - diff = end.tv_sec * 1000 + end.tv_usec/1000; - diff -= timeit_start.tv_sec * 1000 + timeit_start.tv_usec/1000; - printf("%s took %ld.%03ld seconds\n", - desc, diff / 1000, diff % 1000); -} -#else -#define time_start(x) -#define time_end(x) -#endif - -#ifdef MALLOC_CHECK -#include <mcheck.h> -#include <stdio.h> -static void -checkmem(void *p) -{ - if (p) { - int status = mprobe(p); - - switch (status) { - case MCHECK_HEAD: - printf("Memory underrun at %p\n", p); - abort(); - case MCHECK_TAIL: - printf("Memory overrun at %p\n", p); - abort(); - case MCHECK_FREE: - printf("Double free %p\n", p); - abort(); - } - } -} -#define MPROBE(x) checkmem((void *)(x)) -#else -#define MPROBE(x) -#endif - -/* mempool class */ - -#define STRUCT_ALIGN (4) - -typedef struct _MemChunkFreeNode { - struct _MemChunkFreeNode *next; - unsigned int atoms; -} MemChunkFreeNode; - -typedef struct _EMemChunk { - unsigned int blocksize; /* number of atoms in a block */ - unsigned int atomsize; /* size of each atom */ - GPtrArray *blocks; /* blocks of raw memory */ - struct _MemChunkFreeNode *free; -} MemChunk; - -/** - * e_memchunk_new: - * @atomcount: The number of atoms stored in a single malloc'd block of memory. - * @atomsize: The size of each allocation. - * - * Create a new memchunk header. Memchunks are an efficient way to allocate - * and deallocate identical sized blocks of memory quickly, and space efficiently. - * - * e_memchunks are effectively the same as gmemchunks, only faster (much), and - * they use less memory overhead for housekeeping. - * - * Return value: The new header. - **/ -MemChunk *e_memchunk_new(int atomcount, int atomsize) -{ - MemChunk *m = g_malloc(sizeof(*m)); - - m->blocksize = atomcount; - m->atomsize = MAX(atomsize, sizeof(MemChunkFreeNode)); - m->blocks = g_ptr_array_new(); - m->free = NULL; - - return m; -} - -/** - * memchunk_alloc: - * @m: - * - * Allocate a new atom size block of memory from a memchunk. - **/ -void *e_memchunk_alloc(MemChunk *m) -{ - char *b; - MemChunkFreeNode *f; - void *mem; - - f = m->free; - if (f) { - f->atoms--; - if (f->atoms > 0) { - mem = ((char *)f) + (f->atoms*m->atomsize); - } else { - mem = f; - m->free = m->free->next; - } - return mem; - } else { - b = g_malloc(m->blocksize * m->atomsize); - g_ptr_array_add(m->blocks, b); - f = (MemChunkFreeNode *)&b[m->atomsize]; - f->atoms = m->blocksize-1; - f->next = NULL; - m->free = f; - return b; - } -} - -void *e_memchunk_alloc0(EMemChunk *m) -{ - void *mem; - - mem = e_memchunk_alloc(m); - memset(mem, 0, m->atomsize); - - return mem; -} - -/** - * e_memchunk_free: - * @m: - * @mem: Address of atom to free. - * - * Free a single atom back to the free pool of atoms in the given - * memchunk. - **/ -void -e_memchunk_free(MemChunk *m, void *mem) -{ - MemChunkFreeNode *f; - - /* put the location back in the free list. If we knew if the preceeding or following - cells were free, we could merge the free nodes, but it doesn't really add much */ - f = mem; - f->next = m->free; - m->free = f; - f->atoms = 1; - - /* we could store the free list sorted - we could then do the above, and also - probably improve the locality of reference properties for the allocator */ - /* and it would simplify some other algorithms at that, but slow this one down - significantly */ -} - -/** - * e_memchunk_empty: - * @m: - * - * Clean out the memchunk buffers. Marks all allocated memory as free blocks, - * but does not give it back to the system. Can be used if the memchunk - * is to be used repeatedly. - **/ -void -e_memchunk_empty(MemChunk *m) -{ - int i; - MemChunkFreeNode *f, *h = NULL; - - for (i=0;i<m->blocks->len;i++) { - f = (MemChunkFreeNode *)m->blocks->pdata[i]; - f->atoms = m->blocksize; - f->next = h; - h = f; - } - m->free = h; -} - -struct _cleaninfo { - struct _cleaninfo *next; - char *base; - int count; - int size; /* just so tree_search has it, sigh */ -}; - -static int tree_compare(struct _cleaninfo *a, struct _cleaninfo *b) -{ - if (a->base < b->base) - return -1; - else if (a->base > b->base) - return 1; - return 0; -} - -static int tree_search(struct _cleaninfo *a, char *mem) -{ - if (a->base <= mem) { - if (mem < &a->base[a->size]) - return 0; - return 1; - } - return -1; -} - -/** - * e_memchunk_clean: - * @m: - * - * Scan all empty blocks and check for blocks which can be free'd - * back to the system. - * - * This routine may take a while to run if there are many allocated - * memory blocks (if the total number of allocations is many times - * greater than atomcount). - **/ -void -e_memchunk_clean(MemChunk *m) -{ - GTree *tree; - int i; - MemChunkFreeNode *f; - struct _cleaninfo *ci, *hi = NULL; - - f = m->free; - if (m->blocks->len == 0 || f == NULL) - return; - - /* first, setup the tree/list so we can map free block addresses to block addresses */ - tree = g_tree_new((GCompareFunc)tree_compare); - for (i=0;i<m->blocks->len;i++) { - ci = alloca(sizeof(*ci)); - ci->count = 0; - ci->base = m->blocks->pdata[i]; - ci->size = m->blocksize * m->atomsize; - g_tree_insert(tree, ci, ci); - ci->next = hi; - hi = ci; - } - - /* now, scan all free nodes, and count them in their tree node */ - while (f) { - ci = g_tree_search(tree, (GCompareFunc) tree_search, f); - if (ci) { - ci->count += f->atoms; - } else { - g_warning("error, can't find free node in memory block\n"); - } - f = f->next; - } - - /* if any nodes are all free, free & unlink them */ - ci = hi; - while (ci) { - if (ci->count == m->blocksize) { - MemChunkFreeNode *prev = NULL; - - f = m->free; - while (f) { - if (tree_search (ci, (void *) f) == 0) { - /* prune this node from our free-node list */ - if (prev) - prev->next = f->next; - else - m->free = f->next; - } else { - prev = f; - } - - f = f->next; - } - - g_ptr_array_remove_fast(m->blocks, ci->base); - g_free(ci->base); - } - ci = ci->next; - } - - g_tree_destroy(tree); -} - -/** - * e_memchunk_destroy: - * @m: - * - * Free the memchunk header, and all associated memory. - **/ -void -e_memchunk_destroy(MemChunk *m) -{ - int i; - - if (m == NULL) - return; - - for (i=0;i<m->blocks->len;i++) - g_free(m->blocks->pdata[i]); - g_ptr_array_free(m->blocks, TRUE); - g_free(m); -} - -typedef struct _MemPoolNode { - struct _MemPoolNode *next; - - int free; - char data[1]; -} MemPoolNode; - -typedef struct _MemPoolThresholdNode { - struct _MemPoolThresholdNode *next; - char data[1]; -} MemPoolThresholdNode; - -typedef struct _EMemPool { - int blocksize; - int threshold; - unsigned int align; - struct _MemPoolNode *blocks; - struct _MemPoolThresholdNode *threshold_blocks; -} MemPool; - -/* a pool of mempool header blocks */ -static MemChunk *mempool_memchunk; -#ifdef G_THREADS_ENABLED -static GStaticMutex mempool_mutex = G_STATIC_MUTEX_INIT; -#endif - -/** - * e_mempool_new: - * @blocksize: The base blocksize to use for all system alocations. - * @threshold: If the allocation exceeds the threshold, then it is - * allocated separately and stored in a separate list. - * @flags: Alignment options: E_MEMPOOL_ALIGN_STRUCT uses native - * struct alignment, E_MEMPOOL_ALIGN_WORD aligns to 16 bits (2 bytes), - * and E_MEMPOOL_ALIGN_BYTE aligns to the nearest byte. The default - * is to align to native structures. - * - * Create a new mempool header. Mempools can be used to efficiently - * allocate data which can then be freed as a whole. - * - * Mempools can also be used to efficiently allocate arbitrarily - * aligned data (such as strings) without incurring the space overhead - * of aligning each allocation (which is not required for strings). - * - * However, each allocation cannot be freed individually, only all - * or nothing. - * - * Return value: - **/ -MemPool *e_mempool_new(int blocksize, int threshold, EMemPoolFlags flags) -{ - MemPool *pool; - -#ifdef G_THREADS_ENABLED - g_static_mutex_lock(&mempool_mutex); -#endif - if (mempool_memchunk == NULL) { - mempool_memchunk = e_memchunk_new(8, sizeof(MemPool)); - } - pool = e_memchunk_alloc(mempool_memchunk); -#ifdef G_THREADS_ENABLED - g_static_mutex_unlock(&mempool_mutex); -#endif - if (threshold >= blocksize) - threshold = blocksize * 2 / 3; - pool->blocksize = blocksize; - pool->threshold = threshold; - pool->blocks = NULL; - pool->threshold_blocks = NULL; - - switch (flags & E_MEMPOOL_ALIGN_MASK) { - case E_MEMPOOL_ALIGN_STRUCT: - default: - pool->align = STRUCT_ALIGN-1; - break; - case E_MEMPOOL_ALIGN_WORD: - pool->align = 2-1; - break; - case E_MEMPOOL_ALIGN_BYTE: - pool->align = 1-1; - } - return pool; -} - -/** - * e_mempool_alloc: - * @pool: - * @size: - * - * Allocate a new data block in the mempool. Size will - * be rounded up to the mempool's alignment restrictions - * before being used. - **/ -void *e_mempool_alloc(MemPool *pool, register int size) -{ - size = (size + pool->align) & (~(pool->align)); - if (size>=pool->threshold) { - MemPoolThresholdNode *n; - - n = g_malloc(sizeof(*n) - sizeof(char) + size); - n->next = pool->threshold_blocks; - pool->threshold_blocks = n; - return &n->data[0]; - } else { - register MemPoolNode *n; - - n = pool->blocks; - if (n && n->free >= size) { - n->free -= size; - return &n->data[n->free]; - } - - /* maybe we could do some sort of the free blocks based on size, but - it doubt its worth it at all */ - - n = g_malloc(sizeof(*n) - sizeof(char) + pool->blocksize); - n->next = pool->blocks; - pool->blocks = n; - n->free = pool->blocksize - size; - return &n->data[n->free]; - } -} - -char *e_mempool_strdup(EMemPool *pool, const char *str) -{ - char *out; - - out = e_mempool_alloc(pool, strlen(str)+1); - strcpy(out, str); - - return out; -} - -/** - * e_mempool_flush: - * @pool: - * @freeall: Free all system allocated blocks as well. - * - * Flush used memory and mark allocated blocks as free. - * - * If @freeall is #TRUE, then all allocated blocks are free'd - * as well. Otherwise only blocks above the threshold are - * actually freed, and the others are simply marked as empty. - **/ -void e_mempool_flush(MemPool *pool, int freeall) -{ - MemPoolThresholdNode *tn, *tw; - MemPoolNode *pw, *pn; - - tw = pool->threshold_blocks; - while (tw) { - tn = tw->next; - g_free(tw); - tw = tn; - } - pool->threshold_blocks = NULL; - - if (freeall) { - pw = pool->blocks; - while (pw) { - pn = pw->next; - g_free(pw); - pw = pn; - } - pool->blocks = NULL; - } else { - pw = pool->blocks; - while (pw) { - pw->free = pool->blocksize; - pw = pw->next; - } - } -} - -/** - * e_mempool_destroy: - * @pool: - * - * Free all memory associated with a mempool. - **/ -void e_mempool_destroy(MemPool *pool) -{ - if (pool) { - e_mempool_flush(pool, 1); -#ifdef G_THREADS_ENABLED - g_static_mutex_lock(&mempool_mutex); -#endif - e_memchunk_free(mempool_memchunk, pool); -#ifdef G_THREADS_ENABLED - g_static_mutex_unlock(&mempool_mutex); -#endif - } -} - - -/* - string array classes -*/ - -#define STRV_UNPACKED ((unsigned char)(~0)) - -struct _EStrv { - unsigned char length; /* how many entries we have (or the token STRV_UNPACKED) */ - char data[1]; /* data follows */ -}; - -struct _s_strv_string { - char *string; /* the string to output */ - char *free; /* a string to free, if we referenced it */ -}; - -struct _e_strvunpacked { - unsigned char type; /* we overload last to indicate this is unpacked */ - MemPool *pool; /* pool of memory for strings */ - struct _EStrv *source; /* if we were converted from a packed one, keep the source around for a while */ - unsigned int length; - struct _s_strv_string strings[1]; /* the string array data follows */ -}; - -/** - * e_strv_new: - * @size: The number of elements in the strv. Currently this is limited - * to 254 elements. - * - * Create a new strv (string array) header. strv's can be used to - * create and work with arrays of strings that can then be compressed - * into a space-efficient static structure. This is useful - * where a number of strings are to be stored for lookup, and not - * generally edited afterwards. - * - * The size limit is currently 254 elements. This will probably not - * change as arrays of this size suffer significant performance - * penalties when looking up strings with high indices. - * - * Return value: - **/ -struct _EStrv * -e_strv_new(int size) -{ - struct _e_strvunpacked *s; - - g_assert(size<255); - - s = g_malloc(sizeof(*s) + (size-1)*sizeof(s->strings[0])); - s(printf("new strv=%p, size = %d bytes\n", s, sizeof(*s) + (size-1)*sizeof(char *))); - s->type = STRV_UNPACKED; - s->pool = NULL; - s->length = size; - s->source = NULL; - memset(s->strings, 0, size*sizeof(s->strings[0])); - - return (struct _EStrv *)s; -} - -static struct _e_strvunpacked * -strv_unpack(struct _EStrv *strv) -{ - struct _e_strvunpacked *s; - register char *p; - int i; - - s(printf("unpacking\n")); - - s = (struct _e_strvunpacked *)e_strv_new(strv->length); - p = strv->data; - for (i=0;i<s->length;i++) { - if (i>0) - while (*p++) - ; - s->strings[i].string = p; - } - s->source = strv; - s->type = STRV_UNPACKED; - - return s; -} - -/** - * e_strv_set_ref: - * @strv: - * @index: - * @str: - * - * Set a string array element by reference. The string - * is not copied until the array is packed. - * - * If @strv has been packed, then it is unpacked ready - * for more inserts, and should be packed again once finished with. - * The memory used by the original @strv is not freed until - * the new strv is packed, or freed itself. - * - * Return value: A new EStrv if the strv has already - * been packed, otherwise @strv. - **/ -struct _EStrv * -e_strv_set_ref(struct _EStrv *strv, int index, char *str) -{ - struct _e_strvunpacked *s; - - s(printf("set ref %d '%s'\nawkmeharder: %s\n ", index, str, str)); - - if (strv->length != STRV_UNPACKED) - s = strv_unpack(strv); - else - s = (struct _e_strvunpacked *)strv; - - g_assert(index>=0 && index < s->length); - - s->strings[index].string = str; - - return (struct _EStrv *)s; -} - -/** - * e_strv_set_ref_free: - * @strv: - * @index: - * @str: - * - * Set a string by reference, similar to set_ref, but also - * free the string when finished with it. The string - * is not copied until the strv is packed, and not at - * all if the index is overwritten. - * - * Return value: @strv if already unpacked, otherwise an packed - * EStrv. - **/ -struct _EStrv * -e_strv_set_ref_free(struct _EStrv *strv, int index, char *str) -{ - struct _e_strvunpacked *s; - - s(printf("set ref %d '%s'\nawkmeevenharder: %s\n ", index, str, str)); - - if (strv->length != STRV_UNPACKED) - s = strv_unpack(strv); - else - s = (struct _e_strvunpacked *)strv; - - g_assert(index>=0 && index < s->length); - - s->strings[index].string = str; - if (s->strings[index].free) - g_free(s->strings[index].free); - s->strings[index].free = str; - - return (struct _EStrv *)s; -} - -/** - * e_strv_set: - * @strv: - * @index: - * @str: - * - * Set a string array reference. The string @str is copied - * into the string array at location @index. - * - * If @strv has been packed, then it is unpacked ready - * for more inserts, and should be packed again once finished with. - * - * Return value: A new EStrv if the strv has already - * been packed, otherwise @strv. - **/ -struct _EStrv * -e_strv_set(struct _EStrv *strv, int index, const char *str) -{ - struct _e_strvunpacked *s; - - s(printf("set %d '%s'\n", index, str)); - - if (strv->length != STRV_UNPACKED) - s = strv_unpack(strv); - else - s = (struct _e_strvunpacked *)strv; - - g_assert(index>=0 && index < s->length); - - if (s->pool == NULL) - s->pool = e_mempool_new(1024, 512, E_MEMPOOL_ALIGN_BYTE); - - s->strings[index].string = e_mempool_alloc(s->pool, strlen(str)+1); - strcpy(s->strings[index].string, str); - - return (struct _EStrv *)s; -} - -/** - * e_strv_pack: - * @strv: - * - * Pack the @strv into a space efficient structure for later lookup. - * - * All strings are packed into a single allocated block, separated - * by single \0 characters, together with a count byte. - * - * Return value: - **/ -struct _EStrv * -e_strv_pack(struct _EStrv *strv) -{ - struct _e_strvunpacked *s; - int len, i; - register char *src, *dst; - - if (strv->length == STRV_UNPACKED) { - s = (struct _e_strvunpacked *)strv; - - s(printf("packing string\n")); - - len = 0; - for (i=0;i<s->length;i++) - len += s->strings[i].string?strlen(s->strings[i].string)+1:1; - - strv = g_malloc(sizeof(*strv) + len); - s(printf("allocating strv=%p, size = %d\n", strv, sizeof(*strv)+len)); - strv->length = s->length; - dst = strv->data; - for (i=0;i<s->length;i++) { - if ((src = s->strings[i].string)) { - while ((*dst++ = *src++)) - ; - } else { - *dst++ = 0; - } - } - e_strv_destroy((struct _EStrv *)s); - } - return strv; -} - -/** - * e_strv_get: - * @strv: - * @index: - * - * Retrieve a string by index. This function works - * identically on both packed and unpacked strv's, although - * may be much slower on a packed strv. - * - * Return value: - **/ -char * -e_strv_get(struct _EStrv *strv, int index) -{ - struct _e_strvunpacked *s; - char *p; - - if (strv->length != STRV_UNPACKED) { - g_assert(index>=0 && index < strv->length); - p = strv->data; - while (index > 0) { - while (*p++ != 0) - ; - index--; - } - return p; - } else { - s = (struct _e_strvunpacked *)strv; - g_assert(index>=0 && index < s->length); - return s->strings[index].string?s->strings[index].string:""; - } -} - -/** - * e_strv_destroy: - * @strv: - * - * Free a strv and all associated memory. Works on packed - * or unpacked strv's. - **/ -void -e_strv_destroy(struct _EStrv *strv) -{ - struct _e_strvunpacked *s; - int i; - - s(printf("freeing strv\n")); - - if (strv->length == STRV_UNPACKED) { - s = (struct _e_strvunpacked *)strv; - if (s->pool) - e_mempool_destroy(s->pool); - if (s->source) - e_strv_destroy(s->source); - for (i=0;i<s->length;i++) { - if (s->strings[i].free) - g_free(s->strings[i].free); - } - } - - s(printf("freeing strv=%p\n", strv)); - - g_free(strv); -} - - - -/* string pool stuff */ - -/* TODO: - garbage collection, using the following technique: - Create a memchunk for each possible size of poolv, and allocate every poolv from those - To garbage collect, scan all memchunk internally, ignoring any free areas (or mark each - poolv when freeing it - set length 0?), and find out which strings are not anywhere, - then free them. - - OR: - Just keep a refcount in the hashtable, instead of duplicating the key pointer. - - either would also require a free for the mempool, so ignore it for now */ - -/*#define POOLV_REFCNT*/ /* Define to enable refcounting code that does - automatic garbage collection of unused strings */ - -static GHashTable *poolv_pool = NULL; -static EMemPool *poolv_mempool = NULL; - -#ifdef MALLOC_CHECK -static GPtrArray *poolv_table = NULL; -#endif - -#ifdef PROFILE_POOLV -static gulong poolv_hits = 0; -static gulong poolv_misses = 0; -static unsigned long poolv_mem, poolv_count; -#endif - -#ifdef G_THREADS_ENABLED -static GStaticMutex poolv_mutex = G_STATIC_MUTEX_INIT; -#endif - -struct _EPoolv { - unsigned char length; - char *s[1]; -}; - -/** - * e_poolv_new: @size: The number of elements in the poolv, maximum of 254 elements. - * - * create a new poolv (string vector which shares a global string - * pool). poolv's can be used to work with arrays of strings which - * save memory by eliminating duplicated allocations of the same - * string. - * - * this is useful when you have a log of read-only strings that do not - * go away and are duplicated a lot (such as email headers). - * - * we should probably in the future ref count the strings contained in - * the hash table, but for now let's not. - * - * Return value: new pooled string vector - **/ -EPoolv * -e_poolv_new(unsigned int size) -{ - EPoolv *poolv; - - g_assert(size < 255); - - poolv = g_malloc0(sizeof (*poolv) + (size - 1) * sizeof (char *)); - poolv->length = size; - -#ifdef G_THREADS_ENABLED - g_static_mutex_lock(&poolv_mutex); -#endif - if (!poolv_pool) - poolv_pool = g_hash_table_new(g_str_hash, g_str_equal); - - if (!poolv_mempool) - poolv_mempool = e_mempool_new(32 * 1024, 512, E_MEMPOOL_ALIGN_BYTE); - -#ifdef MALLOC_CHECK - { - int i; - - if (poolv_table == NULL) - poolv_table = g_ptr_array_new(); - - for (i=0;i<poolv_table->len;i++) - MPROBE(poolv_table->pdata[i]); - - g_ptr_array_add(poolv_table, poolv); - } -#endif - -#ifdef G_THREADS_ENABLED - g_static_mutex_unlock(&poolv_mutex); -#endif - - p(printf("new poolv=%p\tsize=%d\n", poolv, sizeof(*poolv) + (size-1)*sizeof(char *))); - -#ifdef PROFILE_POOLV - poolv_count++; -#endif - return poolv; -} - -/** - * e_poolv_cpy: - * @dest: destination pooled string vector - * @src: source pooled string vector - * - * Copy the contents of a pooled string vector - * - * Return value: @dest, which may be re-allocated if the strings - * are different lengths. - **/ -EPoolv * -e_poolv_cpy(EPoolv *dest, const EPoolv *src) -{ -#ifdef POOLV_REFCNT - int i; - unsigned int ref; - char *key; -#endif - - p2(g_return_val_if_fail (dest != NULL, NULL)); - p2(g_return_val_if_fail (src != NULL, NULL)); - - MPROBE(dest); - MPROBE(src); - - if (dest->length != src->length) { - e_poolv_destroy(dest); - dest = e_poolv_new(src->length); - } - -#ifdef POOLV_REFCNT -#ifdef G_THREADS_ENABLED - g_static_mutex_lock(&poolv_mutex); -#endif - /* ref new copies */ - for (i=0;i<src->length;i++) { - if (src->s[i]) { - if (g_hash_table_lookup_extended(poolv_pool, src->s[i], (void **)&key, (void **)&ref)) { - g_hash_table_insert(poolv_pool, key, (void *)(ref+1)); - } else { - g_assert_not_reached(); - } - } - } - - /* unref the old ones */ - for (i=0;i<dest->length;i++) { - if (dest->s[i]) { - if (g_hash_table_lookup_extended(poolv_pool, dest->s[i], (void **)&key, (void **)&ref)) { - /* if ref == 1 free it */ - g_assert(ref > 0); - g_hash_table_insert(poolv_pool, key, (void *)(ref-1)); - } else { - g_assert_not_reached(); - } - } - } -#ifdef G_THREADS_ENABLED - g_static_mutex_unlock(&poolv_mutex); -#endif -#endif - - memcpy(dest->s, src->s, src->length * sizeof (char *)); - - return dest; -} - -#ifdef PROFILE_POOLV -static void -poolv_profile_update (void) -{ - static time_t last_time = 0; - time_t new_time; - - new_time = time (NULL); - if (new_time - last_time < 5) - return; - - printf("poolv profile: %lu hits, %lu misses: %d%% hit rate, memory: %lu, instances: %lu\n", - poolv_hits, poolv_misses, - (int)(100.0 * ((double) poolv_hits / (double) (poolv_hits + poolv_misses))), - poolv_mem, poolv_count); - - last_time = new_time; -} -#endif - -/** - * e_poolv_set: - * @poolv: pooled string vector - * @index: index in vector of string - * @str: string to set - * @freeit: whether the caller is releasing its reference to the - * string - * - * Set a string vector reference. If the caller will no longer be - * referencing the string, freeit should be TRUE. Otherwise, this - * will duplicate the string if it is not found in the pool. - * - * Return value: @poolv - **/ -EPoolv * -e_poolv_set (EPoolv *poolv, int index, char *str, int freeit) -{ -#ifdef POOLV_REFCNT - unsigned int ref; - char *key; -#endif - - p2(g_return_val_if_fail (poolv != NULL, NULL)); - - g_assert(index >=0 && index < poolv->length); - - MPROBE(poolv); - - p(printf("setting %d `%s'\n", index, str)); - - if (!str) { -#ifdef POOLV_REFCNT - if (poolv->s[index]) { - if (g_hash_table_lookup_extended(poolv_pool, poolv->s[index], (void **)&key, (void **)&ref)) { - g_assert(ref > 0); - g_hash_table_insert(poolv_pool, key, (void *)(ref-1)); - } else { - g_assert_not_reached(); - } - } -#endif - poolv->s[index] = NULL; - return poolv; - } - -#ifdef G_THREADS_ENABLED - g_static_mutex_lock(&poolv_mutex); -#endif - -#ifdef POOLV_REFCNT - if (g_hash_table_lookup_extended(poolv_pool, str, (void **)&key, (void **)&ref)) { - g_hash_table_insert(poolv_pool, key, (void *)(ref+1)); - poolv->s[index] = key; -# ifdef PROFILE_POOLV - poolv_hits++; - poolv_profile_update (); -# endif - } else { -# ifdef PROFILE_POOLV - poolv_misses++; - poolv_mem += strlen(str); - poolv_profile_update (); -# endif - poolv->s[index] = e_mempool_strdup(poolv_mempool, str); - g_hash_table_insert(poolv_pool, poolv->s[index], (void *)1); - } - -#else /* !POOLV_REFCNT */ - if ((poolv->s[index] = g_hash_table_lookup(poolv_pool, str)) != NULL) { -# ifdef PROFILE_POOLV - poolv_hits++; - poolv_profile_update (); -# endif - } else { -# ifdef PROFILE_POOLV - poolv_misses++; - poolv_mem += strlen(str); - poolv_profile_update (); -# endif - poolv->s[index] = e_mempool_strdup(poolv_mempool, str); - g_hash_table_insert(poolv_pool, poolv->s[index], poolv->s[index]); - } -#endif /* !POOLV_REFCNT */ - -#ifdef G_THREADS_ENABLED - g_static_mutex_unlock(&poolv_mutex); -#endif - - if (freeit) - g_free(str); - - return poolv; -} - -/** - * e_poolv_get: - * @poolv: pooled string vector - * @index: index in vector of string - * - * Retrieve a string by index. This could possibly just be a macro. - * - * Since the pool is never freed, this string does not need to be - * duplicated, but should not be modified. - * - * Return value: string at that index. - **/ -const char * -e_poolv_get(EPoolv *poolv, int index) -{ - g_assert(poolv != NULL); - g_assert(index>= 0 && index < poolv->length); - - MPROBE(poolv); - - p(printf("get %d = `%s'\n", index, poolv->s[index])); - - return poolv->s[index]?poolv->s[index]:""; -} - -/** - * e_poolv_destroy: - * @poolv: pooled string vector to free - * - * Free a pooled string vector. This doesn't free the strings from - * the vector, however. - **/ -void -e_poolv_destroy(EPoolv *poolv) -{ -#ifdef POOLV_REFCNT - int i; - unsigned int ref; - char *key; - - MPROBE(poolv); - -#ifdef G_THREADS_ENABLED - g_static_mutex_lock(&poolv_mutex); -#endif - -#ifdef MALLOC_CHECK - for (i=0;i<poolv_table->len;i++) - MPROBE(poolv_table->pdata[i]); - - g_ptr_array_remove_fast(poolv_table, poolv); -#endif - - for (i=0;i<poolv->length;i++) { - if (poolv->s[i]) { - if (g_hash_table_lookup_extended(poolv_pool, poolv->s[i], (void **)&key, (void **)&ref)) { - /* if ref == 1 free it */ - g_assert(ref > 0); - g_hash_table_insert(poolv_pool, key, (void *)(ref-1)); - } else { - g_assert_not_reached(); - } - } - } -#ifdef G_THREADS_ENABLED - g_static_mutex_unlock(&poolv_mutex); -#endif -#endif - -#ifdef PROFILE_POOLV - poolv_count++; -#endif - g_free(poolv); -} - -#if 0 - -#define CHUNK_SIZE (20) -#define CHUNK_COUNT (32) - -#define s(x) - -main() -{ - int i; - MemChunk *mc; - void *mem, *last; - GMemChunk *gmc; - struct _EStrv *s; - - s = strv_new(8); - s = strv_set(s, 1, "Testing 1"); - s = strv_set(s, 2, "Testing 2"); - s = strv_set(s, 3, "Testing 3"); - s = strv_set(s, 4, "Testing 4"); - s = strv_set(s, 5, "Testing 5"); - s = strv_set(s, 6, "Testing 7"); - - for (i=0;i<8;i++) { - printf("s[%d] = %s\n", i, strv_get(s, i)); - } - - s(sleep(5)); - - printf("packing ...\n"); - s = strv_pack(s); - - for (i=0;i<8;i++) { - printf("s[%d] = %s\n", i, strv_get(s, i)); - } - - printf("setting ...\n"); - - s = strv_set_ref(s, 1, "Testing 1 x"); - - for (i=0;i<8;i++) { - printf("s[%d] = %s\n", i, strv_get(s, i)); - } - - printf("packing ...\n"); - s = strv_pack(s); - - for (i=0;i<8;i++) { - printf("s[%d] = %s\n", i, strv_get(s, i)); - } - - strv_free(s); - -#if 0 - time_start("Using memchunks"); - mc = memchunk_new(CHUNK_COUNT, CHUNK_SIZE); - for (i=0;i<1000000;i++) { - mem = memchunk_alloc(mc); - if ((i & 1) == 0) - memchunk_free(mc, mem); - } - s(sleep(10)); - memchunk_destroy(mc); - time_end("allocating 1000000 memchunks, freeing 500k"); - - time_start("Using gmemchunks"); - gmc = g_mem_chunk_new("memchunk", CHUNK_SIZE, CHUNK_SIZE*CHUNK_COUNT, G_ALLOC_AND_FREE); - for (i=0;i<1000000;i++) { - mem = g_mem_chunk_alloc(gmc); - if ((i & 1) == 0) - g_mem_chunk_free(gmc, mem); - } - s(sleep(10)); - g_mem_chunk_destroy(gmc); - time_end("allocating 1000000 gmemchunks, freeing 500k"); - - time_start("Using memchunks"); - mc = memchunk_new(CHUNK_COUNT, CHUNK_SIZE); - for (i=0;i<1000000;i++) { - mem = memchunk_alloc(mc); - } - s(sleep(10)); - memchunk_destroy(mc); - time_end("allocating 1000000 memchunks"); - - time_start("Using gmemchunks"); - gmc = g_mem_chunk_new("memchunk", CHUNK_SIZE, CHUNK_COUNT*CHUNK_SIZE, G_ALLOC_ONLY); - for (i=0;i<1000000;i++) { - mem = g_mem_chunk_alloc(gmc); - } - s(sleep(10)); - g_mem_chunk_destroy(gmc); - time_end("allocating 1000000 gmemchunks"); - - time_start("Using malloc"); - for (i=0;i<1000000;i++) { - malloc(CHUNK_SIZE); - } - time_end("allocating 1000000 malloc"); -#endif - -} - -#endif diff --git a/e-util/e-memory.h b/e-util/e-memory.h deleted file mode 100644 index 9cc89f2f23..0000000000 --- a/e-util/e-memory.h +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright (C) 2001, Ximian Inc. - * - * Authors: Michael Zucchi <notzed@ximian.com> - * Jacob Berkman <jacob@ximian.com> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General Public - * License as published by the Free Software Foundation. - * - * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - * USA - */ - -#ifndef _E_MEMORY_H -#define _E_MEMORY_H - -/* memchunks - allocate/free fixed-size blocks of memory */ -/* this is like gmemchunk, only faster and less overhead (only 4 bytes for every atomcount allocations) */ -typedef struct _EMemChunk EMemChunk; - -EMemChunk *e_memchunk_new(int atomcount, int atomsize); -void *e_memchunk_alloc(EMemChunk *m); -void *e_memchunk_alloc0(EMemChunk *m); -void e_memchunk_free(EMemChunk *m, void *mem); -void e_memchunk_empty(EMemChunk *m); -void e_memchunk_clean(EMemChunk *m); -void e_memchunk_destroy(EMemChunk *m); - -/* mempools - allocate variable sized blocks of memory, and free as one */ -/* allocation is very fast, but cannot be freed individually */ -typedef struct _EMemPool EMemPool; -typedef enum { - E_MEMPOOL_ALIGN_STRUCT = 0, /* allocate to native structure alignment */ - E_MEMPOOL_ALIGN_WORD = 1, /* allocate to words - 16 bit alignment */ - E_MEMPOOL_ALIGN_BYTE = 2, /* allocate to bytes - 8 bit alignment */ - E_MEMPOOL_ALIGN_MASK = 3, /* which bits determine the alignment information */ -} EMemPoolFlags; - -EMemPool *e_mempool_new(int blocksize, int threshold, EMemPoolFlags flags); -void *e_mempool_alloc(EMemPool *pool, int size); -char *e_mempool_strdup(EMemPool *pool, const char *str); -void e_mempool_flush(EMemPool *pool, int freeall); -void e_mempool_destroy(EMemPool *pool); - -/* strv's string arrays that can be efficiently modified and then compressed mainly for retrival */ -/* building is relatively fast, once compressed it takes the minimum amount of memory possible to store */ -typedef struct _EStrv EStrv; - -EStrv *e_strv_new(int size); -EStrv *e_strv_set_ref(EStrv *strv, int index, char *str); -EStrv *e_strv_set_ref_free(EStrv *strv, int index, char *str); -EStrv *e_strv_set(EStrv *strv, int index, const char *str); -EStrv *e_strv_pack(EStrv *strv); -char *e_strv_get(EStrv *strv, int index); -void e_strv_destroy(EStrv *strv); - -/* poolv's are similar to strv's, but they store common strings */ -typedef struct _EPoolv EPoolv; - -EPoolv *e_poolv_new(unsigned int size); -EPoolv *e_poolv_cpy(EPoolv *dest, const EPoolv *src); -EPoolv *e_poolv_set(EPoolv *poolv, int index, char *str, int freeit); -const char *e_poolv_get(EPoolv *poolv, int index); -void e_poolv_destroy(EPoolv *poolv); - -#endif /* ! _E_MEMORY_H */ diff --git a/e-util/e-menu.h b/e-util/e-menu.h index a6ff19c907..80bac35470 100644 --- a/e-util/e-menu.h +++ b/e-util/e-menu.h @@ -24,7 +24,7 @@ #define __E_MENU_H__ #include <glib-object.h> -#include "e-util/e-msgport.h" +#include "libedataserver/e-msgport.h" #ifdef __cplusplus extern "C" { diff --git a/e-util/e-msgport.c b/e-util/e-msgport.c deleted file mode 100644 index f360a3f157..0000000000 --- a/e-util/e-msgport.c +++ /dev/null @@ -1,1250 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* - * Authors: Michael Zucchi <notzed@ximian.com> - * - * Copyright 2002 Ximian, Inc. (www.ximian.com) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General Public - * License as published by the Free Software Foundation. - * - * 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., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - * - */ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include <sys/time.h> -#include <sys/types.h> -#include <unistd.h> -#include <errno.h> -#include <string.h> -#include <stdio.h> - -#include <pthread.h> - -#include <glib.h> - -#ifdef HAVE_NSS -#include <nspr.h> -#endif - -#include "e-msgport.h" - -#define m(x) /* msgport debug */ -#define t(x) /* thread debug */ -#define c(x) /* cache debug */ - -void e_dlist_init(EDList *v) -{ - v->head = (EDListNode *)&v->tail; - v->tail = 0; - v->tailpred = (EDListNode *)&v->head; -} - -EDListNode *e_dlist_addhead(EDList *l, EDListNode *n) -{ - n->next = l->head; - n->prev = (EDListNode *)&l->head; - l->head->prev = n; - l->head = n; - return n; -} - -EDListNode *e_dlist_addtail(EDList *l, EDListNode *n) -{ - n->next = (EDListNode *)&l->tail; - n->prev = l->tailpred; - l->tailpred->next = n; - l->tailpred = n; - return n; -} - -EDListNode *e_dlist_remove(EDListNode *n) -{ - n->next->prev = n->prev; - n->prev->next = n->next; - return n; -} - -EDListNode *e_dlist_remhead(EDList *l) -{ - EDListNode *n, *nn; - - n = l->head; - nn = n->next; - if (nn) { - nn->prev = n->prev; - l->head = nn; - return n; - } - return NULL; -} - -EDListNode *e_dlist_remtail(EDList *l) -{ - EDListNode *n, *np; - - n = l->tailpred; - np = n->prev; - if (np) { - np->next = n->next; - l->tailpred = np; - return n; - } - return NULL; -} - -int e_dlist_empty(EDList *l) -{ - return (l->head == (EDListNode *)&l->tail); -} - -int e_dlist_length(EDList *l) -{ - EDListNode *n, *nn; - int count = 0; - - n = l->head; - nn = n->next; - while (nn) { - count++; - n = nn; - nn = n->next; - } - - return count; -} - -struct _EMCache { - GMutex *lock; - GHashTable *key_table; - EDList lru_list; - size_t node_size; - int node_count; - time_t timeout; - GFreeFunc node_free; -}; - -/** - * em_cache_new: - * @timeout: - * @nodesize: - * @nodefree: - * - * Setup a new timeout cache. @nodesize is the size of nodes in the - * cache, and @nodefree will be called to free YOUR content. - * - * Return value: - **/ -EMCache * -em_cache_new(time_t timeout, size_t nodesize, GFreeFunc nodefree) -{ - struct _EMCache *emc; - - emc = g_malloc0(sizeof(*emc)); - emc->node_size = nodesize; - emc->key_table = g_hash_table_new(g_str_hash, g_str_equal); - emc->node_free = nodefree; - e_dlist_init(&emc->lru_list); - emc->lock = g_mutex_new(); - emc->timeout = timeout; - - return emc; -} - -/** - * em_cache_destroy: - * @emc: - * - * destroy the cache, duh. - **/ -void -em_cache_destroy(EMCache *emc) -{ - em_cache_clear(emc); - g_mutex_free(emc->lock); - g_free(emc); -} - -/** - * em_cache_lookup: - * @emc: - * @key: - * - * Lookup a cache node. once you're finished with it, you need to - * unref it. - * - * Return value: - **/ -EMCacheNode * -em_cache_lookup(EMCache *emc, const char *key) -{ - EMCacheNode *n; - - g_mutex_lock(emc->lock); - n = g_hash_table_lookup(emc->key_table, key); - if (n) { - e_dlist_remove((EDListNode *)n); - e_dlist_addhead(&emc->lru_list, (EDListNode *)n); - n->stamp = time(0); - n->ref_count++; - } - g_mutex_unlock(emc->lock); - - c(printf("looking up '%s' %s\n", key, n?"found":"not found")); - - return n; -} - -/** - * em_cache_node_new: - * @emc: - * @key: - * - * Create a new key'd cache node. The node will not be added to the - * cache until you insert it. - * - * Return value: - **/ -EMCacheNode * -em_cache_node_new(EMCache *emc, const char *key) -{ - EMCacheNode *n; - - /* this could use memchunks, but its probably overkill */ - n = g_malloc0(emc->node_size); - n->key = g_strdup(key); - - return n; -} - -/** - * em_cache_node_unref: - * @emc: - * @n: - * - * unref a cache node, you can only unref nodes which have been looked - * up. - **/ -void -em_cache_node_unref(EMCache *emc, EMCacheNode *n) -{ - g_mutex_lock(emc->lock); - g_assert(n->ref_count > 0); - n->ref_count--; - g_mutex_unlock(emc->lock); -} - -/** - * em_cache_add: - * @emc: - * @n: - * - * Add a cache node to the cache, once added the memory is owned by - * the cache. If there are conflicts and the old node is still in - * use, then the new node is not added, otherwise it is added and any - * nodes older than the expire time are flushed. - **/ -void -em_cache_add(EMCache *emc, EMCacheNode *n) -{ - EMCacheNode *old, *prev; - EDList old_nodes; - - e_dlist_init(&old_nodes); - - g_mutex_lock(emc->lock); - old = g_hash_table_lookup(emc->key_table, n->key); - if (old != NULL) { - if (old->ref_count == 0) { - g_hash_table_remove(emc->key_table, old->key); - e_dlist_remove((EDListNode *)old); - e_dlist_addtail(&old_nodes, (EDListNode *)old); - goto insert; - } else { - e_dlist_addtail(&old_nodes, (EDListNode *)n); - } - } else { - time_t now; - insert: - now = time(0); - g_hash_table_insert(emc->key_table, n->key, n); - e_dlist_addhead(&emc->lru_list, (EDListNode *)n); - n->stamp = now; - emc->node_count++; - - c(printf("inserting node %s\n", n->key)); - - old = (EMCacheNode *)emc->lru_list.tailpred; - prev = old->prev; - while (prev && old->stamp < now - emc->timeout) { - if (old->ref_count == 0) { - c(printf("expiring node %s\n", old->key)); - g_hash_table_remove(emc->key_table, old->key); - e_dlist_remove((EDListNode *)old); - e_dlist_addtail(&old_nodes, (EDListNode *)old); - } - old = prev; - prev = prev->prev; - } - } - - g_mutex_unlock(emc->lock); - - while ((old = (EMCacheNode *)e_dlist_remhead(&old_nodes))) { - emc->node_free(old); - g_free(old->key); - g_free(old); - } -} - -/** - * em_cache_clear: - * @emc: - * - * clear the cache. just for api completeness. - **/ -void -em_cache_clear(EMCache *emc) -{ - EMCacheNode *node; - EDList old_nodes; - - e_dlist_init(&old_nodes); - g_mutex_lock(emc->lock); - while ((node = (EMCacheNode *)e_dlist_remhead(&emc->lru_list))) - e_dlist_addtail(&old_nodes, (EDListNode *)node); - g_mutex_unlock(emc->lock); - - while ((node = (EMCacheNode *)e_dlist_remhead(&old_nodes))) { - emc->node_free(node); - g_free(node->key); - g_free(node); - } -} - -struct _EMsgPort { - EDList queue; - int condwait; /* how many waiting in condwait */ - union { - int pipe[2]; - struct { - int read; - int write; - } fd; - } pipe; -#ifdef HAVE_NSS - struct { - PRFileDesc *read; - PRFileDesc *write; - } prpipe; -#endif - /* @#@$#$ glib stuff */ - GCond *cond; - GMutex *lock; -}; - -EMsgPort *e_msgport_new(void) -{ - EMsgPort *mp; - - mp = g_malloc(sizeof(*mp)); - e_dlist_init(&mp->queue); - mp->lock = g_mutex_new(); - mp->cond = g_cond_new(); - mp->pipe.fd.read = -1; - mp->pipe.fd.write = -1; -#ifdef HAVE_NSS - mp->prpipe.read = NULL; - mp->prpipe.write = NULL; -#endif - mp->condwait = 0; - - return mp; -} - -void e_msgport_destroy(EMsgPort *mp) -{ - g_mutex_free(mp->lock); - g_cond_free(mp->cond); - if (mp->pipe.fd.read != -1) { - close(mp->pipe.fd.read); - close(mp->pipe.fd.write); - } -#ifdef HAVE_NSS - if (mp->prpipe.read) { - PR_Close(mp->prpipe.read); - PR_Close(mp->prpipe.write); - } -#endif - g_free(mp); -} - -/* get a fd that can be used to wait on the port asynchronously */ -int e_msgport_fd(EMsgPort *mp) -{ - int fd; - - g_mutex_lock(mp->lock); - fd = mp->pipe.fd.read; - if (fd == -1) { - pipe(mp->pipe.pipe); - fd = mp->pipe.fd.read; - } - g_mutex_unlock(mp->lock); - - return fd; -} - -#ifdef HAVE_NSS -PRFileDesc *e_msgport_prfd(EMsgPort *mp) -{ - PRFileDesc *fd; - - g_mutex_lock(mp->lock); - fd = mp->prpipe.read; - if (fd == NULL) { - PR_CreatePipe(&mp->prpipe.read, &mp->prpipe.write); - fd = mp->prpipe.read; - } - g_mutex_unlock(mp->lock); - - return fd; -} -#endif - -void e_msgport_put(EMsgPort *mp, EMsg *msg) -{ - int fd; -#ifdef HAVE_NSS - PRFileDesc *prfd; -#endif - - m(printf("put:\n")); - g_mutex_lock(mp->lock); - e_dlist_addtail(&mp->queue, &msg->ln); - if (mp->condwait > 0) { - m(printf("put: condwait > 0, waking up\n")); - g_cond_signal(mp->cond); - } - fd = mp->pipe.fd.write; -#ifdef HAVE_NSS - prfd = mp->prpipe.write; -#endif - g_mutex_unlock(mp->lock); - - if (fd != -1) { - m(printf("put: have pipe, writing notification to it\n")); - write(fd, "", 1); - } - -#ifdef HAVE_NSS - if (prfd != NULL) { - m(printf("put: have pr pipe, writing notification to it\n")); - PR_Write(prfd, "", 1); - } -#endif - m(printf("put: done\n")); -} - -static void -msgport_cleanlock(void *data) -{ - EMsgPort *mp = data; - - g_mutex_unlock(mp->lock); -} - -EMsg *e_msgport_wait(EMsgPort *mp) -{ - EMsg *msg; - - m(printf("wait:\n")); - g_mutex_lock(mp->lock); - while (e_dlist_empty(&mp->queue)) { - if (mp->pipe.fd.read != -1) { - fd_set rfds; - int retry; - - m(printf("wait: waitng on pipe\n")); - g_mutex_unlock(mp->lock); - do { - FD_ZERO(&rfds); - FD_SET(mp->pipe.fd.read, &rfds); - retry = select(mp->pipe.fd.read+1, &rfds, NULL, NULL, NULL) == -1 && errno == EINTR; - pthread_testcancel(); - } while (retry); - g_mutex_lock(mp->lock); - m(printf("wait: got pipe\n")); -#ifdef HAVE_NSS - } else if (mp->prpipe.read != NULL) { - PRPollDesc polltable[1]; - int retry; - - m(printf("wait: waitng on pr pipe\n")); - g_mutex_unlock(mp->lock); - do { - polltable[0].fd = mp->prpipe.read; - polltable[0].in_flags = PR_POLL_READ|PR_POLL_ERR; - retry = PR_Poll(polltable, 1, PR_INTERVAL_NO_TIMEOUT) == -1 && PR_GetError() == PR_PENDING_INTERRUPT_ERROR; - pthread_testcancel(); - } while (retry); - g_mutex_lock(mp->lock); - m(printf("wait: got pr pipe\n")); -#endif /* HAVE_NSS */ - } else { - m(printf("wait: waiting on condition\n")); - mp->condwait++; - /* if we are cancelled in the cond-wait, then we need to unlock our lock when we cleanup */ - pthread_cleanup_push(msgport_cleanlock, mp); - g_cond_wait(mp->cond, mp->lock); - pthread_cleanup_pop(0); - m(printf("wait: got condition\n")); - mp->condwait--; - } - } - msg = (EMsg *)mp->queue.head; - m(printf("wait: message = %p\n", msg)); - g_mutex_unlock(mp->lock); - m(printf("wait: done\n")); - return msg; -} - -EMsg *e_msgport_get(EMsgPort *mp) -{ - EMsg *msg; - char dummy[1]; - - g_mutex_lock(mp->lock); - msg = (EMsg *)e_dlist_remhead(&mp->queue); - if (msg) { - if (mp->pipe.fd.read != -1) - read(mp->pipe.fd.read, dummy, 1); -#ifdef HAVE_NSS - if (mp->prpipe.read != NULL) { - int c; - c = PR_Read(mp->prpipe.read, dummy, 1); - g_assert(c == 1); - } -#endif - } - m(printf("get: message = %p\n", msg)); - g_mutex_unlock(mp->lock); - - return msg; -} - -void e_msgport_reply(EMsg *msg) -{ - if (msg->reply_port) { - e_msgport_put(msg->reply_port, msg); - } - /* else lost? */ -} - -struct _thread_info { - pthread_t id; - int busy; -}; - -struct _EThread { - struct _EThread *next; - struct _EThread *prev; - - EMsgPort *server_port; - EMsgPort *reply_port; - pthread_mutex_t mutex; - e_thread_t type; - int queue_limit; - - int waiting; /* if we are waiting for a new message, count of waiting processes */ - pthread_t id; /* id of our running child thread */ - GList *id_list; /* if THREAD_NEW, then a list of our child threads in thread_info structs */ - - EThreadFunc destroy; - void *destroy_data; - - EThreadFunc received; - void *received_data; - - EThreadFunc lost; - void *lost_data; -}; - -/* All active threads */ -static EDList ethread_list = E_DLIST_INITIALISER(ethread_list); -static pthread_mutex_t ethread_lock = PTHREAD_MUTEX_INITIALIZER; - -#define E_THREAD_NONE ((pthread_t)~0) -#define E_THREAD_QUIT_REPLYPORT ((struct _EMsgPort *)~0) - -static void thread_destroy_msg(EThread *e, EMsg *m); - -static struct _thread_info *thread_find(EThread *e, pthread_t id) -{ - GList *node; - struct _thread_info *info; - - node = e->id_list; - while (node) { - info = node->data; - if (info->id == id) - return info; - node = node->next; - } - return NULL; -} - -#if 0 -static void thread_remove(EThread *e, pthread_t id) -{ - GList *node; - struct _thread_info *info; - - node = e->id_list; - while (node) { - info = node->data; - if (info->id == id) { - e->id_list = g_list_remove(e->id_list, info); - g_free(info); - } - node = node->next; - } -} -#endif - -EThread *e_thread_new(e_thread_t type) -{ - EThread *e; - - e = g_malloc0(sizeof(*e)); - pthread_mutex_init(&e->mutex, 0); - e->type = type; - e->server_port = e_msgport_new(); - e->id = E_THREAD_NONE; - e->queue_limit = INT_MAX; - - pthread_mutex_lock(ðread_lock); - e_dlist_addtail(ðread_list, (EDListNode *)e); - pthread_mutex_unlock(ðread_lock); - - return e; -} - -/* close down the threads & resources etc */ -void e_thread_destroy(EThread *e) -{ - int busy = FALSE; - EMsg *msg; - struct _thread_info *info; - GList *l; - - /* make sure we soak up all the messages first */ - while ( (msg = e_msgport_get(e->server_port)) ) { - thread_destroy_msg(e, msg); - } - - pthread_mutex_lock(&e->mutex); - - switch(e->type) { - case E_THREAD_QUEUE: - case E_THREAD_DROP: - /* if we have a thread, 'kill' it */ - if (e->id != E_THREAD_NONE) { - pthread_t id = e->id; - - t(printf("Sending thread '%d' quit message\n", id)); - - e->id = E_THREAD_NONE; - - msg = g_malloc0(sizeof(*msg)); - msg->reply_port = E_THREAD_QUIT_REPLYPORT; - e_msgport_put(e->server_port, msg); - - pthread_mutex_unlock(&e->mutex); - t(printf("Joining thread '%d'\n", id)); - pthread_join(id, 0); - t(printf("Joined thread '%d'!\n", id)); - pthread_mutex_lock(&e->mutex); - } - busy = e->id != E_THREAD_NONE; - break; - case E_THREAD_NEW: - /* first, send everyone a quit message */ - l = e->id_list; - while (l) { - info = l->data; - t(printf("Sending thread '%d' quit message\n", info->id)); - msg = g_malloc0(sizeof(*msg)); - msg->reply_port = E_THREAD_QUIT_REPLYPORT; - e_msgport_put(e->server_port, msg); - l = l->next; - } - - /* then, wait for everyone to quit */ - while (e->id_list) { - info = e->id_list->data; - e->id_list = g_list_remove(e->id_list, info); - pthread_mutex_unlock(&e->mutex); - t(printf("Joining thread '%d'\n", info->id)); - pthread_join(info->id, 0); - t(printf("Joined thread '%d'!\n", info->id)); - pthread_mutex_lock(&e->mutex); - g_free(info); - } - busy = g_list_length(e->id_list) != 0; - break; - } - - pthread_mutex_unlock(&e->mutex); - - /* and clean up, if we can */ - if (busy) { - g_warning("threads were busy, leaked EThread"); - return; - } - - pthread_mutex_lock(ðread_lock); - e_dlist_remove((EDListNode *)e); - pthread_mutex_unlock(ðread_lock); - - pthread_mutex_destroy(&e->mutex); - e_msgport_destroy(e->server_port); - g_free(e); -} - -/* set the queue maximum depth, what happens when the queue - fills up depends on the queue type */ -void e_thread_set_queue_limit(EThread *e, int limit) -{ - e->queue_limit = limit; -} - -/* set a msg destroy callback, this can not call any e_thread functions on @e */ -void e_thread_set_msg_destroy(EThread *e, EThreadFunc destroy, void *data) -{ - pthread_mutex_lock(&e->mutex); - e->destroy = destroy; - e->destroy_data = data; - pthread_mutex_unlock(&e->mutex); -} - -/* set a message lost callback, called if any message is discarded */ -void e_thread_set_msg_lost(EThread *e, EThreadFunc lost, void *data) -{ - pthread_mutex_lock(&e->mutex); - e->lost = lost; - e->lost_data = lost; - pthread_mutex_unlock(&e->mutex); -} - -/* set a reply port, if set, then send messages back once finished */ -void e_thread_set_reply_port(EThread *e, EMsgPort *reply_port) -{ - e->reply_port = reply_port; -} - -/* set a received data callback */ -void e_thread_set_msg_received(EThread *e, EThreadFunc received, void *data) -{ - pthread_mutex_lock(&e->mutex); - e->received = received; - e->received_data = data; - pthread_mutex_unlock(&e->mutex); -} - -/* find out if we're busy doing any work, e==NULL, check for all work */ -int e_thread_busy(EThread *e) -{ - int busy = FALSE; - - if (e == NULL) { - pthread_mutex_lock(ðread_lock); - e = (EThread *)ethread_list.head; - while (e->next && !busy) { - busy = e_thread_busy(e); - e = e->next; - } - pthread_mutex_unlock(ðread_lock); - } else { - pthread_mutex_lock(&e->mutex); - switch (e->type) { - case E_THREAD_QUEUE: - case E_THREAD_DROP: - busy = e->waiting != 1 && e->id != E_THREAD_NONE; - break; - case E_THREAD_NEW: - busy = e->waiting != g_list_length(e->id_list); - break; - } - pthread_mutex_unlock(&e->mutex); - } - - return busy; -} - -static void -thread_destroy_msg(EThread *e, EMsg *m) -{ - EThreadFunc func; - void *func_data; - - /* we do this so we never get an incomplete/unmatched callback + data */ - pthread_mutex_lock(&e->mutex); - func = e->destroy; - func_data = e->destroy_data; - pthread_mutex_unlock(&e->mutex); - - if (func) - func(e, m, func_data); -} - -static void -thread_received_msg(EThread *e, EMsg *m) -{ - EThreadFunc func; - void *func_data; - - /* we do this so we never get an incomplete/unmatched callback + data */ - pthread_mutex_lock(&e->mutex); - func = e->received; - func_data = e->received_data; - pthread_mutex_unlock(&e->mutex); - - if (func) - func(e, m, func_data); - else - g_warning("No processing callback for EThread, message unprocessed"); -} - -static void -thread_lost_msg(EThread *e, EMsg *m) -{ - EThreadFunc func; - void *func_data; - - /* we do this so we never get an incomplete/unmatched callback + data */ - pthread_mutex_lock(&e->mutex); - func = e->lost; - func_data = e->lost_data; - pthread_mutex_unlock(&e->mutex); - - if (func) - func(e, m, func_data); -} - -/* the actual thread dispatcher */ -static void * -thread_dispatch(void *din) -{ - EThread *e = din; - EMsg *m; - struct _thread_info *info; - pthread_t self = pthread_self(); - - t(printf("dispatch thread started: %ld\n", pthread_self())); - - while (1) { - pthread_mutex_lock(&e->mutex); - m = e_msgport_get(e->server_port); - if (m == NULL) { - /* nothing to do? If we are a 'new' type thread, just quit. - Otherwise, go into waiting (can be cancelled here) */ - info = NULL; - switch (e->type) { - case E_THREAD_NEW: - case E_THREAD_QUEUE: - case E_THREAD_DROP: - info = thread_find(e, self); - if (info) - info->busy = FALSE; - e->waiting++; - pthread_mutex_unlock(&e->mutex); - e_msgport_wait(e->server_port); - pthread_mutex_lock(&e->mutex); - e->waiting--; - pthread_mutex_unlock(&e->mutex); - break; -#if 0 - case E_THREAD_NEW: - e->id_list = g_list_remove(e->id_list, (void *)pthread_self()); - pthread_mutex_unlock(&e->mutex); - return 0; -#endif - } - - continue; - } else if (m->reply_port == E_THREAD_QUIT_REPLYPORT) { - t(printf("Thread %d got quit message\n", self)); - /* Handle a quit message, say we're quitting, free the message, and break out of the loop */ - info = thread_find(e, self); - if (info) - info->busy = 2; - pthread_mutex_unlock(&e->mutex); - g_free(m); - break; - } else { - info = thread_find(e, self); - if (info) - info->busy = TRUE; - } - pthread_mutex_unlock(&e->mutex); - - t(printf("got message in dispatch thread\n")); - - /* process it */ - thread_received_msg(e, m); - - /* if we have a reply port, send it back, otherwise, lose it */ - if (m->reply_port) { - e_msgport_reply(m); - } else { - thread_destroy_msg(e, m); - } - } - - return NULL; -} - -/* send a message to the thread, start thread if necessary */ -void e_thread_put(EThread *e, EMsg *msg) -{ - pthread_t id; - EMsg *dmsg = NULL; - - pthread_mutex_lock(&e->mutex); - - /* the caller forgot to tell us what to do, well, we can't do anything can we */ - if (e->received == NULL) { - pthread_mutex_unlock(&e->mutex); - g_warning("EThread called with no receiver function, no work to do!"); - thread_destroy_msg(e, msg); - return; - } - - msg->reply_port = e->reply_port; - - switch(e->type) { - case E_THREAD_QUEUE: - /* if the queue is full, lose this new addition */ - if (e_dlist_length(&e->server_port->queue) < e->queue_limit) { - e_msgport_put(e->server_port, msg); - } else { - printf("queue limit reached, dropping new message\n"); - dmsg = msg; - } - break; - case E_THREAD_DROP: - /* if the queue is full, lose the oldest (unprocessed) message */ - if (e_dlist_length(&e->server_port->queue) < e->queue_limit) { - e_msgport_put(e->server_port, msg); - } else { - printf("queue limit reached, dropping old message\n"); - e_msgport_put(e->server_port, msg); - dmsg = e_msgport_get(e->server_port); - } - break; - case E_THREAD_NEW: - /* it is possible that an existing thread can catch this message, so - we might create a thread with no work to do. - but that doesn't matter, the other alternative that it be lost is worse */ - e_msgport_put(e->server_port, msg); - if (e->waiting == 0 - && g_list_length(e->id_list) < e->queue_limit - && pthread_create(&id, NULL, thread_dispatch, e) == 0) { - struct _thread_info *info = g_malloc0(sizeof(*info)); - t(printf("created NEW thread %ld\n", id)); - info->id = id; - info->busy = TRUE; - e->id_list = g_list_append(e->id_list, info); - } - pthread_mutex_unlock(&e->mutex); - return; - } - - /* create the thread, if there is none to receive it yet */ - if (e->id == E_THREAD_NONE) { - int err; - - if ((err = pthread_create(&e->id, NULL, thread_dispatch, e)) != 0) { - g_warning("Could not create dispatcher thread, message queued?: %s", strerror(err)); - e->id = E_THREAD_NONE; - } - } - - pthread_mutex_unlock(&e->mutex); - - if (dmsg) { - thread_lost_msg(e, dmsg); - thread_destroy_msg(e, dmsg); - } -} - -/* yet-another-mutex interface */ -struct _EMutex { - int type; - pthread_t owner; - short waiters; - short depth; - pthread_mutex_t mutex; - pthread_cond_t cond; -}; - -/* sigh, this is just painful to have to need, but recursive - read/write, etc mutexes just aren't very common in thread - implementations */ -/* TODO: Just make it use recursive mutexes if they are available */ -EMutex *e_mutex_new(e_mutex_t type) -{ - struct _EMutex *m; - - m = g_malloc(sizeof(*m)); - m->type = type; - m->waiters = 0; - m->depth = 0; - m->owner = E_THREAD_NONE; - - switch (type) { - case E_MUTEX_SIMPLE: - pthread_mutex_init(&m->mutex, 0); - break; - case E_MUTEX_REC: - pthread_mutex_init(&m->mutex, 0); - pthread_cond_init(&m->cond, 0); - break; - /* read / write ? flags for same? */ - } - - return m; -} - -int e_mutex_destroy(EMutex *m) -{ - int ret = 0; - - switch (m->type) { - case E_MUTEX_SIMPLE: - ret = pthread_mutex_destroy(&m->mutex); - if (ret == -1) - g_warning("EMutex destroy failed: %s", strerror(errno)); - g_free(m); - break; - case E_MUTEX_REC: - ret = pthread_mutex_destroy(&m->mutex); - if (ret == -1) - g_warning("EMutex destroy failed: %s", strerror(errno)); - ret = pthread_cond_destroy(&m->cond); - if (ret == -1) - g_warning("EMutex destroy failed: %s", strerror(errno)); - g_free(m); - - } - return ret; -} - -int e_mutex_lock(EMutex *m) -{ - pthread_t id; - int err; - - switch (m->type) { - case E_MUTEX_SIMPLE: - return pthread_mutex_lock(&m->mutex); - case E_MUTEX_REC: - id = pthread_self(); - if ((err = pthread_mutex_lock(&m->mutex)) != 0) - return err; - while (1) { - if (m->owner == E_THREAD_NONE) { - m->owner = id; - m->depth = 1; - break; - } else if (id == m->owner) { - m->depth++; - break; - } else { - m->waiters++; - if ((err = pthread_cond_wait(&m->cond, &m->mutex)) != 0) - return err; - m->waiters--; - } - } - return pthread_mutex_unlock(&m->mutex); - } - - return EINVAL; -} - -int e_mutex_unlock(EMutex *m) -{ - int err; - - switch (m->type) { - case E_MUTEX_SIMPLE: - return pthread_mutex_unlock(&m->mutex); - case E_MUTEX_REC: - if ((err = pthread_mutex_lock(&m->mutex)) != 0) - return err; - g_assert(m->owner == pthread_self()); - - m->depth--; - if (m->depth == 0) { - m->owner = E_THREAD_NONE; - if (m->waiters > 0) - pthread_cond_signal(&m->cond); - } - return pthread_mutex_unlock(&m->mutex); - } - - errno = EINVAL; - return -1; -} - -void e_mutex_assert_locked(EMutex *m) -{ - g_return_if_fail (m->type == E_MUTEX_REC); - pthread_mutex_lock(&m->mutex); - g_assert(m->owner == pthread_self()); - pthread_mutex_unlock(&m->mutex); -} - -int e_mutex_cond_wait(void *vcond, EMutex *m) -{ - int ret; - pthread_cond_t *cond = vcond; - - switch(m->type) { - case E_MUTEX_SIMPLE: - return pthread_cond_wait(cond, &m->mutex); - case E_MUTEX_REC: - if ((ret = pthread_mutex_lock(&m->mutex)) != 0) - return ret; - g_assert(m->owner == pthread_self()); - ret = pthread_cond_wait(cond, &m->mutex); - g_assert(m->owner == pthread_self()); - pthread_mutex_unlock(&m->mutex); - return ret; - default: - g_return_val_if_reached(-1); - } -} - -#ifdef STANDALONE -EMsgPort *server_port; - - -void *fdserver(void *data) -{ - int fd; - EMsg *msg; - int id = (int)data; - fd_set rfds; - - fd = e_msgport_fd(server_port); - - while (1) { - int count = 0; - - printf("server %d: waiting on fd %d\n", id, fd); - FD_ZERO(&rfds); - FD_SET(fd, &rfds); - select(fd+1, &rfds, NULL, NULL, NULL); - printf("server %d: Got async notification, checking for messages\n", id); - while ((msg = e_msgport_get(server_port))) { - printf("server %d: got message\n", id); - sleep(1); - printf("server %d: replying\n", id); - e_msgport_reply(msg); - count++; - } - printf("server %d: got %d messages\n", id, count); - } -} - -void *server(void *data) -{ - EMsg *msg; - int id = (int)data; - - while (1) { - printf("server %d: waiting\n", id); - msg = e_msgport_wait(server_port); - msg = e_msgport_get(server_port); - if (msg) { - printf("server %d: got message\n", id); - sleep(1); - printf("server %d: replying\n", id); - e_msgport_reply(msg); - } else { - printf("server %d: didn't get message\n", id); - } - } -} - -void *client(void *data) -{ - EMsg *msg; - EMsgPort *replyport; - int i; - - replyport = e_msgport_new(); - msg = g_malloc0(sizeof(*msg)); - msg->reply_port = replyport; - for (i=0;i<10;i++) { - /* synchronous operation */ - printf("client: sending\n"); - e_msgport_put(server_port, msg); - printf("client: waiting for reply\n"); - e_msgport_wait(replyport); - e_msgport_get(replyport); - printf("client: got reply\n"); - } - - printf("client: sleeping ...\n"); - sleep(2); - printf("client: sending multiple\n"); - - for (i=0;i<10;i++) { - msg = g_malloc0(sizeof(*msg)); - msg->reply_port = replyport; - e_msgport_put(server_port, msg); - } - - printf("client: receiving multiple\n"); - for (i=0;i<10;i++) { - e_msgport_wait(replyport); - msg = e_msgport_get(replyport); - g_free(msg); - } - - printf("client: done\n"); -} - -int main(int argc, char **argv) -{ - pthread_t serverid, clientid; - - g_thread_init(NULL); - - server_port = e_msgport_new(); - - /*pthread_create(&serverid, NULL, server, (void *)1);*/ - pthread_create(&serverid, NULL, fdserver, (void *)1); - pthread_create(&clientid, NULL, client, NULL); - - sleep(60); - - return 0; -} -#endif diff --git a/e-util/e-msgport.h b/e-util/e-msgport.h deleted file mode 100644 index 6347564c0f..0000000000 --- a/e-util/e-msgport.h +++ /dev/null @@ -1,111 +0,0 @@ - -#ifndef _E_MSGPORT_H -#define _E_MSGPORT_H - -#include <time.h> -#include <glib.h> - -/* double-linked list yeah another one, deal */ -typedef struct _EDListNode { - struct _EDListNode *next; - struct _EDListNode *prev; -} EDListNode; - -typedef struct _EDList { - struct _EDListNode *head; - struct _EDListNode *tail; - struct _EDListNode *tailpred; -} EDList; - -#define E_DLIST_INITIALISER(l) { (EDListNode *)&l.tail, 0, (EDListNode *)&l.head } - -void e_dlist_init(EDList *v); -EDListNode *e_dlist_addhead(EDList *l, EDListNode *n); -EDListNode *e_dlist_addtail(EDList *l, EDListNode *n); -EDListNode *e_dlist_remove(EDListNode *n); -EDListNode *e_dlist_remhead(EDList *l); -EDListNode *e_dlist_remtail(EDList *l); -int e_dlist_empty(EDList *l); -int e_dlist_length(EDList *l); - -/* a time-based cache */ -typedef struct _EMCache EMCache; -typedef struct _EMCacheNode EMCacheNode; - -/* subclass this for your data nodes, EMCache is opaque */ -struct _EMCacheNode { - struct _EMCacheNode *next, *prev; - char *key; - int ref_count; - time_t stamp; -}; - -EMCache *em_cache_new(time_t timeout, size_t nodesize, GFreeFunc nodefree); -void em_cache_destroy(EMCache *emc); -EMCacheNode *em_cache_lookup(EMCache *emc, const char *key); -EMCacheNode *em_cache_node_new(EMCache *emc, const char *key); -void em_cache_node_unref(EMCache *emc, EMCacheNode *n); -void em_cache_add(EMCache *emc, EMCacheNode *n); -void em_cache_clear(EMCache *emc); - -/* message ports - a simple inter-thread 'ipc' primitive */ -/* opaque handle */ -typedef struct _EMsgPort EMsgPort; - -/* header for any message */ -typedef struct _EMsg { - EDListNode ln; - EMsgPort *reply_port; -} EMsg; - -EMsgPort *e_msgport_new(void); -void e_msgport_destroy(EMsgPort *mp); -/* get a fd that can be used to wait on the port asynchronously */ -int e_msgport_fd(EMsgPort *mp); -void e_msgport_put(EMsgPort *mp, EMsg *msg); -EMsg *e_msgport_wait(EMsgPort *mp); -EMsg *e_msgport_get(EMsgPort *mp); -void e_msgport_reply(EMsg *msg); -#ifdef HAVE_NSS -struct PRFileDesc *e_msgport_prfd(EMsgPort *mp); -#endif - -/* e threads, a server thread with a message based request-response, and flexible queuing */ -typedef struct _EThread EThread; - -typedef enum { - E_THREAD_QUEUE = 0, /* run one by one, until done, if the queue_limit is reached, discard new request */ - E_THREAD_DROP, /* run one by one, until done, if the queue_limit is reached, discard oldest requests */ - E_THREAD_NEW, /* always run in a new thread, if the queue limit is reached, new requests are - stored in the queue until a thread becomes available for it, creating a thread pool */ -} e_thread_t; - -typedef void (*EThreadFunc)(EThread *, EMsg *, void *data); - -EThread *e_thread_new(e_thread_t type); -void e_thread_destroy(EThread *e); -void e_thread_set_queue_limit(EThread *e, int limit); -void e_thread_set_msg_lost(EThread *e, EThreadFunc destroy, void *data); -void e_thread_set_msg_destroy(EThread *e, EThreadFunc destroy, void *data); -void e_thread_set_reply_port(EThread *e, EMsgPort *reply_port); -void e_thread_set_msg_received(EThread *e, EThreadFunc received, void *data); -void e_thread_put(EThread *e, EMsg *msg); -int e_thread_busy(EThread *e); - -/* sigh, another mutex interface, this one allows different mutex types, portably */ -typedef struct _EMutex EMutex; - -typedef enum _e_mutex_t { - E_MUTEX_SIMPLE, /* == pthread_mutex */ - E_MUTEX_REC, /* recursive mutex */ -} e_mutex_t; - -EMutex *e_mutex_new(e_mutex_t type); -int e_mutex_destroy(EMutex *m); -int e_mutex_lock(EMutex *m); -int e_mutex_unlock(EMutex *m); -void e_mutex_assert_locked(EMutex *m); -/* this uses pthread cond's */ -int e_mutex_cond_wait(void *cond, EMutex *m); - -#endif diff --git a/e-util/e-passwords.c b/e-util/e-passwords.c index f799796818..879f055eb4 100644 --- a/e-util/e-passwords.c +++ b/e-util/e-passwords.c @@ -51,7 +51,7 @@ #include <gtk/gtkmessagedialog.h> #include "e-passwords.h" -#include "e-msgport.h" +#include "libedataserver/e-msgport.h" #include "widgets/misc/e-error.h" #ifndef ENABLE_THREADS diff --git a/e-util/e-path.c b/e-util/e-path.c deleted file mode 100644 index 089ee03842..0000000000 --- a/e-util/e-path.c +++ /dev/null @@ -1,255 +0,0 @@ -/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ -/* e-path.c - * - * Copyright (C) 2001 Ximian, Inc. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General Public - * License as published by the Free Software Foundation. - * - * 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., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#include <config.h> - -#include <sys/types.h> -#include <dirent.h> -#include <string.h> -#include <sys/stat.h> -#include <unistd.h> -#include <glib.h> - -#include "e-path.h" - -#define SUBFOLDER_DIR_NAME "subfolders" -#define SUBFOLDER_DIR_NAME_LEN 10 - -/** - * e_path_to_physical: - * @prefix: a prefix to prepend to the path, or %NULL - * @path: the virtual path to convert to a filesystem path. - * - * This converts the "virtual" path @path into an expanded form that - * allows a given name to refer to both a file and a directory. The - * expanded path will have a "subfolders" directory inserted between - * each path component. If the path ends with "/", the returned - * physical path will end with "/subfolders" - * - * If @prefix is non-%NULL, it will be prepended to the returned path. - * - * Return value: the expanded path - **/ -char * -e_path_to_physical (const char *prefix, const char *vpath) -{ - const char *p, *newp; - char *dp; - char *ppath; - int ppath_len; - int prefix_len; - - while (*vpath == '/') - vpath++; - if (!prefix) - prefix = ""; - - /* Calculate the length of the real path. */ - ppath_len = strlen (vpath); - ppath_len++; /* For the ending zero. */ - - prefix_len = strlen (prefix); - ppath_len += prefix_len; - ppath_len++; /* For the separating slash. */ - - /* Take account of the fact that we need to translate every - * separator into `subfolders/'. - */ - p = vpath; - while (1) { - newp = strchr (p, '/'); - if (newp == NULL) - break; - - ppath_len += SUBFOLDER_DIR_NAME_LEN; - ppath_len++; /* For the separating slash. */ - - /* Skip consecutive slashes. */ - while (*newp == '/') - newp++; - - p = newp; - }; - - ppath = g_malloc (ppath_len); - dp = ppath; - - memcpy (dp, prefix, prefix_len); - dp += prefix_len; - *(dp++) = '/'; - - /* Copy the mangled path. */ - p = vpath; - while (1) { - newp = strchr (p, '/'); - if (newp == NULL) { - strcpy (dp, p); - break; - } - - memcpy (dp, p, newp - p + 1); /* `+ 1' to copy the slash too. */ - dp += newp - p + 1; - - memcpy (dp, SUBFOLDER_DIR_NAME, SUBFOLDER_DIR_NAME_LEN); - dp += SUBFOLDER_DIR_NAME_LEN; - - *(dp++) = '/'; - - /* Skip consecutive slashes. */ - while (*newp == '/') - newp++; - - p = newp; - } - - return ppath; -} - - -static gboolean -find_folders_recursive (const char *physical_path, const char *path, - EPathFindFoldersCallback callback, gpointer data) -{ - DIR *dir; - char *subfolder_directory_path; - gboolean ok; - - if (*path) { - if (!callback (physical_path, path, data)) - return FALSE; - - subfolder_directory_path = g_strdup_printf ("%s/%s", physical_path, SUBFOLDER_DIR_NAME); - } else { - /* On the top level, we have no folders and, - * consequently, no subfolder directory. - */ - - subfolder_directory_path = g_strdup (physical_path); - } - - /* Now scan the subfolders and load them. */ - dir = opendir (subfolder_directory_path); - if (dir == NULL) { - g_free (subfolder_directory_path); - return TRUE; - } - - ok = TRUE; - while (ok) { - struct stat file_stat; - struct dirent *dirent; - char *file_path; - char *new_path; - - dirent = readdir (dir); - if (dirent == NULL) - break; - - if (strcmp (dirent->d_name, ".") == 0 || strcmp (dirent->d_name, "..") == 0) - continue; - - file_path = g_strdup_printf ("%s/%s", subfolder_directory_path, - dirent->d_name); - - if (stat (file_path, &file_stat) < 0 || - ! S_ISDIR (file_stat.st_mode)) { - g_free (file_path); - continue; - } - - new_path = g_strdup_printf ("%s/%s", path, dirent->d_name); - - ok = find_folders_recursive (file_path, new_path, callback, data); - - g_free (file_path); - g_free (new_path); - } - - closedir (dir); - g_free (subfolder_directory_path); - - return ok; -} - -/** - * e_path_find_folders: - * @prefix: directory to start from - * @callback: Callback to invoke on each folder - * @data: Data for @callback - * - * Walks the folder tree starting at @prefix and calls @callback - * on each folder. - * - * Return value: %TRUE on success, %FALSE if an error occurs at any point - **/ -gboolean -e_path_find_folders (const char *prefix, - EPathFindFoldersCallback callback, - gpointer data) -{ - return find_folders_recursive (prefix, "", callback, data); -} - - -/** - * e_path_rmdir: - * @prefix: a prefix to prepend to the path, or %NULL - * @path: the virtual path to convert to a filesystem path. - * - * This removes the directory pointed to by @prefix and @path - * and attempts to remove its parent "subfolders" directory too - * if it's empty. - * - * Return value: -1 (with errno set) if it failed to rmdir the - * specified directory. 0 otherwise, whether or not it removed - * the parent directory. - **/ -int -e_path_rmdir (const char *prefix, const char *vpath) -{ - char *physical_path, *p; - - /* Remove the directory itself */ - physical_path = e_path_to_physical (prefix, vpath); - if (rmdir (physical_path) == -1) { - g_free (physical_path); - return -1; - } - - /* Attempt to remove its parent "subfolders" directory, - * ignoring errors since it might not be empty. - */ - - p = strrchr (physical_path, '/'); - if (p[1] == '\0') { - g_free (physical_path); - return 0; - } - *p = '\0'; - p = strrchr (physical_path, '/'); - if (!p || strcmp (p + 1, SUBFOLDER_DIR_NAME) != 0) { - g_free (physical_path); - return 0; - } - - rmdir (physical_path); - g_free (physical_path); - return 0; -} diff --git a/e-util/e-path.h b/e-util/e-path.h deleted file mode 100644 index 58c12874da..0000000000 --- a/e-util/e-path.h +++ /dev/null @@ -1,39 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* - * Copyright (C) 2001 Ximian, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General Public - * License as published by the Free Software Foundation. - * - * 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 library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#ifndef __E_PATH__ -#define __E_PATH__ - -#include <glib.h> - -/* FIXME: deprecated - This is used exclusively for the legacy imap cache code. DO NOT use this in any new code */ - -typedef gboolean (*EPathFindFoldersCallback) (const char *physical_path, - const char *path, - gpointer user_data); - -char * e_path_to_physical (const char *prefix, const char *vpath); - -gboolean e_path_find_folders (const char *prefix, - EPathFindFoldersCallback callback, - gpointer data); - -int e_path_rmdir (const char *prefix, const char *vpath); -#endif /* __E_PATH__ */ diff --git a/e-util/e-plugin.c b/e-util/e-plugin.c index b5ef769556..5948de45d8 100644 --- a/e-util/e-plugin.c +++ b/e-util/e-plugin.c @@ -7,7 +7,7 @@ #include <gconf/gconf-client.h> #include "e-plugin.h" -#include "e-msgport.h" +#include "libedataserver/e-msgport.h" /* plugin debug */ #define pd(x) diff --git a/e-util/e-popup.h b/e-util/e-popup.h index f4556f453e..36d45bcf51 100644 --- a/e-util/e-popup.h +++ b/e-util/e-popup.h @@ -24,7 +24,7 @@ #define __E_POPUP_H__ #include <glib-object.h> -#include "e-util/e-msgport.h" +#include "libedataserver/e-msgport.h" #ifdef __cplusplus extern "C" { diff --git a/e-util/e-sexp.c b/e-util/e-sexp.c deleted file mode 100644 index 724859f388..0000000000 --- a/e-util/e-sexp.c +++ /dev/null @@ -1,1381 +0,0 @@ -/* - * Copyright 2000 Ximian (www.ximian.com). - * - * A simple, extensible s-exp evaluation engine. - * - * Author : - * Michael Zucchi <notzed@ximian.com> - - * This program is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General Public - * License as published by the Free Software Foundation. - * - * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - * USA - */ - -/* - The following built-in s-exp's are supported: - - list = (and list*) - perform an intersection of a number of lists, and return that. - - bool = (and bool*) - perform a boolean AND of boolean values. - - list = (or list*) - perform a union of a number of lists, returning the new list. - - bool = (or bool*) - perform a boolean OR of boolean values. - - int = (+ int*) - Add integers. - - string = (+ string*) - Concat strings. - - time_t = (+ time_t*) - Add time_t values. - - int = (- int int*) - Subtract integers from the first. - - time_t = (- time_t*) - Subtract time_t values from the first. - - int = (cast-int string|int|bool) - Cast to an integer value. - - string = (cast-string string|int|bool) - Cast to an string value. - - Comparison operators: - - bool = (< int int) - bool = (> int int) - bool = (= int int) - - bool = (< string string) - bool = (> string string) - bool = (= string string) - - bool = (< time_t time_t) - bool = (> time_t time_t) - bool = (= time_t time_t) - Perform a comparision of 2 integers, 2 string values, or 2 time values. - - Function flow: - - type = (if bool function) - type = (if bool function function) - Choose a flow path based on a boolean value - - type = (begin func func func) - Execute a sequence. The last function return is the return type. -*/ - - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include <stdio.h> -#include <stdlib.h> -#include <time.h> -#include <string.h> - -#include "e-sexp.h" -#include "e-memory.h" - -#define p(x) /* parse debug */ -#define r(x) /* run debug */ -#define d(x) /* general debug */ - - -static struct _ESExpTerm * parse_list(ESExp *f, int gotbrace); -static struct _ESExpTerm * parse_value(ESExp *f); - -static void parse_dump_term(struct _ESExpTerm *t, int depth); - -#ifdef E_SEXP_IS_G_OBJECT -static GObjectClass *parent_class; -#endif - -static GScannerConfig scanner_config = -{ - ( " \t\r\n") /* cset_skip_characters */, - ( G_CSET_a_2_z - "_+-<=>?" - G_CSET_A_2_Z) /* cset_identifier_first */, - ( G_CSET_a_2_z - "_0123456789-<>?" - G_CSET_A_2_Z - G_CSET_LATINS - G_CSET_LATINC ) /* cset_identifier_nth */, - ( ";\n" ) /* cpair_comment_single */, - - FALSE /* case_sensitive */, - - TRUE /* skip_comment_multi */, - TRUE /* skip_comment_single */, - TRUE /* scan_comment_multi */, - TRUE /* scan_identifier */, - TRUE /* scan_identifier_1char */, - FALSE /* scan_identifier_NULL */, - TRUE /* scan_symbols */, - FALSE /* scan_binary */, - TRUE /* scan_octal */, - TRUE /* scan_float */, - TRUE /* scan_hex */, - FALSE /* scan_hex_dollar */, - TRUE /* scan_string_sq */, - TRUE /* scan_string_dq */, - TRUE /* numbers_2_int */, - FALSE /* int_2_float */, - FALSE /* identifier_2_string */, - TRUE /* char_2_token */, - FALSE /* symbol_2_token */, - FALSE /* scope_0_fallback */, -}; - -/* jumps back to the caller of f->failenv, only to be called from inside a callback */ -void -e_sexp_fatal_error(struct _ESExp *f, char *why, ...) -{ - va_list args; - - if (f->error) - g_free(f->error); - - va_start(args, why); - f->error = g_strdup_vprintf(why, args); - va_end(args); - - longjmp(f->failenv, 1); -} - -const char * -e_sexp_error(struct _ESExp *f) -{ - return f->error; -} - -struct _ESExpResult * -e_sexp_result_new(struct _ESExp *f, int type) -{ - struct _ESExpResult *r = e_memchunk_alloc0(f->result_chunks); - r->type = type; - return r; -} - -void -e_sexp_result_free(struct _ESExp *f, struct _ESExpResult *t) -{ - if (t == NULL) - return; - - switch(t->type) { - case ESEXP_RES_ARRAY_PTR: - g_ptr_array_free(t->value.ptrarray, TRUE); - break; - case ESEXP_RES_BOOL: - case ESEXP_RES_INT: - case ESEXP_RES_TIME: - break; - case ESEXP_RES_STRING: - g_free(t->value.string); - break; - case ESEXP_RES_UNDEFINED: - break; - default: - g_assert_not_reached(); - } - e_memchunk_free(f->result_chunks, t); -} - -/* used in normal functions if they have to abort, and free their arguments */ -void -e_sexp_resultv_free(struct _ESExp *f, int argc, struct _ESExpResult **argv) -{ - int i; - - for (i=0;i<argc;i++) { - e_sexp_result_free(f, argv[i]); - } -} - -/* implementations for the builtin functions */ - -/* can you tell, i dont like glib? */ -/* we can only itereate a hashtable from a called function */ -struct _glib_sux_donkeys { - int count; - GPtrArray *uids; -}; - -/* ok, store any values that are in all sets */ -static void -g_lib_sux_htand(char *key, int value, struct _glib_sux_donkeys *fuckup) -{ - if (value == fuckup->count) { - g_ptr_array_add(fuckup->uids, key); - } -} - -/* or, store all unique values */ -static void -g_lib_sux_htor(char *key, int value, struct _glib_sux_donkeys *fuckup) -{ - g_ptr_array_add(fuckup->uids, key); -} - -static ESExpResult * -term_eval_and(struct _ESExp *f, int argc, struct _ESExpTerm **argv, void *data) -{ - struct _ESExpResult *r, *r1; - GHashTable *ht = g_hash_table_new(g_str_hash, g_str_equal); - struct _glib_sux_donkeys lambdafoo; - int type=-1; - int bool = TRUE; - int i; - - r(printf("( and\n")); - - r = e_sexp_result_new(f, ESEXP_RES_UNDEFINED); - - for (i=0;bool && i<argc;i++) { - r1 = e_sexp_term_eval(f, argv[i]); - if (type == -1) - type = r1->type; - if (type != r1->type) { - e_sexp_result_free(f, r); - e_sexp_result_free(f, r1); - g_hash_table_destroy(ht); - e_sexp_fatal_error(f, "Invalid types in AND"); - } else if (r1->type == ESEXP_RES_ARRAY_PTR) { - char **a1; - int l1, j; - - a1 = (char **)r1->value.ptrarray->pdata; - l1 = r1->value.ptrarray->len; - for (j=0;j<l1;j++) { - gpointer ptr; - int n; - ptr = g_hash_table_lookup(ht, a1[j]); - n = GPOINTER_TO_INT(ptr); - g_hash_table_insert(ht, a1[j], GINT_TO_POINTER(n+1)); - } - } else if (r1->type == ESEXP_RES_BOOL) { - bool = bool && r1->value.bool; - } - e_sexp_result_free(f, r1); - } - - if (type == ESEXP_RES_ARRAY_PTR) { - lambdafoo.count = argc; - lambdafoo.uids = g_ptr_array_new(); - g_hash_table_foreach(ht, (GHFunc)g_lib_sux_htand, &lambdafoo); - r->type = ESEXP_RES_ARRAY_PTR; - r->value.ptrarray = lambdafoo.uids; - } else if (type == ESEXP_RES_BOOL) { - r->type = ESEXP_RES_BOOL; - r->value.bool = bool; - } - - g_hash_table_destroy(ht); - - return r; -} - -static ESExpResult * -term_eval_or(struct _ESExp *f, int argc, struct _ESExpTerm **argv, void *data) -{ - struct _ESExpResult *r, *r1; - GHashTable *ht = g_hash_table_new(g_str_hash, g_str_equal); - struct _glib_sux_donkeys lambdafoo; - int type = -1; - int bool = FALSE; - int i; - - r(printf("(or \n")); - - r = e_sexp_result_new(f, ESEXP_RES_UNDEFINED); - - for (i=0;!bool && i<argc;i++) { - r1 = e_sexp_term_eval(f, argv[i]); - if (type == -1) - type = r1->type; - if (r1->type != type) { - e_sexp_result_free(f, r); - e_sexp_result_free(f, r1); - g_hash_table_destroy(ht); - e_sexp_fatal_error(f, "Invalid types in OR"); - } else if (r1->type == ESEXP_RES_ARRAY_PTR) { - char **a1; - int l1, j; - - a1 = (char **)r1->value.ptrarray->pdata; - l1 = r1->value.ptrarray->len; - for (j=0;j<l1;j++) { - g_hash_table_insert(ht, a1[j], (void *)1); - } - } else if (r1->type == ESEXP_RES_BOOL) { - bool |= r1->value.bool; - } - e_sexp_result_free(f, r1); - } - - if (type == ESEXP_RES_ARRAY_PTR) { - lambdafoo.count = argc; - lambdafoo.uids = g_ptr_array_new(); - g_hash_table_foreach(ht, (GHFunc)g_lib_sux_htor, &lambdafoo); - r->type = ESEXP_RES_ARRAY_PTR; - r->value.ptrarray = lambdafoo.uids; - } else if (type == ESEXP_RES_BOOL) { - r->type = ESEXP_RES_BOOL; - r->value.bool = bool; - } - g_hash_table_destroy(ht); - - return r; -} - -static ESExpResult * -term_eval_not(struct _ESExp *f, int argc, struct _ESExpResult **argv, void *data) -{ - int res = TRUE; - ESExpResult *r; - - if (argc>0) { - if (argv[0]->type == ESEXP_RES_BOOL - && argv[0]->value.bool) - res = FALSE; - } - r = e_sexp_result_new(f, ESEXP_RES_BOOL); - r->value.bool = res; - return r; -} - -/* this should support all arguments ...? */ -static ESExpResult * -term_eval_lt(struct _ESExp *f, int argc, struct _ESExpTerm **argv, void *data) -{ - struct _ESExpResult *r, *r1, *r2; - - r = e_sexp_result_new(f, ESEXP_RES_UNDEFINED); - - if (argc == 2) { - r1 = e_sexp_term_eval(f, argv[0]); - r2 = e_sexp_term_eval(f, argv[1]); - if (r1->type != r2->type) { - e_sexp_result_free(f, r1); - e_sexp_result_free(f, r2); - e_sexp_result_free(f, r); - e_sexp_fatal_error(f, "Incompatible types in compare <"); - } else if (r1->type == ESEXP_RES_INT) { - r->type = ESEXP_RES_BOOL; - r->value.bool = r1->value.number < r2->value.number; - } else if (r1->type == ESEXP_RES_TIME) { - r->type = ESEXP_RES_BOOL; - r->value.bool = r1->value.time < r2->value.time; - } else if (r1->type == ESEXP_RES_STRING) { - r->type = ESEXP_RES_BOOL; - r->value.bool = strcmp(r1->value.string, r2->value.string) < 0; - } - e_sexp_result_free(f, r1); - e_sexp_result_free(f, r2); - } - return r; -} - -/* this should support all arguments ...? */ -static ESExpResult * -term_eval_gt(struct _ESExp *f, int argc, struct _ESExpTerm **argv, void *data) -{ - struct _ESExpResult *r, *r1, *r2; - - r = e_sexp_result_new(f, ESEXP_RES_UNDEFINED); - - if (argc == 2) { - r1 = e_sexp_term_eval(f, argv[0]); - r2 = e_sexp_term_eval(f, argv[1]); - if (r1->type != r2->type) { - e_sexp_result_free(f, r1); - e_sexp_result_free(f, r2); - e_sexp_result_free(f, r); - e_sexp_fatal_error(f, "Incompatible types in compare >"); - } else if (r1->type == ESEXP_RES_INT) { - r->type = ESEXP_RES_BOOL; - r->value.bool = r1->value.number > r2->value.number; - } else if (r1->type == ESEXP_RES_TIME) { - r->type = ESEXP_RES_BOOL; - r->value.bool = r1->value.time > r2->value.time; - } else if (r1->type == ESEXP_RES_STRING) { - r->type = ESEXP_RES_BOOL; - r->value.bool = strcmp(r1->value.string, r2->value.string) > 0; - } - e_sexp_result_free(f, r1); - e_sexp_result_free(f, r2); - } - return r; -} - -/* this should support all arguments ...? */ -static ESExpResult * -term_eval_eq(struct _ESExp *f, int argc, struct _ESExpTerm **argv, void *data) -{ - struct _ESExpResult *r, *r1, *r2; - - r = e_sexp_result_new(f, ESEXP_RES_BOOL); - - if (argc == 2) { - r1 = e_sexp_term_eval(f, argv[0]); - r2 = e_sexp_term_eval(f, argv[1]); - if (r1->type != r2->type) { - r->value.bool = FALSE; - } else if (r1->type == ESEXP_RES_INT) { - r->value.bool = r1->value.number == r2->value.number; - } else if (r1->type == ESEXP_RES_BOOL) { - r->value.bool = r1->value.bool == r2->value.bool; - } else if (r1->type == ESEXP_RES_TIME) { - r->value.bool = r1->value.time == r2->value.time; - } else if (r1->type == ESEXP_RES_STRING) { - r->value.bool = strcmp(r1->value.string, r2->value.string) == 0; - } - e_sexp_result_free(f, r1); - e_sexp_result_free(f, r2); - } - return r; -} - -static ESExpResult * -term_eval_plus(struct _ESExp *f, int argc, struct _ESExpResult **argv, void *data) -{ - struct _ESExpResult *r=NULL; - int type; - int i; - - if (argc>0) { - type = argv[0]->type; - switch(type) { - case ESEXP_RES_INT: { - int total = argv[0]->value.number; - for (i=1;i<argc && argv[i]->type == ESEXP_RES_INT;i++) { - total += argv[i]->value.number; - } - if (i<argc) { - e_sexp_resultv_free(f, argc, argv); - e_sexp_fatal_error(f, "Invalid types in (+ ints)"); - } - r = e_sexp_result_new(f, ESEXP_RES_INT); - r->value.number = total; - break; } - case ESEXP_RES_STRING: { - GString *s = g_string_new(argv[0]->value.string); - for (i=1;i<argc && argv[i]->type == ESEXP_RES_STRING;i++) { - g_string_append(s, argv[i]->value.string); - } - if (i<argc) { - e_sexp_resultv_free(f, argc, argv); - e_sexp_fatal_error(f, "Invalid types in (+ strings)"); - } - r = e_sexp_result_new(f, ESEXP_RES_STRING); - r->value.string = s->str; - g_string_free(s, FALSE); - break; } - case ESEXP_RES_TIME: { - time_t total; - - total = argv[0]->value.time; - - for (i = 1; i < argc && argv[i]->type == ESEXP_RES_TIME; i++) - total += argv[i]->value.time; - - if (i < argc) { - e_sexp_resultv_free (f, argc, argv); - e_sexp_fatal_error (f, "Invalid types in (+ time_t)"); - } - - r = e_sexp_result_new (f, ESEXP_RES_TIME); - r->value.time = total; - break; } - } - } - - if (!r) { - r = e_sexp_result_new(f, ESEXP_RES_INT); - r->value.number = 0; - } - return r; -} - -static ESExpResult * -term_eval_sub(struct _ESExp *f, int argc, struct _ESExpResult **argv, void *data) -{ - struct _ESExpResult *r=NULL; - int type; - int i; - - if (argc>0) { - type = argv[0]->type; - switch(type) { - case ESEXP_RES_INT: { - int total = argv[0]->value.number; - for (i=1;i<argc && argv[i]->type == ESEXP_RES_INT;i++) { - total -= argv[i]->value.number; - } - if (i<argc) { - e_sexp_resultv_free(f, argc, argv); - e_sexp_fatal_error(f, "Invalid types in -"); - } - r = e_sexp_result_new(f, ESEXP_RES_INT); - r->value.number = total; - break; } - case ESEXP_RES_TIME: { - time_t total; - - total = argv[0]->value.time; - - for (i = 1; i < argc && argv[i]->type == ESEXP_RES_TIME; i++) - total -= argv[i]->value.time; - - if (i < argc) { - e_sexp_resultv_free (f, argc, argv); - e_sexp_fatal_error (f, "Invalid types in (- time_t)"); - } - - r = e_sexp_result_new (f, ESEXP_RES_TIME); - r->value.time = total; - break; } - } - } - - if (!r) { - r = e_sexp_result_new(f, ESEXP_RES_INT); - r->value.number = 0; - } - return r; -} - -/* cast to int */ -static ESExpResult * -term_eval_castint(struct _ESExp *f, int argc, struct _ESExpResult **argv, void *data) -{ - struct _ESExpResult *r; - - if (argc != 1) - e_sexp_fatal_error(f, "Incorrect argument count to (int )"); - - r = e_sexp_result_new(f, ESEXP_RES_INT); - switch (argv[0]->type) { - case ESEXP_RES_INT: - r->value.number = argv[0]->value.number; - break; - case ESEXP_RES_BOOL: - r->value.number = argv[0]->value.bool != 0; - break; - case ESEXP_RES_STRING: - r->value.number = strtoul(argv[0]->value.string, 0, 10); - break; - default: - e_sexp_result_free(f, r); - e_sexp_fatal_error(f, "Invalid type in (cast-int )"); - } - - return r; -} - -/* cast to string */ -static ESExpResult * -term_eval_caststring(struct _ESExp *f, int argc, struct _ESExpResult **argv, void *data) -{ - struct _ESExpResult *r; - - if (argc != 1) - e_sexp_fatal_error(f, "Incorrect argument count to (cast-string )"); - - r = e_sexp_result_new(f, ESEXP_RES_STRING); - switch (argv[0]->type) { - case ESEXP_RES_INT: - r->value.string = g_strdup_printf("%d", argv[0]->value.number); - break; - case ESEXP_RES_BOOL: - r->value.string = g_strdup_printf("%d", argv[0]->value.bool != 0); - break; - case ESEXP_RES_STRING: - r->value.string = g_strdup(argv[0]->value.string); - break; - default: - e_sexp_result_free(f, r); - e_sexp_fatal_error(f, "Invalid type in (int )"); - } - - return r; -} - -/* implements 'if' function */ -static ESExpResult * -term_eval_if(struct _ESExp *f, int argc, struct _ESExpTerm **argv, void *data) -{ - struct _ESExpResult *r; - int doit; - - if (argc >=2 && argc<=3) { - r = e_sexp_term_eval(f, argv[0]); - doit = (r->type == ESEXP_RES_BOOL && r->value.bool); - e_sexp_result_free(f, r); - if (doit) { - return e_sexp_term_eval(f, argv[1]); - } else if (argc>2) { - return e_sexp_term_eval(f, argv[2]); - } - } - return e_sexp_result_new(f, ESEXP_RES_UNDEFINED); -} - -/* implements 'begin' statement */ -static ESExpResult * -term_eval_begin(struct _ESExp *f, int argc, struct _ESExpTerm **argv, void *data) -{ - struct _ESExpResult *r=NULL; - int i; - - for (i=0;i<argc;i++) { - if (r) - e_sexp_result_free(f, r); - r = e_sexp_term_eval(f, argv[i]); - } - if (r) - return r; - else - return e_sexp_result_new(f, ESEXP_RES_UNDEFINED); -} - - -/* this must only be called from inside term evaluation callbacks! */ -struct _ESExpResult * -e_sexp_term_eval(struct _ESExp *f, struct _ESExpTerm *t) -{ - struct _ESExpResult *r = NULL; - int i; - struct _ESExpResult **argv; - - g_return_val_if_fail(t != NULL, NULL); - - r(printf("eval term :\n")); - r(parse_dump_term(t, 0)); - - switch (t->type) { - case ESEXP_TERM_STRING: - r(printf(" (string \"%s\")\n", t->value.string)); - r = e_sexp_result_new(f, ESEXP_RES_STRING); - /* erk, this shoul;dn't need to strdup this ... */ - r->value.string = g_strdup(t->value.string); - break; - case ESEXP_TERM_INT: - r(printf(" (int %d)\n", t->value.number)); - r = e_sexp_result_new(f, ESEXP_RES_INT); - r->value.number = t->value.number; - break; - case ESEXP_TERM_BOOL: - r(printf(" (int %d)\n", t->value.number)); - r = e_sexp_result_new(f, ESEXP_RES_BOOL); - r->value.bool = t->value.bool; - break; - case ESEXP_TERM_TIME: - r(printf(" (time_t %d)\n", t->value.time)); - r = e_sexp_result_new (f, ESEXP_RES_TIME); - r->value.time = t->value.time; - break; - case ESEXP_TERM_IFUNC: - if (t->value.func.sym->f.ifunc) - r = t->value.func.sym->f.ifunc(f, t->value.func.termcount, t->value.func.terms, t->value.func.sym->data); - break; - case ESEXP_TERM_FUNC: - /* first evaluate all arguments to result types */ - argv = alloca(sizeof(argv[0]) * t->value.func.termcount); - for (i=0;i<t->value.func.termcount;i++) { - argv[i] = e_sexp_term_eval(f, t->value.func.terms[i]); - } - /* call the function */ - if (t->value.func.sym->f.func) - r = t->value.func.sym->f.func(f, t->value.func.termcount, argv, t->value.func.sym->data); - - e_sexp_resultv_free(f, t->value.func.termcount, argv); - break; - default: - e_sexp_fatal_error(f, "Unknown type in parse tree: %d", t->type); - } - - if (r==NULL) - r = e_sexp_result_new(f, ESEXP_RES_UNDEFINED); - - return r; -} - -#ifdef TESTER -static void -eval_dump_result(ESExpResult *r, int depth) -{ - int i; - - if (r==NULL) { - printf("null result???\n"); - return; - } - - for (i=0;i<depth;i++) - printf(" "); - - switch (r->type) { - case ESEXP_RES_ARRAY_PTR: - printf("array pointers\n"); - break; - case ESEXP_RES_INT: - printf("int: %d\n", r->value.number); - break; - case ESEXP_RES_STRING: - printf("string: '%s'\n", r->value.string); - break; - case ESEXP_RES_BOOL: - printf("bool: %c\n", r->value.bool?'t':'f'); - break; - case ESEXP_RES_TIME: - printf("time_t: %ld\n", (long) r->value.time); - break; - case ESEXP_RES_UNDEFINED: - printf(" <undefined>\n"); - break; - } - printf("\n"); -} -#endif - -static void -parse_dump_term(struct _ESExpTerm *t, int depth) -{ - int i; - - if (t==NULL) { - printf("null term??\n"); - return; - } - - for (i=0;i<depth;i++) - printf(" "); - - switch (t->type) { - case ESEXP_TERM_STRING: - printf(" \"%s\"", t->value.string); - break; - case ESEXP_TERM_INT: - printf(" %d", t->value.number); - break; - case ESEXP_TERM_BOOL: - printf(" #%c", t->value.bool?'t':'f'); - break; - case ESEXP_TERM_TIME: - printf(" %ld", (long) t->value.time); - break; - case ESEXP_TERM_IFUNC: - case ESEXP_TERM_FUNC: - printf(" (function %s\n", t->value.func.sym->name); - /*printf(" [%d] ", t->value.func.termcount);*/ - for (i=0;i<t->value.func.termcount;i++) { - parse_dump_term(t->value.func.terms[i], depth+1); - } - for (i=0;i<depth;i++) - printf(" "); - printf(" )"); - break; - case ESEXP_TERM_VAR: - printf(" (variable %s )\n", t->value.var->name); - break; - default: - printf("unknown type: %d\n", t->type); - } - - printf("\n"); -} - -/* - PARSER -*/ - -static struct _ESExpTerm * -parse_term_new(struct _ESExp *f, int type) -{ - struct _ESExpTerm *s = e_memchunk_alloc0(f->term_chunks); - s->type = type; - return s; -} - -static void -parse_term_free(struct _ESExp *f, struct _ESExpTerm *t) -{ - int i; - - if (t==NULL) { - return; - } - - switch (t->type) { - case ESEXP_TERM_INT: - case ESEXP_TERM_BOOL: - case ESEXP_TERM_TIME: - case ESEXP_TERM_VAR: - break; - - case ESEXP_TERM_STRING: - g_free(t->value.string); - break; - - case ESEXP_TERM_FUNC: - case ESEXP_TERM_IFUNC: - for (i=0;i<t->value.func.termcount;i++) { - parse_term_free(f, t->value.func.terms[i]); - } - g_free(t->value.func.terms); - break; - - default: - printf("parse_term_free: unknown type: %d\n", t->type); - } - e_memchunk_free(f->term_chunks, t); -} - -static struct _ESExpTerm ** -parse_values(ESExp *f, int *len) -{ - int token; - struct _ESExpTerm **terms; - int i, size = 0; - GScanner *gs = f->scanner; - GSList *list = NULL, *l; - - p(printf("parsing values\n")); - - while ( (token = g_scanner_peek_next_token(gs)) != G_TOKEN_EOF - && token != ')') { - list = g_slist_prepend(list, parse_value(f)); - size++; - } - - /* go over the list, and put them backwards into the term array */ - terms = g_malloc(size * sizeof(*terms)); - l = list; - for (i=size-1;i>=0;i--) { - g_assert(l); - g_assert(l->data); - terms[i] = l->data; - l = g_slist_next(l); - } - g_slist_free(list); - - p(printf("found %d subterms\n", size)); - *len = size; - - p(printf("done parsing values\n")); - return terms; -} - -static struct _ESExpTerm * -parse_value(ESExp *f) -{ - int token, negative = FALSE; - struct _ESExpTerm *t = NULL; - GScanner *gs = f->scanner; - struct _ESExpSymbol *s; - - p(printf("parsing value\n")); - - token = g_scanner_get_next_token(gs); - switch(token) { - case G_TOKEN_LEFT_PAREN: - p(printf("got brace, its a list!\n")); - return parse_list(f, TRUE); - case G_TOKEN_STRING: - p(printf("got string '%s'\n", g_scanner_cur_value(gs).v_string)); - t = parse_term_new(f, ESEXP_TERM_STRING); - t->value.string = g_strdup(g_scanner_cur_value(gs).v_string); - break; - case '-': - p(printf ("got negative int?\n")); - token = g_scanner_get_next_token (gs); - if (token != G_TOKEN_INT) { - e_sexp_fatal_error (f, "Invalid format for a integer value"); - return NULL; - } - - negative = TRUE; - /* fall through... */ - case G_TOKEN_INT: - t = parse_term_new(f, ESEXP_TERM_INT); - t->value.number = g_scanner_cur_value(gs).v_int; - if (negative) - t->value.number = -t->value.number; - p(printf("got int %d\n", t->value.number)); - break; - case '#': { - char *str; - - p(printf("got bool?\n")); - token = g_scanner_get_next_token(gs); - if (token != G_TOKEN_IDENTIFIER) { - e_sexp_fatal_error (f, "Invalid format for a boolean value"); - return NULL; - } - - str = g_scanner_cur_value (gs).v_identifier; - - g_assert (str != NULL); - if (!(strlen (str) == 1 && (str[0] == 't' || str[0] == 'f'))) { - e_sexp_fatal_error (f, "Invalid format for a boolean value"); - return NULL; - } - - t = parse_term_new(f, ESEXP_TERM_BOOL); - t->value.bool = (str[0] == 't'); - break; } - case G_TOKEN_SYMBOL: - s = g_scanner_cur_value(gs).v_symbol; - p(printf("got symbol '%s'\n", s->name)); - switch (s->type) { - case ESEXP_TERM_FUNC: - case ESEXP_TERM_IFUNC: - /* this is basically invalid, since we can't use function - pointers, but let the runtime catch it ... */ - t = parse_term_new(f, s->type); - t->value.func.sym = s; - t->value.func.terms = parse_values(f, &t->value.func.termcount); - break; - case ESEXP_TERM_VAR: - t = parse_term_new(f, s->type); - t->value.var = s; - break; - default: - e_sexp_fatal_error(f, "Invalid symbol type: %s: %d", s->name, s->type); - } - break; - case G_TOKEN_IDENTIFIER: - p(printf("got unknown identifider '%s'\n", g_scanner_cur_value(gs).v_identifier)); - e_sexp_fatal_error(f, "Unknown identifier: %s", g_scanner_cur_value(gs).v_identifier); - break; - default: - e_sexp_fatal_error(f, "Unexpected token encountered: %d", token); - } - p(printf("done parsing value\n")); - return t; -} - -/* FIXME: this needs some robustification */ -static struct _ESExpTerm * -parse_list(ESExp *f, int gotbrace) -{ - int token; - struct _ESExpTerm *t = NULL; - GScanner *gs = f->scanner; - - p(printf("parsing list\n")); - if (gotbrace) - token = '('; - else - token = g_scanner_get_next_token(gs); - if (token =='(') { - token = g_scanner_get_next_token(gs); - switch(token) { - case G_TOKEN_SYMBOL: { - struct _ESExpSymbol *s; - - s = g_scanner_cur_value(gs).v_symbol; - p(printf("got funciton: %s\n", s->name)); - t = parse_term_new(f, s->type); - p(printf("created new list %p\n", t)); - /* if we have a variable, find out its base type */ - while (s->type == ESEXP_TERM_VAR) { - s = ((ESExpTerm *)(s->data))->value.var; - } - if (s->type == ESEXP_TERM_FUNC - || s->type == ESEXP_TERM_IFUNC) { - t->value.func.sym = s; - t->value.func.terms = parse_values(f, &t->value.func.termcount); - } else { - parse_term_free(f, t); - e_sexp_fatal_error(f, "Trying to call variable as function: %s", s->name); - } - break; } - case G_TOKEN_IDENTIFIER: - e_sexp_fatal_error(f, "Unknown identifier: %s", g_scanner_cur_value(gs).v_identifier); - break; - default: - e_sexp_fatal_error(f, "Unexpected token encountered: %d", token); - } - token = g_scanner_get_next_token(gs); - if (token != ')') { - e_sexp_fatal_error(f, "Missing ')'"); - } - } else { - e_sexp_fatal_error(f, "Missing '('"); - } - - p(printf("returning list %p\n", t)); - return t; -} - -static void e_sexp_finalise(void *); - -#ifdef E_SEXP_IS_G_OBJECT -static void -e_sexp_class_init (ESExpClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - - object_class->finalize = e_sexp_finalise; - - parent_class = g_type_class_ref (g_object_get_type ()); -} -#endif - -/* 'builtin' functions */ -static struct { - char *name; - ESExpFunc *func; - int type; /* set to 1 if a function can perform shortcut evaluation, or - doesn't execute everything, 0 otherwise */ -} symbols[] = { - { "and", (ESExpFunc *)term_eval_and, 1 }, - { "or", (ESExpFunc *)term_eval_or, 1 }, - { "not", (ESExpFunc *)term_eval_not, 0 }, - { "<", (ESExpFunc *)term_eval_lt, 1 }, - { ">", (ESExpFunc *)term_eval_gt, 1 }, - { "=", (ESExpFunc *)term_eval_eq, 1 }, - { "+", (ESExpFunc *)term_eval_plus, 0 }, - { "-", (ESExpFunc *)term_eval_sub, 0 }, - { "cast-int", (ESExpFunc *)term_eval_castint, 0 }, - { "cast-string", (ESExpFunc *)term_eval_caststring, 0 }, - { "if", (ESExpFunc *)term_eval_if, 1 }, - { "begin", (ESExpFunc *)term_eval_begin, 1 }, -}; - -static void -free_symbol(void *key, void *value, void *data) -{ - struct _ESExpSymbol *s = value; - - g_free(s->name); - g_free(s); -} - -static void -e_sexp_finalise(void *o) -{ - ESExp *s = (ESExp *)o; - - if (s->tree) { - parse_term_free(s, s->tree); - s->tree = NULL; - } - - e_memchunk_destroy(s->term_chunks); - e_memchunk_destroy(s->result_chunks); - - g_scanner_scope_foreach_symbol(s->scanner, 0, free_symbol, 0); - g_scanner_destroy(s->scanner); - -#ifdef E_SEXP_IS_G_OBJECT - G_OBJECT_CLASS (parent_class)->finalize (o); -#endif -} - -static void -e_sexp_init (ESExp *s) -{ - int i; - - s->scanner = g_scanner_new(&scanner_config); - s->term_chunks = e_memchunk_new(16, sizeof(struct _ESExpTerm)); - s->result_chunks = e_memchunk_new(16, sizeof(struct _ESExpResult)); - - /* load in builtin symbols? */ - for(i=0;i<sizeof(symbols)/sizeof(symbols[0]);i++) { - if (symbols[i].type == 1) { - e_sexp_add_ifunction(s, 0, symbols[i].name, (ESExpIFunc *)symbols[i].func, &symbols[i]); - } else { - e_sexp_add_function(s, 0, symbols[i].name, symbols[i].func, &symbols[i]); - } - } - -#ifndef E_SEXP_IS_G_OBJECT - s->refcount = 1; -#endif -} - -#ifdef E_SEXP_IS_G_OBJECT -GType -e_sexp_get_type (void) -{ - static GType type = 0; - - if (!type) { - static const GTypeInfo info = { - sizeof (ESExpClass), - NULL, /* base_class_init */ - NULL, /* base_class_finalize */ - (GClassInitFunc) e_sexp_class_init, - NULL, /* class_finalize */ - NULL, /* class_data */ - sizeof (ESExp), - 0, /* n_preallocs */ - (GInstanceInitFunc) e_sexp_init, - }; - - type = g_type_register_static (G_TYPE_OBJECT, "ESExp", &info, 0); - } - - return type; -} -#endif - -ESExp * -e_sexp_new (void) -{ -#ifdef E_SEXP_IS_G_OBJECT - ESExp *f = (ESexp *) g_object_new (E_TYPE_SEXP, NULL); -#else - ESExp *f = g_malloc0 (sizeof (ESExp)); - e_sexp_init (f); -#endif - - return f; -} - -#ifndef E_SEXP_IS_G_OBJECT -void -e_sexp_ref (ESExp *f) -{ - f->refcount++; -} - -void -e_sexp_unref (ESExp *f) -{ - f->refcount--; - if (f->refcount == 0) { - e_sexp_finalise(f); - g_free(f); - } -} -#endif - -void -e_sexp_add_function(ESExp *f, int scope, char *name, ESExpFunc *func, void *data) -{ - struct _ESExpSymbol *s; - - g_return_if_fail (IS_E_SEXP (f)); - g_return_if_fail (name != NULL); - - e_sexp_remove_symbol (f, scope, name); - - s = g_malloc0(sizeof(*s)); - s->name = g_strdup(name); - s->f.func = func; - s->type = ESEXP_TERM_FUNC; - s->data = data; - g_scanner_scope_add_symbol(f->scanner, scope, s->name, s); -} - -void -e_sexp_add_ifunction(ESExp *f, int scope, char *name, ESExpIFunc *ifunc, void *data) -{ - struct _ESExpSymbol *s; - - g_return_if_fail (IS_E_SEXP (f)); - g_return_if_fail (name != NULL); - - e_sexp_remove_symbol (f, scope, name); - - s = g_malloc0(sizeof(*s)); - s->name = g_strdup(name); - s->f.ifunc = ifunc; - s->type = ESEXP_TERM_IFUNC; - s->data = data; - g_scanner_scope_add_symbol(f->scanner, scope, s->name, s); -} - -void -e_sexp_add_variable(ESExp *f, int scope, char *name, ESExpTerm *value) -{ - struct _ESExpSymbol *s; - - g_return_if_fail (IS_E_SEXP (f)); - g_return_if_fail (name != NULL); - - s = g_malloc0(sizeof(*s)); - s->name = g_strdup(name); - s->type = ESEXP_TERM_VAR; - s->data = value; - g_scanner_scope_add_symbol(f->scanner, scope, s->name, s); -} - -void -e_sexp_remove_symbol(ESExp *f, int scope, char *name) -{ - int oldscope; - struct _ESExpSymbol *s; - - g_return_if_fail (IS_E_SEXP (f)); - g_return_if_fail (name != NULL); - - oldscope = g_scanner_set_scope(f->scanner, scope); - s = g_scanner_lookup_symbol(f->scanner, name); - g_scanner_scope_remove_symbol(f->scanner, scope, name); - g_scanner_set_scope(f->scanner, oldscope); - if (s) { - g_free(s->name); - g_free(s); - } -} - -int -e_sexp_set_scope(ESExp *f, int scope) -{ - g_return_val_if_fail (IS_E_SEXP (f), 0); - - return g_scanner_set_scope(f->scanner, scope); -} - -void -e_sexp_input_text(ESExp *f, const char *text, int len) -{ - g_return_if_fail (IS_E_SEXP (f)); - g_return_if_fail (text != NULL); - - g_scanner_input_text(f->scanner, text, len); -} - -void -e_sexp_input_file (ESExp *f, int fd) -{ - g_return_if_fail (IS_E_SEXP (f)); - - g_scanner_input_file(f->scanner, fd); -} - -/* returns -1 on error */ -int -e_sexp_parse(ESExp *f) -{ - g_return_val_if_fail (IS_E_SEXP (f), -1); - - if (setjmp(f->failenv)) { - g_warning("Error in parsing: %s", f->error); - return -1; - } - - if (f->tree) - parse_term_free(f, f->tree); - - f->tree = parse_value (f); - - return 0; -} - -/* returns NULL on error */ -struct _ESExpResult * -e_sexp_eval(ESExp *f) -{ - g_return_val_if_fail (IS_E_SEXP (f), NULL); - g_return_val_if_fail (f->tree != NULL, NULL); - - if (setjmp(f->failenv)) { - g_warning("Error in execution: %s", f->error); - return NULL; - } - - return e_sexp_term_eval(f, f->tree); -} - -/** - * e_sexp_encode_bool: - * @s: - * @state: - * - * Encode a bool into an s-expression @s. Bools are - * encoded using #t #f syntax. - **/ -void -e_sexp_encode_bool(GString *s, gboolean state) -{ - if (state) - g_string_append(s, " #t"); - else - g_string_append(s, " #f"); -} - -/** - * e_sexp_encode_string: - * @s: Destination string. - * @string: String expression. - * - * Add a c string @string to the s-expression stored in - * the gstring @s. Quotes are added, and special characters - * are escaped appropriately. - **/ -void -e_sexp_encode_string(GString *s, const char *string) -{ - char c; - const char *p; - - if (string == NULL) - p = ""; - else - p = string; - g_string_append(s, " \""); - while ( (c = *p++) ) { - if (c=='\\' || c=='\"' || c=='\'') - g_string_append_c(s, '\\'); - g_string_append_c(s, c); - } - g_string_append(s, "\""); -} - -#ifdef TESTER -int main(int argc, char **argv) -{ - ESExp *f; - char *t = "(+ \"foo\" \"\\\"\" \"bar\" \"\\\\ blah \\x \")"; - ESExpResult *r; - - gtk_init(&argc, &argv); - - f = e_sexp_new(); - - e_sexp_add_variable(f, 0, "test", NULL); - - e_sexp_input_text(f, t, strlen(t)); - e_sexp_parse(f); - - if (f->tree) { - parse_dump_term(f->tree, 0); - } - - r = e_sexp_eval(f); - if (r) { - eval_dump_result(r, 0); - } else { - printf("no result?|\n"); - } - - return 0; -} -#endif diff --git a/e-util/e-sexp.h b/e-util/e-sexp.h deleted file mode 100644 index 5f41c97dcc..0000000000 --- a/e-util/e-sexp.h +++ /dev/null @@ -1,172 +0,0 @@ -/* - generic s-exp evaluator class -*/ -#ifndef _E_SEXP_H -#define _E_SEXP_H - -#include <setjmp.h> -#include <time.h> -#include <glib.h> - -#ifdef E_SEXP_IS_G_OBJECT -#include <glib-object.h> -#endif - -#ifdef E_SEXP_IS_G_OBJECT -#define E_TYPE_SEXP (e_sexp_get_type ()) -#define E_SEXP(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), E_TYPE_SEXP, ESExp)) -#define E_SEXP_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), E_TYPE_SEXP, ESExpClass)) -#define IS_E_SEXP(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), E_TYPE_SEXP)) -#define IS_E_SEXP_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), E_TYPE_SEXP)) -#define E_SEXP_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), E_TYPE_SEXP, ESExpClass)) -#else -#define E_TYPE_SEXP (0) -#define E_SEXP(obj) ((struct _ESExp *) (obj)) -#define E_SEXP_CLASS(klass) ((struct _ESExpClass *) (klass)) -#define IS_E_SEXP(obj) (1) -#define IS_E_SEXP_CLASS(obj) (1) -#define E_SEXP_GET_CLASS(obj) (NULL) -#endif - -typedef struct _ESExp ESExp; -typedef struct _ESExpClass ESExpClass; - -typedef struct _ESExpSymbol ESExpSymbol; -typedef struct _ESExpResult ESExpResult; -typedef struct _ESExpTerm ESExpTerm; - -typedef struct _ESExpResult *(ESExpFunc)(struct _ESExp *sexp, int argc, - struct _ESExpResult **argv, - void *data); - -typedef struct _ESExpResult *(ESExpIFunc)(struct _ESExp *sexp, int argc, - struct _ESExpTerm **argv, - void *data); - -enum _ESExpResultType { - ESEXP_RES_ARRAY_PTR=0, /* type is a ptrarray, what it points to is implementation dependant */ - ESEXP_RES_INT, /* type is a number */ - ESEXP_RES_STRING, /* type is a pointer to a single string */ - ESEXP_RES_BOOL, /* boolean type */ - ESEXP_RES_TIME, /* time_t type */ - ESEXP_RES_UNDEFINED /* unknown type */ -}; - -struct _ESExpResult { - enum _ESExpResultType type; - union { - GPtrArray *ptrarray; - int number; - char *string; - int bool; - time_t time; - } value; -}; - -enum _ESExpTermType { - ESEXP_TERM_INT = 0, /* integer literal */ - ESEXP_TERM_BOOL, /* boolean literal */ - ESEXP_TERM_STRING, /* string literal */ - ESEXP_TERM_TIME, /* time_t literal (number of seconds past the epoch) */ - ESEXP_TERM_FUNC, /* normal function, arguments are evaluated before calling */ - ESEXP_TERM_IFUNC, /* immediate function, raw terms are arguments */ - ESEXP_TERM_VAR, /* variable reference */ -}; - -struct _ESExpSymbol { - int type; /* ESEXP_TERM_FUNC or ESEXP_TERM_VAR */ - char *name; - void *data; - union { - ESExpFunc *func; - ESExpIFunc *ifunc; - } f; -}; - -struct _ESExpTerm { - enum _ESExpTermType type; - union { - char *string; - int number; - int bool; - time_t time; - struct { - struct _ESExpSymbol *sym; - struct _ESExpTerm **terms; - int termcount; - } func; - struct _ESExpSymbol *var; - } value; -}; - - - -struct _ESExp { -#ifdef E_SEXP_IS_G_OBJECT - GObject parent_object; -#else - int refcount; -#endif - GScanner *scanner; /* for parsing text version */ - ESExpTerm *tree; /* root of expression tree */ - - /* private stuff */ - jmp_buf failenv; - char *error; - - /* TODO: may also need a pool allocator for term strings, so we dont lose them - in error conditions? */ - struct _EMemChunk *term_chunks; - struct _EMemChunk *result_chunks; -}; - -struct _ESExpClass { -#ifdef E_SEXP_IS_G_OBJECT - GObjectClass parent_class; -#else - int dummy; -#endif -}; - -#ifdef E_SEXP_IS_G_OBJECT -GType e_sexp_get_type (void); -#endif -ESExp *e_sexp_new (void); -#ifdef E_SEXP_IS_G_OBJECT -#define e_sexp_ref(f) g_object_ref (f) -#define e_sexp_unref(f) g_object_unref (f) -#else -void e_sexp_ref (ESExp *f); -void e_sexp_unref (ESExp *f); -#endif -void e_sexp_add_function (ESExp *f, int scope, char *name, ESExpFunc *func, void *data); -void e_sexp_add_ifunction (ESExp *f, int scope, char *name, ESExpIFunc *func, void *data); -void e_sexp_add_variable (ESExp *f, int scope, char *name, ESExpTerm *value); -void e_sexp_remove_symbol (ESExp *f, int scope, char *name); -int e_sexp_set_scope (ESExp *f, int scope); - -void e_sexp_input_text (ESExp *f, const char *text, int len); -void e_sexp_input_file (ESExp *f, int fd); - - -int e_sexp_parse (ESExp *f); -ESExpResult *e_sexp_eval (ESExp *f); - -ESExpResult *e_sexp_term_eval (struct _ESExp *f, struct _ESExpTerm *t); -ESExpResult *e_sexp_result_new (struct _ESExp *f, int type); -void e_sexp_result_free (struct _ESExp *f, struct _ESExpResult *t); - -/* used in normal functions if they have to abort, to free their arguments */ -void e_sexp_resultv_free (struct _ESExp *f, int argc, struct _ESExpResult **argv); - -/* utility functions for creating s-exp strings. */ -void e_sexp_encode_bool (GString *s, gboolean state); -void e_sexp_encode_string (GString *s, const char *string); - -/* only to be called from inside a callback to signal a fatal execution error */ -void e_sexp_fatal_error (struct _ESExp *f, char *why, ...); - -/* return the error string */ -const char *e_sexp_error (struct _ESExp *f); - -#endif /* _E_SEXP_H */ diff --git a/e-util/e-trie.c b/e-util/e-trie.c deleted file mode 100644 index 2edf94df34..0000000000 --- a/e-util/e-trie.c +++ /dev/null @@ -1,345 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* - * Authors: Jeffrey Stedfast <fejj@ximian.com> - * - * Copyright 2002 Ximian, Inc. (www.ximian.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., 59 Temple Street #330, Boston, MA 02111-1307, USA. - * - */ - - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include <stdio.h> -#include <string.h> - -#include "e-trie.h" -#include "e-memory.h" - -#define d(x) - -struct _trie_state { - struct _trie_state *next; - struct _trie_state *fail; - struct _trie_match *match; - unsigned int final; - int id; -}; - -struct _trie_match { - struct _trie_match *next; - struct _trie_state *state; - gunichar c; -}; - -struct _ETrie { - struct _trie_state root; - GPtrArray *fail_states; - gboolean icase; - - EMemChunk *match_chunks; - EMemChunk *state_chunks; -}; - - -static inline gunichar -trie_utf8_getc (const unsigned char **in, size_t inlen) -{ - register const unsigned char *inptr = *in; - const unsigned char *inend = inptr + inlen; - register unsigned char c, r; - register gunichar u, m; - - if (inlen == 0) - return 0; - - r = *inptr++; - if (r < 0x80) { - *in = inptr; - u = r; - } else if (r < 0xfe) { /* valid start char? */ - u = r; - m = 0x7f80; /* used to mask out the length bits */ - do { - if (inptr >= inend) - return 0; - - c = *inptr++; - if ((c & 0xc0) != 0x80) - goto error; - - u = (u << 6) | (c & 0x3f); - r <<= 1; - m <<= 5; - } while (r & 0x40); - - *in = inptr; - - u &= ~m; - } else { - error: - *in = (*in)+1; - u = 0xfffe; - } - - return u; -} - - -ETrie * -e_trie_new (gboolean icase) -{ - ETrie *trie; - - trie = g_new (ETrie, 1); - trie->root.next = NULL; - trie->root.fail = NULL; - trie->root.match = NULL; - trie->root.final = 0; - - trie->fail_states = g_ptr_array_sized_new (8); - trie->icase = icase; - - trie->match_chunks = e_memchunk_new (8, sizeof (struct _trie_match)); - trie->state_chunks = e_memchunk_new (8, sizeof (struct _trie_state)); - - return trie; -} - -void -e_trie_free (ETrie *trie) -{ - g_ptr_array_free (trie->fail_states, TRUE); - e_memchunk_destroy (trie->match_chunks); - e_memchunk_destroy (trie->state_chunks); - g_free (trie); -} - - - -static struct _trie_match * -g (struct _trie_state *s, gunichar c) -{ - struct _trie_match *m = s->match; - - while (m && m->c != c) - m = m->next; - - return m; -} - -static struct _trie_state * -trie_insert (ETrie *trie, int depth, struct _trie_state *q, gunichar c) -{ - struct _trie_match *m; - - m = e_memchunk_alloc (trie->match_chunks); - m->next = q->match; - m->c = c; - - q->match = m; - q = m->state = e_memchunk_alloc (trie->state_chunks); - q->match = NULL; - q->fail = &trie->root; - q->final = 0; - q->id = -1; - - if (trie->fail_states->len < depth + 1) { - unsigned int size = trie->fail_states->len; - - size = MAX (size + 64, depth + 1); - g_ptr_array_set_size (trie->fail_states, size); - } - - q->next = trie->fail_states->pdata[depth]; - trie->fail_states->pdata[depth] = q; - - return q; -} - - -#if 1 -static void -dump_trie (struct _trie_state *s, int depth) -{ - char *p = g_alloca ((depth * 2) + 1); - struct _trie_match *m; - - memset (p, ' ', depth * 2); - p[depth * 2] = '\0'; - - fprintf (stderr, "%s[state] %p: final=%d; pattern-id=%d; fail=%p\n", - p, s, s->final, s->id, s->fail); - m = s->match; - while (m) { - fprintf (stderr, " %s'%c' -> %p\n", p, m->c, m->state); - if (m->state) - dump_trie (m->state, depth + 1); - - m = m->next; - } -} -#endif - - -/* - * final = empty set - * FOR p = 1 TO #pat - * q = root - * FOR j = 1 TO m[p] - * IF g(q, pat[p][j]) == null - * insert(q, pat[p][j]) - * ENDIF - * q = g(q, pat[p][j]) - * ENDFOR - * final = union(final, q) - * ENDFOR -*/ - -void -e_trie_add (ETrie *trie, const char *pattern, int pattern_id) -{ - const unsigned char *inptr = (const unsigned char *) pattern; - struct _trie_state *q, *q1, *r; - struct _trie_match *m, *n; - int i, depth = 0; - gunichar c; - - /* Step 1: add the pattern to the trie */ - - q = &trie->root; - - while ((c = trie_utf8_getc (&inptr, -1))) { - if (trie->icase) - c = g_unichar_tolower (c); - - m = g (q, c); - if (m == NULL) { - q = trie_insert (trie, depth, q, c); - } else { - q = m->state; - } - - depth++; - } - - q->final = depth; - q->id = pattern_id; - - /* Step 2: compute failure graph */ - - for (i = 0; i < trie->fail_states->len; i++) { - q = trie->fail_states->pdata[i]; - while (q) { - m = q->match; - while (m) { - c = m->c; - q1 = m->state; - r = q->fail; - while (r && (n = g (r, c)) == NULL) - r = r->fail; - - if (r != NULL) { - q1->fail = n->state; - if (q1->fail->final > q1->final) - q1->final = q1->fail->final; - } else { - if ((n = g (&trie->root, c))) - q1->fail = n->state; - else - q1->fail = &trie->root; - } - - m = m->next; - } - - q = q->next; - } - } - - d(fprintf (stderr, "\nafter adding pattern '%s' to trie %p:\n", pattern, trie)); - d(dump_trie (&trie->root, 0)); -} - -/* - * Aho-Corasick - * - * q = root - * FOR i = 1 TO n - * WHILE q != fail AND g(q, text[i]) == fail - * q = h(q) - * ENDWHILE - * IF q == fail - * q = root - * ELSE - * q = g(q, text[i]) - * ENDIF - * IF isElement(q, final) - * RETURN TRUE - * ENDIF - * ENDFOR - * RETURN FALSE - */ - -const char * -e_trie_search (ETrie *trie, const char *buffer, size_t buflen, int *matched_id) -{ - const unsigned char *inptr, *inend, *prev, *pat; - register size_t inlen = buflen; - struct _trie_state *q; - struct _trie_match *m; - gunichar c; - - inptr = (const unsigned char *) buffer; - inend = inptr + buflen; - - q = &trie->root; - pat = prev = inptr; - while ((c = trie_utf8_getc (&inptr, inlen))) { - inlen = (inend - inptr); - - if (c != 0xfffe) { - if (trie->icase) - c = g_unichar_tolower (c); - - while (q != NULL && (m = g (q, c)) == NULL) - q = q->fail; - - if (q == &trie->root) - pat = prev; - - if (q == NULL) { - q = &trie->root; - pat = inptr; - } else if (m != NULL) { - q = m->state; - - if (q->final) { - if (matched_id) - *matched_id = q->id; - - return (const char *) pat; - } - } - } - - prev = inptr; - } - - return NULL; -} diff --git a/e-util/e-trie.h b/e-util/e-trie.h deleted file mode 100644 index cabf5fc627..0000000000 --- a/e-util/e-trie.h +++ /dev/null @@ -1,47 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* - * Authors: Jeffrey Stedfast <fejj@ximian.com> - * - * Copyright 2002 Ximian, Inc. (www.ximian.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., 59 Temple Street #330, Boston, MA 02111-1307, USA. - * - */ - - -#ifndef __E_TRIE_H__ -#define __E_TRIE_H__ - -#ifdef __cplusplus -extern "C" { -#pragma } -#endif /* __cplusplus */ - -#include <glib.h> - -typedef struct _ETrie ETrie; - -ETrie *e_trie_new (gboolean icase); -void e_trie_free (ETrie *trie); - -void e_trie_add (ETrie *trie, const char *pattern, int pattern_id); - -const char *e_trie_search (ETrie *trie, const char *buffer, size_t buflen, int *matched_id); - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* __E_TRIE_H__ */ |