]>
git.zerfleddert.de Git - micropolis/blob - src/tclx/src/tclxstr.c
4 * Extended TCL string and character manipulation commands.
5 *-----------------------------------------------------------------------------
6 * Copyright 1992 Karl Lehenbauer and Mark Diekhans.
8 * Permission to use, copy, modify, and distribute this software and its
9 * documentation for any purpose and without fee is hereby granted, provided
10 * that the above copyright notice appear in all copies. Karl Lehenbauer and
11 * Mark Diekhans make no representations about the suitability of this
12 * software for any purpose. It is provided "as is" without express or
14 *-----------------------------------------------------------------------------
15 * $Id: tclXstring.c,v 2.0 1992/10/16 04:51:16 markd Rel $
16 *-----------------------------------------------------------------------------
22 * Prototypes of internal functions.
25 ExpandString
_ANSI_ARGS_((unsigned char *s
,
26 unsigned char buf
[]));
30 *-----------------------------------------------------------------------------
33 * Implements the cindex TCL command:
34 * cindex string indexExpr
37 * Returns the character indexed by index (zero based) from
40 *-----------------------------------------------------------------------------
44 ClientData clientData
,
53 Tcl_AppendResult (interp
, tclXWrongArgs
, argv
[0],
54 " string indexExpr", (char *) NULL
);
58 if (Tcl_ExprLong (interp
, argv
[2], &index
) != TCL_OK
)
60 if (index
>= strlen (argv
[1]))
63 interp
->result
[0] = argv
[1][index
];
64 interp
->result
[1] = 0;
70 *-----------------------------------------------------------------------------
73 * Implements the clength TCL command:
77 * Returns the length of string in characters.
79 *-----------------------------------------------------------------------------
83 ClientData clientData
,
91 Tcl_AppendResult (interp
, tclXWrongArgs
, argv
[0], " string",
96 sprintf (interp
->result
, "%d", strlen (argv
[1]));
99 } /* Tcl_ClengthCmd */
102 *-----------------------------------------------------------------------------
105 * Implements the crange and csubstr TCL commands:
106 * crange string firstExpr lastExpr
107 * csubstr string firstExpr lengthExpr
110 * Standard Tcl result.
111 *-----------------------------------------------------------------------------
115 ClientData clientData
,
125 int isRange
= (argv
[0][1] == 'r'); /* csubstr or crange */
128 Tcl_AppendResult (interp
, tclXWrongArgs
, argv
[0],
129 " string firstExpr ",
130 (isRange
) ? "lastExpr" : "lengthExpr",
135 if (Tcl_ExprLong (interp
, argv
[2], &first
) != TCL_OK
)
138 fullLen
= strlen (argv
[1]);
139 if (first
>= fullLen
)
142 if (STREQU (argv
[3], "end"))
143 subLen
= fullLen
- first
;
145 if (Tcl_ExprLong (interp
, argv
[3], &subLen
) != TCL_OK
)
149 if (subLen
< first
) {
150 Tcl_AppendResult (interp
, "last is before first",
154 subLen
= subLen
- first
+1;
157 if (first
+ subLen
> fullLen
)
158 subLen
= fullLen
- first
;
161 strPtr
= argv
[1] + first
;
163 holdChar
= strPtr
[subLen
];
164 strPtr
[subLen
] = '\0';
165 Tcl_SetResult (interp
, strPtr
, TCL_VOLATILE
);
166 strPtr
[subLen
] = holdChar
;
170 } /* Tcl_CrangeCmd */
173 *-----------------------------------------------------------------------------
175 * Tcl_ReplicateCmd --
176 * Implements the replicate TCL command:
177 * replicate string countExpr
178 * See the string(TCL) manual page.
181 * Returns string replicated count times.
183 *-----------------------------------------------------------------------------
187 ClientData clientData
,
194 register char *srcPtr
, *scanPtr
, *newPtr
;
195 register long newLen
, cnt
;
198 Tcl_AppendResult (interp
, tclXWrongArgs
, argv
[0],
199 " string countExpr", (char *) NULL
);
203 if (Tcl_ExprLong (interp
, argv
[2], &repCount
) != TCL_OK
)
207 newLen
= strlen (srcPtr
) * repCount
;
208 if (newLen
>= TCL_RESULT_SIZE
)
209 Tcl_SetResult (interp
, ckalloc ((unsigned) newLen
+ 1), TCL_DYNAMIC
);
211 newPtr
= interp
->result
;
212 for (cnt
= 0; cnt
< repCount
; cnt
++) {
213 for (scanPtr
= srcPtr
; *scanPtr
!= 0; scanPtr
++)
214 *newPtr
++ = *scanPtr
;
220 } /* Tcl_ReplicateCmd */
223 *-----------------------------------------------------------------------------
226 * Build an expand version of a translit range specification.
229 * TRUE it the expansion is ok, FALSE it its too long.
231 *-----------------------------------------------------------------------------
233 #define MAX_EXPANSION 255
236 ExpandString (unsigned char *s
, unsigned char buf
[])
241 while((*s
!=0) && i
< MAX_EXPANSION
) {
242 if(s
[1] == '-' && s
[2] > s
[0]) {
243 for(j
= s
[0]; j
<= s
[2]; j
++)
250 return (i
< MAX_EXPANSION
);
254 *-----------------------------------------------------------------------------
257 * Implements the TCL translit command:
258 * translit inrange outrange string
261 * Standard TCL results.
263 *-----------------------------------------------------------------------------
267 ClientData clientData
,
273 unsigned char from
[MAX_EXPANSION
+1];
274 unsigned char to
[MAX_EXPANSION
+1];
275 unsigned char map
[MAX_EXPANSION
+1];
276 unsigned char *s
, *t
;
280 Tcl_AppendResult (interp
, tclXWrongArgs
, argv
[0],
281 " from to string", (char *) NULL
);
285 if (!ExpandString ((unsigned char *) argv
[1], from
)) {
286 interp
->result
= "inrange expansion too long";
290 if (!ExpandString ((unsigned char *) argv
[2], to
)) {
291 interp
->result
= "outrange expansion too long";
295 for (idx
= 0; idx
<= MAX_EXPANSION
; idx
++)
298 for (idx
= 0; to
[idx
] != '\0'; idx
++) {
299 if (from
[idx
] != '\0')
300 map
[from
[idx
]] = to
[idx
];
304 if (to
[idx
] != '\0') {
305 interp
->result
= "inrange longer than outrange";
309 for (; from
[idx
] != '\0'; idx
++)
310 map
[from
[idx
]] = 0;
312 for (s
= t
= (unsigned char *) argv
[3]; *s
!= '\0'; s
++) {
318 Tcl_SetResult (interp
, argv
[3], TCL_VOLATILE
);
324 *-----------------------------------------------------------------------------
328 * This function implements the 'ctype' command:
331 * Where class is one of the following:
332 * digit, xdigit, lower, upper, alpha, alnum,
333 * space, cntrl, punct, print, graph, ascii, char or ord.
336 * One or zero: Depending if all the characters in the string are of
337 * the desired class. Char and ord provide conversions and return the
340 *-----------------------------------------------------------------------------
344 ClientData clientData
,
350 register char *class;
351 register char *scanPtr
= argv
[2];
354 Tcl_AppendResult (interp
, tclXWrongArgs
, argv
[0], " class string",
362 * Handle conversion requests.
364 if (STREQU (class, "char")) {
367 if (Tcl_GetInt (interp
, argv
[2], &number
) != TCL_OK
)
369 if ((number
< 0) || (number
> 255)) {
370 Tcl_AppendResult (interp
, "number must be in the range 0..255",
375 interp
->result
[0] = number
;
376 interp
->result
[1] = 0;
380 if (STREQU (class, "ord")) {
381 if (strlen (argv
[2]) != 1) {
382 Tcl_AppendResult (interp
, "string to convert must be only one",
383 " character", (char *) NULL
);
387 sprintf(interp
->result
, "%d", (int)(*argv
[2]));
392 * Select based on the first letter of the 'class' argument to chose the
393 * macro to test characters with. In some cases another character must be
394 * switched on to determine which macro to use. This is gross, but better
395 * we only have to do a string compare once to test if class is correct.
397 if ((class [2] == 'n') && STREQU (class, "alnum")) {
398 for (; *scanPtr
!= 0; scanPtr
++) {
399 if (!isalnum (*scanPtr
))
404 if ((class [2] == 'p') && STREQU (class, "alpha")) {
405 for (; *scanPtr
!= 0; scanPtr
++) {
406 if (! isalpha (*scanPtr
))
411 if ((class [1] == 's') && STREQU (class, "ascii")) {
412 for (; *scanPtr
!= 0; scanPtr
++) {
413 if (!isascii (*scanPtr
))
418 if (STREQU (class, "cntrl")) {
419 for (; *scanPtr
!= 0; scanPtr
++) {
420 if (!iscntrl (*scanPtr
))
425 if (STREQU (class, "digit")) {
426 for (; *scanPtr
!= 0; scanPtr
++) {
427 if (!isdigit (*scanPtr
))
432 if (STREQU (class, "graph")) {
433 for (; *scanPtr
!= 0; scanPtr
++) {
434 if (!isgraph (*scanPtr
))
439 if (STREQU (class, "lower")) {
440 for (; *scanPtr
!= 0; scanPtr
++) {
441 if (!islower (*scanPtr
))
446 if ((class [1] == 'r') && STREQU (class, "print")) {
447 for (; *scanPtr
!= 0; scanPtr
++) {
448 if (!isprint (*scanPtr
))
453 if ((class [1] == 'u') && STREQU (class, "punct")) {
454 for (; *scanPtr
!= 0; scanPtr
++) {
455 if (!ispunct (*scanPtr
))
460 if (STREQU (class, "space")) {
461 for (; *scanPtr
!= 0; scanPtr
++) {
462 if (!isspace (*scanPtr
))
467 if (STREQU (class, "upper")) {
468 for (; *scanPtr
!= 0; scanPtr
++) {
469 if (!isupper (*scanPtr
))
474 if (STREQU (class, "xdigit")) {
475 for (; *scanPtr
!= 0; scanPtr
++) {
476 if (!isxdigit (*scanPtr
))
482 * No match on subcommand.
484 Tcl_AppendResult (interp
, "unrecognized class specification: \"", class,
485 "\", expected one of: alnum, alpha, ascii, char, ",
486 "cntrl, digit, graph, lower, ord, print, punct, space, ",
487 "upper or xdigit", (char *) NULL
);
491 * Return true or false, depending if the end was reached. Always return
492 * false for a null string.
495 if ((*scanPtr
== 0) && (scanPtr
!= argv
[2]))
496 interp
->result
= "1";
498 interp
->result
= "0";