/[ascend]/trunk/base/generic/compiler/notate.c
ViewVC logotype

Contents of /trunk/base/generic/compiler/notate.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 709 - (show annotations) (download) (as text)
Wed Jun 28 16:28:57 2006 UTC (13 years, 5 months ago) by johnpye
File MIME type: text/x-csrc
File size: 25609 byte(s)
Monster commit!
Lots of recommenting and reorganising of external relations-related stuff.
Replaced a lot of ascmalloc and asccalloc calls with the new ASC_NEW* macros.
Fixed (?) the problem Art is having with icons in PyGTK.
Turned on -Wall in SConstruct and fixed up a stack of warnings.
Removed the redundant exit(2) from after Asc_Panic calls and added __attribute__((noreturn)).
Set doxygen to create callgraphs to level 2, updated doxyfile to version 1.4.7.
Fixed up building of extfntest.c.
1 /*
2 * notate.c
3 * By Ben Allan
4 * 4/98
5 * Part of ASCEND
6 * Version: $Revision: 1.9 $
7 * Version control file: $RCSfile: notate.c,v $
8 * Date last modified: $Date: 1998/06/18 18:44:58 $
9 * Last modified by: $Author: ballan $
10 *
11 * This file is part of the Ascend Language Interpreter.
12 *
13 * Copyright (C) 1998 Carnegie Mellon University
14 *
15 * The Ascend Language Interpreter is free software; you can
16 * redistribute it and/or modify it under the terms of the GNU
17 * General Public License as published by the Free Software
18 * Foundation; either version 2 of the License, or (at your option)
19 * any later version.
20 *
21 * The Ascend Language Interpreter is distributed in hope that it
22 * will be useful, but WITHOUT ANY WARRANTY; without even the implied
23 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
24 * See the GNU General Public License for more details.
25 *
26 * You should have received a copy of the GNU General Public License
27 * along with the program; if not, write to the Free Software
28 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139 USA. Check
29 * the file named COPYING.
30 */
31 /* This file defines and manages a little (we hope)
32 * database system for storing NOTES in-core in a variety
33 * of quickly accessible ways.
34 * If scale gets to be an issue, this could become a wrapper
35 * for a real database someday.
36 * This implementation is not optimized for anything -- the
37 * intent here is to learn if it can be done at all.
38 */
39 #include <utilities/ascConfig.h>
40 #include <utilities/ascMalloc.h>
41 #include <general/list.h>
42 #include <general/pool.h>
43 #include "compiler.h"
44 #include "symtab.h"
45 #include "braced.h"
46 #include "vlist.h"
47 #include "fractions.h"
48 #include "dimen.h"
49 #include "expr_types.h"
50 #include "sets.h"
51 #include "name.h"
52 #include "instance_enum.h"
53 #include "cmpfunc.h"
54 #include "notate.h"
55
56 struct Note {
57 symchar *typename; /* ascend type library name, if any, for context. */
58 symchar *id; /* child name in type, if only for 1 child, or SELF */
59 symchar *method; /* method name type, if in method context */
60 symchar *lang; /* language keyword in '' */
61 CONST char *filename; /* where note is from */
62 struct bracechar *t; /* text of the note */
63 VOIDPTR data; /* note data */
64 int line; /* where note occured, to our best guess */
65 enum NoteData kind; /* void pointer type */
66 int refcount; /* number of database references to the note */
67 int found; /* 0 normal. 1 if found. 2 if collected. search flag */
68 struct data_base *db; /* database */
69 struct Note *next; /* database master list chain */
70 };
71
72 struct note_bucket {
73 symchar *key; /* hash key. type, id, or other heap pointer. */
74 struct note_bucket *next; /* next bucket. duh */
75 void *obj; /* data for bucket. usually a note or list. */
76 };
77
78 /* replace this with a pool */
79 #define NPALLOC ASC_NEW(struct Note)
80 #define NPFREE(n) ascfree(n)
81
82 /* replace this with a pool */
83 #define NBALLOC ASC_NEW(struct note_bucket)
84 #define NBFREE(b) ascfree(b)
85
86 /* increment note reference count */
87 #define ReferenceNote(n) ((n)->refcount++)
88
89 /* list of held tokens for clients */
90 #define GNT db->note_tokens
91
92 #define NTAB 1024
93 #define PTRHASH(p) (((((long) (p))*1103515245) >> 20) & 1023)
94
95 /*
96 * This module manages possibly several databases of this sort.
97 */
98 struct data_base {
99 struct Note *all; /* all notes committed */
100 struct gl_list_t *note_tokens;
101 symchar *dbid; /* name of this database */
102 struct data_base *next; /* linked list of databases */
103 struct note_bucket *typetab[NTAB]; /* hash keyed on type name */
104 struct note_bucket *idtab[NTAB]; /* hash keyed on id name */
105 int dead;
106 };
107
108 /*
109 * All the databases have this in common and initing one
110 * will init all the fields if it has not been inited.
111 * Destroying the last dbid will also uninit all these fields.
112 */
113 #define NDB g_notes_data_base
114 static struct fixed_data {
115 symchar *inlinenote; /* symtab entry 'inline' */
116 symchar *selfnote; /* symtab entry 'SELF' */
117 symchar *librarynote; /* symtab entry 'Loaded Libraries' */
118 symchar *globalnote; /* symtab entry 'All Known Files' */
119 /* pool_t */
120 struct data_base *dblist; /* list of created databases */
121 } g_notes_data_base = {NULL,NULL,NULL,NULL,NULL};
122
123 /* fwd declaration */
124 static struct Note *CopyNote(struct Note *);
125
126 struct NoteTmp *CreateNoteTmp(symchar *lang, struct bracechar *bt,
127 void *varlist, int line)
128 {
129 struct NoteTmp *nt;
130 nt = ASC_NEW(struct NoteTmp);
131 nt->lang = lang;
132 nt->bt = bt;
133 nt->vardata = varlist;
134 nt->line = line;
135 nt->next = NULL;
136 return nt;
137 }
138
139 /* var data and bt assumed not our problem */
140 void DestroyNoteTmpList(struct NoteTmp *head)
141 {
142 struct NoteTmp *old;
143 while (head != NULL) {
144 old = head;
145 head = old->next;
146 ascfree(old);
147 }
148 }
149
150 struct NoteTmp *LinkNoteTmp(struct NoteTmp *new, struct NoteTmp *chain)
151 {
152 if (chain == NULL) {
153 return new;
154 }
155 if (new == NULL) {
156 return chain;
157 }
158 new->next = chain;
159 return new;
160 }
161
162 /* return pointer to database if it is in global list and not dead. */
163 static
164 struct data_base *FindDatabase(symchar *dbid)
165 {
166 struct data_base *db;
167 db = NDB.dblist;
168 while (db != NULL) {
169 if (db->dbid == dbid && !(db->dead)) {
170 return db;
171 }
172 db = db->next;
173 }
174 return NULL;
175 }
176
177 /* delete dead entries from the dblist and frees them.
178 * Stupid implementation.
179 */
180 static
181 void ClearDeadDB(void)
182 {
183 struct data_base *db, *odb;
184 struct gl_list_t *keep;
185 unsigned long len;
186 if (NDB.dblist == NULL) {
187 return;
188 }
189 keep = gl_create(3);
190 if (keep == NULL) {return;}
191 db = NDB.dblist;
192 while (db != NULL) {
193 if (!db->dead) {
194 gl_append_ptr(keep,db);
195 db = db->next;
196 } else {
197 odb = db;
198 db = db->next;
199 ascfree(odb);
200 }
201 }
202 NDB.dblist = NULL;
203 len = gl_length(keep);
204 while (len > 0) {
205 db = (struct data_base *)gl_fetch(keep,len);
206 db->next = NDB.dblist;
207 NDB.dblist = db;
208 len--;
209 }
210 gl_destroy(keep);
211 }
212
213 /* this should be between the declarations and the execution in any call
214 * that takes a dbid as a data source.
215 * It defines a variable db, checks that dbid given is correct, and
216 * returns failval if not. failval should be appropriate to context.
217 * It's miniscully wasteful so that it can END in ; in use as
218 * CHECKDB(1); Use CHECKDBV for void functions.
219 */
220 #define CHECKDB(failval) struct data_base *db; \
221 if (FindDatabase(dbid) == NULL) { return (failval); } db = FindDatabase(dbid)
222 #define CHECKDBV struct data_base *db; \
223 if (FindDatabase(dbid) == NULL) { return; } db = FindDatabase(dbid)
224
225 /* init the database. return 0 if successful. NULL is not considered dbid. */
226 int InitNotesDatabase(symchar *dbid)
227 {
228 int c;
229 struct data_base *db;
230 NDB.librarynote = AddSymbolL("Loaded Libraries",16);
231 NDB.globalnote = AddSymbolL("All Known Files",15);
232 NDB.inlinenote = AddSymbolL("inline",6);
233 NDB.selfnote = AddSymbolL("SELF",4);
234 if (dbid==NULL) {
235 return 1;
236 }
237 db = ASC_NEW(struct data_base);
238 if (db == NULL) {
239 return 1;
240 }
241 /* init pool here if exists and NDB.dblist == NULL. */
242 db->all = NULL;
243 db->dbid = dbid;
244 db->note_tokens = NULL;
245 db->dead = 0;
246 db->next = NDB.dblist;
247 NDB.dblist = db;
248 for (c=0;c < NTAB;c++) {
249 db->typetab[c] = NULL;
250 db->idtab[c] = NULL;
251 }
252 return 0;
253 }
254
255 /* bucket is assumed to contain a gl_list of notes matching key */
256 static
257 void NoteDestroyHash(struct note_bucket **tab, int size)
258 {
259 struct note_bucket *old,*next;
260 int c;
261 for (c = 0; c < size; c++) {
262 next = tab[c];
263 tab[c] = NULL;
264 while (next != NULL) {
265 old = next;
266 next = old->next;
267 if (old->obj != NULL) {
268 gl_iterate((struct gl_list_t *)old->obj,(DestroyFunc)DestroyNote);
269 gl_destroy((struct gl_list_t *)old->obj);
270 }
271 NBFREE(old);
272 }
273 }
274 }
275
276 struct gl_list_t *ListNotesDatabases(void)
277 {
278 struct data_base *db;
279 struct gl_list_t *names;
280 db = NDB.dblist;
281 names = gl_create(2);
282 if (names == NULL) {
283 return NULL;
284 }
285 while (db != NULL) {
286 if (!(db->dead)) {
287 gl_append_ptr(names,(VOIDPTR)db->dbid);
288 }
289 db = db->next;
290 }
291 return names;
292 }
293
294 static
295 void RealDestroyDatabase(struct data_base *db, symchar *dbid)
296 {
297 struct Note *old, *next;
298 if (GNT != NULL) {
299 ReleaseNoteData(dbid,(void *)0x1);
300 }
301 NoteDestroyHash(db->typetab,NTAB);
302 NoteDestroyHash(db->idtab,NTAB);
303 next = db->all;
304 db->all = NULL;
305 while (next != NULL) {
306 old = next;
307 next = old->next;
308 DestroyNote(old);
309 }
310 db->dead = 1;
311 }
312
313 void DestroyNotesDatabase(symchar *dbid)
314 {
315 struct data_base *db;
316
317 if (dbid == (symchar *)0x1) {
318 db = NDB.dblist;
319 while (db != NULL) {
320 RealDestroyDatabase(db,db->dbid);
321 db = db->next;
322 }
323 } else {
324 db = FindDatabase(dbid);
325 if (db == NULL) {
326 return;
327 }
328 RealDestroyDatabase(db,dbid);
329 }
330 ClearDeadDB();
331 }
332
333 /* clear any notes associated with the type named out of
334 * database. Useful if replacing a type.
335 */
336 void DestroyNotesOnType(symchar *dbid, symchar *typename)
337 {
338 struct note_bucket *b, *prev = NULL;
339 unsigned long len;
340 struct gl_list_t *nl;
341 struct Note *n,*p;
342 long index;
343 CHECKDBV;
344
345 /* find type table data and dump it */
346 index = PTRHASH(typename);
347 b = db->typetab[index];
348 if (b==NULL) {
349 return;
350 }
351 if (b->key == typename) {
352 db->typetab[index] = b->next;
353 } else {
354 while (b != NULL && b->key != typename) {
355 prev = b;
356 b = b->next;
357 }
358 if (b==NULL) {
359 return; /* very odd */
360 }
361 prev->next = b->next;
362 }
363 gl_iterate((struct gl_list_t *)b->obj,(DestroyFunc)DestroyNote);
364 gl_destroy((struct gl_list_t *)b->obj);
365 NBFREE(b);
366
367 /* run through other tables looking for type and kill those entries. */
368 /* we eliminate the notes from the gl_lists, not table buckets, since
369 * the only reason to delete a type instead of the whole database
370 * is to replace it.
371 */
372 /* id table */
373 for (index = 0; index < NTAB; index++) {
374 b = db->idtab[index];
375 while (b != NULL) {
376 nl = (struct gl_list_t *)b->obj;
377 len = gl_length(nl);
378 for (; len > 0; len--) {
379 n = (struct Note *)gl_fetch(nl,len);
380 if (n->typename == typename) {
381 gl_delete(nl,len,0);
382 DestroyNote(n);
383 }
384 }
385 b = b->next;
386 }
387 }
388
389 /* run through ndb.all looking for type and kill those. */
390 /* eat occurences of typename at head of list */
391 while (db->all != NULL && db->all->typename == typename) {
392 n = db->all;
393 db->all = n->next;
394 DestroyNote(n);
395 }
396 /* eat interior occurences. this loop will not change db->all. */
397 if (db->all != NULL) {
398 p = db->all;
399 n = p->next;
400 while (n != NULL) {
401 if (n->typename == typename) {
402 p->next = n->next;
403 DestroyNote(n);
404 } else {
405 p = n;
406 }
407 n = p->next;
408 }
409 }
410 }
411
412 /* returns e if it is in the main list NDB.all. returns NULL if not. */
413 static
414 struct Note *FindNote(symchar *dbid, struct Note *e)
415 {
416 struct Note *n;
417 CHECKDB(NULL);
418 n = db->all;
419 while (n != NULL) {
420 if (n == e) {
421 return e;
422 }
423 n = n->next;
424 }
425 return NULL;
426 }
427
428 /* check list for worthiness and keep it, converting pointer to
429 * void for user.
430 */
431 void *HoldNoteData(symchar *dbid, struct gl_list_t *nl)
432 {
433 CHECKDB(NULL);
434 if (nl == NULL) {
435 return NULL;
436 }
437 if (GNT == NULL) {
438 GNT = gl_create(2);
439 if (GNT == NULL) {
440 return NULL;
441 }
442 }
443 /* reject list if first note is bogus. mostly safe. */
444 if (gl_length(nl) > 0L &&
445 FindNote(dbid,(struct Note *)gl_fetch(nl,1)) == NULL) {
446 return NULL;
447 }
448 gl_append_ptr(GNT,nl);
449 return (void *)nl;
450 }
451
452 struct gl_list_t *HeldNotes(symchar *dbid, void *token)
453 {
454 unsigned long pos;
455 struct gl_list_t *nl;
456 CHECKDB(NULL);
457 if (token == NULL || GNT == NULL) {
458 return NULL;
459 }
460 pos = gl_ptr_search(GNT,token,0);
461 if (pos != 0) {
462 nl = (struct gl_list_t *)gl_fetch(GNT,pos);
463 return nl;
464 }
465 return NULL;
466 }
467
468 void ReleaseNoteData(symchar *dbid, void *token)
469 {
470 unsigned long pos;
471 struct gl_list_t *nl;
472 CHECKDBV;
473 if (token == NULL || GNT == NULL) {
474 return;
475 }
476 if (token == (void *)0x1) {
477 gl_iterate(GNT,(DestroyFunc)gl_destroy);
478 gl_destroy(GNT);
479 GNT = NULL;
480 return;
481 }
482 pos = gl_ptr_search(GNT,token,0);
483 if (pos != 0) {
484 nl = (struct gl_list_t *)gl_fetch(GNT,pos);
485 assert(nl==token);
486 gl_destroy(nl);
487 gl_delete(GNT,pos,0);
488 }
489 }
490
491 /*
492 */
493 struct gl_list_t *GetNotes(symchar *dbid,
494 symchar *type, symchar *lang,
495 symchar *id, symchar *method, enum NoteData nd)
496 {
497 struct gl_list_t *result;
498 struct Note *n;
499 CHECKDB(NULL);
500 /* unimplemented optimized searches */
501 /* if type but not id or method given, grab its bucket and list and
502 * match lang, nd as needed.
503 */
504 /* do something here */
505 /*
506 * If id or method given, grab its bucket and filter using the
507 * other fields. filter sequence type, method, nd.
508 */
509 /* do something here */
510
511 /* do the damned expensive thing here until the above get done */
512 n= db->all;
513 result = gl_create(40);
514 if (result == NULL) {
515 return NULL;
516 }
517 while (n != NULL) {
518 /* nd_wild, NOTESWILD is the wildcard */
519 if ((type == NOTESWILD || type == n->typename) &&
520 (id == NOTESWILD || id == n->id) &&
521 (method == NOTESWILD || method == n->method) &&
522 (lang == NOTESWILD || lang == n->lang) &&
523 (nd == nd_wild || nd == n->kind)) {
524 gl_append_ptr(result,n);
525 }
526 n = n->next;
527 }
528 return result;
529 }
530
531 /* manual search of a list, since user may hand us a sorted but
532 * not by ptr list.
533 * returns 1 if list or data is NULL or if data is found in list.
534 * Else returns 0;
535 */
536 static
537 int inDataListOrWild(void *data, struct gl_list_t *list)
538 {
539 unsigned long len;
540 void *elt;
541 if (list == NULL) {
542 return 0;
543 }
544 if (list == NOTESWILDLIST) {
545 return 1;
546 }
547 len = gl_length(list);
548 for (; len > 0; len--) {
549 elt = gl_fetch(list,len);
550 if (elt == data || (enum NoteData)elt == nd_wild) {
551 return 1;
552 }
553 }
554 return 0;
555 }
556
557 /* manual search of a list, since user may hand us a sorted but
558 * not by ptr list.
559 * returns 1 if list or data is NULL or if data is found in list.
560 * Else returns 0;
561 */
562 static
563 int inDataListOrNull(void *data, struct gl_list_t *list)
564 {
565 unsigned long len;
566 void *elt;
567 if (list == NULL) {
568 return 0;
569 }
570 if (list == NOTESWILDLIST) {
571 return 1;
572 }
573 len = gl_length(list);
574 for (; len > 0; len--) {
575 elt = gl_fetch(list,len);
576 if (elt == data || elt == NOTESWILD) {
577 return 1;
578 }
579 }
580 return 0;
581 }
582 /*
583 * GetNotesList(typelist,langlist,idlist,ndlist);
584 * Returns the list of notes matching any combination of the
585 * keys stored in the gl_lists given. So, for example,
586 * if you want the notes on id in typename or any ancestor,
587 * cookup up the list of ancestor type names, stick id in idlist,
588 * and pass NULL,nd_empty for the other two arguments.
589 */
590 struct gl_list_t *GetNotesList(symchar *dbid,
591 struct gl_list_t *types,
592 struct gl_list_t *langs,
593 struct gl_list_t *ids,
594 struct gl_list_t *methods,
595 struct gl_list_t *nds)
596 {
597 struct gl_list_t *result;
598 struct Note *n;
599 CHECKDB(NULL);
600
601 /* unimplemented optimized searches */
602 /* if type but not id or method given, grab its bucket and list and
603 * match lang, nd as needed.
604 */
605 /* do something here */
606 /*
607 * If id or method given, grab its bucket and filter using the
608 * other fields. filter sequence type, method, nd.
609 */
610 /* do something here */
611
612 /* do the damned expensive thing here until the above get done */
613 n= db->all;
614 result = gl_create(40);
615 if (result == NULL) {
616 return NULL;
617 }
618 while (n != NULL) {
619 if (inDataListOrNull((void *)(n->typename),types) &&
620 inDataListOrNull((void *)(n->id),ids) &&
621 inDataListOrNull((void *)(n->lang),langs) &&
622 inDataListOrNull((void *)(n->method),methods) &&
623 inDataListOrWild((void *)(n->kind),nds)) {
624 gl_append_ptr(result,n);
625 }
626 n = n->next;
627 }
628 return result;
629 }
630
631 struct gl_list_t *GetExactNote(symchar *dbid, struct Note *e)
632 {
633 struct gl_list_t *result;
634 struct Note *n;
635
636 result = gl_create(1);
637 if (result == NULL) {
638 return NULL;
639 }
640 n = FindNote(dbid,e);
641 if (n != NULL) {
642 gl_append_ptr(result,e);
643 }
644 return result;
645 }
646
647 symchar *GetNoteId(struct Note *n)
648 {
649 if (n != NULL) {
650 return n->id;
651 }
652 return NULL;
653 }
654
655 symchar *GetNoteMethod(struct Note *n)
656 {
657 if (n != NULL) {
658 return n->method;
659 }
660 return NULL;
661 }
662
663 symchar *GetNoteType(struct Note *n)
664 {
665 if (n != NULL) {
666 return n->typename;
667 }
668 return NULL;
669 }
670
671 symchar *GetNoteLanguage(struct Note *n)
672 {
673 if (n != NULL) {
674 return n->lang;
675 }
676 return NULL;
677 }
678
679 CONST char *GetNoteFilename(struct Note *n)
680 {
681 if (n != NULL) {
682 return n->filename;
683 }
684 return NULL;
685 }
686
687 int GetNoteLineNum(struct Note *n)
688 {
689 if (n != NULL) {
690 return n->line;
691 }
692 return 0;
693 }
694
695 struct bracechar *GetNoteText(struct Note *n)
696 {
697 if (n != NULL) {
698 return n->t;
699 }
700 return NULL;
701 }
702
703 enum NoteData GetNoteEnum(struct Note *n)
704 {
705 if (n != NULL) {
706 return n->kind;
707 }
708 return nd_empty;
709 }
710
711 void *GetNoteData(struct Note *n, enum NoteData nd)
712 {
713 if (n != NULL && nd == n->kind) {
714 return n->data;
715 }
716 return NULL;
717 }
718
719 struct gl_list_t *GetNotesAllLanguages(symchar *dbid)
720 {
721 struct Note *n;
722 struct gl_list_t *result;
723 CHECKDB(NULL);
724 result = gl_create(40);
725 if (result == NULL) {
726 return NULL;
727 }
728 n= db->all;
729 while (n != NULL) {
730 /* null, empty is the wildcard */
731 if (n->lang != NULL && gl_ptr_search(result,n->lang,1)==0) {
732 /* if you see lang repeats, change 1 to 0 above */
733 gl_insert_sorted(result,(void *)n->lang,(CmpFunc)CmpPtrs);
734 }
735 n = n->next;
736 }
737 return result;
738
739 }
740
741 symchar *GlobalNote(void)
742 {
743 return NDB.globalnote;
744 }
745
746 symchar *LibraryNote(void)
747 {
748 return NDB.librarynote;
749 }
750
751 symchar *InlineNote(void)
752 {
753 return NDB.inlinenote;
754 }
755
756 symchar *SelfNote(void)
757 {
758 return NDB.selfnote;
759 }
760
761 /* creates and inserts bucket, returning pointer.
762 * return NULL if malloc fail.
763 */
764 static
765 struct note_bucket *AddEntry(struct note_bucket **tab, symchar *key, void *obj)
766 {
767 long index;
768 struct note_bucket *new;
769
770 index = PTRHASH(key);
771 new = NBALLOC;
772 if (new==NULL) {
773 return NULL;
774 }
775 new->key = key;
776 new->obj = obj;
777 new->next = tab[index];
778 tab[index] = new;
779 return new;
780 }
781
782 static
783 struct note_bucket *FindEntry(struct note_bucket **tab, symchar *key)
784 {
785 struct note_bucket *b;
786 long index;
787 index = PTRHASH(key);
788 b = tab[index];
789 while (b != NULL && b->key != key) {
790 b = b->next;
791 }
792 return b;
793 }
794
795
796 /* add finished note to tables.
797 * idtable buckets match both methods and ids.
798 * typetable matches typename.
799 */
800 static
801 int InsertNote(struct data_base *db, struct Note *n)
802 {
803 struct note_bucket *b;
804 struct gl_list_t *matches;
805
806 if (n == NULL) {
807 return 0;
808 }
809
810 /* insert in master list */
811 n->next = db->all;
812 db->all = n;
813
814 /* insert in id in id table. buckets in id typically short lists */
815 if (n->id != NULL) {
816 b = FindEntry(db->idtab,n->id);
817 if (b==NULL) {
818 matches = gl_create(2);
819 if (matches == NULL) {
820 return 1;
821 }
822 b = AddEntry(db->idtab,n->id,matches);
823 }
824 if (b == NULL) {
825 return 1;
826 }
827 matches = (struct gl_list_t *)(b->obj);
828 ReferenceNote(n);
829 gl_append_ptr(matches,(VOIDPTR)n);
830 }
831
832 /* insert in method in id table. buckets in id typically short lists */
833 if (n->method != NULL) {
834 b = FindEntry(db->idtab,n->method);
835 if (b==NULL) {
836 matches = gl_create(2);
837 if (matches == NULL) {
838 return 1;
839 }
840 b = AddEntry(db->idtab,n->method,matches);
841 }
842 if (b == NULL) {
843 return 1;
844 }
845 matches = (struct gl_list_t *)(b->obj);
846 ReferenceNote(n);
847 gl_append_ptr(matches,(VOIDPTR)n);
848 }
849
850 /* insert in type table. buckets in type contain fairly big lists. */
851 if (n->typename != NULL) {
852 b = FindEntry(db->typetab,n->typename);
853 if (b==NULL) {
854 matches = gl_create(5);
855 if (matches == NULL) {
856 return 1;
857 }
858 b = AddEntry(db->typetab,n->typename,matches);
859 }
860 if (b == NULL) {
861 return 1;
862 }
863 matches = (struct gl_list_t *)(b->obj);
864 ReferenceNote(n);
865 gl_append_ptr(matches,(VOIDPTR)n);
866 }
867
868 return 0;
869 }
870
871 /* Add a note to the database.
872 * CommitNote(note);
873 */
874 int CommitNote(symchar *dbid, struct Note *n)
875 {
876 CONST struct VariableList *vl;
877 CONST struct Name *name;
878 struct Note *new;
879 int errcnt=0;
880 symchar *id;
881 CHECKDB(1);
882
883 assert(n->db == NULL);
884 n->db = db;
885 if (n->kind == nd_vlist) {
886 vl = (struct VariableList *)(n->data);
887 while (vl != NULL) {
888 name = NamePointer(vl);
889 id = SimpleNameIdPtr(name);
890 new = CopyNote(n);
891 if (id == NULL) {
892 new->kind = nd_name;
893 new->data = (VOIDPTR)name;
894 } else {
895 new->id = id;
896 }
897 errcnt += InsertNote(db,new);
898 vl = NextVariableNode(vl);
899 }
900 }
901 errcnt += InsertNote(db,n);
902 return errcnt;
903 }
904
905 struct Note *CreateNote(symchar *type, symchar *lang,
906 symchar *id, symchar *method, CONST char *file,
907 struct bracechar *t, int line,
908 VOIDPTR data, enum NoteData nd)
909 {
910 struct Note *n;
911 if (t==NULL) {
912 return NULL;
913 }
914 n = NPALLOC;
915 n->typename = type;
916 n->lang = lang;
917 n->db = NULL;
918 n->id = id;
919 n->method = method;
920 n->filename = file;
921 n->t = t;
922 n->line = line;
923 n->refcount = 0;
924 switch (nd) {
925 case nd_name:
926 case nd_vlist:
927 case nd_module:
928 case nd_anonymous:
929 n->data = data;
930 n->kind = nd;
931 break;
932 case nd_empty:
933 case nd_wild:
934 default:
935 n->data = NULL;
936 n->kind = nd_empty;
937 }
938 return n;
939 }
940
941 /* does not copy vlist data and nd, if found.
942 * OTHERWISE copies everything about the note.
943 * The text t is copied by reference.
944 * this cannot be used to move a note between databases.
945 */
946 static
947 struct Note *CopyNote(struct Note *old)
948 {
949 struct Note *n;
950 if (old==NULL) {
951 return NULL;
952 }
953 n = NPALLOC;
954 n->typename = old->typename;
955 n->lang = old->lang;
956 n->id = old->id;
957 n->db = old->db;
958 n->method = old->method;
959 n->filename = old->filename;
960 n->t = CopyBraceChar(old->t);
961 n->line = old->line;
962 n->refcount = 0;
963 switch (old->kind) {
964 case nd_name:
965 case nd_module:
966 case nd_anonymous:
967 n->data = old->data;
968 n->kind = old->kind;
969 break;
970 case nd_vlist: /* original holder owns this */
971 case nd_empty:
972 default:
973 n->data = NULL;
974 n->kind = nd_empty;
975 }
976 return n;
977 }
978
979 void DestroyNote(struct Note *n)
980 {
981 if (n==NULL) {
982 return;
983 }
984 if (!(n->refcount)) {
985 DestroyBraceChar(n->t); /* bracechar plays reference games itself */
986 switch (n->kind) {
987 case nd_vlist:
988 DestroyVariableList((struct VariableList *)n->data);
989 break;
990 case nd_wild:
991 case nd_empty:
992 case nd_name:
993 case nd_module:
994 case nd_anonymous:
995 break;
996 }
997 NPFREE(n);
998 } else {
999 (n->refcount)--;
1000 }
1001 }
1002
1003 struct NoteEngine {
1004 int enginekey;
1005 void *reinterp;
1006 NEInitFunc recompile;
1007 NECompareFunc reexec;
1008 };
1009 #define ENGINEMAGIC 345987607
1010
1011 struct gl_list_t *GetMatchingNotes(symchar *dbid, char *pattern,void *token,
1012 struct NoteEngine *engine)
1013 {
1014 struct gl_list_t *result;
1015 unsigned long len;
1016 struct gl_list_t *oldlist;
1017 struct Note *n;
1018 int trash = 0;
1019 void *regexp;
1020 char *string;
1021 CHECKDB(NULL);
1022
1023 if (pattern == (char *)NULL || strlen(pattern) == 0 ||
1024 engine == (struct NoteEngine *)NULL ||
1025 engine->recompile == (NEInitFunc)NULL ||
1026 engine->reexec == (NECompareFunc)NULL) {
1027 return NULL;
1028 }
1029 oldlist = HeldNotes(dbid,token);
1030 if (token != NULL && oldlist == NULL) {
1031 return NULL;
1032 }
1033 if (oldlist == NULL) {
1034 oldlist = GetNotes(dbid,NOTESWILD,NOTESWILD,NOTESWILD,NOTESWILD,nd_wild);
1035 trash = 1;
1036 }
1037 if (oldlist == NULL) {
1038 return NULL;
1039 }
1040 if (gl_length(oldlist)==0) {
1041 if (trash) {
1042 gl_destroy(oldlist);
1043 }
1044 return NULL;
1045 }
1046 result = gl_create(10);
1047 regexp = engine->recompile(engine->reinterp,pattern);
1048 if (regexp == NULL) {
1049 if (trash) {
1050 gl_destroy(oldlist);
1051 }
1052 return result;
1053 }
1054 len = gl_length(oldlist);
1055 for (; len > 0; len--) {
1056 n = (struct Note *)gl_fetch(oldlist,len);
1057 if (n == NULL || GetNoteEnum(n) == nd_vlist) {
1058 continue;
1059 }
1060 string = (char *)BCS(GetNoteText(n));
1061 if (string == NULL) {
1062 continue;
1063 }
1064 switch (engine->reexec(engine->reinterp,regexp,string,string)) {
1065 case 1:
1066 gl_append_ptr(result,n);
1067 break;
1068 case 0:
1069 case -1:
1070 default:
1071 break;
1072 }
1073 }
1074 if (trash) {
1075 gl_destroy(oldlist);
1076 }
1077 return result;
1078 }
1079
1080 struct NoteEngine *NotesCreateEngine(void *ned,
1081 NEInitFunc neif,
1082 NECompareFunc necf)
1083 {
1084 struct NoteEngine *ne;
1085 ne = ASC_NEW(struct NoteEngine);
1086 if (neif == (NEInitFunc)NULL || necf == (NECompareFunc)NULL) {
1087 return (struct NoteEngine *)NULL;
1088 }
1089 if (ne == (struct NoteEngine *)NULL) {
1090 return (struct NoteEngine *)NULL;
1091 }
1092 ne->enginekey = ENGINEMAGIC;
1093 ne->reinterp = ned;
1094 ne->recompile = neif;
1095 ne->reexec = necf;
1096 return ne;
1097 }
1098
1099 void NotesDestroyEngine(struct NoteEngine *e)
1100 {
1101 if (e != NULL && e->enginekey == ENGINEMAGIC ) {
1102 e->enginekey = -1;
1103 ascfree(e);
1104 }
1105 }

john.pye@anu.edu.au
ViewVC Help
Powered by ViewVC 1.1.22