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

Contents of /trunk/ascend/compiler/notate.c

Parent Directory Parent Directory | Revision Log Revision Log


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

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