1 /*  Part of XPCE --- The SWI-Prolog GUI toolkit
2 
3     Author:        Jan Wielemaker and Anjo Anjewierden
4     E-mail:        jan@swi.psy.uva.nl
5     WWW:           http://www.swi.psy.uva.nl/projects/xpce/
6     Copyright (c)  1985-2002, University of Amsterdam
7     All rights reserved.
8 
9     Redistribution and use in source and binary forms, with or without
10     modification, are permitted provided that the following conditions
11     are met:
12 
13     1. Redistributions of source code must retain the above copyright
14        notice, this list of conditions and the following disclaimer.
15 
16     2. Redistributions in binary form must reproduce the above copyright
17        notice, this list of conditions and the following disclaimer in
18        the documentation and/or other materials provided with the
19        distribution.
20 
21     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22     "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23     LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24     FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25     COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26     INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27     BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29     CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30     LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31     ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32     POSSIBILITY OF SUCH DAMAGE.
33 */
34 
35 #include <h/kernel.h>
36 #include "../unx/proto.h"		/* file operations */
37 
38 forwards Cell	newCell(Chain, Any);
39 forwards Cell	previousCell(Chain, Cell);
40 static status	deleteCurrentChain(Chain ch);
41 static Int	getCellIndexChain(Chain ch, Cell c);
42 
43 #define ChangedChain(ch, op, ctx) \
44 	if ( onFlag(ch, F_INSPECT) && notNil(ClassChain->changed_messages) ) \
45 	  changedObject(ch, op, ctx, EAV)
46 
47 /* (JW)	Class chain is not a truely object oriented class as its internal
48 	representation as cell is no class.  assign() is used such that
49 	reference counts to other objects are kept, most internal
50 	assignments are done with '='.
51  */
52 
53 static Cell
newCell(Chain ch,register Any value)54 newCell(Chain ch, register Any value)
55 { Cell cell;
56 
57   cell = alloc(sizeof(struct cell));
58   cell->value = NIL;
59   cell->next  = NIL;
60   assignField((Instance) ch, &cell->value, value);
61 
62   return cell;
63 }
64 
65 
66 static void
freeCell(Chain ch,Cell cell)67 freeCell(Chain ch, Cell cell)
68 { assignField((Instance) ch, &cell->value, NIL);
69 
70   unalloc(sizeof(struct cell), cell);
71 }
72 
73 
74 static Cell
previousCell(Chain ch,register Cell next)75 previousCell(Chain ch, register Cell next)
76 { register Cell cell;
77 
78   for_cell(cell, ch)
79     if (cell->next == next)
80       return cell;
81   fail;
82 }
83 
84 
85 status
initialiseChainv(Chain ch,int argc,Any * argv)86 initialiseChainv(Chain ch, int argc, Any *argv)
87 { int i;
88 
89   assign(ch, size, ZERO);
90   ch->current = ch->head = ch->tail = NIL;
91   for(i=0; i<argc; i++)
92     appendChain(ch, argv[i]);
93 
94   succeed;
95 }
96 
97 
98 static Chain
getConvertChain(Any ctx,Vector v)99 getConvertChain(Any ctx, Vector v)
100 { Chain ch = answerObject(ClassChain, EAV);
101   int n = valInt(v->size);
102   Any *e = v->elements;
103 
104   for( ; --n >= 0; e++ )
105   { appendChain(ch, *e);
106   }
107 
108   answer(ch);
109 }
110 
111 
112 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
113 Load/store a chain on a file. Format:
114 
115 <chain>		::= {<cell>} 'X'
116 
117 <cell>		::= 'e' <object>	(cell holding <object>)
118 		  | 'E' <object>	(`current' cell holding <object>)
119 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
120 
121 static status
storeChain(Chain ch,FileObj file)122 storeChain(Chain ch, FileObj file)
123 { Cell cell;
124 
125   TRY(storeSlotsObject(ch, file));
126   for_cell(cell, ch)
127   { storeCharFile(file, cell == ch->current ? 'E' : 'e');
128     TRY( storeObject(cell->value, file) );
129   }
130   storeCharFile(file, 'X');
131 
132   succeed;
133 }
134 
135 static status
loadChain(Chain ch,IOSTREAM * fd,ClassDef def)136 loadChain(Chain ch, IOSTREAM *fd, ClassDef def)
137 { Any obj;
138   Cell current;
139   char c;
140 
141   if ( restoreVersion != 2 )
142     TRY(loadSlotsObject(ch, fd, def));
143 
144   current = ch->current = ch->head = ch->tail = NIL;
145   assign(ch, size, ZERO);
146 
147   for(;;)
148     switch( c=Sgetc(fd) )
149     { case 'e':
150       case 'E':
151 	  TRY( obj=loadObject(fd) );
152 	  appendChain(ch, obj);
153 	  if ( c == 'E' )
154 	    current = ch->tail;
155 	  continue;
156       case 'X':
157 	  ch->current = current;
158 	  succeed;
159       default:
160 	  errorPce(LoadFile, NAME_illegalCharacter,
161 		   toInt(c), toInt(Stell(fd)));
162     }
163 }
164 
165 
166 static status
unlinkChain(Chain ch)167 unlinkChain(Chain ch)
168 { return clearChain(ch);
169 }
170 
171 
172 static status
cloneChain(Chain ch,Chain clone)173 cloneChain(Chain ch, Chain clone)
174 { Cell cell;
175 
176   clonePceSlots(ch, clone);
177   clone->current = clone->head = clone->tail = NIL;
178 
179   for_cell(cell, ch)
180   { appendChain(clone, getClone2Object(cell->value));
181     if ( ch->current == cell )
182       clone->current = clone->tail;
183   }
184 
185   assign(clone, size, ch->size);
186 
187   succeed;
188 }
189 
190 
191 status
clearChain(Chain ch)192 clearChain(Chain ch)
193 { Cell p, q;
194 
195   for_cell_save(p, q, ch)
196   { ch->head = q;
197     freeCell(ch, p);
198   }
199   ch->head = ch->tail = ch->current = NIL;
200   assign(ch, size, ZERO);
201   ChangedChain(ch, NAME_clear, EAV);
202 
203   succeed;
204 }
205 
206 
207 static status
truncateChain(Chain ch,Int to)208 truncateChain(Chain ch, Int to)
209 { int n = valInt(to);
210   int i = 0;
211   Cell p, q;
212 
213   if ( n <= 0 )
214     return clearChain(ch);
215 
216   for_cell_save(p, q, ch)
217   { if ( i == n-1 )
218     { p->next = NIL;
219       ch->tail = p;
220       assign(ch, size, to);
221       ChangedChain(ch, NAME_truncate, to);
222     } else if ( i >= n )
223     { if ( ch->current == p )
224 	ch->current = NIL;
225 
226       freeCell(ch, p);
227     }
228 
229     i++;
230   }
231 
232   succeed;
233 }
234 
235 
236 Int
getSizeChain(Chain ch)237 getSizeChain(Chain ch)
238 { answer(ch->size);
239 }
240 
241 
242 status
prependChain(register Chain ch,Any obj)243 prependChain(register Chain ch, Any obj)
244 { Cell cell;
245 
246   cell = newCell(ch, obj);
247 
248   if (isNil(ch->head))
249     ch->head = ch->tail = cell;
250   else
251     cell->next = ch->head,
252     ch->head = cell;
253 
254   assign(ch, size, inc(ch->size));
255   ChangedChain(ch, NAME_insert, ONE);
256 
257   succeed;
258 }
259 
260 
261 status
appendChain(register Chain ch,Any obj)262 appendChain(register Chain ch, Any obj)
263 { Cell cell;
264 
265   cell = newCell(ch, obj);
266 
267   if (isNil(ch->head))
268   { ch->head = ch->tail = cell;
269   } else
270   { ch->tail->next = cell;
271     ch->tail = cell;
272   }
273 
274   assign(ch, size, inc(ch->size));
275   ChangedChain(ch, NAME_insert, getSizeChain(ch));
276 
277   succeed;
278 }
279 
280 
281 status
addChain(register Chain ch,Any obj)282 addChain(register Chain ch, Any obj)
283 { if ( !memberChain(ch, obj) )
284     return prependChain(ch, obj);
285 
286   succeed;
287 }
288 
289 
290 status
insertChain(Chain ch,Any obj)291 insertChain(Chain ch, Any obj)
292 { Cell cell, prev, current = ch->current;
293 
294   if ( current == ch->head )
295     return prependChain(ch, obj);
296   if ( isNil(current) )
297     return appendChain(ch, obj);
298 
299   cell = newCell(ch, obj);
300   prev = previousCell(ch, current);
301   prev->next = cell;
302   cell->next = current;
303   ch->current = cell;
304 
305   assign(ch, size, inc(ch->size));
306   ChangedChain(ch, NAME_insert, getCellIndexChain(ch, cell));
307 
308   succeed;
309 }
310 
311 
312 status
insertAfterChain(Chain ch,Any obj,Any obj2)313 insertAfterChain(Chain ch, Any obj, Any obj2)
314 { int i = 1;
315   Cell cell;
316 
317   if ( isNil(obj2) )
318     return prependChain(ch, obj);
319 
320   for_cell(cell, ch)
321   { if ( cell->value == obj2 )
322     { if ( ch->tail == cell )
323       { return appendChain(ch, obj);
324       } else
325       { Cell c2 = newCell(ch, obj);
326 
327 	c2->next = cell->next;
328 	cell->next = c2;
329 	assign(ch, size, inc(ch->size));
330 	ChangedChain(ch, NAME_insert, toInt(i+1));
331 
332 	succeed;
333       }
334     }
335 
336     i++;
337   }
338 
339   fail;
340 }
341 
342 
343 status
insertBeforeChain(Chain ch,Any obj,Any obj2)344 insertBeforeChain(Chain ch, Any obj, Any obj2)
345 { int i = 1;
346   Cell cell, prev = NIL;
347 
348   for_cell(cell, ch)
349   { if ( cell->value == obj2 )
350     { if ( isNil(prev) )
351       { return prependChain(ch, obj);
352       } else
353       { Cell c2 = newCell(ch, obj);
354 
355 	c2->next = prev->next;
356 	prev->next = c2;
357 	assign(ch, size, inc(ch->size));
358 	ChangedChain(ch, NAME_insert, toInt(i));
359 
360 	succeed;
361       }
362     }
363 
364     prev = cell;
365     i++;
366   }
367 
368   return appendChain(ch, obj);
369 }
370 
371 
372 static Cell
findCellChain(Chain ch,Any obj,int * idx)373 findCellChain(Chain ch, Any obj, int *idx)
374 { Cell cell;
375   int i=1;
376 
377   for_cell(cell, ch)
378   { if ( cell->value == obj )
379     { if ( idx )
380 	*idx = i;
381       return cell;
382     }
383     i++;
384   }
385 
386   return NULL;
387 }
388 
389 
390 status
swapChain(Chain ch,Any obj1,Any obj2)391 swapChain(Chain ch, Any obj1, Any obj2)
392 { Cell c1, c2;
393   int i1, i2;
394 
395   if ( !(c1=findCellChain(ch, obj1, &i1)) ||
396        !(c2=findCellChain(ch, obj2, &i2)) )
397     fail;
398 
399   c2->value = obj1;
400   c1->value = obj2;
401 
402   ChangedChain(ch, NAME_cell, toInt(i1));
403   ChangedChain(ch, NAME_cell, toInt(i2));
404 
405   succeed;
406 }
407 
408 
409 status
deleteHeadChain(Chain ch)410 deleteHeadChain(Chain ch)
411 { EXISTS(ch->head);
412 
413   return deleteCellChain(ch, ch->head);
414 }
415 
416 
417 static status
deleteTailChain(Chain ch)418 deleteTailChain(Chain ch)
419 { EXISTS(ch->tail);
420 
421   return deleteCellChain(ch, ch->tail);
422 }
423 
424 
425 status
deleteChain(Chain ch,register Any obj)426 deleteChain(Chain ch, register Any obj)
427 { register Cell cell, p;
428   int i;
429 
430   EXISTS(ch->head);
431 
432   if ( notNil(ch->current) && ch->current->value == obj )
433     ch->current = NIL;
434 
435   if (ch->head == ch->tail)
436   { Cell head = ch->head;
437 
438     if ( head->value != obj )
439       fail;
440     ch->head = ch->tail = NIL;
441     freeCell(ch, head);
442     assign(ch, size, ZERO);
443     ChangedChain(ch, NAME_clear, EAV);
444     succeed;
445   }
446 
447   if (ch->head->value == obj)
448   { Cell head = ch->head;
449 
450     ch->head = head->next;
451     freeCell(ch, head);
452     assign(ch, size, dec(ch->size));
453     ChangedChain(ch, NAME_delete, ONE);
454     succeed;
455   }
456 
457   for(p=ch->head, cell=p->next, i=2;
458       notNil(cell);
459       p=cell, cell=cell->next, i++)
460   { if (cell->value == obj)
461     { p->next = cell->next;
462       if (cell == ch->tail)
463 	ch->tail = p;
464       freeCell(ch, cell);
465       assign(ch, size, dec(ch->size));
466       ChangedChain(ch, NAME_delete, toInt(i));
467       succeed;
468     }
469   }
470 
471   fail;
472 }
473 
474 
475 static status
deleteCurrentChain(Chain ch)476 deleteCurrentChain(Chain ch)
477 { if ( notNil(ch->current) )
478     return deleteCellChain(ch, ch->current);
479 
480   succeed;
481 }
482 
483 
484 status
deleteCellChain(Chain ch,Cell cell)485 deleteCellChain(Chain ch, Cell cell)
486 { Cell prev;
487   Int i = ONE;
488 
489   if ( cell == ch->head  && ch->head == ch->tail )
490   { Cell head = ch->head;
491 
492     ch->head = ch->tail = ch->current = NIL;
493     freeCell(ch, head);
494     ChangedChain(ch, NAME_clear, EAV);
495     assign(ch, size, ZERO);
496 
497     succeed;
498   }
499 
500   if (cell == ch->head)
501   { ch->head = cell->next;
502   } else
503   { if ( notNil(ClassChain->changed_messages) )
504       i = getCellIndexChain(ch, cell);
505     prev = previousCell(ch, cell);
506     prev->next = cell->next;
507     if (cell == ch->tail)
508       ch->tail = prev;
509   }
510   if ( cell == ch->current )
511     ch->current = NIL;
512   freeCell(ch, cell);
513   assign(ch, size, dec(ch->size));
514   ChangedChain(ch, NAME_delete, i);
515 
516   succeed;
517 }
518 
519 
520 static status
deleteAllChain(Chain ch,Any obj)521 deleteAllChain(Chain ch, Any obj)
522 { while( deleteChain(ch, obj) )
523     ;					/* can be more efficient */
524 
525   succeed;
526 }
527 
528 
529 status
memberChain(Chain ch,Any obj)530 memberChain(Chain ch, Any obj)
531 { register Cell cell;
532 
533   for_cell(cell, ch)
534   { if ( cell->value == obj )
535       succeed;
536   }
537   fail;
538 }
539 
540 
541 static status
currentChain(Chain ch,Any obj)542 currentChain(Chain ch, Any obj)
543 { if ( isNil(obj) )
544   { ch->current = NIL;
545     succeed;
546   } else
547   { Cell cell;
548 
549     for_cell(cell, ch)
550     { if ( cell->value == obj )
551       { ch->current = cell;
552 	succeed;
553       }
554     }
555     fail;
556   }
557 }
558 
559 
560 static status
currentNoChain(Chain ch,Int index)561 currentNoChain(Chain ch, Int index)
562 { register Cell cell;
563   register int i = valInt(index);
564 
565   if (i == 0)
566   { ch->current = NIL;
567     succeed;
568   }
569 
570   for_cell(cell, ch)
571   { if (--i < 1)
572     { ch->current = cell;
573       succeed;
574     }
575   }
576   fail;
577 }
578 
579 
580 static Int
getCurrentNoChain(Chain ch)581 getCurrentNoChain(Chain ch)
582 { Cell cell;
583   int n;
584 
585   if (isNil(ch->current))
586     fail;
587 
588   for(n=1, cell=ch->head; cell != ch->current; cell=cell->next)
589     n++;
590 
591   answer(toInt(n));
592 }
593 
594 
595 static Any
getCurrentChain(Chain ch)596 getCurrentChain(Chain ch)
597 { EXISTS(ch->current);
598   answer(ch->current->value);
599 }
600 
601 
602 Any
getNextChain(Chain ch,Any val)603 getNextChain(Chain ch, Any val)
604 { if ( isDefault(val) )			/* old code */
605   { Any result;
606 
607     EXISTS(ch->current);
608     result = ch->current->value;
609     ch->current = ch->current->next;
610 
611     answer(result);
612   } else
613   { Cell cell;
614 
615     for_cell(cell, ch)
616     { if ( cell->value == val )
617       { if ( notNil(cell->next) )
618 	  answer(cell->next->value);
619 	break;
620       }
621     }
622 
623     fail;
624   }
625 }
626 
627 
628 Any
getPreviousChain(Chain ch,Any val)629 getPreviousChain(Chain ch, Any val)
630 { Cell cell;
631   Cell prev = NULL;
632 
633   for_cell(cell, ch)
634   { if ( cell->value == val )
635     { if ( prev )
636 	answer(prev->value);
637       fail;
638     }
639 
640     prev = cell;
641   }
642 
643   fail;
644 }
645 
646 
647 status
forAllChain(Chain ch,Code code,BoolObj safe)648 forAllChain(Chain ch, Code code, BoolObj safe)
649 { int i = 1;
650   Any av[2];
651 
652   if ( safe == OFF )
653   { Cell cell;
654 
655     for_cell(cell, ch)
656     { av[0] = cell->value;
657       av[1] = toInt(i++);
658       if ( !forwardCodev(code, 2, av) )
659 	fail;
660     }
661   } else
662   { Any obj;
663 
664     for_chain(ch, obj,
665 	      { av[0] = obj;
666 		av[1] = toInt(i++);
667 		if ( !forwardCodev(code, 2, av) )
668 		  fail;
669 	      });
670   }
671 
672   succeed;
673 }
674 
675 
676 status
forSomeChain(Chain ch,Code code,BoolObj safe)677 forSomeChain(Chain ch, Code code, BoolObj safe)
678 { Any av[2];
679   int i = 1;
680 
681   if ( safe == OFF )
682   { Cell cell;
683 
684     for_cell(cell, ch)
685     { av[0] = cell->value;
686       av[1] = toInt(i++);
687 
688       forwardCodev(code, 2, av);
689     }
690   } else
691   { Any obj;
692 
693     for_chain(ch, obj,
694 	      { av[0] = obj;
695 		av[1] = toInt(i++);
696 
697 		forwardCodev(code, 2, av);
698 	      });
699   }
700 
701   succeed;
702 }
703 
704 
705 Any
getFindChain(Chain ch,Code code)706 getFindChain(Chain ch, Code code)
707 { Cell cell;
708   Any av[2];
709   int i = 1;
710 
711   for_cell(cell, ch)
712   { av[0] = cell->value;
713     av[1] = toInt(i++);
714 
715     if ( forwardCodev(code, 2, av) )
716       answer(cell->value);
717   }
718 
719   fail;
720 }
721 
722 
723 Chain
getFindAllChain(Chain ch,Code code)724 getFindAllChain(Chain ch, Code code)
725 { Chain result = answerObject(ClassChain, EAV);
726   Cell cell;
727   Any av[2];
728   int i = 1;
729 
730   for_cell(cell, ch)
731   { av[0] = cell->value;
732     av[1] = toInt(i++);
733 
734     if ( forwardCodev(code, 2, av) )
735       appendChain(result, cell->value);
736   }
737 
738   answer(result);
739 }
740 
741 
742 static Chain
getMapChain(Chain ch,Function f)743 getMapChain(Chain ch, Function f)
744 { Chain result = answerObject(ClassChain, EAV);
745   Any av[2];
746   int i = 1;
747   Cell cell;
748 
749   for_cell(cell, ch)
750   { Any rval;
751 
752     av[0] = cell->value;
753     av[1] = toInt(i++);
754     if ( (rval = getForwardFunctionv(f, 2, av)) )
755       appendChain(result, rval);
756   }
757 
758   answer(result);
759 }
760 
761 
762 static status
findChain(Chain ch,Code code)763 findChain(Chain ch, Code code)
764 { Cell cell;
765   Any av[2];
766   int i = 1;
767 
768   for_cell(cell, ch)
769   { av[0] = cell->value;
770     av[1] = toInt(i++);
771 
772     if ( forwardCodev(code, 2, av) )
773     { ch->current = cell;
774       succeed;
775     }
776   }
777   fail;
778 }
779 
780 
781 status
mergeChain(Chain ch,Chain ch2)782 mergeChain(Chain ch, Chain ch2)
783 { register Cell cell;
784   register Cell tail = ch->tail;
785 
786   for_cell(cell, ch2)
787   { appendChain(ch, cell->value);
788     if ( cell == tail )			/* @ch ->merge @ch */
789       break;
790   }
791 
792   succeed;
793 }
794 
795 
796 static status
unionChain(Chain ch,Chain ch2)797 unionChain(Chain ch, Chain ch2)
798 { register Cell cell;
799 
800   for_cell(cell, ch2)
801   { if ( !memberChain(ch, cell->value) )
802       appendChain(ch, cell->value);
803   }
804   succeed;
805 }
806 
807 
808 static status
intersectionChain(Chain ch,Chain ch2)809 intersectionChain(Chain ch, Chain ch2)
810 { register Cell cell, c2;
811 
812   for_cell_save(cell, c2, ch)
813   { if ( !memberChain(ch2, cell->value) )
814       deleteCellChain(ch, cell);
815   }
816   succeed;
817 }
818 
819 
820 static status
subtractChain(Chain ch,Chain ch2)821 subtractChain(Chain ch, Chain ch2)
822 { Cell cell, c2;
823 
824   for_cell_save(cell, c2, ch)
825   { if ( memberChain(ch2, cell->value) )
826       deleteCellChain(ch, cell);
827   }
828   succeed;
829 
830 }
831 
832 
833 status
replaceChain(Chain ch,Any obj1,Any obj2)834 replaceChain(Chain ch, Any obj1, Any obj2)
835 { Cell cell;
836 
837   for_cell(cell, ch)
838   { if ( cell->value == obj1 )
839       cellValueChain(ch, PointerToInt(cell), obj2);
840   }
841 
842   succeed;
843 }
844 
845 
846 static status
intersectsChain(Chain ch,Chain ch2)847 intersectsChain(Chain ch, Chain ch2)
848 { Cell cell;
849 
850   for_cell(cell, ch)
851   { if ( memberChain(ch2, cell->value) )
852       succeed;
853   }
854 
855   fail;
856 }
857 
858 
859 static status
equalChain(Chain ch,Chain ch2)860 equalChain(Chain ch, Chain ch2)
861 { Cell c1, c2;
862 
863   if ( !instanceOfObject(ch2, ClassChain) )
864     fail;
865 
866   for(c1 = ch->head, c2 = ch2->head;
867       notNil(c1) && notNil(c2);
868       c1 = c1->next, c2 = c2->next)
869   { if ( c1->value != c2->value )
870       fail;
871   }
872 
873   if ( c1 == c2 )			/* should both be NIL */
874     succeed;
875 
876   fail;
877 }
878 
879 
880 status
emptyChain(Chain ch)881 emptyChain(Chain ch)
882 { if ( isNil(ch) || isNil(ch->head) )
883     succeed;
884 
885   fail;
886 }
887 
888 
889 Chain
getCopyChain(Chain ch)890 getCopyChain(Chain ch)
891 { if ( notNil(ch) )
892   { Chain r = answerObject(classOfObject(ch), EAV); /* Same class */
893     Cell cell;
894 
895     for_cell(cell, ch)
896       appendChain(r, cell->value);
897 
898     answer(r);
899   }
900 
901   answer(NIL);
902 }
903 
904 
905 static Chain
getMergeChain(Chain ch,Chain ch2)906 getMergeChain(Chain ch, Chain ch2)
907 { register Cell cell;
908   Chain r;
909 
910   r = answerObject(ClassChain, EAV);
911 
912   for_cell(cell, ch)
913     appendChain(r, cell->value);
914   for_cell(cell, ch2)
915     appendChain(r, cell->value);
916 
917   answer(r);
918 }
919 
920 
921 static Chain
getUnionChain(Chain ch,Chain ch2)922 getUnionChain(Chain ch, Chain ch2)
923 { register Cell cell;
924   Chain r;
925 
926   r = answerObject(classOfObject(ch), EAV);
927 
928   for_cell(cell, ch)
929   { if (memberChain(r, cell->value) != FAIL)
930       continue;
931     appendChain(r, cell->value);
932   }
933 
934   for_cell(cell, ch2)
935   { if (memberChain(r, cell->value) != FAIL)
936       continue;
937     appendChain(r, cell->value);
938   }
939 
940   answer(r);
941 }
942 
943 
944 static int
forwardCompareCode(Code c,Any o1,Any o2)945 forwardCompareCode(Code c, Any o1, Any o2)
946 { Any argv[2];
947 
948   argv[0] = o1;
949   argv[1] = o2;
950 
951   if ( isFunction(c) )
952   { Any r;
953 
954     withArgs(2, argv, r = getExecuteFunction((Function)c));
955 
956     if ( equalName(r, NAME_smaller) || (isInteger(r) && valInt(r) < 0) )
957       return -1;
958     else if ( r == NAME_equal || r == ZERO )
959       return 0;
960     else
961       return 1;
962   } else
963   { status r;
964 
965     withArgs(2, argv, r = executeCode(c));
966 
967     return r ? -1 : 1;
968   }
969 }
970 
971 
972 int
qsortCompareObjects(const void * o1,const void * o2)973 qsortCompareObjects(const void *o1, const void *o2)
974 { int rval = forwardCompareCode(qsortCompareCode, *((Any *) o1), *((Any *)o2));
975 
976   DEBUG(NAME_sort, Cprintf("compare %s %s --> %d\n",
977 			   pp(*((Any *)o1)), pp(*((Any *)o2)), rval));
978 
979   return qsortReverse ? -rval : rval;
980 }
981 
982 
983 status
sortChain(Chain ch,Code msg,BoolObj unique)984 sortChain(Chain ch, Code msg, BoolObj unique)
985 { if ( isDefault(msg) )
986     return sortNamesChain(ch, unique);
987   else
988   { int size = valInt(ch->size);
989     Any *buf = (Any *)alloca(sizeof(Any) * size);
990     Cell cell;
991     int i;
992     Code old = qsortCompareCode;		/* make reentrant */
993 
994     qsortCompareCode = msg;
995 
996     i = 0;
997     for_cell(cell, ch)
998     { buf[i] = cell->value;
999       if ( isObject(buf[i]) )
1000 	addRefObj(buf[i]);
1001       i++;
1002     }
1003     qsort(buf, size, sizeof(Any), qsortCompareObjects);
1004     clearChain(ch);
1005     for(i=0; i<size; i++)
1006     { if ( unique != ON ||
1007 	   i == 0 ||
1008 	   qsortCompareObjects(&buf[i-1], &buf[i]) != 0 )
1009 	appendChain(ch, buf[i]);
1010     }
1011     for(i=0; i<size; i++)
1012     { if ( isObject(buf[i]) )
1013       {	delRefObj(buf[i]);
1014 	freeableObj(buf[i]);
1015       }
1016     }
1017 
1018     qsortCompareCode = old;
1019     succeed;
1020   }
1021 }
1022 
1023 typedef struct
1024 { CharArray	name;			/* name of object */
1025   Any		object;			/* the object */
1026 } scell, *Scell;
1027 
1028 
1029 static int
compare_names(const void * p1,const void * p2)1030 compare_names(const void *p1, const void *p2)
1031 { Scell s1 = (Scell)p1;
1032   Scell s2 = (Scell)p2;
1033 
1034   return str_cmp(&s1->name->data, &s2->name->data);
1035 }
1036 
1037 
1038 status
sortNamesChain(Chain ch,BoolObj unique)1039 sortNamesChain(Chain ch, BoolObj unique)
1040 { int size = valInt(ch->size);
1041   Scell buf = (Scell)alloca(sizeof(scell) * size);
1042   Cell cell;
1043   int i;
1044   AnswerMark m;
1045 
1046   markAnswerStack(m);
1047 
1048   i = 0;
1049   for_cell(cell, ch)
1050   { buf[i].object = cell->value;
1051     if ( isObject(buf[i].object) ) addRefObj(buf[i].object);
1052     if ( instanceOfObject(cell->value, ClassCharArray) )
1053       buf[i].name = cell->value;
1054     else
1055       buf[i].name = getv(cell->value, NAME_printName, 0, NULL);
1056 
1057     i++;
1058   }
1059   qsort(buf, size, sizeof(scell), compare_names);
1060   clearChain(ch);
1061   for(i=0; i<size; i++)
1062   { if ( unique != ON ||
1063 	 i == 0 ||
1064 	 compare_names(&buf[i-1], &buf[i]) != 0 )
1065       appendChain(ch, buf[i].object);
1066   }
1067   for(i=0; i<size; i++)
1068   { if ( isObject(buf[i].object) )
1069     { delRefObj(buf[i].object);
1070       freeableObj(buf[i].object);
1071     }
1072   }
1073 
1074   rewindAnswerStack(m, NIL);
1075 
1076   succeed;
1077 }
1078 
1079 
1080 Tuple
getCompleteNameChain(Chain ch,CharArray prefix,Function map,BoolObj ignore_case)1081 getCompleteNameChain(Chain ch, CharArray prefix, Function map,
1082 		     BoolObj ignore_case)
1083 { Chain matches = NIL;
1084   LocalString(common, prefix->data.s_iswide, LINESIZE);
1085   Cell cell;
1086 
1087   for_cell(cell, ch)
1088   { Any obj = cell->value;
1089     string prt;
1090     status rval;
1091 					/* get printable representation */
1092     if ( isNil(map) )
1093       rval = toString(obj, &prt);
1094     else if ( isDefault(map) )
1095       rval = toString(getv(obj, NAME_printName, 0, NULL), &prt);
1096     else
1097       rval = toString(getForwardFunctionv(map, 1, &obj), &prt);
1098 
1099     if ( rval )
1100     { if ( ((ignore_case == ON && str_icase_prefix(&prt, &prefix->data)) ||
1101 	    (ignore_case != ON && str_prefix(&prt, &prefix->data))) &&
1102 	   prt.s_size < LINESIZE ) /* hit */
1103       { if ( isNil(matches) )
1104 	{ matches = answerObject(ClassChain, obj, EAV);
1105 	  str_cpy(common, &prt);
1106 	} else
1107 	{ if ( ignore_case == ON )
1108 	    common->s_size = str_icase_common_length(&prt, common);
1109 	  else
1110 	    common->s_size = str_common_length(&prt, common);
1111 
1112 	  appendChain(matches, obj);
1113 	}
1114       }
1115     } else
1116     { errorPce(obj, NAME_noPrintName);
1117       fail;
1118     }
1119   }
1120 
1121   if ( notNil(matches) )
1122   { str_pad(common);
1123     answer(answerObject(ClassTuple, matches, StringToString(common), EAV));
1124   } else
1125     fail;
1126 }
1127 
1128 
1129 Chain
getIntersectionChain(Chain ch,Chain ch2)1130 getIntersectionChain(Chain ch, Chain ch2)
1131 { register Cell cell;
1132   Chain r;
1133 
1134   r = answerObject(classOfObject(ch), EAV);
1135 
1136   for_cell(cell, ch)
1137   { if (memberChain(ch2, cell->value) != FAIL)
1138       appendChain(r, cell->value);
1139   }
1140 
1141   answer(r);
1142 }
1143 
1144 
1145 Any
getHeadChain(Chain ch)1146 getHeadChain(Chain ch)
1147 { EXISTS(ch->head);
1148 
1149   answer(ch->head->value);
1150 }
1151 
1152 
1153 Any
getDeleteHeadChain(Chain ch)1154 getDeleteHeadChain(Chain ch)
1155 { Any result;
1156 
1157   EXISTS(ch->head);
1158   result = ch->head->value;
1159   if ( isObject(result) && !isProtectedObj(result) )
1160   { if ( isFreedObj(result) )
1161     { deleteHeadChain(ch);
1162       errorPce(ch, NAME_freedObject, result);
1163       fail;
1164     }
1165     addCodeReference(result);
1166     deleteHeadChain(ch);
1167     delCodeReference(result);
1168     pushAnswerObject(result);
1169   } else
1170     deleteHeadChain(ch);
1171 
1172   answer(result);
1173 }
1174 
1175 
1176 Any
getTailChain(Chain ch)1177 getTailChain(Chain ch)
1178 { EXISTS(ch->tail);
1179 
1180   answer(ch->tail->value);
1181 }
1182 
1183 
1184 static Chain
getSubChain(Chain ch,Int start,Int end)1185 getSubChain(Chain ch, Int start, Int end)
1186 { int f, t;
1187   Chain r = answerObject(classOfObject(ch), EAV);
1188   int i = 0;
1189   Cell cell;
1190 
1191   if ( isDefault(end) )
1192     end = ch->size;
1193   f = valInt(start);
1194   t = valInt(end);
1195 
1196   for_cell(cell, ch)
1197   { if ( i>=f )
1198     { if ( i >= t )
1199 	break;
1200 
1201       appendChain(r, cell->value);
1202     }
1203 
1204     i++;
1205   }
1206 
1207   answer(r);
1208 }
1209 
1210 
1211 
1212 static status
uniqueChain(Chain ch)1213 uniqueChain(Chain ch)
1214 { Cell cell, cell2;
1215 
1216   for_cell(cell, ch)
1217   { Cell next;
1218 
1219     for (cell2=cell->next; notNil(cell2); cell2=next)
1220     { next = cell2->next;
1221 
1222       if (cell2->value == cell->value)
1223 	deleteCellChain(ch, cell2);
1224     }
1225   }
1226   succeed;
1227 }
1228 
1229 
1230 status
moveBeforeChain(Chain ch,Any obj1,Any obj2)1231 moveBeforeChain(Chain ch, Any obj1, Any obj2)
1232 { Cell cell;
1233 
1234   if ( obj1 == obj2 )
1235     fail;
1236 
1237   TRY( currentChain(ch, obj2) );
1238   cell = ch->current;
1239   addCodeReference(obj1);
1240   if ( !deleteChain(ch, obj1) )
1241   { delCodeReference(obj1);
1242     fail;
1243   }
1244   ch->current = cell;
1245   insertChain(ch, obj1);
1246   delCodeReference(obj1);
1247 
1248   succeed;
1249 }
1250 
1251 
1252 status
moveAfterChain(Chain ch,Any obj1,Any obj2)1253 moveAfterChain(Chain ch, Any obj1, Any obj2)
1254 { Cell cell;
1255   int is_obj = isObject(obj1);
1256   status rval;
1257 
1258   if ( notDefault(obj2) && notNil(obj2) )
1259   { if ( obj1 == obj2 || !currentChain(ch, obj2) )
1260       fail;
1261     cell = ch->current->next;
1262     if ( notNil(cell) && cell->value == obj1 )
1263       succeed;				/* already true */
1264   } else
1265   { if ( obj1 == getHeadChain(ch) )
1266       succeed;
1267     cell = ch->head;
1268   }
1269 
1270   if ( is_obj )
1271     addCodeReference(obj1);
1272 
1273   if ( deleteChain(ch, obj1) )
1274   { ch->current = cell;
1275     insertChain(ch, obj1);
1276 
1277     rval = SUCCEED;
1278   } else
1279     rval = FAIL;
1280 
1281   if ( is_obj )
1282     delCodeReference(obj1);
1283 
1284   return rval;
1285 }
1286 
1287 
1288 status
beforeChain(Chain ch,Any obj1,Any obj2)1289 beforeChain(Chain ch, Any obj1, Any obj2)
1290 { Cell cell;
1291   int i1 = 0, i2 = 0, i=1;
1292 
1293   for_cell(cell, ch)
1294   { if ( cell->value == obj1 )
1295       i1 = i;
1296     if ( cell->value == obj2 )
1297       i2 = i;
1298 
1299     if ( i1 && i2 )
1300       return (i1 < i2) ? SUCCEED : FAIL;
1301 
1302     i++;
1303   }
1304 
1305   return errorPce(NAME_noMember, !i1 ? obj1 : obj2);
1306 }
1307 
1308 
1309 static status
afterChain(Chain ch,Any obj1,Any obj2)1310 afterChain(Chain ch, Any obj1, Any obj2)
1311 { Cell cell;
1312   int i1 = 0, i2 = 0, i=1;
1313 
1314   for_cell(cell, ch)
1315   { if ( cell->value == obj1 )
1316       i1 = i;
1317     if ( cell->value == obj2 )
1318       i2 = i;
1319 
1320     if ( i1 && i2 )
1321       return (i1 > i2) ? SUCCEED : FAIL;
1322 
1323     i++;
1324   }
1325 
1326   return errorPce(NAME_noMember, !i1 ? obj1 : obj2);
1327 }
1328 
1329 
1330 Any
getNth1Chain(Chain ch,Int index)1331 getNth1Chain(Chain ch, Int index)
1332 { register Cell cell;
1333   register int n = valInt(index);
1334 
1335   for_cell(cell, ch)
1336   { if (--n == 0)
1337       answer(cell->value);
1338   }
1339 
1340   fail;
1341 }
1342 
1343 
1344 static status
nth1Chain(Chain ch,Int index,Any value)1345 nth1Chain(Chain ch, Int index, Any value)
1346 { register Cell cell;
1347   register int n = valInt(index);
1348 
1349   for_cell(cell, ch)
1350   { if (--n == 0)
1351       return cellValueChain(ch, PointerToInt(cell), value);
1352   }
1353 
1354   fail;
1355 }
1356 
1357 
1358 Any
getNth0Chain(Chain ch,Int index)1359 getNth0Chain(Chain ch, Int index)
1360 { register Cell cell;
1361   register int n = valInt(index);
1362 
1363   for_cell(cell, ch)
1364   { if (n-- == 0)
1365       answer(cell->value);
1366   }
1367 
1368   fail;
1369 }
1370 
1371 
1372 static status
nth0Chain(Chain ch,Int index,Any value)1373 nth0Chain(Chain ch, Int index, Any value)
1374 { register Cell cell;
1375   register int n = valInt(index);
1376 
1377   for_cell(cell, ch)
1378   { if (n-- == 0)
1379       return cellValueChain(ch, PointerToInt(cell), value);
1380   }
1381 
1382   fail;
1383 }
1384 
1385 
1386 static Int
getHeadCellChain(Chain ch)1387 getHeadCellChain(Chain ch)
1388 { if ( notNil(ch->head) )
1389     answer(PointerToInt(ch->head));
1390   fail;
1391 }
1392 
1393 
1394 static Int
getNextCellChain(Chain ch,Int c)1395 getNextCellChain(Chain ch, Int c)
1396 { Cell cell = (Cell) IntToPointer(c);
1397 
1398   if ( notNil(cell->next) )
1399     answer(PointerToInt(cell->next));
1400 
1401   fail;
1402 }
1403 
1404 
1405 static Any
getCellValueChain(Chain ch,Int c)1406 getCellValueChain(Chain ch, Int c)
1407 { Cell cell = (Cell) IntToPointer(c);
1408 
1409   answer(cell->value);
1410 }
1411 
1412 
1413 status
cellValueChain(Chain ch,Int c,Any obj)1414 cellValueChain(Chain ch, Int c, Any obj)
1415 { Cell cell = (Cell) IntToPointer(c);
1416 
1417   if ( cell->value != obj )
1418   { assignField((Instance) ch, &cell->value, obj);
1419     ChangedChain(ch, NAME_cell, getCellIndexChain(ch, cell));
1420   }
1421 
1422   succeed;
1423 }
1424 
1425 
1426 Cell
getNth0CellChain(Chain ch,Int index)1427 getNth0CellChain(Chain ch, Int index)
1428 { register Cell cell;
1429   register int n = valInt(index);
1430 
1431   for_cell(cell, ch)
1432   { if ( n-- == 0 )
1433       return cell;
1434   }
1435 
1436   fail;
1437 }
1438 
1439 
1440 static Int
getCellIndexChain(Chain ch,Cell c)1441 getCellIndexChain(Chain ch, Cell c)
1442 { int i = 1;
1443   Cell cell;
1444 
1445   for_cell(cell, ch)
1446   { if ( cell == c )
1447       answer(toInt(i));
1448     i++;
1449   }
1450 
1451   fail;
1452 }
1453 
1454 
1455 Int
getIndexChain(Chain ch,Any obj)1456 getIndexChain(Chain ch, Any obj)
1457 { int n = 0;
1458   Cell cell;
1459 
1460   for_cell(cell, ch)
1461   { n++;
1462     if (cell->value == obj)
1463       answer(toInt(n));
1464   }
1465 
1466   fail;
1467 }
1468 
1469 
1470 Int
getArityChain(Chain ch)1471 getArityChain(Chain ch)
1472 { answer(getSizeChain(ch));
1473 }
1474 
1475 
1476 Any
getArgChain(Chain ch,Int arg)1477 getArgChain(Chain ch, Int arg)
1478 { answer(getNth1Chain(ch, arg));
1479 }
1480 
1481 
1482 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1483 Trapping changes to chains.
1484 
1485 The following elementary changes to a chain are recognised and forwarded:
1486       NAME_insert, Index:	Element is inserted at cell <Index>
1487       NAME_delete, Index:	Element at index <Index> is deleted
1488       NAME_cell,   Index:	Element at index <Index> changed value
1489       NAME_clear:		Chain has been cleared
1490 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
1491 
1492 static status
changedChain(Chain ch,Any * field)1493 changedChain(Chain ch, Any *field)
1494 { succeed;
1495 }
1496 
1497 		 /*******************************
1498 		 *	 CLASS DECLARATION	*
1499 		 *******************************/
1500 
1501 /* Type declaractions */
1502 
1503 static char *T_actionAcode_safeADboolD[] =
1504         { "action=code", "safe=[bool]" };
1505 static char *T_cellValue[] =
1506         { "cell_reference=int", "value=any" };
1507 static char *T_firstAany_secondAany[] =
1508         { "first=any", "second=any" };
1509 static char *T_indexAint_valueAany[] =
1510         { "index=int", "value=any" };
1511 static char *T_replace[] =
1512         { "old=any", "new=any" };
1513 static char *T_completeName[] =
1514         { "prefix=char_array", "extract_name=[function]*",
1515 	  "ignore_case=[bool]" };
1516 static char *T_moveAfter[] =
1517         { "value=any", "after=[any]" };
1518 static char *T_insertAfter[] =
1519         { "value=any", "after=any*" };
1520 static char *T_insertBefore[] =
1521         { "value=any", "before=any" };
1522 static char *T_moveBefore[] =
1523         { "value=any", "before=any" };
1524 static char *T_swap[] =
1525         { "value_1=any", "value_2=any" };
1526 static char *T_sort[] =
1527 	{ "compare=[code|function]", "unique=[bool]" };
1528 static char *T_gsub[] =
1529         { "start=int", "end=[int]" };
1530 
1531 /* Instance Variables */
1532 
1533 static vardecl var_chain[] =
1534 { IV(NAME_size, "int", IV_GET,
1535      NAME_cardinality, "Number of elements"),
1536   IV(NAME_head, "alien:Cell", IV_NONE,
1537      NAME_internal, "Pointer to first cell"),
1538   IV(NAME_tail, "alien:Cell", IV_NONE,
1539      NAME_internal, "Pointer to last cell"),
1540   IV(NAME_current, "alien:Cell", IV_NONE,
1541      NAME_internal, "Pointer to current cell")
1542 };
1543 
1544 /* Send Methods */
1545 
1546 static senddecl send_chain[] =
1547 { SM(NAME_initialise, 1, "member=any ...", initialiseChainv,
1548      DEFAULT, "Create a chain with initial elements"),
1549   SM(NAME_unlink, 0, NULL, unlinkChain,
1550      DEFAULT, "Clear the chain"),
1551   SM(NAME_empty, 0, NULL, emptyChain,
1552      NAME_cardinality, "Test if chain has no elements"),
1553   SM(NAME_cellValue, 2, T_cellValue, cellValueChain,
1554      NAME_cell, "Change value of cell"),
1555   SM(NAME_equal, 1, "chain", equalChain,
1556      NAME_compare, "Test if both chains have the same objects"),
1557   SM(NAME_current, 1, "value=any*", currentChain,
1558      NAME_current, "Make cell with `value' the current cell"),
1559   SM(NAME_currentNo, 1, "index=int", currentNoChain,
1560      NAME_current, "Set current cell to nth-1 (0: no current)"),
1561   SM(NAME_deleteCurrent, 0, NULL, deleteCurrentChain,
1562      NAME_current, "Delete current cell"),
1563   SM(NAME_find, 1, "test=code", findChain,
1564      NAME_current, "Set current to first cell accepted by code"),
1565   SM(NAME_insert, 1, "value=any", insertChain,
1566      NAME_current, "Insert argument before current"),
1567   SM(NAME_nth0, 2, T_indexAint_valueAany, nth0Chain,
1568      NAME_index, "Change content of nth (0-based) cell"),
1569   SM(NAME_nth1, 2, T_indexAint_valueAany, nth1Chain,
1570      NAME_index, "Change content of nth (1-based) cell"),
1571   SM(NAME_forAll, 2, T_actionAcode_safeADboolD, forAllChain,
1572      NAME_iterate, "Run code on all elements, demand acceptance ([safe])"),
1573   SM(NAME_forSome, 2, T_actionAcode_safeADboolD, forSomeChain,
1574      NAME_iterate, "Run code on all elements ([safe])"),
1575   SM(NAME_Append, 1, "value=any|function", appendChain,
1576      NAME_list, "Append argument to chain (not expanding obtainers)"),
1577   SM(NAME_append, 1, "value=any", appendChain,
1578      NAME_list, "Append argument to chain"),
1579   SM(NAME_clear, 0, NULL, clearChain,
1580      NAME_list, "Remove all elements from chain"),
1581   SM(NAME_truncate, 1, "keep=0..", truncateChain,
1582      NAME_list, "Keep the first N elements"),
1583   SM(NAME_delete, 1, "value=any", deleteChain,
1584      NAME_list, "Delete first occurrence of argument"),
1585   SM(NAME_deleteAll, 1, "value=any", deleteAllChain,
1586      NAME_list, "Delete all occurrences of argument"),
1587   SM(NAME_deleteHead, 0, NULL, deleteHeadChain,
1588      NAME_list, "Delete first element"),
1589   SM(NAME_deleteTail, 0, NULL, deleteTailChain,
1590      NAME_list, "Delete last element"),
1591   SM(NAME_insertAfter, 2, T_insertAfter, insertAfterChain,
1592      NAME_list, "Insert first after second object (@nil: prepend)"),
1593   SM(NAME_insertBefore, 2, T_insertBefore, insertBeforeChain,
1594      NAME_list, "Insert first before second object"),
1595   SM(NAME_merge, 1, "chain", mergeChain,
1596      NAME_list, "Append all elements from argument"),
1597   SM(NAME_prepend, 1, "value=any", prependChain,
1598      NAME_list, "Add argument as first element"),
1599   SM(NAME_replace, 2, T_replace, replaceChain,
1600      NAME_list, "Replace all occurrences"),
1601   SM(NAME_after, 2, T_firstAany_secondAany, afterChain,
1602      NAME_order, "Test if first argument is after second"),
1603   SM(NAME_before, 2, T_firstAany_secondAany, beforeChain,
1604      NAME_order, "Test if first argument is before second"),
1605   SM(NAME_moveAfter, 2, T_moveAfter, moveAfterChain,
1606      NAME_order, "Move 1st object just after second"),
1607   SM(NAME_moveBefore, 2, T_moveBefore, moveBeforeChain,
1608      NAME_order, "Move 1st object just before second"),
1609   SM(NAME_sort, 2, T_sort, sortChain,
1610      NAME_order, "Sort according to code (or name)"),
1611   SM(NAME_swap, 2, T_swap, swapChain,
1612      NAME_order, "Swap position of arguments"),
1613   SM(NAME_add, 1, "value=any", addChain,
1614      NAME_set, "Prepend object if not already ->member"),
1615   SM(NAME_intersection, 1, "chain", intersectionChain,
1616      NAME_set, "Delete elements not in argument"),
1617   SM(NAME_intersects, 1, "chain", intersectsChain,
1618      NAME_set, "Test if both chains have a common member"),
1619   SM(NAME_member, 1, "value=any", memberChain,
1620      NAME_set, "Test if argument is an element"),
1621   SM(NAME_subtract, 1, "chain", subtractChain,
1622      NAME_set, "Delete all elements in argument"),
1623   SM(NAME_union, 1, "chain", unionChain,
1624      NAME_set, "Append only new elements from argument"),
1625   SM(NAME_unique, 0, NULL, uniqueChain,
1626      NAME_set, "Remove all duplicates from chain")
1627 };
1628 
1629 /* Get Methods */
1630 
1631 static getdecl get_chain[] =
1632 { GM(NAME_cellValue, 1, "any", "cell_reference=int", getCellValueChain,
1633      NAME_cell, "Value for cell-reference"),
1634   GM(NAME_headCell, 0, "int", NULL, getHeadCellChain,
1635      NAME_cell, "Reference (int) to first cell"),
1636   GM(NAME_nextCell, 1, "cell_reference=int", "cell_reference=int", getNextCellChain,
1637      NAME_cell, "Reference to next cell at reference"),
1638   GM(NAME_completeName, 3, "tuple", T_completeName, getCompleteNameChain,
1639      NAME_completion, "New tuple with matches and common prefix"),
1640   GM(NAME_copy, 0, "chain", NULL, getCopyChain,
1641      NAME_copy, "New chain with same elements"),
1642   GM(NAME_convert, 1, "chain", "vector", getConvertChain,
1643      DEFAULT, "Convert array to linked list"),
1644   GM(NAME_current, 0, "any", NULL, getCurrentChain,
1645      NAME_current, "Value for the current cell"),
1646   GM(NAME_currentNo, 0, "int", NULL, getCurrentNoChain,
1647      NAME_current, "Index number of current cell (1-based)"),
1648   GM(NAME_index, 1, "index=int", "value=any", getIndexChain,
1649      NAME_index, "Index (1-based) at which argument is"),
1650   GM(NAME_next, 1, "any", "[any]", getNextChain,
1651      NAME_index, "Element after given value"),
1652   GM(NAME_nth0, 1, "value=any", "index=int", getNth0Chain,
1653      NAME_index, "Element at 0-based index"),
1654   GM(NAME_nth1, 1, "value=any", "index=int", getNth1Chain,
1655      NAME_index, "Element at 1-based index"),
1656   GM(NAME_previous, 1, "any", "[any]", getPreviousChain,
1657      NAME_index, "Element before given value"),
1658   GM(NAME_find, 1, "any", "test=code", getFindChain,
1659      NAME_iterate, "First element accepted by code"),
1660   GM(NAME_findAll, 1, "chain", "test=code", getFindAllChain,
1661      NAME_iterate, "New chain with elements accepted by code"),
1662   GM(NAME_map, 1, "chain", "function", getMapChain,
1663      NAME_iterate, "New chain with result of applying function"),
1664   GM(NAME_deleteHead, 0, "any", NULL, getDeleteHeadChain,
1665      NAME_list, "First element and delete it"),
1666   GM(NAME_head, 0, "any", NULL, getHeadChain,
1667      NAME_list, "First element"),
1668   GM(NAME_merge, 1, "chain", "chain", getMergeChain,
1669      NAME_list, "New chain holding concatenation"),
1670   GM(NAME_tail, 0, "value=any", NULL, getTailChain,
1671      NAME_list, "Last element"),
1672   GM(NAME_intersection, 1, "chain", "chain", getIntersectionChain,
1673      NAME_set, "New chain holding common elements"),
1674   GM(NAME_union, 1, "chain", "chain", getUnionChain,
1675      NAME_set, "New chain with union of elements"),
1676   GM(NAME_Arg, 1, "any", "index=int", getArgChain,
1677      NAME_term, "Nth-1 argument for object description"),
1678   GM(NAME_Arity, 0, "int", NULL, getArityChain,
1679      NAME_term, "Number of arguments for object description"),
1680   GM(NAME_sub, 2, "chain", T_gsub, getSubChain,
1681      NAME_list, "Get sub-chain from 0-based start and end")
1682 };
1683 
1684 /* Resources */
1685 
1686 #define rc_chain NULL
1687 /*
1688 static classvardecl rc_chain[] =
1689 {
1690 };
1691 */
1692 
1693 /* Class Declaration */
1694 
1695 ClassDecl(chain_decls,
1696           var_chain, send_chain, get_chain, rc_chain,
1697           ARGC_UNKNOWN, NULL,
1698           "$Rev$");
1699 
1700 
1701 status
makeClassChain(Class class)1702 makeClassChain(Class class)
1703 { declareClass(class, &chain_decls);
1704 
1705   setLoadStoreFunctionClass(class, loadChain, storeChain);
1706   setCloneFunctionClass(class, cloneChain);
1707   setChangedFunctionClass(class, changedChain);
1708 
1709   succeed;
1710 }
1711 
1712