Add a general purpose hashtable pattern matcher
[jimtcl.git] / jim-array.c
blob112106a8a79b80cdea55a2ba97dd8425fe9b75d6
2 /*
3 * Implements the array command for jim
5 * (c) 2008 Steve Bennett <steveb@workware.net.au>
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above
14 * copyright notice, this list of conditions and the following
15 * disclaimer in the documentation and/or other materials
16 * provided with the distribution.
18 * THIS SOFTWARE IS PROVIDED BY THE JIM TCL PROJECT ``AS IS'' AND ANY
19 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
20 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
21 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
22 * JIM TCL PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
23 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
27 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
29 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 * The views and conclusions contained in the software and documentation
32 * are those of the authors and should not be interpreted as representing
33 * official policies, either expressed or implied, of the Jim Tcl Project.
35 * Based on code originally from Tcl 6.7:
37 * Copyright 1987-1991 Regents of the University of California
38 * Permission to use, copy, modify, and distribute this
39 * software and its documentation for any purpose and without
40 * fee is hereby granted, provided that the above copyright
41 * notice appear in all copies. The University of California
42 * makes no representations about the suitability of this
43 * software for any purpose. It is provided "as is" without
44 * express or implied warranty.
47 #include <limits.h>
48 #include <stdlib.h>
49 #include <string.h>
50 #include <stdio.h>
51 #include <errno.h>
53 #include "jim.h"
54 #include "jimautoconf.h"
55 #include "jim-subcmd.h"
57 static int array_cmd_exists(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
59 /* Just a regular [info exists] */
60 Jim_SetResultInt(interp, Jim_GetVariable(interp, argv[0], 0) != 0);
61 return JIM_OK;
64 static int array_cmd_get(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
66 Jim_Obj *objPtr = Jim_GetVariable(interp, argv[0], JIM_NONE);
68 if (!objPtr) {
69 return JIM_OK;
72 if (argc == 1 || Jim_CompareStringImmediate(interp, argv[1], "*")) {
73 /* Optimise the "all" case */
74 if (Jim_IsList(objPtr)) {
75 if (Jim_ListLength(interp, objPtr) % 2 != 0) {
76 /* A list with an odd number of elements */
77 return JIM_ERR;
80 else if (Jim_DictSize(interp, objPtr) < 0) {
81 /* Can't be converted to a dictionary */
82 return JIM_ERR;
84 Jim_SetResult(interp, objPtr);
85 return JIM_OK;
88 /* Return a list of keys and values where the keys match the pattern */
89 return Jim_DictValues(interp, objPtr, argv[1]);
92 static int array_cmd_names(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
94 Jim_Obj *objPtr = Jim_GetVariable(interp, argv[0], JIM_NONE);
96 if (!objPtr) {
97 return JIM_OK;
100 return Jim_DictKeys(interp, objPtr, argc == 1 ? NULL : argv[1]);
103 static int array_cmd_unset(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
105 int i;
106 int len;
107 Jim_Obj *resultObj;
108 Jim_Obj *objPtr;
109 Jim_Obj **dictValuesObj;
111 if (argc == 1 || Jim_CompareStringImmediate(interp, argv[1], "*")) {
112 /* Unset the whole array */
113 Jim_UnsetVariable(interp, argv[0], JIM_NONE);
114 return JIM_OK;
117 objPtr = Jim_GetVariable(interp, argv[0], JIM_NONE);
119 if (Jim_DictPairs(interp, objPtr, &dictValuesObj, &len) != JIM_OK) {
120 return JIM_ERR;
123 /* Create a new object with the values which don't match */
124 resultObj = Jim_NewDictObj(interp, NULL, 0);
126 for (i = 0; i < len; i += 2) {
127 if (!Jim_StringMatchObj(interp, argv[1], dictValuesObj[i], 0)) {
128 Jim_DictAddElement(interp, resultObj, dictValuesObj[i], dictValuesObj[i + 1]);
131 Jim_Free(dictValuesObj);
133 Jim_SetVariable(interp, argv[0], resultObj);
134 return JIM_OK;
137 static int array_cmd_size(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
139 Jim_Obj *objPtr;
140 int len = 0;
142 /* Not found means zero length */
143 objPtr = Jim_GetVariable(interp, argv[0], JIM_NONE);
144 if (objPtr) {
145 len = Jim_DictSize(interp, objPtr);
146 if (len < 0) {
147 return JIM_ERR;
151 Jim_SetResultInt(interp, len);
153 return JIM_OK;
156 static int array_cmd_set(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
158 int i;
159 int len;
160 Jim_Obj *listObj = argv[1];
161 Jim_Obj *dictObj;
163 len = Jim_ListLength(interp, listObj);
164 if (len % 2) {
165 Jim_SetResultString(interp, "list must have an even number of elements", -1);
166 return JIM_ERR;
169 dictObj = Jim_GetVariable(interp, argv[0], JIM_UNSHARED);
170 if (!dictObj) {
171 /* Doesn't exist, so just set the list directly */
172 return Jim_SetVariable(interp, argv[0], listObj);
175 if (Jim_IsShared(dictObj)) {
176 dictObj = Jim_DuplicateObj(interp, dictObj);
179 for (i = 0; i < len; i += 2) {
180 Jim_Obj *nameObj;
181 Jim_Obj *valueObj;
183 Jim_ListIndex(interp, listObj, i, &nameObj, JIM_NONE);
184 Jim_ListIndex(interp, listObj, i + 1, &valueObj, JIM_NONE);
186 Jim_DictAddElement(interp, dictObj, nameObj, valueObj);
188 return Jim_SetVariable(interp, argv[0], dictObj);
191 static const jim_subcmd_type array_command_table[] = {
192 { "exists",
193 "arrayName",
194 array_cmd_exists,
197 /* Description: Does array exist? */
199 { "get",
200 "arrayName ?pattern?",
201 array_cmd_get,
204 /* Description: Array contents as name value list */
206 { "names",
207 "arrayName ?pattern?",
208 array_cmd_names,
211 /* Description: Array keys as a list */
213 { "set",
214 "arrayName list",
215 array_cmd_set,
218 /* Description: Set array from list */
220 { "size",
221 "arrayName",
222 array_cmd_size,
225 /* Description: Number of elements in array */
227 { "unset",
228 "arrayName ?pattern?",
229 array_cmd_unset,
232 /* Description: Unset elements of an array */
234 { NULL
238 int Jim_arrayInit(Jim_Interp *interp)
240 if (Jim_PackageProvide(interp, "array", "1.0", JIM_ERRMSG))
241 return JIM_ERR;
243 Jim_CreateCommand(interp, "array", Jim_SubCmdProc, (void *)array_command_table, NULL);
244 return JIM_OK;