aboutsummaryrefslogtreecommitdiff
path: root/system/kernel/pdp_type.c_old
diff options
context:
space:
mode:
authorPablo Martín <caedesv@users.sourceforge.net>2003-09-07 21:39:37 +0000
committerPablo Martín <caedesv@users.sourceforge.net>2003-09-07 21:39:37 +0000
commit599a8e20c02fa48bab5102d15fab79dd6b631c95 (patch)
tree80e8760e6a8fdc7d9144370dc569b38232b2b315 /system/kernel/pdp_type.c_old
parentb509942daafa671a5b5ede267b6e786619ce8173 (diff)
Updating to last version of pdp 0.12.2
svn path=/trunk/externals/pdp/; revision=940
Diffstat (limited to 'system/kernel/pdp_type.c_old')
-rw-r--r--system/kernel/pdp_type.c_old542
1 files changed, 542 insertions, 0 deletions
diff --git a/system/kernel/pdp_type.c_old b/system/kernel/pdp_type.c_old
new file mode 100644
index 0000000..4e42d53
--- /dev/null
+++ b/system/kernel/pdp_type.c_old
@@ -0,0 +1,542 @@
+/*
+ * Pure Data Packet system implementation. : code for handling different packet types
+ * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+
+/* this file contains type handling routines
+ note: pd symbols are used for type identification
+ for porting to other hosts, i suggest reimplementing t_pdp_symbol */
+
+// debug
+
+#include <fnmatch.h>
+#include <stdarg.h>
+#include <string.h>
+#include <pthread.h>
+#include "pdp.h"
+
+/*
+
+
+
+*/
+
+
+#define D if (0)
+
+
+static t_pdp_conversion *conversion_list;
+
+#define CACHE_SIZE 32
+static t_pdp_conversion *cached_conversion_list_start;
+static t_pdp_conversion cached_conversion_array[CACHE_SIZE];
+
+/* mutex */
+static pthread_mutex_t pdp_hash_mutex;
+static pthread_mutex_t pdp_conversion_mutex;
+static pthread_mutex_t pdp_cache_mutex;
+
+#define HASHSIZE 1024
+static t_pdp_symbol *pdp_symhash[HASHSIZE];
+
+
+/* shamelessly copied from pd src and made thread safe */
+t_pdp_symbol *_pdp_dogensym(char *s, t_pdp_symbol *oldsym)
+{
+ t_pdp_symbol **sym1, *sym2;
+ unsigned int hash1 = 0, hash2 = 0;
+ int length = 0;
+ char *s2 = s;
+ while (*s2)
+ {
+ hash1 += *s2;
+ hash2 += hash1;
+ length++;
+ s2++;
+ }
+ sym1 = pdp_symhash + (hash2 & (HASHSIZE-1));
+
+ /* lock hash */
+ pthread_mutex_lock(&pdp_hash_mutex);
+
+ while (sym2 = *sym1)
+ {
+ if (!strcmp(sym2->s_name, s)) goto gotit;
+ sym1 = &sym2->s_next;
+ }
+ if (oldsym) sym2 = oldsym;
+ else
+ {
+ sym2 = (t_pdp_symbol *)pdp_alloc(sizeof(*sym2));
+ sym2->s_name = pdp_alloc(length+1);
+ _pdp_symbol_clear_namespaces(sym2);
+ sym2->s_next = 0;
+ strcpy(sym2->s_name, s);
+ }
+ *sym1 = sym2;
+
+ gotit:
+
+ /* unlock hash */
+ pthread_mutex_unlock(&pdp_hash_mutex);
+ return (sym2);
+}
+
+t_pdp_symbol *pdp_gensym(char *s)
+{
+ return(_pdp_dogensym(s, 0));
+}
+
+/* convert a type to a list */
+t_pdp_list *pdp_type_to_list(t_pdp_symbol *type)
+{
+ char *c = type->s_name;
+ char *lastname = c;
+ char tmp[100];
+ int n = 0;
+ t_pdp_list *l = pdp_list_new(0);
+
+ while(*c){
+ if (*c == '/'){
+ strncpy(tmp, lastname, n);
+ tmp[n] = 0;
+ pdp_list_add_back(l, a_symbol, (t_pdp_word)pdp_gensym(tmp));
+ c++;
+ lastname = c;
+ n = 0;
+ }
+ else{
+ c++;
+ n++;
+ }
+ }
+ pdp_list_add_back(l, a_symbol, (t_pdp_word)pdp_gensym(lastname));
+
+ return l;
+}
+
+
+/* get the description symbol. this includes some compat transition stuff with a warning */
+t_pdp_symbol *pdp_packet_get_description(int packet)
+{
+ t_pdp *header = pdp_packet_header(packet);
+
+ if (!header) return pdp_gensym("invalid");
+ else if (!header->desc){
+ /* if description is not defined, try to reconstruct it (for backwards compat) */
+ if (header->type == PDP_IMAGE){
+ post("FIXME: pdp_type_get_description: packet %d has no description. using workaround.", packet);
+ return pdp_packet_image_get_description(packet);
+ }
+ else
+ return pdp_gensym("unknown");
+ }
+ else return header->desc;
+}
+
+
+
+/* this runs a conversion program */
+int _pdp_type_run_conversion_program(t_pdp_conversion_program *program,
+ int packet, t_pdp_symbol *dest_template)
+{
+ /* run a conversion program:
+ treat the source packet as readonly, and cleanup intermediates, such
+ that the net result is the production of a new packet, with the
+ source packet intact. */
+
+ int p, tmp;
+
+ D post("DEBUG: _pdp_type_run_conversion_program: program = %x", program);
+
+ // run the first line of the program
+ D post("DEBUG: _pdp_type_run_conversion_program: method = %x", *program);
+ p = (*program->method)(packet, dest_template);
+ D post("DEBUG: _pdp_type_run_conversion_program: packet returned = %d, type = %s", p, pdp_packet_get_description(p)->s_name);
+
+ // run the remaining lines + cleanup intermediates
+ for (program = program->next; program ; program = program->next){
+ D post("DEBUG: _pdp_type_run_conversion_program: next method ptr = %x", *program->method);
+ tmp = (*program->method)(p, dest_template);
+ pdp_packet_mark_unused(p);
+ p = tmp;
+ }
+ return p;
+}
+
+
+/* find a conversion program */
+t_pdp_conversion_program *
+_pdp_type_find_conversion_program(t_pdp_symbol *src_pattern, t_pdp_symbol *dst_pattern)
+{
+ t_pdp_conversion *c;
+ t_pdp_conversion_program *retval = 0;
+
+ /* lock conversion list */
+ pthread_mutex_lock(&pdp_conversion_mutex);
+
+ for (c = conversion_list; c; c=c->next){
+ /* can be a wildcard match */
+ if (pdp_type_description_match(src_pattern, c->src_pattern) &&
+ pdp_type_description_match(dst_pattern, c->dst_pattern)) {
+ /* found a program */
+ D post("DEBUG: _pdp_type_find_conversion_program: found: %s -> %s", c->src_pattern->s_name, c->dst_pattern->s_name);
+ retval = c->program;
+ goto gotit;
+ }
+ }
+
+ /* no conversion program was found */
+ retval = 0;
+ gotit:
+
+ /* lock conversion list */
+ pthread_mutex_unlock(&pdp_conversion_mutex);
+ return retval;
+}
+
+/* find a cached conversion program */
+t_pdp_conversion_program *
+_pdp_type_find_cached_conversion_program(t_pdp_symbol *src_pattern, t_pdp_symbol *dst_pattern)
+{
+ t_pdp_conversion *c;
+ t_pdp_conversion_program *retval = 0;
+
+ /* lock cached list */
+ pthread_mutex_lock(&pdp_cache_mutex);
+
+ for (c = cached_conversion_list_start; c; c=c->next){
+ /* must be exact match */
+ if ((src_pattern == c->src_pattern) &&
+ (dst_pattern == c->dst_pattern)) {
+ /* found a program */
+ D post("DEBUG: _pdp_type_find_cached_conversion_program: found: %s -> %s", c->src_pattern->s_name, c->dst_pattern->s_name);
+ retval = c->program;
+ goto gotit;
+ }
+ }
+
+ retval = 0;
+
+ gotit:
+
+ /* un lock cached list */
+ pthread_mutex_unlock(&pdp_cache_mutex);
+
+ /* no conversion program was found */
+ return retval;
+}
+
+
+/* conversion program manipulations */
+void pdp_conversion_program_free(t_pdp_conversion_program *program)
+{
+ t_pdp_conversion_program *p = 0;
+ while (program) {
+ p = program;
+ program = program->next;
+ pdp_dealloc (p);
+ }
+}
+
+/* debug print */
+void _pdp_conversion_program_print(t_pdp_conversion_program *program)
+{
+ D post("DEBUG: conversion program: %x", program);
+ while(program){
+ D post("DEBUG: method: %x", program->method);
+ program = program->next;
+ }
+}
+
+t_pdp_conversion_program *pdp_conversion_program_new(t_pdp_conversion_method method, ...)
+{
+ t_pdp_conversion_program head;
+ t_pdp_conversion_program *p = &head;
+ t_pdp_conversion_method m = method;
+ va_list ap;
+
+ D post("DEBUG: pdp_conversion_program_new:BEGIN");
+
+ p = p->next = (t_pdp_conversion_program *)pdp_alloc(sizeof(*p));
+ p->method = m;
+ va_start(ap, method);
+ while (m = va_arg(ap, t_pdp_conversion_method)){
+ p = p->next = (t_pdp_conversion_program *)pdp_alloc(sizeof(*p));
+ p->method = m;
+ }
+ p->next = 0; // terminate list
+ va_end(ap);
+
+ D post("DEBUG: pdp_conversion_program_new:END");
+ D _pdp_conversion_program_print(head.next);
+
+ return head.next;
+}
+
+t_pdp_conversion_program *pdp_conversion_program_copy(t_pdp_conversion_program *program)
+{
+ t_pdp_conversion_program head;
+ t_pdp_conversion_program *p = &head;
+
+ for(;program; program=program->next){
+ p = p->next = (t_pdp_conversion_program *)pdp_alloc(sizeof(*p));
+ p->method = program->method;
+ }
+ p->next = 0;
+ return head.next;
+}
+
+void pdp_conversion_program_add(t_pdp_conversion_program *program, t_pdp_conversion_program *tail)
+{
+ t_pdp_conversion_program *p = program;
+
+ //D post("DEBUG: pdp_conversion_program_add:BEGIN");
+
+
+ while (p->next) p = p->next;
+ p->next = pdp_conversion_program_copy(tail);
+
+ //D post("DEBUG: pdp_conversion_program_add:END");
+
+}
+
+/* conversion registration */
+void pdp_type_register_conversion (t_pdp_symbol *src_pattern, t_pdp_symbol *dst_pattern, t_pdp_conversion_program *program)
+{
+ t_pdp_conversion head;
+ t_pdp_conversion *c = &head;
+
+ /* lock conversion list */
+ pthread_mutex_lock(&pdp_conversion_mutex);
+
+ head.next = conversion_list;
+
+ while (c->next) c=c->next; // add a new one to the end
+ c = c->next = (t_pdp_conversion *)pdp_alloc(sizeof(*c));
+ c->src_pattern = src_pattern;
+ c->dst_pattern = dst_pattern;
+ c->program = program;
+ c->next = 0;
+
+ conversion_list = head.next;
+
+ /* unlock conversion list */
+ pthread_mutex_unlock(&pdp_conversion_mutex);
+
+}
+
+/* register a cached conversion */
+void pdp_type_register_cached_conversion (t_pdp_symbol *src_pattern, t_pdp_symbol *dst_pattern, t_pdp_conversion_program *program)
+{
+
+ t_pdp_conversion *save, *c, *c2;
+
+ /* unlock cahed conversion list */
+ pthread_mutex_lock(&pdp_cache_mutex);
+
+ c2 = save = cached_conversion_list_start;
+ while (c2->next->next) c2 = c2->next;
+ c = c2->next;
+ c2->next = 0;
+ if (c->program) pdp_conversion_program_free(c->program);
+ c->src_pattern = src_pattern;
+ c->dst_pattern = dst_pattern;
+ c->program = program;
+ c->next = save;
+ cached_conversion_list_start = c;
+
+ /* unlock cached conversion list */
+ pthread_mutex_unlock(&pdp_cache_mutex);
+}
+
+/* convert a given packet to a certain type (template) */
+int _pdp_packet_convert(int packet, t_pdp_symbol *dest_template)
+{
+ t_pdp_symbol *type = pdp_packet_get_description(packet);
+ t_pdp_symbol *tmp_type = 0;
+ int tmp_packet = -1;
+
+ t_pdp_conversion_program *program = 0;
+ t_pdp_conversion_program *program_last = 0;
+ t_pdp_conversion_program *program_tail = 0;
+
+ /* check if there is a program in the cached list, if so run it */
+ if (program = _pdp_type_find_cached_conversion_program(type, dest_template))
+ return _pdp_type_run_conversion_program(program, packet, dest_template);
+
+ /* if it is not cached, iteratively convert
+ and save program on top of cache list if a conversion path (program) was found */
+
+ // run first conversion that matches
+ program = pdp_conversion_program_copy(_pdp_type_find_conversion_program(type, dest_template));
+ program_last = program;
+ if (!program){
+ D post("DEBUG: pdp_type_convert: (1) can't convert %s to %s", type->s_name, dest_template->s_name);
+ return -1;
+ }
+ tmp_packet = _pdp_type_run_conversion_program(program, packet, dest_template);
+ tmp_type = pdp_packet_get_description(tmp_packet);
+
+ // run more conversions if necessary, deleting intermediate packets
+ while (!pdp_type_description_match(tmp_type, dest_template)){
+ int new_packet;
+ program_tail = _pdp_type_find_conversion_program(tmp_type, dest_template);
+ if (!program_tail){
+ D post("DEBUG: pdp_type_convert: (2) can't convert %s to %s", tmp_type->s_name, dest_template->s_name);
+ pdp_packet_mark_unused(tmp_packet);
+ pdp_conversion_program_free(program);
+ return -1;
+ }
+ if (program_last == program_tail){
+ post("ERROR: pdp_packet_convert: conversion loop detected");
+ }
+ program_last = program_tail;
+
+ pdp_conversion_program_add(program, program_tail);
+ new_packet = _pdp_type_run_conversion_program(program_tail, tmp_packet, dest_template);
+ pdp_packet_mark_unused(tmp_packet);
+ tmp_packet = new_packet;
+ tmp_type = pdp_packet_get_description(tmp_packet);
+ }
+
+ // save the conversion program
+ pdp_type_register_cached_conversion(type, dest_template, program);
+
+ // return resulting packet
+ return tmp_packet;
+
+}
+
+/* convert or copy ro */
+int pdp_packet_convert_ro(int packet, t_pdp_symbol *dest_template)
+{
+ t_pdp_symbol *type = pdp_packet_get_description(packet);
+
+ /* if it is compatible, return a ro copy */
+ if (pdp_type_description_match(type, dest_template)) return pdp_packet_copy_ro(packet);
+
+ /* if not, convert to a new type */
+ else return _pdp_packet_convert(packet, dest_template);
+}
+
+/* convert or copy rw */
+int pdp_packet_convert_rw(int packet, t_pdp_symbol *dest_template)
+{
+ t_pdp_symbol *type = pdp_packet_get_description(packet);
+
+ /* if it is compatible, just return a rw copy */
+ if (pdp_type_description_match(type, dest_template)) return pdp_packet_copy_rw(packet);
+
+ /* if not, convert to a new type */
+ else return _pdp_packet_convert(packet, dest_template);
+}
+
+
+static void _setup_type_cache(t_pdp_symbol *s)
+{
+ t_pdp_list *l = pdp_type_to_list(s);
+ pthread_mutex_lock(&pdp_hash_mutex); //lock to prevent re-entry
+ if (!s->s_type){
+ s->s_type = l;
+ l = 0;
+ }
+ pthread_mutex_unlock(&pdp_hash_mutex);
+ if (l) pdp_list_free(l);
+}
+
+/* check if a type description fits a template
+ this function is symmetric */
+int pdp_type_description_match(t_pdp_symbol *description, t_pdp_symbol *pattern)
+{
+
+
+#if 1
+ t_pdp_atom *ad, *ap;
+ t_pdp_symbol *wildcard = pdp_gensym("*");
+
+ /* same type -> match */
+ if (description == pattern) return 1;
+
+ /* use the description list stored in the symbol for comparison */
+ if (!(description->s_type)) _setup_type_cache(description);
+ if (!(pattern->s_type)) _setup_type_cache(pattern);
+
+ /* check size */
+ if (description->s_type->elements != pattern->s_type->elements) return 0;
+
+ /* compare symbols of type list */
+ for(ad=description->s_type->first, ap=pattern->s_type->first; ad; ad=ad->next, ap=ap->next){
+ if (ad->w.w_symbol == wildcard) continue;
+ if (ap->w.w_symbol == wildcard) continue;
+ if (ad->w.w_symbol != ap->w.w_symbol) return 0; /* difference and not a wildcard */
+ }
+
+ /* type templates match */
+ return 1;
+
+
+#else
+ int retval = 0;
+ if (description == pattern) retval = 1;
+ //else retval = (!fnmatch(pattern->s_name, description->s_name, FNM_FILE_NAME));
+
+ //hack: make a symmetric match symmetric by calling fnmatch a second time with reversed attributes
+ else retval = ((!fnmatch(pattern->s_name, description->s_name, FNM_FILE_NAME))
+ ||(!fnmatch(description->s_name, pattern->s_name, FNM_FILE_NAME)));
+
+
+ D post("DEBUG: testing match between %s and %s: %s", description->s_name, pattern->s_name, retval ? "match" : "no match");
+
+ return retval;
+#endif
+}
+
+
+
+
+
+/* setup method */
+void pdp_type_setup(void)
+{
+ int i;
+
+ // create mutexes
+ pthread_mutex_init(&pdp_hash_mutex, NULL);
+ pthread_mutex_init(&pdp_conversion_mutex, NULL);
+ pthread_mutex_init(&pdp_cache_mutex, NULL);
+
+ // init hash
+ memset(pdp_symhash, 0, HASHSIZE * sizeof(t_pdp_symbol *));
+
+ // init conversion lists
+ conversion_list = 0;
+ for(i=0; i<CACHE_SIZE; i++){
+ t_pdp_conversion *c = cached_conversion_array + i;
+ c->src_pattern = 0;
+ c->dst_pattern = 0;
+ c->program = 0;
+ c->next = c + 1;
+ }
+ cached_conversion_list_start = cached_conversion_array;
+ cached_conversion_array[CACHE_SIZE-1].next = 0;
+
+
+
+}