]>
git.zerfleddert.de Git - micropolis/blob - src/tclx/src/tclxutil.c
f716919d9a20e2b2fb5a5244261ac919e019f93d
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: ";
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 (string
, base
, longPtr
)
61 num
= strtol(string
, &end
, base
);
62 while ((*end
!= '\0') && isspace(*end
)) {
65 if ((end
== string
) || (*end
!= 0))
73 *-----------------------------------------------------------------------------
76 * Convert an Ascii string to an number of the specified base.
79 * o string (I) - String containing a number.
80 * o base (I) - The base to use for the number 8, 10 or 16 or zero to decide
81 * based on the leading characters of the number. Zero to let the number
83 * o intPtr (O) - Place to return the converted number. Will be
84 * unchanged if there is an error.
87 * Returns 1 if the string was a valid number, 0 invalid.
88 *-----------------------------------------------------------------------------
91 Tcl_StrToInt (string
, base
, intPtr
)
99 num
= strtol(string
, &end
, base
);
100 while ((*end
!= '\0') && isspace(*end
)) {
103 if ((end
== string
) || (*end
!= 0))
111 *-----------------------------------------------------------------------------
113 * Tcl_StrToUnsigned --
114 * Convert an Ascii string to an unsigned int of the specified base.
117 * o string (I) - String containing a number.
118 * o base (I) - The base to use for the number 8, 10 or 16 or zero to decide
119 * based on the leading characters of the number. Zero to let the number
120 * determine the base.
121 * o unsignedPtr (O) - Place to return the converted number. Will be
122 * unchanged if there is an error.
125 * Returns 1 if the string was a valid number, 0 invalid.
126 *-----------------------------------------------------------------------------
129 Tcl_StrToUnsigned (string
, base
, unsignedPtr
)
132 unsigned *unsignedPtr
;
137 num
= strtoul (string
, &end
, base
);
138 while ((*end
!= '\0') && isspace(*end
)) {
141 if ((end
== string
) || (*end
!= 0))
146 } /* Tcl_StrToUnsigned */
149 *-----------------------------------------------------------------------------
152 * Convert a string to a double percision floating point number.
155 * string (I) - Buffer containing double value to convert.
156 * doublePtr (O) - The convert floating point number.
158 * TRUE if the number is ok, FALSE if it is illegal.
159 *-----------------------------------------------------------------------------
162 Tcl_StrToDouble (string
, doublePtr
)
169 num
= strtod (string
, &end
);
170 while ((*end
!= '\0') && isspace(*end
)) {
173 if ((end
== string
) || (*end
!= 0))
179 } /* Tcl_StrToDouble */
182 *-----------------------------------------------------------------------------
185 * Utility procedure to down-shift a string. It is written in such
186 * a way as that the target string maybe the same as the source string.
189 * o targetStr (I) - String to store the down-shifted string in. Must
190 * have enough space allocated to store the string. If NULL is specified,
191 * then the string will be dynamicly allocated and returned as the
192 * result of the function. May also be the same as the source string to
194 * o sourceStr (I) - The string to down-shift.
197 * A pointer to the down-shifted string
198 *-----------------------------------------------------------------------------
201 Tcl_DownShift (targetStr
, sourceStr
)
203 CONST
char *sourceStr
;
205 register char theChar
;
207 if (targetStr
== NULL
)
208 targetStr
= ckalloc (strlen ((char *) sourceStr
) + 1);
210 for (; (theChar
= *sourceStr
) != '\0'; sourceStr
++) {
211 if (isupper (theChar
))
212 theChar
= _tolower (theChar
);
213 *targetStr
++ = theChar
;
220 *-----------------------------------------------------------------------------
223 * Utility procedure to up-shift a string.
226 * o targetStr (I) - String to store the up-shifted string in. Must
227 * have enough space allocated to store the string. If NULL is specified,
228 * then the string will be dynamicly allocated and returned as the
229 * result of the function. May also be the same as the source string to
231 * o sourceStr (I) - The string to up-shift.
234 * A pointer to the up-shifted string
235 *-----------------------------------------------------------------------------
238 Tcl_UpShift (targetStr
, sourceStr
)
240 CONST
char *sourceStr
;
242 register char theChar
;
244 if (targetStr
== NULL
)
245 targetStr
= ckalloc (strlen ((char *) sourceStr
) + 1);
247 for (; (theChar
= *sourceStr
) != '\0'; sourceStr
++) {
248 if (islower (theChar
))
249 theChar
= _toupper (theChar
);
250 *targetStr
++ = theChar
;
257 *-----------------------------------------------------------------------------
259 * Tcl_ExpandDynBuf --
261 * Expand a dynamic buffer so that it will have room to hold the
262 * specified additional space. If `appendSize' is zero, the buffer
263 * size will just be doubled.
265 *-----------------------------------------------------------------------------
268 Tcl_ExpandDynBuf (dynBufPtr
, appendSize
)
269 dynamicBuf_t
*dynBufPtr
;
272 int newSize
, minSize
;
275 newSize
= dynBufPtr
->size
* 2;
276 minSize
= dynBufPtr
->len
+ 1 + appendSize
;
277 if (newSize
< minSize
)
280 oldBufPtr
= dynBufPtr
->ptr
;
281 dynBufPtr
->ptr
= ckalloc (newSize
);
282 memcpy (dynBufPtr
->ptr
, oldBufPtr
, dynBufPtr
->len
+ 1);
283 if (oldBufPtr
!= dynBufPtr
->buf
)
284 ckfree ((char *) oldBufPtr
);
285 dynBufPtr
->size
= newSize
;
289 *-----------------------------------------------------------------------------
293 * Initializes a dynamic buffer.
295 *-----------------------------------------------------------------------------
298 Tcl_DynBufInit (dynBufPtr
)
299 dynamicBuf_t
*dynBufPtr
;
301 dynBufPtr
->buf
[0] = '\0';
302 dynBufPtr
->ptr
= dynBufPtr
->buf
;
303 dynBufPtr
->size
= INIT_DYN_BUFFER_SIZE
;
308 *-----------------------------------------------------------------------------
312 * Clean up a dynamic buffer, release space if it was dynamicly
315 *-----------------------------------------------------------------------------
318 Tcl_DynBufFree (dynBufPtr
)
319 dynamicBuf_t
*dynBufPtr
;
321 if (dynBufPtr
->ptr
!= dynBufPtr
->buf
)
322 ckfree (dynBufPtr
->ptr
);
326 *-----------------------------------------------------------------------------
328 * Tcl_DynBufReturn --
330 * Return the contents of the dynamic buffer as an interpreter result.
331 * Don't call DynBufFree after calling this procedure. The dynamic buffer
332 * must be re-initialized to reuse it.
334 *-----------------------------------------------------------------------------
337 Tcl_DynBufReturn (interp
, dynBufPtr
)
339 dynamicBuf_t
*dynBufPtr
;
341 if (dynBufPtr
->ptr
!= dynBufPtr
->buf
)
342 Tcl_SetResult (interp
, dynBufPtr
->ptr
, TCL_DYNAMIC
);
344 Tcl_SetResult (interp
, dynBufPtr
->ptr
, TCL_VOLATILE
);
348 *-----------------------------------------------------------------------------
350 * Tcl_DynBufAppend --
352 * Append the specified string to the dynamic buffer, expanding if
353 * necessary. Assumes the string in the buffer is zero terminated.
355 *-----------------------------------------------------------------------------
358 Tcl_DynBufAppend (dynBufPtr
, newStr
)
359 dynamicBuf_t
*dynBufPtr
;
362 int newLen
, currentUsed
;
364 newLen
= strlen (newStr
);
365 if ((dynBufPtr
->len
+ newLen
+ 1) > dynBufPtr
->size
)
366 Tcl_ExpandDynBuf (dynBufPtr
, newLen
);
367 strcpy (dynBufPtr
->ptr
+ dynBufPtr
->len
, newStr
);
368 dynBufPtr
->len
+= newLen
;
372 *-----------------------------------------------------------------------------
374 * Tcl_DynamicFgets --
376 * Reads a line from a file into a dynamic buffer. The buffer will be
377 * expanded, if necessary and reads are done until EOL or EOF is reached.
378 * Any data already in the buffer will be overwritten. if append is not
379 * specified. Even if an error or EOF is encountered, the buffer should
380 * be cleaned up, as storage may have still been allocated.
383 * If data was transfered, returns 1, if EOF was encountered without
384 * transfering any data, returns 0. If an error occured, returns, -1.
386 *-----------------------------------------------------------------------------
389 Tcl_DynamicFgets (dynBufPtr
, filePtr
, append
)
390 dynamicBuf_t
*dynBufPtr
;
400 if (dynBufPtr
->len
+ 1 == dynBufPtr
->size
)
401 Tcl_ExpandDynBuf (dynBufPtr
, 0);
403 readVal
= getc (filePtr
);
404 if (readVal
== '\n') /* Is it a new-line? */
406 if (readVal
== EOF
) { /* Is it an EOF or an error? */
407 if (feof (filePtr
)) {
410 return -1; /* Error */
412 dynBufPtr
->ptr
[dynBufPtr
->len
++] = readVal
;
414 dynBufPtr
->ptr
[dynBufPtr
->len
] = '\0';
415 return (readVal
== EOF
) ? 0 : 1;
419 *-----------------------------------------------------------------------------
423 * Given a string, produce the corresponding long value.
426 * The return value is normally TCL_OK; in this case *intPtr
427 * will be set to the integer value equivalent to string. If
428 * string is improperly formed then TCL_ERROR is returned and
429 * an error message will be left in interp->result.
434 *-----------------------------------------------------------------------------
437 Tcl_GetLong(interp
, string
, longPtr
)
438 Tcl_Interp
*interp
; /* Interpreter to use for error reporting. */
439 CONST
char *string
; /* String containing a (possibly signed)
440 * integer in a form acceptable to strtol. */
441 long *longPtr
; /* Place to store converted result. */
446 i
= strtol(string
, &end
, 0);
447 while ((*end
!= '\0') && isspace(*end
)) {
450 if ((end
== string
) || (*end
!= 0)) {
451 Tcl_AppendResult (interp
, "expected integer but got \"", string
,
452 "\"", (char *) NULL
);
460 *-----------------------------------------------------------------------------
464 * Given a string, produce the corresponding unsigned integer value.
467 * The return value is normally TCL_OK; in this case *intPtr
468 * will be set to the integer value equivalent to string. If
469 * string is improperly formed then TCL_ERROR is returned and
470 * an error message will be left in interp->result.
475 *-----------------------------------------------------------------------------
478 Tcl_GetUnsigned(interp
, string
, unsignedPtr
)
479 Tcl_Interp
*interp
; /* Interpreter to use for error reporting. */
480 CONST
char *string
; /* String containing a (possibly signed)
481 * integer in a form acceptable to strtoul. */
482 unsigned *unsignedPtr
; /* Place to store converted result. */
488 * Since some strtoul functions don't detect negative numbers, check
491 while (isspace(*string
))
493 if (string
[0] == '-')
496 i
= strtoul(string
, &end
, 0);
497 while ((*end
!= '\0') && isspace(*end
))
500 if ((end
== string
) || (*end
!= '\0'))
507 Tcl_AppendResult (interp
, "expected unsigned integer but got \"",
508 string
, "\"", (char *) NULL
);
513 *-----------------------------------------------------------------------------
515 * Tcl_ConvertFileHandle --
517 * Convert a file handle to its file number. The file handle maybe one
518 * of "stdin", "stdout" or "stderr" or "fileNNN", were NNN is the file
519 * number. If the handle is invalid, -1 is returned and a error message
520 * will be returned in interp->result. This is used when the file may
521 * not be currently open.
523 *-----------------------------------------------------------------------------
526 Tcl_ConvertFileHandle (interp
, handle
)
532 if (handle
[0] == 's') {
533 if (STREQU (handle
, "stdin"))
535 else if (STREQU (handle
, "stdout"))
537 else if (STREQU (handle
, "stderr"))
540 if (STRNEQU (handle
, "file", 4))
541 Tcl_StrToInt (&handle
[4], 10, &fileId
);
544 Tcl_AppendResult (interp
, "invalid file handle: ", handle
,
550 *-----------------------------------------------------------------------------
552 * Tcl_SetupFileEntry --
554 * Set up an entry in the Tcl file table for a file number, including the stdio
558 * o interp (I) - Current interpreter.
559 * o fileNum (I) - File number to set up the entry for.
560 * o readable (I) - TRUE if read access to the file.
561 * o writable (I) - TRUE if write access to the file.
563 * TCL_OK or TCL_ERROR;
564 *-----------------------------------------------------------------------------
567 Tcl_SetupFileEntry (interp
, fileNum
, readable
, writable
)
573 Interp
*iPtr
= (Interp
*) interp
;
579 * Set up a stdio FILE control block for the new file.
581 if (readable
&& writable
) {
583 } else if (writable
) {
588 fileCBPtr
= fdopen (fileNum
, mode
);
589 if (fileCBPtr
== NULL
) {
590 iPtr
->result
= Tcl_UnixError (interp
);
595 * Put the file in the Tcl table.
597 TclMakeFileTable (iPtr
, fileNum
);
598 if (iPtr
->filePtrArray
[fileno (fileCBPtr
)] != NULL
)
599 panic ("file already open");
600 filePtr
= (OpenFile
*) ckalloc (sizeof (OpenFile
));
601 iPtr
->filePtrArray
[fileno (fileCBPtr
)] = filePtr
;
603 filePtr
->f
= fileCBPtr
;
605 filePtr
->readable
= readable
;
606 filePtr
->writable
= writable
;
607 filePtr
->numPids
= 0;
608 filePtr
->pidPtr
= NULL
;
609 filePtr
->errorId
= -1;
615 *-----------------------------------------------------------------------------
618 * does the equivalent of the Unix "system" library call, but
619 * uses waitpid to wait on the correct process, rather than
620 * waiting on all processes and throwing the exit statii away
621 * for the processes it isn't interested in, plus does it with
625 * Standard TCL results, may return the UNIX system error message.
627 *-----------------------------------------------------------------------------
630 Tcl_System (interp
, command
)
634 int processID
, waitStatus
, processStatus
;
636 if ((processID
= Tcl_Fork()) < 0) {
637 interp
->result
= Tcl_UnixError (interp
);
640 if (processID
== 0) {
641 if (execl ("/bin/sh", "sh", "-c", command
, (char *) NULL
) < 0) {
642 interp
->result
= Tcl_UnixError (interp
);
651 #ifndef TCL_HAVE_WAITPID
652 if (Tcl_WaitPids(1, &processID
, &processStatus
) == -1) {
653 interp
->result
= Tcl_UnixError (interp
);
657 if (waitpid (processID
, &processStatus
, 0) == -1) {
658 interp
->result
= Tcl_UnixError (interp
);
662 return (WEXITSTATUS(processStatus
));
667 *--------------------------------------------------------------
669 * Tcl_ReturnDouble --
671 * Format a double to the maximum precision supported on
672 * this machine. If the number formats to an even integer,
673 * a ".0" is append to assure that the value continues to
674 * represent a floating point number.
677 * A standard Tcl result. If the result is TCL_OK, then the
678 * interpreter's result is set to the string value of the
679 * double. If the result is TCL_OK, then interp->result
680 * contains an error message (If the number had the value of
681 * "not a number" or "infinite").
686 *--------------------------------------------------------------
690 Tcl_ReturnDouble(interp
, number
)
691 Tcl_Interp
*interp
; /* ->result gets converted number */
692 double number
; /* Number to convert */
694 static int precision
= 0;
695 register char *scanPtr
;
698 * On the first call, determine the number of decimal digits that represent
699 * the precision of a double.
701 if (precision
== 0) {
705 sprintf (interp
->result
, "%.0f", pow (2.0, (double) DSIGNIF
));
706 precision
= strlen (interp
->result
);
710 sprintf (interp
->result
, "%.*g", precision
, number
);
713 * Scan the number for "." or "e" to assure that the number has not been
714 * converted to an integer. Also check for NaN on infinite
717 scanPtr
= interp
->result
;
718 if (scanPtr
[0] == '-')
720 for (; isdigit (*scanPtr
); scanPtr
++)
729 interp
->result
= "Floating point error, result is not a number";
733 interp
->result
= "Floating point error, result is infinite";
743 * If we made it here, this sprintf returned something we did not expect.
745 Tcl_AppendResult (interp
, ": unexpected floating point conversion result",