2 * Implements the tcl::prefix command for Jim Tcl
4 * (c) 2011 Steve Bennett <steveb@workware.net.au>
6 * See LICENSE for license details.
13 * Returns the common initial length of the two strings.
15 static int JimStringCommonLength(const char *str1
, int charlen1
, const char *str2
, int charlen2
)
18 while (charlen1
-- && charlen2
--) {
21 str1
+= utf8_tounicode(str1
, &c1
);
22 str2
+= utf8_tounicode(str2
, &c2
);
33 static int Jim_TclPrefixCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
38 static const char * const options
[] = { "match", "all", "longest", NULL
};
39 enum { OPT_MATCH
, OPT_ALL
, OPT_LONGEST
};
42 Jim_WrongNumArgs(interp
, 1, argv
, "subcommand ?arg ...?");
45 if (Jim_GetEnum(interp
, argv
[1], options
, &option
, NULL
, JIM_ERRMSG
| JIM_ENUM_ABBREV
) != JIM_OK
)
55 Jim_Obj
*errorObj
= NULL
;
56 Jim_Obj
*messageObj
= NULL
;
57 static const char * const matchoptions
[] = { "-error", "-exact", "-message", NULL
};
58 enum { OPT_MATCH_ERROR
, OPT_MATCH_EXACT
, OPT_MATCH_MESSAGE
};
59 int flags
= JIM_ERRMSG
| JIM_ENUM_ABBREV
;
62 Jim_WrongNumArgs(interp
, 2, argv
, "?options? table string");
65 tableObj
= argv
[argc
- 2];
66 stringObj
= argv
[argc
- 1];
68 for (i
= 2; i
< argc
; i
++) {
70 if (Jim_GetEnum(interp
, argv
[i
], matchoptions
, &matchoption
, "option", JIM_ERRMSG
| JIM_ENUM_ABBREV
) != JIM_OK
)
72 switch (matchoption
) {
74 flags
&= ~JIM_ENUM_ABBREV
;
79 Jim_SetResultString(interp
, "missing error options", -1);
83 if (Jim_Length(errorObj
) % 2) {
84 Jim_SetResultString(interp
, "error options must have an even number of elements", -1);
89 case OPT_MATCH_MESSAGE
:
91 Jim_SetResultString(interp
, "missing message", -1);
99 tablesize
= Jim_ListLength(interp
, tableObj
);
100 table
= Jim_Alloc((tablesize
+ 1) * sizeof(*table
));
101 for (i
= 0; i
< tablesize
; i
++) {
102 Jim_ListIndex(interp
, tableObj
, i
, &objPtr
, JIM_NONE
);
103 table
[i
] = Jim_String(objPtr
);
107 ret
= Jim_GetEnum(interp
, stringObj
, table
, &i
, messageObj
? Jim_String(messageObj
) : NULL
, flags
);
110 Jim_ListIndex(interp
, tableObj
, i
, &objPtr
, JIM_NONE
);
111 Jim_SetResult(interp
, objPtr
);
114 if (tablesize
== 0) {
115 Jim_SetResultFormatted(interp
, "bad option \"%#s\": no valid options", stringObj
);
119 if (Jim_Length(errorObj
) == 0) {
120 Jim_SetEmptyResult(interp
);
123 /* Do this the easy way. Build a list to evaluate */
124 objPtr
= Jim_NewStringObj(interp
, "return -level 0 -code error", -1);
125 Jim_ListAppendList(interp
, objPtr
, errorObj
);
126 Jim_ListAppendElement(interp
, objPtr
, Jim_GetResult(interp
));
127 return Jim_EvalObjList(interp
, objPtr
);
135 Jim_WrongNumArgs(interp
, 2, argv
, "table string");
140 int listlen
= Jim_ListLength(interp
, argv
[2]);
141 objPtr
= Jim_NewListObj(interp
, NULL
, 0);
142 for (i
= 0; i
< listlen
; i
++) {
143 Jim_Obj
*valObj
= Jim_ListGetIndex(interp
, argv
[2], i
);
144 if (Jim_StringCompareLenObj(interp
, argv
[3], valObj
, 0) == 0) {
145 Jim_ListAppendElement(interp
, objPtr
, valObj
);
148 Jim_SetResult(interp
, objPtr
);
154 Jim_WrongNumArgs(interp
, 2, argv
, "table string");
157 else if (Jim_ListLength(interp
, argv
[2])) {
158 const char *longeststr
= NULL
;
164 int listlen
= Jim_ListLength(interp
, argv
[2]);
165 for (i
= 0; i
< listlen
; i
++) {
166 Jim_Obj
*valObj
= Jim_ListGetIndex(interp
, argv
[2], i
);
168 if (Jim_StringCompareLenObj(interp
, stringObj
, valObj
, 0)) {
169 /* Does not begin with 'string' */
173 if (longeststr
== NULL
) {
174 longestlen
= Jim_Utf8Length(interp
, valObj
);
175 longeststr
= Jim_String(valObj
);
178 longestlen
= JimStringCommonLength(longeststr
, longestlen
, Jim_String(valObj
), Jim_Utf8Length(interp
, valObj
));
182 Jim_SetResultString(interp
, longeststr
, longestlen
);
190 int Jim_tclprefixInit(Jim_Interp
*interp
)
192 if (Jim_PackageProvide(interp
, "tclprefix", "1.0", JIM_ERRMSG
)) {
196 Jim_CreateCommand(interp
, "tcl::prefix", Jim_TclPrefixCoreCommand
, NULL
, NULL
);