/* * Pure Data Packet system implementation. : code implementing pf's namespace (symbols) * Copyright (c) by Tom Schouten * * 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. * */ // #define _GNU_SOURCE // for vasprintf. obviously this is not portable.. FIXME #include #include #include #include #include #include #include #include // some extra prototypes void *pf_alloc(int size); void pf_dealloc(void *data); #define HASHSIZE 1024 static pf_symbol_t *pf_symhash[HASHSIZE]; static void symbol_init(pf_symbol_t *s) { memset(s, 0, sizeof(*s)); } pf_symbol_t* pf_vsymbolf(char *fmt, va_list ap){ /* as far as i understand, va_copy is necessary on archs that don't pass the arguments on the stack.. seemed to crash on PPC without it */ /* get size */ va_list aq; va_copy(aq, ap); int len = vsnprintf(0, 0, fmt, aq); va_end(aq); /* alloc + print */ char tmp[len+1]; vsprintf(tmp, fmt, ap); return pf_symbol(tmp); } pf_symbol_t *pf_symbolf(char *fmt, ...){ pf_symbol_t *s; va_list ap; va_start(ap, fmt); s = pf_vsymbolf(fmt, ap); va_end(ap); return s; } /* shamelessly copied from pd src */ static pf_symbol_t *dogensym(char *s, pf_symbol_t *oldsym) { pf_symbol_t **sym1, *sym2; unsigned int hash1 = 0, hash2 = 0; int length = 0; char *s2 = s; PF_ASSERT(s[0]); // empty symbols are illegal while (*s2) { char c = *s2; /* catch illegal symbol names early */ if ((c == ' ') || (c == '\t') || (c == '\n')){ pf_post("WARNING: symbol contains invalid character '%c'", s, c); PF_ASSERT(0); } hash1 += c; hash2 += hash1; length++; s2++; } sym1 = pf_symhash + (hash2 & (HASHSIZE-1)); while (sym2 = *sym1) { if (!strcmp(sym2->s_name, s)) goto gotit; sym1 = &sym2->s_next; } if (oldsym){ sym2 = oldsym; } else { sym2 = (pf_symbol_t *)pf_alloc(sizeof(*sym2)); symbol_init(sym2); sym2->s_name = pf_alloc(length+1); sym2->s_next = 0; sym2->s_stack = 0; strcpy(sym2->s_name, s); } *sym1 = sym2; gotit: return (sym2); } pf_symbol_t *pf_symbol(char *s) { return(dogensym(s, 0)); } // memory management: care needs to be taken here when the types are // atoms, so i'm using explicit atom allocation here. // static + wrapper functions to avoid linking problems on Darwin static pf_symbol_t _pf_sym_wildcard; static pf_symbol_t _pf_sym_float; static pf_symbol_t _pf_sym_int; static pf_symbol_t _pf_sym_symbol; static pf_symbol_t _pf_sym_packet; static pf_symbol_t _pf_sym_pointer; static pf_symbol_t _pf_sym_invalid; static pf_symbol_t _pf_sym_list; static pf_symbol_t _pf_sym_atom; static pf_symbol_t _pf_sym_null; pf_symbol_t * pf_symbol_list(void) {return &_pf_sym_list;} pf_symbol_t * pf_symbol_atom(void) {return &_pf_sym_atom;} pf_symbol_t * pf_symbol_wildcard(void) {return &_pf_sym_wildcard;} pf_symbol_t * pf_symbol_float(void) {return &_pf_sym_float;} pf_symbol_t * pf_symbol_int(void) {return &_pf_sym_int;} pf_symbol_t * pf_symbol_symbol(void) {return &_pf_sym_symbol;} pf_symbol_t * pf_symbol_invalid(void) {return &_pf_sym_invalid;} static void _sym(char *name, pf_symbol_t *s) { pf_symbol_t *realsym; symbol_init(s); s->s_name = name; realsym = dogensym(name, s); PF_ASSERT(realsym == s); // if this fails, the symbol was already defined } void pf_symbol_setup(void) { // init symbol hash memset(pf_symhash, 0, HASHSIZE * sizeof(pf_symbol_t *)); // bind to bypass hashing for often used symbols _sym("*", &_pf_sym_wildcard); _sym("float", &_pf_sym_float); _sym("int", &_pf_sym_int); _sym("symbol", &_pf_sym_symbol); _sym("packet", &_pf_sym_packet); _sym("pointer", &_pf_sym_pointer); _sym("invalid", &_pf_sym_invalid); _sym("list", &_pf_sym_list); _sym("atom", &_pf_sym_atom); _sym("null", &_pf_sym_null); }