]>
cvs.zerfleddert.de Git - micropolis/blob - src/tclx/src/tclxutil.c
4 * Utility functions for Extended Tcl.
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: tclXutil.c,v 2.0 1992/10/16 04:51:21 markd Rel $
16 *-----------------------------------------------------------------------------
22 # define _tolower tolower
23 # define _toupper toupper
27 * Used to return argument messages by most commands.
29 char *tclXWrongArgs
= "wrong # args: ";
31 extern double pow (double, double);
35 *-----------------------------------------------------------------------------
38 * Convert an Ascii string to an long number of the specified base.
41 * o string (I) - String containing a number.
42 * o base (I) - The base to use for the number 8, 10 or 16 or zero to decide
43 * based on the leading characters of the number. Zero to let the number
45 * o longPtr (O) - Place to return the converted number. Will be
46 * unchanged if there is an error.
49 * Returns 1 if the string was a valid number, 0 invalid.
50 *-----------------------------------------------------------------------------
53 Tcl_StrToLong (CONST
char *string
, int base
, long *longPtr
)
58 num
= strtol(string
, &end
, base
);
59 while ((*end
!= '\0') && isspace(*end
)) {
62 if ((end
== string
) || (*end
!= 0))
70 *-----------------------------------------------------------------------------
73 * Convert an Ascii string to an number of the specified base.
76 * o string (I) - String containing a number.
77 * o base (I) - The base to use for the number 8, 10 or 16 or zero to decide
78 * based on the leading characters of the number. Zero to let the number
80 * o intPtr (O) - Place to return the converted number. Will be
81 * unchanged if there is an error.
84 * Returns 1 if the string was a valid number, 0 invalid.
85 *-----------------------------------------------------------------------------
88 Tcl_StrToInt (CONST
char *string
, int base
, int *intPtr
)
93 num
= strtol(string
, &end
, base
);
94 while ((*end
!= '\0') && isspace(*end
)) {
97 if ((end
== string
) || (*end
!= 0))
105 *-----------------------------------------------------------------------------
107 * Tcl_StrToUnsigned --
108 * Convert an Ascii string to an unsigned int of the specified base.
111 * o string (I) - String containing a number.
112 * o base (I) - The base to use for the number 8, 10 or 16 or zero to decide
113 * based on the leading characters of the number. Zero to let the number
114 * determine the base.
115 * o unsignedPtr (O) - Place to return the converted number. Will be
116 * unchanged if there is an error.
119 * Returns 1 if the string was a valid number, 0 invalid.
120 *-----------------------------------------------------------------------------
123 Tcl_StrToUnsigned (CONST
char *string
, int base
, unsigned *unsignedPtr
)
128 num
= strtoul (string
, &end
, base
);
129 while ((*end
!= '\0') && isspace(*end
)) {
132 if ((end
== string
) || (*end
!= 0))
137 } /* Tcl_StrToUnsigned */
140 *-----------------------------------------------------------------------------
143 * Convert a string to a double percision floating point number.
146 * string (I) - Buffer containing double value to convert.
147 * doublePtr (O) - The convert floating point number.
149 * TRUE if the number is ok, FALSE if it is illegal.
150 *-----------------------------------------------------------------------------
153 Tcl_StrToDouble (CONST
char *string
, double *doublePtr
)
158 num
= strtod (string
, &end
);
159 while ((*end
!= '\0') && isspace(*end
)) {
162 if ((end
== string
) || (*end
!= 0))
168 } /* Tcl_StrToDouble */
171 *-----------------------------------------------------------------------------
174 * Utility procedure to down-shift a string. It is written in such
175 * a way as that the target string maybe the same as the source string.
178 * o targetStr (I) - String to store the down-shifted string in. Must
179 * have enough space allocated to store the string. If NULL is specified,
180 * then the string will be dynamicly allocated and returned as the
181 * result of the function. May also be the same as the source string to
183 * o sourceStr (I) - The string to down-shift.
186 * A pointer to the down-shifted string
187 *-----------------------------------------------------------------------------
190 Tcl_DownShift (char *targetStr
, CONST
char *sourceStr
)
192 register char theChar
;
194 if (targetStr
== NULL
)
195 targetStr
= ckalloc (strlen ((char *) sourceStr
) + 1);
197 for (; (theChar
= *sourceStr
) != '\0'; sourceStr
++) {
198 if (isupper (theChar
))
199 theChar
= _tolower (theChar
);
200 *targetStr
++ = theChar
;
207 *-----------------------------------------------------------------------------
210 * Utility procedure to up-shift a string.
213 * o targetStr (I) - String to store the up-shifted string in. Must
214 * have enough space allocated to store the string. If NULL is specified,
215 * then the string will be dynamicly allocated and returned as the
216 * result of the function. May also be the same as the source string to
218 * o sourceStr (I) - The string to up-shift.
221 * A pointer to the up-shifted string
222 *-----------------------------------------------------------------------------
225 Tcl_UpShift (char *targetStr
, CONST
char *sourceStr
)
227 register char theChar
;
229 if (targetStr
== NULL
)
230 targetStr
= ckalloc (strlen ((char *) sourceStr
) + 1);
232 for (; (theChar
= *sourceStr
) != '\0'; sourceStr
++) {
233 if (islower (theChar
))
234 theChar
= _toupper (theChar
);
235 *targetStr
++ = theChar
;
242 *-----------------------------------------------------------------------------
244 * Tcl_ExpandDynBuf --
246 * Expand a dynamic buffer so that it will have room to hold the
247 * specified additional space. If `appendSize' is zero, the buffer
248 * size will just be doubled.
250 *-----------------------------------------------------------------------------
253 Tcl_ExpandDynBuf (dynamicBuf_t
*dynBufPtr
, int appendSize
)
255 int newSize
, minSize
;
258 newSize
= dynBufPtr
->size
* 2;
259 minSize
= dynBufPtr
->len
+ 1 + appendSize
;
260 if (newSize
< minSize
)
263 oldBufPtr
= dynBufPtr
->ptr
;
264 dynBufPtr
->ptr
= ckalloc (newSize
);
265 memcpy (dynBufPtr
->ptr
, oldBufPtr
, dynBufPtr
->len
+ 1);
266 if (oldBufPtr
!= dynBufPtr
->buf
)
267 ckfree ((char *) oldBufPtr
);
268 dynBufPtr
->size
= newSize
;
272 *-----------------------------------------------------------------------------
276 * Initializes a dynamic buffer.
278 *-----------------------------------------------------------------------------
281 Tcl_DynBufInit (dynamicBuf_t
*dynBufPtr
)
283 dynBufPtr
->buf
[0] = '\0';
284 dynBufPtr
->ptr
= dynBufPtr
->buf
;
285 dynBufPtr
->size
= INIT_DYN_BUFFER_SIZE
;
290 *-----------------------------------------------------------------------------
294 * Clean up a dynamic buffer, release space if it was dynamicly
297 *-----------------------------------------------------------------------------
300 Tcl_DynBufFree (dynamicBuf_t
*dynBufPtr
)
302 if (dynBufPtr
->ptr
!= dynBufPtr
->buf
)
303 ckfree (dynBufPtr
->ptr
);
307 *-----------------------------------------------------------------------------
309 * Tcl_DynBufReturn --
311 * Return the contents of the dynamic buffer as an interpreter result.
312 * Don't call DynBufFree after calling this procedure. The dynamic buffer
313 * must be re-initialized to reuse it.
315 *-----------------------------------------------------------------------------
318 Tcl_DynBufReturn (Tcl_Interp
*interp
, dynamicBuf_t
*dynBufPtr
)
320 if (dynBufPtr
->ptr
!= dynBufPtr
->buf
)
321 Tcl_SetResult (interp
, dynBufPtr
->ptr
, TCL_DYNAMIC
);
323 Tcl_SetResult (interp
, dynBufPtr
->ptr
, TCL_VOLATILE
);
327 *-----------------------------------------------------------------------------
329 * Tcl_DynBufAppend --
331 * Append the specified string to the dynamic buffer, expanding if
332 * necessary. Assumes the string in the buffer is zero terminated.
334 *-----------------------------------------------------------------------------
337 Tcl_DynBufAppend (dynamicBuf_t
*dynBufPtr
, char *newStr
)
339 int newLen
, currentUsed
;
341 newLen
= strlen (newStr
);
342 if ((dynBufPtr
->len
+ newLen
+ 1) > dynBufPtr
->size
)
343 Tcl_ExpandDynBuf (dynBufPtr
, newLen
);
344 strcpy (dynBufPtr
->ptr
+ dynBufPtr
->len
, newStr
);
345 dynBufPtr
->len
+= newLen
;
349 *-----------------------------------------------------------------------------
351 * Tcl_DynamicFgets --
353 * Reads a line from a file into a dynamic buffer. The buffer will be
354 * expanded, if necessary and reads are done until EOL or EOF is reached.
355 * Any data already in the buffer will be overwritten. if append is not
356 * specified. Even if an error or EOF is encountered, the buffer should
357 * be cleaned up, as storage may have still been allocated.
360 * If data was transfered, returns 1, if EOF was encountered without
361 * transfering any data, returns 0. If an error occured, returns, -1.
363 *-----------------------------------------------------------------------------
366 Tcl_DynamicFgets (dynamicBuf_t
*dynBufPtr
, FILE *filePtr
, int append
)
374 if (dynBufPtr
->len
+ 1 == dynBufPtr
->size
)
375 Tcl_ExpandDynBuf (dynBufPtr
, 0);
377 readVal
= getc (filePtr
);
378 if (readVal
== '\n') /* Is it a new-line? */
380 if (readVal
== EOF
) { /* Is it an EOF or an error? */
381 if (feof (filePtr
)) {
384 return -1; /* Error */
386 dynBufPtr
->ptr
[dynBufPtr
->len
++] = readVal
;
388 dynBufPtr
->ptr
[dynBufPtr
->len
] = '\0';
389 return (readVal
== EOF
) ? 0 : 1;
393 *-----------------------------------------------------------------------------
397 * Given a string, produce the corresponding long value.
400 * The return value is normally TCL_OK; in this case *intPtr
401 * will be set to the integer value equivalent to string. If
402 * string is improperly formed then TCL_ERROR is returned and
403 * an error message will be left in interp->result.
408 *-----------------------------------------------------------------------------
412 Tcl_Interp
*interp
, /* Interpreter to use for error reporting. */
413 CONST
char *string
, /* String containing a (possibly signed)
414 * integer in a form acceptable to strtol. */
415 long *longPtr
/* Place to store converted result. */
421 i
= strtol(string
, &end
, 0);
422 while ((*end
!= '\0') && isspace(*end
)) {
425 if ((end
== string
) || (*end
!= 0)) {
426 Tcl_AppendResult (interp
, "expected integer but got \"", string
,
427 "\"", (char *) NULL
);
435 *-----------------------------------------------------------------------------
439 * Given a string, produce the corresponding unsigned integer value.
442 * The return value is normally TCL_OK; in this case *intPtr
443 * will be set to the integer value equivalent to string. If
444 * string is improperly formed then TCL_ERROR is returned and
445 * an error message will be left in interp->result.
450 *-----------------------------------------------------------------------------
454 Tcl_Interp
*interp
, /* Interpreter to use for error reporting. */
455 CONST
char *string
, /* String containing a (possibly signed)
456 * integer in a form acceptable to strtoul. */
457 unsigned *unsignedPtr
/* Place to store converted result. */
464 * Since some strtoul functions don't detect negative numbers, check
467 while (isspace(*string
))
469 if (string
[0] == '-')
472 i
= strtoul(string
, &end
, 0);
473 while ((*end
!= '\0') && isspace(*end
))
476 if ((end
== string
) || (*end
!= '\0'))
483 Tcl_AppendResult (interp
, "expected unsigned integer but got \"",
484 string
, "\"", (char *) NULL
);
489 *-----------------------------------------------------------------------------
491 * Tcl_ConvertFileHandle --
493 * Convert a file handle to its file number. The file handle maybe one
494 * of "stdin", "stdout" or "stderr" or "fileNNN", were NNN is the file
495 * number. If the handle is invalid, -1 is returned and a error message
496 * will be returned in interp->result. This is used when the file may
497 * not be currently open.
499 *-----------------------------------------------------------------------------
502 Tcl_ConvertFileHandle (Tcl_Interp
*interp
, char *handle
)
506 if (handle
[0] == 's') {
507 if (STREQU (handle
, "stdin"))
509 else if (STREQU (handle
, "stdout"))
511 else if (STREQU (handle
, "stderr"))
514 if (STRNEQU (handle
, "file", 4))
515 Tcl_StrToInt (&handle
[4], 10, &fileId
);
518 Tcl_AppendResult (interp
, "invalid file handle: ", handle
,
524 *-----------------------------------------------------------------------------
526 * Tcl_SetupFileEntry --
528 * Set up an entry in the Tcl file table for a file number, including the stdio
532 * o interp (I) - Current interpreter.
533 * o fileNum (I) - File number to set up the entry for.
534 * o readable (I) - TRUE if read access to the file.
535 * o writable (I) - TRUE if write access to the file.
537 * TCL_OK or TCL_ERROR;
538 *-----------------------------------------------------------------------------
541 Tcl_SetupFileEntry (Tcl_Interp
*interp
, int fileNum
, int readable
, int writable
)
543 Interp
*iPtr
= (Interp
*) interp
;
549 * Set up a stdio FILE control block for the new file.
551 if (readable
&& writable
) {
553 } else if (writable
) {
558 fileCBPtr
= fdopen (fileNum
, mode
);
559 if (fileCBPtr
== NULL
) {
560 iPtr
->result
= Tcl_UnixError (interp
);
565 * Put the file in the Tcl table.
567 TclMakeFileTable (iPtr
, fileNum
);
568 if (iPtr
->filePtrArray
[fileno (fileCBPtr
)] != NULL
)
569 panic ("file already open");
570 filePtr
= (OpenFile
*) ckalloc (sizeof (OpenFile
));
571 iPtr
->filePtrArray
[fileno (fileCBPtr
)] = filePtr
;
573 filePtr
->f
= fileCBPtr
;
575 filePtr
->readable
= readable
;
576 filePtr
->writable
= writable
;
577 filePtr
->numPids
= 0;
578 filePtr
->pidPtr
= NULL
;
579 filePtr
->errorId
= -1;
585 *-----------------------------------------------------------------------------
588 * does the equivalent of the Unix "system" library call, but
589 * uses waitpid to wait on the correct process, rather than
590 * waiting on all processes and throwing the exit statii away
591 * for the processes it isn't interested in, plus does it with
595 * Standard TCL results, may return the UNIX system error message.
597 *-----------------------------------------------------------------------------
600 Tcl_System (Tcl_Interp
*interp
, char *command
)
602 int processID
, waitStatus
, processStatus
;
604 if ((processID
= Tcl_Fork()) < 0) {
605 interp
->result
= Tcl_UnixError (interp
);
608 if (processID
== 0) {
609 if (execl ("/bin/sh", "sh", "-c", command
, (char *) NULL
) < 0) {
610 interp
->result
= Tcl_UnixError (interp
);
619 #ifndef TCL_HAVE_WAITPID
620 if (Tcl_WaitPids(1, &processID
, &processStatus
) == -1) {
621 interp
->result
= Tcl_UnixError (interp
);
625 if (waitpid (processID
, &processStatus
, 0) == -1) {
626 interp
->result
= Tcl_UnixError (interp
);
630 return (WEXITSTATUS(processStatus
));
635 *--------------------------------------------------------------
637 * Tcl_ReturnDouble --
639 * Format a double to the maximum precision supported on
640 * this machine. If the number formats to an even integer,
641 * a ".0" is append to assure that the value continues to
642 * represent a floating point number.
645 * A standard Tcl result. If the result is TCL_OK, then the
646 * interpreter's result is set to the string value of the
647 * double. If the result is TCL_OK, then interp->result
648 * contains an error message (If the number had the value of
649 * "not a number" or "infinite").
654 *--------------------------------------------------------------
659 Tcl_Interp
*interp
, /* ->result gets converted number */
660 double number
/* Number to convert */
663 static int precision
= 0;
664 register char *scanPtr
;
667 * On the first call, determine the number of decimal digits that represent
668 * the precision of a double.
670 if (precision
== 0) {
674 sprintf (interp
->result
, "%.0f", pow (2.0, (double) DSIGNIF
));
675 precision
= strlen (interp
->result
);
679 sprintf (interp
->result
, "%.*g", precision
, number
);
682 * Scan the number for "." or "e" to assure that the number has not been
683 * converted to an integer. Also check for NaN on infinite
686 scanPtr
= interp
->result
;
687 if (scanPtr
[0] == '-')
689 for (; isdigit (*scanPtr
); scanPtr
++)
698 interp
->result
= "Floating point error, result is not a number";
702 interp
->result
= "Floating point error, result is infinite";
712 * If we made it here, this sprintf returned something we did not expect.
714 Tcl_AppendResult (interp
, ": unexpected floating point conversion result",