/****************************************************************************** Copyright (c) 1992, 1995, 1996 Xerox Corporation. All rights reserved. Portions of this code were written by Stephen White, aka ghond. Use and copying of this software and preparation of derivative works based upon this software are permitted. Any distribution of this software or derivative works must comply with all applicable United States export control laws. This software is made available AS IS, and Xerox Corporation makes no warranty about the software, its performance or its conformity to any specification. Any person obtaining a copy of this software is requested to send their name and post office or electronic mail address to: Pavel Curtis Xerox PARC 3333 Coyote Hill Rd. Palo Alto, CA 94304 Pavel@Xerox.Com *****************************************************************************/ #include #include #include "pconfig.h" #include "functions.h" #include "list.h" #include "streams.h" #include "storage.h" #include "structures.h" #include "utils.h" Var new_list(int size) { Var new; if (size == 0) { static Var emptylist; if (emptylist.v.list == 0) { emptylist.type = TYPE_LIST; emptylist.v.list = mymalloc(1 * sizeof(Var), M_LIST); emptylist.v.list[0].type = TYPE_INT; emptylist.v.list[0].v.num = 0; } /* give the lucky winner a reference */ addref(emptylist.v.list); return emptylist; } new.type = TYPE_LIST; new.v.list = (Var *) mymalloc((size + 1) * sizeof(Var), M_LIST); new.v.list[0].type = TYPE_INT; new.v.list[0].v.num = size; return new; } Var setadd(Var list, Var value) { if (ismember(value, list, 0)) { free_var(value); return list; } return listappend(list, value); } Var setremove(Var list, Var value) { int i; if ((i = ismember(value, list, 0)) != 0) { return listdelete(list, i); } else { return list; } } int ismember(Var lhs, Var rhs, int case_matters) { int i; for (i = 1; i <= rhs.v.list[0].v.num; i++) { if (equality(lhs, rhs.v.list[i], case_matters)) { return i; } } return 0; } Var listset(Var list, Var value, int pos) { free_var(list.v.list[pos]); list.v.list[pos] = value; return list; } static Var doinsert(Var list, Var value, int pos) { Var new; int i; int size = list.v.list[0].v.num + 1; if (var_refcount(list) == 1 && pos == size) { list.v.list = (Var *) myrealloc(list.v.list, (size + 1) * sizeof(Var), M_LIST); list.v.list[0].v.num = size; list.v.list[pos] = value; return list; } new = new_list(size); for (i = 1; i < pos; i++) new.v.list[i] = var_ref(list.v.list[i]); new.v.list[pos] = value; for (i = pos; i <= list.v.list[0].v.num; i++) new.v.list[i + 1] = var_ref(list.v.list[i]); free_var(list); return new; } Var listinsert(Var list, Var value, int pos) { if (pos <= 0) pos = 1; else if (pos > list.v.list[0].v.num) pos = list.v.list[0].v.num + 1; return doinsert(list, value, pos); } Var listappend(Var list, Var value) { return doinsert(list, value, list.v.list[0].v.num + 1); } Var listdelete(Var list, int pos) { Var new; int i; new = new_list(list.v.list[0].v.num - 1); for (i = 1; i < pos; i++) { new.v.list[i] = var_ref(list.v.list[i]); } for (i = pos + 1; i <= list.v.list[0].v.num; i++) new.v.list[i - 1] = var_ref(list.v.list[i]); free_var(list); /* free old list */ return new; } Var listconcat(Var first, Var second) { int lsecond = second.v.list[0].v.num; int lfirst = first.v.list[0].v.num; Var new; int i; new = new_list(lsecond + lfirst); for (i = 1; i <= lfirst; i++) new.v.list[i] = var_ref(first.v.list[i]); for (i = 1; i <= lsecond; i++) new.v.list[i + lfirst] = var_ref(second.v.list[i]); free_var(first); free_var(second); return new; } Var listrangeset(Var base, int from, int to, Var value) { /* base and value are free'd */ int index, offset = 0; int val_len = value.v.list[0].v.num; int base_len = base.v.list[0].v.num; int lenleft = (from > 1) ? from - 1 : 0; int lenmiddle = val_len; int lenright = (base_len > to) ? base_len - to : 0; int newsize = lenleft + lenmiddle + lenright; Var ans; ans = new_list(newsize); for (index = 1; index <= lenleft; index++) ans.v.list[++offset] = var_ref(base.v.list[index]); for (index = 1; index <= lenmiddle; index++) ans.v.list[++offset] = var_ref(value.v.list[index]); for (index = 1; index <= lenright; index++) ans.v.list[++offset] = var_ref(base.v.list[to + index]); free_var(base); free_var(value); return ans; } Var sublist(Var list, int lower, int upper) { if (lower > upper) { free_var(list); return new_list(0); } else { Var r; int i; r = new_list(upper - lower + 1); for (i = lower; i <= upper; i++) r.v.list[i - lower + 1] = var_ref(list.v.list[i]); free_var(list); return r; } } static const char * list2str(Var * args) { static Stream *str = 0; int i; if (!str) str = new_stream(100); for (i = 1; i <= args[0].v.num; i++) { switch (args[i].type) { case TYPE_INT: stream_printf(str, "%d", args[i].v.num); break; case TYPE_OBJ: stream_printf(str, "#%d", args[i].v.obj); break; case TYPE_STR: stream_add_string(str, args[i].v.str); break; case TYPE_ERR: stream_add_string(str, unparse_error(args[i].v.err)); break; case TYPE_FLOAT: stream_printf(str, "%g", *args[i].v.fnum); break; case TYPE_LIST: stream_add_string(str, "{list}"); break; } } return reset_stream(str); } const char * value2str(Var value) { Var list; const char *str; list = new_list(1); list.v.list[1] = var_ref(value); str = list2str(list.v.list); free_var(list); return str; } Var strrangeset(Var base, int from, int to, Var value) { /* base and value are free'd */ int index, offset = 0; int val_len = strlen(value.v.str); int base_len = strlen(base.v.str); int lenleft = (from > 1) ? from - 1 : 0; int lenmiddle = val_len; int lenright = (base_len > to) ? base_len - to : 0; int newsize = lenleft + lenmiddle + lenright; Var ans; char *s; ans.type = TYPE_STR; s = mymalloc(sizeof(char) * (newsize + 1), M_STRING); for (index = 0; index < lenleft; index++) s[offset++] = base.v.str[index]; for (index = 0; index < lenmiddle; index++) s[offset++] = value.v.str[index]; for (index = 0; index < lenright; index++) s[offset++] = base.v.str[index + to]; s[offset] = '\0'; ans.v.str = s; free_var(base); free_var(value); return ans; } Var substr(Var str, int lower, int upper) { Var r; r.type = TYPE_STR; if (lower > upper) r.v.str = str_dup(""); else { int loop, index = 0; char *s = mymalloc(upper - lower + 2, M_STRING); for (loop = lower - 1; loop < upper; loop++) s[index++] = str.v.str[loop]; s[index] = '\0'; r.v.str = s; } free_var(str); return r; } Var strget(Var str, Var i) { Var r; char *s; r.type = TYPE_STR; s = str_dup(" "); s[0] = str.v.str[i.v.num - 1]; r.v.str = s; return r; } char rcsid_list[] = "$Id: list.c,v 1.1.1.1 2004/02/26 13:13:56 jesse Exp $"; /* * $Log: list.c,v $ * Revision 1.1.1.1 2004/02/26 13:13:56 jesse * Initial import into CVS * * Revision 1.5 1998/12/14 13:17:57 nop * Merge UNSAFE_OPTS (ref fixups); fix Log tag placement to fit CVS whims * * Revision 1.4 1997/07/07 03:24:54 nop * Merge UNSAFE_OPTS (r5) after extensive testing. * * Revision 1.3.2.3 1997/07/03 08:04:01 bjj * Pattern cache was not storing case_matters flag, causing many patterns to * be impossible to find in the cache. * * Revision 1.3.2.2 1997/05/20 14:55:52 nop * Include Jason's patch for bf_decode_binary losing on systems where * char is signed. * * Revision 1.3.2.1 1997/03/21 15:22:56 bjj * doinsert reallocs for appending to refcnt 1 lists. note that this wins * because it avoids all the var_ref/free_var that's done in the general case, * not because it avoids malloc/free. the general case could also benefit from * using memcpy when the refcnt is 1, rather than looping with var_ref. * * Revision 1.3 1997/03/03 06:20:04 bjj * new_list(0) now returns the same empty list to every caller * * Revision 1.2 1997/03/03 04:18:46 nop * GNU Indent normalization * * Revision 1.1.1.1 1997/03/03 03:45:00 nop * LambdaMOO 1.8.0p5 * * Revision 2.7 1996/03/11 23:35:17 pavel * Fixed bad use of possibly-signed characters in decode_binary(). * Release 1.8.0p1. * * Revision 2.6 1996/02/18 23:17:24 pavel * Added value_hash(), string_hash(), and binary_hash(). Release 1.8.0beta3. * * Revision 2.5 1996/02/08 07:02:09 pavel * Added support for floating-point numbers. Fixed registration of * decode_binary(). Renamed err/logf() to errlog/oklog() and TYPE_NUM to * TYPE_INT. Updated copyright notice for 1996. Release 1.8.0beta1. * * Revision 2.4 1996/01/16 07:26:56 pavel * Fixed `case_matters' arguments to strsub(), index(), rindex(), match(), and * rmatch() to allow values of any type. Release 1.8.0alpha6. * * Revision 2.3 1996/01/11 07:42:14 pavel * Added support for C's crypt() function being unavailable. Fixed potential * string overread in case of a too-short salt argument to MOO's crypt() * function. Added built-ins encode_binary() and decode_binary(), in support * of new binary I/O facilities. Release 1.8.0alpha5. * * Revision 2.2 1995/12/31 03:25:04 pavel * Added missing #include "options.h". Release 1.8.0alpha4. * * Revision 2.1 1995/12/11 07:43:20 pavel * Moved value_bytes built-in function to here. * * Release 1.8.0alpha2. * * Revision 2.0 1995/11/30 04:24:03 pavel * New baseline version, corresponding to release 1.8.0alpha1. * * Revision 1.12 1992/10/23 23:03:47 pavel * Added copyright notice. * * Revision 1.11 1992/10/23 19:27:07 pavel * Removed a place where a local structure variable was initialized in its * declaration, since some compilers can't hack that. * Added the `%%' -> `%' transformation to substitute(). * * Revision 1.10 1992/10/21 03:02:35 pavel * Converted to use new automatic configuration system. * * Revision 1.9 1992/10/17 20:33:17 pavel * Global rename of strdup->str_dup, strref->str_ref, vardup->var_dup, and * varref->var_ref. * Added some (int) casts to placate over-protective compilers. * * Revision 1.8 1992/09/08 22:15:09 pjames * Updated strrangeset() and listrangeset() to use correct algorithm. * * Revision 1.7 1992/09/08 22:03:45 pjames * Added all code from bf_str_list.c, and some code from bf_type.c. * * Revision 1.6 1992/08/31 22:31:47 pjames * Changed some `char *'s to `const char *' and fixed code accordingly. * * Revision 1.5 1992/08/28 23:20:22 pjames * Added `listrangeset()' and `strrangeset()'. * * Revision 1.4 1992/08/28 16:29:10 pjames * Added some varref()'s. * Removed some free_var()'s, due to ref-counting. * Changed some my_free()'s to free_var(). * Made `substr()' preserve the string it is passed. * * Revision 1.3 1992/08/10 16:53:46 pjames * Updated #includes. * * Revision 1.2 1992/07/21 00:04:04 pavel * Added rcsid_ declaration to hold the RCS ident. string. * * Revision 1.1 1992/07/20 23:23:12 pavel * Initial RCS-controlled version. */