1 /*
2 * This file was written by Bill Cox, originally in 1991, and maintained since. It is hereby
3 * placed into the public domain.
4 */
5
6 #include <stdlib.h>
7 #include <stdio.h>
8 #include <time.h>
9 #include <ctype.h>
10 #include <string.h>
11 #include <errno.h>
12 #include "ddutil.h"
13 #include "utmem.h"
14
15 bool _utInitialized = false;
16 utSymtab utTheSymtab;
17 uint32 utSetjmpLine[UT_MAX_SETJMP_DEPTH];
18 char *utSetjmpFile[UT_MAX_SETJMP_DEPTH];
19 char *utConfigDirectory = NULL;
20 static char *utExeDirectory = NULL;
21 static char *utExeFullPath = NULL;
22 static FILE *utLogFile = NULL;
23 static FILE *utReportFile = NULL;
24 static FILE *utDebugFile = NULL;
25 static char *utLogFileName = NULL;
26 static char *utReportFileName = NULL;
27 static char *utDebugFileName = NULL;
28 uint32 utDebugVal = 0;
29 uint32 utVerboseVal = 0;
30 #define UT_MAX_BUFFERS 42
31 static char *utBuffers[UT_MAX_BUFFERS];
32 static uint16 utNextBuffer;
33 static uint32 utBufferSizes[UT_MAX_BUFFERS];
34 static time_t utTimers[UT_MAX_BUFFERS];
35 static uint16 utTimerDepth = 0;
36 static utErrorProc utUserErrProc = NULL, utUserWarningProc = NULL, utUserStatusProc = NULL, utUserLogMessageProc = NULL;
37 static utExitProc utUserExitProc = NULL;
38 static char *utVersion = NULL;
39 int16 utSetjmpDepth = 0;
40 static uint32 utSymNextIndex;
41 static bool utMessageHeaderEnabled = false;
42
43 /*--------------------------------------------------------------------------------------------------
44 Like ansi sprintf.
45 --------------------------------------------------------------------------------------------------*/
utSprintf(char * format,...)46 char *utSprintf(
47 char *format,
48 ...)
49 {
50 va_list ap;
51 char *returnBuffer;
52
53 va_start(ap, format);
54 returnBuffer = utVsprintf(format, ap);
55 va_end(ap);
56 return returnBuffer;
57 }
58
59 /*--------------------------------------------------------------------------------------------------
60 Enable the message header tags to add info to the messages
61 --------------------------------------------------------------------------------------------------*/
utEnableMessageHeaders(bool value)62 void utEnableMessageHeaders(
63 bool value)
64 {
65 utMessageHeaderEnabled = value;
66 }
67
68 /*--------------------------------------------------------------------------------------------------
69 get the message prefix
70 --------------------------------------------------------------------------------------------------*/
getMessageNameFromType(utMessageType msgType)71 static char* getMessageNameFromType(
72 utMessageType msgType)
73 {
74 switch(msgType) {
75 case UT_MESSAGE_INFO: return "INFO:";
76 case UT_MESSAGE_WARNING: return "WARNING:";
77 case UT_MESSAGE_ERROR: return "ERROR:";
78 case UT_MESSAGE_EXIT: return "EXIT:";
79 case UT_MESSAGE_DETAILS: return "DETAILS:";
80 case UT_MESSAGE_INTERNAL: return "DEBUG:";
81 case UT_MESSAGE_REPORT: return "REPORT: ";
82 }
83 return "";
84 }
85
86 /*--------------------------------------------------------------------------------------------------
87 Log a message to the debug file.
88 --------------------------------------------------------------------------------------------------*/
utLogMessageType(utMessageType msgType,char * format,...)89 void utLogMessageType(
90 utMessageType msgType,
91 char *format,
92 ...)
93 {
94 va_list ap;
95 char *buff;
96
97 va_start(ap, format);
98 buff = utVsprintf((char *)format, ap);
99 va_end(ap);
100 if(utMessageHeaderEnabled || msgType == UT_MESSAGE_ERROR || msgType == UT_MESSAGE_EXIT ||
101 msgType == UT_MESSAGE_WARNING) {
102 buff = utSprintf("%s%s", getMessageNameFromType(msgType), buff);
103 }
104 if(utUserLogMessageProc != NULL) {
105 (utUserLogMessageProc)(buff);
106 }
107 if(utLogFile == NULL) {
108 return;
109 }
110 fputs(buff, utLogFile);
111 fflush(utLogFile);
112 }
113
114 /*--------------------------------------------------------------------------------------------------
115 Function to report results
116 --------------------------------------------------------------------------------------------------*/
utReport(char * format,...)117 void utReport(
118 char *format, ...)
119 {
120 va_list ap;
121 char *buff;
122
123 va_start(ap, format);
124 buff = utVsprintf(format, ap);
125 va_end(ap);
126 if(utReportFile == NULL) {
127 utLogMessageType(UT_MESSAGE_REPORT, "%s", buff);
128 return;
129 }
130 fputs(buff, utReportFile);
131 fflush(utReportFile);
132 }
133
134 /*--------------------------------------------------------------------------------------------------
135 Same as utLogDebug but without the newline & prefix.
136 --------------------------------------------------------------------------------------------------*/
utDebug(char * format,...)137 bool utDebug(
138 char *format,
139 ...)
140 {
141 va_list ap;
142 char *buff;
143
144 va_start(ap, format);
145 buff = utVsprintf((char *)format, ap);
146 va_end(ap);
147 if(utDebugFile == NULL) {
148 utLogMessageType(UT_MESSAGE_INTERNAL, "%s", buff);
149 return true;
150 }
151 fputs(buff, utDebugFile);
152 fflush(utDebugFile);
153 return true; /* So utDebug can be used in ',' expressions */
154 }
155
156 /*--------------------------------------------------------------------------------------------------
157 Log a message to the debug file.
158 --------------------------------------------------------------------------------------------------*/
utLogDebug(char * format,...)159 void utLogDebug(
160 char *format,
161 ...)
162 {
163 va_list ap;
164 char *buff;
165
166 va_start(ap, format);
167 buff = utVsprintf((char *)format, ap);
168 va_end(ap);
169 if(utUserStatusProc != NULL) {
170 utStatus("%s\n", buff);
171 } else if(!utMessageHeaderEnabled) {
172 printf("%s\n", buff);
173 fflush(stdout);
174 }
175 utDebug("%s\n", buff);
176 }
177
178 /*--------------------------------------------------------------------------------------------------
179 Log a message to the debug file.
180 --------------------------------------------------------------------------------------------------*/
utLogString(char * format,...)181 void utLogString(
182 char *format,
183 ...)
184 {
185 va_list ap;
186 char *buff;
187
188 va_start(ap, format);
189 buff = utVsprintf((char *)format, ap);
190 va_end(ap);
191 if(utUserStatusProc != NULL) {
192 utStatus("%s", buff);
193 } else if(!utMessageHeaderEnabled) {
194 printf("%s", buff);
195 fflush(stdout);
196 }
197 utLogMessageType(UT_MESSAGE_INFO, "%s", buff);
198 }
199
200 /*--------------------------------------------------------------------------------------------------
201 Log a message to the debug file.
202 --------------------------------------------------------------------------------------------------*/
utLogMessage(char * format,...)203 void utLogMessage(
204 char *format,
205 ...)
206 {
207 va_list ap;
208 char *buff;
209
210 va_start(ap, format);
211 buff = utVsprintf((char *)format, ap);
212 va_end(ap);
213 if(utUserStatusProc != NULL) {
214 utStatus("%s\n", buff);
215 } else {
216 printf("%s\n", buff);
217 fflush(stdout);
218 }
219 utLogMessageType(UT_MESSAGE_INFO, "%s\n", buff);
220 }
221
222 /*--------------------------------------------------------------------------------------------------
223 Print a message, and start recording the time since this message.
224 --------------------------------------------------------------------------------------------------*/
utStartTimer(char * format,...)225 uint32 utStartTimer(
226 char *format,
227 ...)
228 {
229 va_list ap;
230 char *buff;
231 uint16 timerID = utTimerDepth++;
232
233 utTimers[timerID] = time(NULL);
234 if(format != NULL) {
235 va_start(ap, format);
236 buff = utVsprintf((char *)format, ap);
237 va_end(ap);
238 utLogMessageType(UT_MESSAGE_INFO, "%s\n", buff);
239 if(utUserStatusProc != NULL) {
240 utLogMessage("%s", buff);
241 } else {
242 printf("%s\n", buff);
243 fflush(stdout);
244 }
245 }
246 return timerID;
247 }
248
249 /*--------------------------------------------------------------------------------------------------
250 Print a message about the length of the current timer.
251 --------------------------------------------------------------------------------------------------*/
utStopTimer(uint32 timerID,char * format,...)252 void utStopTimer(
253 uint32 timerID,
254 char *format,
255 ...)
256 {
257 va_list ap;
258 char *buff;
259 uint32 deltaTime = (uint32)difftime(time(NULL), utTimers[--utTimerDepth]);
260 uint32 hours, minutes, seconds;
261
262 if(timerID != utTimerDepth) {
263 utWarning("Timer start/stop mismatch!");
264 }
265 hours = deltaTime/3600;
266 deltaTime -= hours*3600;
267 minutes = deltaTime/60;
268 deltaTime -= minutes*60;
269 seconds = deltaTime;
270 va_start(ap, format);
271 buff = utVsprintf((char *)format, ap);
272 va_end(ap);
273 utLogMessageType(UT_MESSAGE_INFO, "%s %u:%02u:%02u\n", buff, hours, minutes, seconds);
274 if(utUserStatusProc != NULL) {
275 utStatus("%s %u:%02u:%02u\n", buff, hours, minutes, seconds);
276 } else {
277 printf("%s %u:%02u:%02u\n", buff, hours, minutes, seconds);
278 fflush(stdout);
279 }
280 }
281
282 /*--------------------------------------------------------------------------------------------------
283 Function to log errors without a message box to log file.
284 --------------------------------------------------------------------------------------------------*/
utLogError(char * format,...)285 void utLogError(
286 char *format,
287 ...)
288 {
289 va_list ap;
290 char *buff;
291
292 va_start(ap, format);
293 buff = utVsprintf(format, ap);
294 va_end(ap);
295 utLogMessageType(UT_MESSAGE_ERROR, "%s\n", buff);
296 }
297
298 /*--------------------------------------------------------------------------------------------------
299 Function to Send a message to the log file. Prefix with a time stamp line and a comment character.
300 --------------------------------------------------------------------------------------------------*/
utLogTimeStamp(char * message,...)301 void utLogTimeStamp(
302 char *message,
303 ...)
304 {
305 time_t timeInt = time(NULL);
306 char *timeStr = ctime(&timeInt);
307 va_list ap;
308 char *buff1;
309
310 va_start(ap, message);
311 buff1 = utVsprintf(message, ap);
312 va_end(ap);
313 utLogMessageType(UT_MESSAGE_INFO, "%s : %s", buff1, timeStr);
314 }
315
316 /*--------------------------------------------------------------------------------------------------
317 Function to log the status of a tool to log file
318 --------------------------------------------------------------------------------------------------*/
utStatus(char * format,...)319 void utStatus(
320 char *format, ...)
321 {
322 va_list ap;
323 char *buff;
324
325 va_start(ap, format);
326 buff = utVsprintf(format, ap);
327 va_end(ap);
328 if(utUserStatusProc != NULL) {
329 (utUserStatusProc)(buff);
330 } else {
331 printf("%s", buff);
332 fflush(stdout);
333 }
334 }
335
336 static char *utExitFileName;
337 static uint32 utExitLineNum;
338 /*--------------------------------------------------------------------------------------------------
339 Exit with a fatal error message.
340 --------------------------------------------------------------------------------------------------*/
utExit_(char * format,...)341 void utExit_(
342 char *format,
343 ...)
344 {
345 va_list ap;
346 char *buff;
347
348 va_start(ap, format);
349 buff = utVsprintf((char *)format, ap);
350 va_end(ap);
351 if(utUserStatusProc != NULL) {
352 utStatus("%s\n", buff);
353 } else if(!utMessageHeaderEnabled) {
354 printf("%s\n", buff);
355 fflush(stdout);
356 }
357 if(utExitFileName == NULL) {
358 utLogMessageType(UT_MESSAGE_EXIT, "%s\n", buff);
359 } else {
360 utLogMessageType(UT_MESSAGE_EXIT, "%s:%u %s\n", utExitFileName, utExitLineNum, buff);
361 }
362 if(utUserErrProc != NULL) {
363 (utUserErrProc)(buff);
364 }
365 exit(1);
366 }
367
368 /*--------------------------------------------------------------------------------------------------
369 Set the file and line globals so that utExit_ can print them. Return utExit_ so it can be called
370 with the user's parameters.
371 --------------------------------------------------------------------------------------------------*/
utSetFileAndLineAndReturnExitFunc(char * fileName,uint32 lineNum)372 utExitProcType utSetFileAndLineAndReturnExitFunc(
373 char *fileName,
374 uint32 lineNum)
375 {
376 utExitFileName = fileName;
377 utExitLineNum = lineNum;
378 return &utExit_;
379 }
380
381 /*--------------------------------------------------------------------------------------------------
382 Post a warning message.
383 --------------------------------------------------------------------------------------------------*/
utWarning(char * format,...)384 void utWarning(
385 char *format,
386 ...)
387 {
388 va_list ap;
389 char *buff;
390
391 va_start(ap, format);
392 buff = utVsprintf((char *)format, ap);
393 va_end(ap);
394 if(utUserStatusProc != NULL) {
395 utStatus("%s\n", buff);
396 } else if(!utMessageHeaderEnabled) {
397 printf("%s\n", buff);
398 fflush(stdout);
399 }
400 utLogMessageType(UT_MESSAGE_WARNING, "%s\n", buff);
401 if(utUserWarningProc != NULL) {
402 (utUserWarningProc)(buff);
403 }
404 }
405
406 /*--------------------------------------------------------------------------------------------------
407 Post a note.
408 --------------------------------------------------------------------------------------------------*/
utNote(char * format,...)409 void utNote(
410 char *format,
411 ...)
412 {
413 va_list ap;
414 char *buff;
415
416 va_start(ap, format);
417 buff = utVsprintf((char *)format, ap);
418 va_end(ap);
419 utReport("%s\n", buff);
420 }
421
422 /*--------------------------------------------------------------------------------------------------
423 Post an error message, and longjump.
424 This function just returns a value so that it can be used for inline macros as a return value.
425 --------------------------------------------------------------------------------------------------*/
utError(char * format,...)426 void utError(
427 char *format,
428 ...)
429 {
430 va_list ap;
431 char *buff;
432
433 va_start(ap, format);
434 buff = utVsprintf((char *)format, ap);
435 va_end(ap);
436 if(utUserStatusProc != NULL) {
437 utStatus("%s\n", buff);
438 } else if(!utMessageHeaderEnabled) {
439 printf("%s\n", buff);
440 fflush(stdout);
441 }
442 utLogMessageType(UT_MESSAGE_ERROR, "%s\n", buff);
443 utLongjmp();
444 }
445
446 /*--------------------------------------------------------------------------------------------------
447 Post an error message, and exit. Do not report file and line number, since this is a user error.
448 --------------------------------------------------------------------------------------------------*/
utCriticalError(char * format,...)449 void utCriticalError(
450 char *format,
451 ...)
452 {
453 va_list ap;
454 char *buff;
455
456 va_start(ap, format);
457 buff = utVsprintf((char *)format, ap);
458 va_end(ap);
459 utLogMessageType(UT_MESSAGE_ERROR, "%s\n", buff);
460 exit(1);
461 }
462
463 /*--------------------------------------------------------------------------------------------------
464 Cry and die.
465 --------------------------------------------------------------------------------------------------*/
utAssert_(char * fileName,uint32 line,char * text)466 void utAssert_(
467 char *fileName,
468 uint32 line,
469 char *text)
470 {
471 utMemCheck();
472 utExitFileName = NULL; /* we don't want "util.c" and the utAssert line number to print */
473 utExit_("Assertion failed in file %s on line %u: %s", fileName, line, text);
474 }
475
476 /*--------------------------------------------------------------------------------------------------
477 Set the name of the Error callback.
478 --------------------------------------------------------------------------------------------------*/
utSetErrorCallback(utErrorProc errorProc)479 void utSetErrorCallback(
480 utErrorProc errorProc)
481 {
482 utUserErrProc = errorProc;
483 }
484
485 /*--------------------------------------------------------------------------------------------------
486 Set the name of the Warning callback.
487 --------------------------------------------------------------------------------------------------*/
utSetWarningCallback(utErrorProc warningProc)488 void utSetWarningCallback(
489 utErrorProc warningProc)
490 {
491 utUserWarningProc = warningProc;
492 }
493
494 /*--------------------------------------------------------------------------------------------------
495 Set the name of the status update callback.
496 --------------------------------------------------------------------------------------------------*/
utSetStatusCallback(utErrorProc statusProc)497 void utSetStatusCallback(
498 utErrorProc statusProc)
499 {
500 utUserStatusProc = statusProc;
501 }
502
503 /*--------------------------------------------------------------------------------------------------
504 Set the name of the log message callback.
505 --------------------------------------------------------------------------------------------------*/
utSetLogMessageCallback(utErrorProc logMessageProc)506 void utSetLogMessageCallback(
507 utErrorProc logMessageProc)
508 {
509 utUserLogMessageProc = logMessageProc;
510 }
511
512 /*--------------------------------------------------------------------------------------------------
513 Get the name of the Error callback.
514 --------------------------------------------------------------------------------------------------*/
utGetErrorCallback(void)515 utErrorProc utGetErrorCallback(void)
516 {
517 return utUserErrProc;
518 }
519
520 /*--------------------------------------------------------------------------------------------------
521 Get the name of the Warning callback.
522 --------------------------------------------------------------------------------------------------*/
utGetWarningCallback(void)523 utErrorProc utGetWarningCallback(void)
524 {
525 return utUserWarningProc;
526 }
527
528 /*--------------------------------------------------------------------------------------------------
529 Get the name of the status update callback.
530 --------------------------------------------------------------------------------------------------*/
utGetStatusCallback(void)531 utErrorProc utGetStatusCallback(void)
532 {
533 return utUserStatusProc;
534 }
535
536 /*--------------------------------------------------------------------------------------------------
537 Get the name of the log message callback.
538 --------------------------------------------------------------------------------------------------*/
utGetLogMessageCallback(void)539 utErrorProc utGetLogMessageCallback(void)
540 {
541 return utUserLogMessageProc;
542 }
543
544 /*--------------------------------------------------------------------------------------------------
545 Set the name of the logging file and reset it.
546 --------------------------------------------------------------------------------------------------*/
utInitDebugFile(char * fileName)547 void utInitDebugFile(
548 char *fileName)
549 {
550 utSetDebugFile(fileName);
551 }
552
553 /*--------------------------------------------------------------------------------------------------
554 Just return the logi file name.
555 --------------------------------------------------------------------------------------------------*/
utGetDebugFile(void)556 FILE *utGetDebugFile(void)
557 {
558 return utDebugFile;
559 }
560
561 /*--------------------------------------------------------------------------------------------------
562 Just return the logi file name.
563 --------------------------------------------------------------------------------------------------*/
utGetDebugFileName(void)564 char *utGetDebugFileName(void)
565 {
566 return utDebugFileName;
567 }
568
569 /*--------------------------------------------------------------------------------------------------
570 Set the name of the logging file without resetting it.
571 --------------------------------------------------------------------------------------------------*/
utSetDebugFile(char * fileName)572 void utSetDebugFile(
573 char *fileName)
574 {
575 if(utDebugFile != NULL) {
576 fclose(utDebugFile);
577 utDebugFile = NULL;
578 }
579 if(utDebugFileName != NULL) {
580 utFree(utDebugFileName);
581 }
582 utDebugFileName = utNewA(char, strlen(fileName) + 1);
583 strcpy(utDebugFileName, fileName);
584 utDebugFile = fopen(fileName, "w");
585 }
586
587 /*--------------------------------------------------------------------------------------------------
588 Set the name of the logging file and reset it.
589 --------------------------------------------------------------------------------------------------*/
utInitReportFile(char * fileName)590 void utInitReportFile(
591 char *fileName)
592 {
593 utSetReportFile(fileName);
594 }
595
596 /*--------------------------------------------------------------------------------------------------
597 Just return the logi file name.
598 --------------------------------------------------------------------------------------------------*/
utGetReportFile(void)599 FILE *utGetReportFile(void)
600 {
601 return utReportFile;
602 }
603
604 /*--------------------------------------------------------------------------------------------------
605 Just return the logi file name.
606 --------------------------------------------------------------------------------------------------*/
utGetReportFileName(void)607 char *utGetReportFileName(void)
608 {
609 return utReportFileName;
610 }
611
612 /*--------------------------------------------------------------------------------------------------
613 Set the name of the logging file without resetting it.
614 --------------------------------------------------------------------------------------------------*/
utSetReportFile(char * fileName)615 void utSetReportFile(
616 char *fileName)
617 {
618 if(utReportFile != NULL) {
619 fclose(utReportFile);
620 }
621 if(utReportFileName != NULL) {
622 utFree(utReportFileName);
623 }
624 utReportFileName = utNewA(char, strlen(fileName) + 1);
625 strcpy(utReportFileName, fileName);
626 utReportFile = fopen(fileName, "w");
627 }
628
629 /*--------------------------------------------------------------------------------------------------
630 Set the name of the logging file and reset it.
631 --------------------------------------------------------------------------------------------------*/
utInitLogFile(char * fileName)632 void utInitLogFile(
633 char *fileName)
634 {
635 utSetLogFile(fileName);
636 }
637
638 /*--------------------------------------------------------------------------------------------------
639 Just return the logi file name.
640 --------------------------------------------------------------------------------------------------*/
utGetLogFileName(void)641 char *utGetLogFileName(void)
642 {
643 return utLogFileName;
644 }
645
646 /*--------------------------------------------------------------------------------------------------
647 Just return the logi file name.
648 --------------------------------------------------------------------------------------------------*/
utGetLogFile(void)649 FILE *utGetLogFile(void)
650 {
651 return utLogFile;
652 }
653
654 /*--------------------------------------------------------------------------------------------------
655 Set the name of the logging file without resetting it.
656 --------------------------------------------------------------------------------------------------*/
utSetLogFile(char * fileName)657 void utSetLogFile(
658 char *fileName)
659 {
660 if(utLogFile != NULL) {
661 fclose(utLogFile);
662 }
663 if(utLogFileName != NULL) {
664 utFree(utLogFileName);
665 }
666 utLogFileName = utNewA(char, strlen(fileName) + 1);
667 strcpy(utLogFileName, fileName);
668 utLogFile = fopen(fileName, "w");
669 }
670
671 /*--------------------------------------------------------------------------------------------------
672 Set the name of the configuration file directory.
673 --------------------------------------------------------------------------------------------------*/
utSetConfigDirectory(char * dirName)674 void utSetConfigDirectory(
675 char *dirName)
676 {
677 if(utConfigDirectory != NULL) {
678 utFree(utConfigDirectory);
679 }
680 utConfigDirectory = utNewA(char, strlen(dirName) + 1);
681 strcpy(utConfigDirectory, dirName);
682 }
683
684 /*--------------------------------------------------------------------------------------------------
685 Set the name of the executable file directory.
686 --------------------------------------------------------------------------------------------------*/
utSetExeDirectory(char * dirName)687 void utSetExeDirectory(
688 char *dirName)
689 {
690 if(utExeDirectory != NULL) {
691 utFree(utExeDirectory);
692 }
693 utExeDirectory = utNewA(char, strlen(dirName) + 1);
694 strcpy(utExeDirectory, dirName);
695 }
696
697 /*--------------------------------------------------------------------------------------------------
698 Return the exec directory.
699 --------------------------------------------------------------------------------------------------*/
utGetExeDirectory(void)700 char *utGetExeDirectory(void)
701 {
702 return utExeDirectory;
703 }
704
705 /*--------------------------------------------------------------------------------------------------
706 Return the config directory.
707 --------------------------------------------------------------------------------------------------*/
utGetConfigDirectory(void)708 char *utGetConfigDirectory(void)
709 {
710 return utConfigDirectory;
711 }
712
713 /*--------------------------------------------------------------------------------------------------
714 Set the complete path and name of the executable file (argv[0])
715 --------------------------------------------------------------------------------------------------*/
utSetExeFullPath(char * fullName)716 void utSetExeFullPath(
717 char *fullName)
718 {
719 if(utExeFullPath != NULL) {
720 utFree(utExeFullPath);
721 }
722 utExeFullPath = utNewA(char, strlen(fullName) + 1);
723 strcpy(utExeFullPath, fullName);
724 }
725
726 /*--------------------------------------------------------------------------------------------------
727 Return the full path of the executable file.
728 --------------------------------------------------------------------------------------------------*/
utGetExeFullPath(void)729 char *utGetExeFullPath(void)
730 {
731 return utExeFullPath;
732 }
733
734 /*--------------------------------------------------------------------------------------------------
735 Just set the version variable.
736 --------------------------------------------------------------------------------------------------*/
utSetVersion(char * version)737 void utSetVersion(
738 char *version)
739 {
740 if(utVersion != NULL) {
741 utFree(utVersion);
742 }
743 utVersion = utNewA(char, strlen(version) + 1);
744 strcpy(utVersion, version);
745 }
746
747 /*--------------------------------------------------------------------------------------------------
748 Return the version variable.
749 --------------------------------------------------------------------------------------------------*/
utGetVersion(void)750 char *utGetVersion(void)
751 {
752 return utVersion;
753 }
754
755 /*--------------------------------------------------------------------------------------------------
756 Initialize generic buffer memory.
757 --------------------------------------------------------------------------------------------------*/
initBuffers(void)758 static void initBuffers(void)
759 {
760 uint16 xBuffer;
761
762 utNextBuffer = 0;
763 for(xBuffer = 0; xBuffer < UT_MAX_BUFFERS; xBuffer++) {
764 utBufferSizes[xBuffer] = 42;
765 utBuffers[xBuffer] = (char *)calloc(utBufferSizes[xBuffer], sizeof(char));
766 }
767 }
768
769 /*--------------------------------------------------------------------------------------------------
770 Free generic buffer memory.
771 --------------------------------------------------------------------------------------------------*/
freeBuffers(void)772 static void freeBuffers(void)
773 {
774 uint16 xBuffer;
775
776 utNextBuffer = 0;
777 for(xBuffer = 0; xBuffer < UT_MAX_BUFFERS; xBuffer++) {
778 free(utBuffers[xBuffer]);
779 }
780 }
781
782 /*--------------------------------------------------------------------------------------------------
783 Free memory used by the utility module.
784 --------------------------------------------------------------------------------------------------*/
utStop(bool reportTimeAndMemory)785 void utStop(
786 bool reportTimeAndMemory)
787 {
788 if(utInitialized()) {
789 if(utSetjmpDepth > 0 && utSetjmpDepth < UT_MAX_SETJMP_DEPTH) {
790 utWarning("utClose: utSetjmpDepth != 0 (file %s, line %u)",
791 utSetjmpFile[utSetjmpDepth - 1],
792 utSetjmpLine[utSetjmpDepth - 1]);
793 } else if(utSetjmpDepth != 0) {
794 utWarning("utClose: utSetjmpDepth has an invalid value");
795 /* prevents crashes */
796 }
797 if(utTimerDepth != 1) {
798 utWarning("utClose: timer started, but never stopped");
799 } else if(reportTimeAndMemory) {
800 utStopTimer(0, "Process completed in");
801 }
802 utDatabaseManagerStop();
803 utDatabaseStop();
804 utFreePersistenceObjects();
805 utInitialized() = false;
806 if(utReportFile != NULL) {
807 fflush(utReportFile);
808 fclose(utReportFile);
809 utFree(utReportFileName);
810 utReportFileName = NULL;
811 utReportFile = NULL;
812 }
813 if(utDebugFile != NULL) {
814 fflush(utDebugFile);
815 fclose(utDebugFile);
816 utFree(utDebugFileName);
817 utDebugFileName = NULL;
818 utDebugFile = NULL;
819 }
820 if(utLogFile != NULL) {
821 fflush(utLogFile);
822 fclose(utLogFile);
823 utFree(utLogFileName);
824 utLogFileName = NULL;
825 utLogFile = NULL;
826 }
827 if(utConfigDirectory != NULL) {
828 utFree(utConfigDirectory);
829 utConfigDirectory = NULL;
830 }
831 if(utExeDirectory != NULL) {
832 utFree(utExeDirectory);
833 utExeDirectory = NULL;
834 }
835 if(utExeFullPath != NULL) {
836 utFree(utExeFullPath);
837 utExeFullPath = NULL;
838 }
839 if(utVersion != NULL) {
840 utFree(utVersion);
841 utVersion = NULL;
842 }
843 utMemStop(reportTimeAndMemory);
844 freeBuffers();
845 }
846 }
847
848 /*--------------------------------------------------------------------------------------------------
849 Initialize symbol table entries to utSymNull.
850 --------------------------------------------------------------------------------------------------*/
utInitSymTable(void)851 void utInitSymTable(void)
852 {
853 uint32 xSym;
854
855 utTheSymtab = utSymtabAlloc();
856 utSymtabAllocTables(utTheSymtab, 2);
857 for(xSym = 0; xSym < 2; xSym++) {
858 utSymtabSetiTable(utTheSymtab, xSym, utSymNull);
859 }
860 }
861
862 /*--------------------------------------------------------------------------------------------------
863 Initialize local memory.
864 --------------------------------------------------------------------------------------------------*/
utStart(void)865 void utStart(void)
866 {
867 if(!utInitialized()) {
868 utMemStart();
869 utUserErrProc = 0;
870 utUserExitProc = 0;
871 utInitialized() = true;
872 utSetjmpDepth = 0;
873 utTimerDepth = 0;
874 initBuffers();
875 utStartTimer(NULL);
876 utInitSeed(4357);
877 utAllocPersistenceObjects();
878 utDatabaseStart();
879 utInitSymTable();
880 utDatabaseManagerStart();
881 }
882 }
883
884 /*--------------------------------------------------------------------------------------------------
885 Just like mtRealloc, but pass file name and line number.
886 --------------------------------------------------------------------------------------------------*/
utReallocTrace(void * memPtr,size_t num,size_t size,char * fileName,uint32 line)887 void *utReallocTrace(
888 void *memPtr,
889 size_t num,
890 size_t size,
891 char *fileName,
892 uint32 line)
893 {
894 utMemRef mem;
895 size_t newSize = (num + 1)*size;
896
897 if(memPtr == NULL) {
898 return utMallocTrace(num, size, fileName, line);
899 }
900 mem = utqMemPtr(memPtr);
901 utMemCheckTrace(fileName, line);
902 if(!uttMemExists(mem)) {
903 utExit("utRealloc: Bad memory pointer in %s, line %u", fileName, line);
904 }
905 utdMem(mem, true, fileName, line);
906 memPtr = realloc(memPtr, (num + 1)*size);
907 if(memPtr != NULL) {
908 utBuildMem(memPtr, newSize, true, fileName, line);
909 } else {
910 utLogMessage("utRealloc: unable to allocate memory %lu. Total used: %lu",
911 num*(size+1), utUsedMem);
912 }
913 return memPtr;
914
915 }
916
917 /*--------------------------------------------------------------------------------------------------
918 Just like mtMalloc, but pass file name and line number.
919 --------------------------------------------------------------------------------------------------*/
utMallocTrace(size_t sStruct,size_t size,char * fileName,uint32 line)920 void *utMallocTrace(
921 size_t sStruct,
922 size_t size,
923 char *fileName,
924 uint32 line)
925 {
926 size_t sByte = sStruct*size;
927 void *memPtr = malloc(sByte + 1);
928
929 utMemCheckTrace(fileName, line);
930 if(memPtr != NULL) {
931 utBuildMem(memPtr, sByte + 1, true, fileName, line);
932 } else {
933 utLogMessage("utRealloc: unable to allocate memory %lu. Total used: %lu",
934 sByte, utUsedMem);
935 }
936 return memPtr;
937 }
938
939 /*--------------------------------------------------------------------------------------------------
940 Just like calloc, but pass file name and line number.
941 --------------------------------------------------------------------------------------------------*/
utCallocTrace(size_t sStruct,size_t size,char * fileName,uint32 line)942 void *utCallocTrace(
943 size_t sStruct,
944 size_t size,
945 char *fileName,
946 uint32 line)
947 {
948 size_t sByte = sStruct*size;
949 void *memPtr;
950
951 memPtr = utMallocTrace(sStruct, size, fileName, line);
952 if(memPtr) {
953 memset((void *)memPtr, 0, sByte);
954 }
955 return memPtr;
956 }
957
958 /*--------------------------------------------------------------------------------------------------
959 Just like mtFree, but pass file name and line number.
960 --------------------------------------------------------------------------------------------------*/
utFreeTrace(void * memPtr,char * fileName,uint32 line)961 void utFreeTrace(
962 void *memPtr,
963 char *fileName,
964 uint32 line)
965 {
966 utMemRef mem = utqMemPtr(memPtr);
967
968 utMemCheckTrace(fileName, line);
969 if(!uttMemExists(mem)) {
970 utExit("utFree: Bad memory pointer in %s, line %u", fileName, line);
971 }
972 utdMem(mem, true, fileName, line);
973 free(memPtr);
974 }
975
976 /*--------------------------------------------------------------------------------------------------
977 Just find a hash value for the symbol name.
978 --------------------------------------------------------------------------------------------------*/
utHashString(char * name)979 uint32 utHashString(
980 char *name)
981 {
982 uint32 hashValue = 0;
983
984 do {
985 hashValue = utHashValues(hashValue, *name);
986 } while(*name++);
987 return hashValue;
988 }
989
990 /*--------------------------------------------------------------------------------------------------
991 Just find a hash value for the symbol name.
992 --------------------------------------------------------------------------------------------------*/
utHashData(void * data,uint32 length)993 uint32 utHashData(
994 void *data,
995 uint32 length)
996 {
997 uint8 *dataPtr = (uint8 *)data;
998 uint32 hashValue = 0;
999
1000 while(length--) {
1001 hashValue = utHashValues(hashValue, *dataPtr);
1002 dataPtr++;
1003 }
1004 return hashValue;
1005 }
1006
1007 /*--------------------------------------------------------------------------------------------------
1008 Just find a hash value for the float value.
1009 --------------------------------------------------------------------------------------------------*/
utHashFloat(float value)1010 uint32 utHashFloat(
1011 float value)
1012 {
1013 uint8 *data = (uint8 *)(void *)&value;
1014
1015 return utHashData(data, sizeof(float));
1016 }
1017
1018 /*--------------------------------------------------------------------------------------------------
1019 Just find a hash value for the double value.
1020 --------------------------------------------------------------------------------------------------*/
utHashDouble(double value)1021 uint32 utHashDouble(
1022 double value)
1023 {
1024 uint8 *data = (uint8 *)(void *)&value;
1025
1026 return utHashData(data, sizeof(double));
1027 }
1028
1029 /*--------------------------------------------------------------------------------------------------
1030 Symbol table support.
1031 --------------------------------------------------------------------------------------------------*/
1032
1033 /*--------------------------------------------------------------------------------------------------
1034 Find a symbol in the symbol table.
1035 --------------------------------------------------------------------------------------------------*/
symtabFindSym(char * name,uint32 hashValue)1036 static utSym symtabFindSym(
1037 char *name,
1038 uint32 hashValue)
1039 {
1040 uint32 index = (utSymtabGetNumTable(utTheSymtab) - 1) & hashValue;
1041 utSym sym = utSymtabGetiTable(utTheSymtab, index);
1042
1043 while(sym != utSymNull) {
1044 if(!strcmp(name, utSymGetName(sym))) {
1045 return sym;
1046 }
1047 sym = utSymGetNext(sym);
1048 }
1049 return utSymNull;
1050 }
1051
1052 /*--------------------------------------------------------------------------------------------------
1053 Build a new symbol, or return an old one with the same name.
1054 --------------------------------------------------------------------------------------------------*/
addSymTableSym(utSym sym)1055 static void addSymTableSym(
1056 utSym sym)
1057 {
1058 uint32 hashValue = utSymGetHashValue(sym);
1059 uint32 index = (utSymtabGetNumTable(utTheSymtab) - 1) & hashValue;
1060 utSym nextSym = utSymtabGetiTable(utTheSymtab, index);
1061
1062 utSymSetNext(sym, nextSym);
1063 utSymtabSetiTable(utTheSymtab, index, sym);
1064 utSymtabSetNumSym(utTheSymtab, utSymtabGetNumSym(utTheSymtab) + 1);
1065 }
1066
1067 /*--------------------------------------------------------------------------------------------------
1068 Resize the symbol table. Make it twice as big.
1069 --------------------------------------------------------------------------------------------------*/
resizeSymtab(void)1070 static void resizeSymtab(void)
1071 {
1072 utSym sym;
1073 uint32 numSyms = utSymtabGetNumTable(utTheSymtab) << 1;
1074 uint32 xSym;
1075
1076 utSymtabResizeTables(utTheSymtab, numSyms);
1077 for(xSym = 0; xSym < numSyms; xSym++) {
1078 utSymtabSetiTable(utTheSymtab, xSym, utSymNull);
1079 }
1080 utSymtabSetNumSym(utTheSymtab, 0);
1081 utForeachSym(sym) {
1082 addSymTableSym(sym);
1083 } utEndSym;
1084 }
1085
1086 /*--------------------------------------------------------------------------------------------------
1087 Build a new symbol, or return an old one with the same name.
1088 --------------------------------------------------------------------------------------------------*/
utSymCreate(char * name)1089 utSym utSymCreate(
1090 char *name)
1091 {
1092 uint32 hashValue = utHashString(name);
1093 utSym sym = symtabFindSym(name, hashValue);
1094 uint32 length;
1095
1096 if(sym != utSymNull) {
1097 return sym;
1098 }
1099 if(utSymtabGetNumSym(utTheSymtab) == utSymtabGetNumTable(utTheSymtab)) {
1100 resizeSymtab();
1101 }
1102 sym = utSymAlloc();
1103 length = strlen(name) + 1;
1104 utSymSetName(sym, name, length);
1105 utSymSetHashValue(sym, utHashString(name));
1106 addSymTableSym(sym);
1107 return sym;
1108 }
1109
1110 /*--------------------------------------------------------------------------------------------------
1111 Build a new symbol, and add it to the symbol table.
1112 --------------------------------------------------------------------------------------------------*/
utSymCreateFormatted(char * format,...)1113 utSym utSymCreateFormatted(char *format, ...)
1114 {
1115 char *buff;
1116 va_list ap;
1117
1118 va_start(ap, format);
1119 buff = utVsprintf(format, ap);
1120 va_end(ap);
1121 return utSymCreate(buff);
1122 }
1123
1124 /*--------------------------------------------------------------------------------------------------
1125 Find the lower-case version of the symbol, and create it if it does not exist.
1126 --------------------------------------------------------------------------------------------------*/
utSymGetLowerSym(utSym sym)1127 utSym utSymGetLowerSym(
1128 utSym sym)
1129 {
1130 return utSymCreate(utStringToLowerCase(utSymGetName(sym)));
1131 }
1132
1133 /*--------------------------------------------------------------------------------------------------
1134 Allocate a buffer for generic use. There is only a queue of UT_MAX_BUFFERS which can be in use
1135 at any time. This is primarily useful for returning strings from subroutines.
1136 --------------------------------------------------------------------------------------------------*/
utMakeBuffer_(uint32 length)1137 void *utMakeBuffer_(
1138 uint32 length)
1139 {
1140 void *buffer;
1141
1142 if(length > utBufferSizes[utNextBuffer]) {
1143 utBufferSizes[utNextBuffer] = length + length/2;
1144 utBuffers[utNextBuffer] = (char *)realloc(utBuffers[utNextBuffer],
1145 utBufferSizes[utNextBuffer]*sizeof(char));
1146 }
1147 buffer = utBuffers[utNextBuffer];
1148 if(++utNextBuffer == UT_MAX_BUFFERS) {
1149 utNextBuffer = 0;
1150 }
1151 return buffer;
1152 }
1153
1154 /*--------------------------------------------------------------------------------------------------
1155 Print a formated string to the file.
1156 --------------------------------------------------------------------------------------------------*/
utVsprintf(char * format,va_list ap)1157 char *utVsprintf(
1158 char *format,
1159 va_list ap)
1160 {
1161 char buffer[UTSTRLEN];
1162 char *returnBuffer;
1163
1164 vsprintf((char *)buffer, (char *)format, ap);
1165 returnBuffer = utMakeString(strlen(buffer) + 1);
1166 strcpy(returnBuffer, buffer);
1167 return returnBuffer;
1168 }
1169
1170 /*--------------------------------------------------------------------------------------------------
1171 Just replace the file suffix.
1172 --------------------------------------------------------------------------------------------------*/
utReplaceSuffix(char * originalName,char * newSuffix)1173 char *utReplaceSuffix(
1174 char *originalName,
1175 char *newSuffix)
1176 {
1177 uint32 length = strlen(originalName);
1178 char *buffer = utMakeBuffer_(length + strlen(newSuffix) + 1);
1179 char *endPtr;
1180
1181 strcpy(buffer, originalName);
1182 endPtr = buffer + length;
1183 while(endPtr > buffer && *endPtr != '.' && *endPtr != UTDIRSEP) {
1184 endPtr--;
1185 }
1186 if(*endPtr != '.') {
1187 endPtr = buffer + length;
1188 }
1189 strcpy(endPtr, newSuffix);
1190 return buffer;
1191 }
1192
1193 /*--------------------------------------------------------------------------------------------------
1194 Return a temporary copy of a string.
1195 --------------------------------------------------------------------------------------------------*/
utCopyString(char * string)1196 char *utCopyString(
1197 char *string)
1198 {
1199 char *buffer;
1200
1201 if(string == NULL) {
1202 return NULL;
1203 }
1204 buffer = utMakeString(strlen(string) + 1);
1205 strcpy(buffer, string);
1206 return buffer;
1207 }
1208
1209 /*--------------------------------------------------------------------------------------------------
1210 Make a new string by concatenating the two old ones.
1211 --------------------------------------------------------------------------------------------------*/
utCatStrings(char * string1,char * string2)1212 char *utCatStrings(
1213 char *string1,
1214 char *string2)
1215 {
1216 return utSprintf("%s%s", string1, string2);
1217 }
1218
1219 /*--------------------------------------------------------------------------------------------------
1220 Convert a string to upper case.
1221 --------------------------------------------------------------------------------------------------*/
utStringToUpperCase(char * string)1222 char *utStringToUpperCase(
1223 char *string)
1224 {
1225 char *buffer = utCopyString(string);
1226 char *p = buffer;
1227
1228 while(*p != '\0') {
1229 *p = toupper(*p);
1230 p++;
1231 }
1232 return buffer;
1233 }
1234
1235 /*--------------------------------------------------------------------------------------------------
1236 Convert a string to lower case.
1237 --------------------------------------------------------------------------------------------------*/
utStringToLowerCase(char * string)1238 char *utStringToLowerCase(
1239 char *string)
1240 {
1241 char *buffer = utCopyString(string);
1242 char *p = buffer;
1243
1244 while(*p != '\0') {
1245 *p = tolower(*p);
1246 p++;
1247 }
1248 return buffer;
1249 }
1250
1251 /*--------------------------------------------------------------------------------------------------
1252 Return the compile time for the executable. This is in one place only for consistancy.
1253 --------------------------------------------------------------------------------------------------*/
utGetCompileTime(void)1254 char *utGetCompileTime(void)
1255 {
1256 return __DATE__ " " __TIME__;
1257 }
1258
1259 /*--------------------------------------------------------------------------------------------------
1260 Return the date and time as an ASCII string.
1261 --------------------------------------------------------------------------------------------------*/
utGetDateAndTime(void)1262 char *utGetDateAndTime(void)
1263 {
1264 time_t timeval = time(NULL);
1265 struct tm *theTime = localtime(&timeval);
1266
1267 return utSprintf("%02u/%02u/%02u %02u:%02u:%02u", theTime->tm_mon + 1, theTime->tm_mday,
1268 theTime->tm_year % 100, theTime->tm_hour, theTime->tm_min, theTime->tm_sec);
1269 }
1270
1271 /*--------------------------------------------------------------------------------------------------
1272 Return the base name of the path name.
1273 --------------------------------------------------------------------------------------------------*/
utBaseName(char * name)1274 char *utBaseName(
1275 char *name)
1276 {
1277 char *left = strrchr(name, UTDIRSEP);
1278 char *right = name + strlen(name);
1279 char *buffer;
1280
1281 if(left == NULL) {
1282 return utCopyString(name);
1283 }
1284 left++;
1285 buffer = utMakeString(right - left + 1);
1286 strncpy(buffer, left, right - left);
1287 buffer[right - left] = '\0';
1288 return buffer;
1289 }
1290
1291 /*--------------------------------------------------------------------------------------------------
1292 Return the suffix of the filename.
1293 --------------------------------------------------------------------------------------------------*/
utSuffix(char * name)1294 char *utSuffix(
1295 char *name)
1296 {
1297 uint32 i = 0;
1298 uint32 start = UINT32_MAX;
1299 char c = name[i];
1300
1301 while(c != 0) {
1302 i++;
1303 if(c == '.') {
1304 start = i;
1305 }
1306 c = name[i];
1307 }
1308 if(start == UINT32_MAX) {
1309 return NULL;
1310 }
1311 return utCopyString(name + start);
1312 }
1313
1314 /*--------------------------------------------------------------------------------------------------
1315 Return the directory name of the path name.
1316 --------------------------------------------------------------------------------------------------*/
utDirName(char * name)1317 char *utDirName(
1318 char *name)
1319 {
1320 char *end = strrchr(name, UTDIRSEP);
1321 char *buffer;
1322
1323 if(end == NULL) {
1324 return ".";
1325 }
1326 buffer = utMakeString(end - name + 1);
1327 strncpy(buffer, name, end - name);
1328 buffer[end - name] = '\0';
1329 return buffer;
1330 }
1331
1332 /*--------------------------------------------------------------------------------------------------
1333 Just determine if the file exists.
1334 --------------------------------------------------------------------------------------------------*/
utFileExists(char * fileName)1335 bool utFileExists(
1336 char *fileName)
1337 {
1338 FILE *file;
1339
1340 if(fileName == NULL || *fileName == '\0') {
1341 return false;
1342 }
1343 file = fopen(fileName, "r");
1344 if(file != NULL) {
1345 fclose(file);
1346 return true;
1347 }
1348 return false;
1349 }
1350
1351 /*--------------------------------------------------------------------------------------------------
1352 Find a file name in the directory and return the full path if it exists. Otherwise return NULL.
1353 --------------------------------------------------------------------------------------------------*/
findFileInDirectory(char * fileName,char * dirName)1354 static char *findFileInDirectory(
1355 char *fileName,
1356 char *dirName)
1357 {
1358 char *name = utSprintf("%s%c%s", dirName, UTDIRSEP, fileName);
1359
1360 if(utAccess(name, NULL)) {
1361 return name;
1362 }
1363 return NULL;
1364 }
1365
1366 /*--------------------------------------------------------------------------------------------------
1367 Find a file in the path that has the mode.
1368 --------------------------------------------------------------------------------------------------*/
utFindInPath(char * name,char * path)1369 char *utFindInPath(
1370 char *name,
1371 char *path)
1372 {
1373 char *buf = utCopyString(path);
1374 char *p = buf;
1375 char *next, *fileName, *directory;
1376
1377 while(p != '\0') {
1378 next = strchr(p, ':');
1379 if(next != NULL) {
1380 *next++ = '\0';
1381 }
1382 directory = utExpandEnvVariables(p);
1383 fileName = findFileInDirectory(name, directory);
1384 if(fileName != NULL) {
1385 return fileName;
1386 }
1387 p = next;
1388 }
1389 return NULL;
1390 }
1391
1392 /*--------------------------------------------------------------------------------------------------
1393 Find the matching '}' in the string.
1394 --------------------------------------------------------------------------------------------------*/
findMatchingBracket(char * string)1395 static char *findMatchingBracket(
1396 char *string)
1397 {
1398 uint32 numBraces = 0;
1399 char c;
1400
1401 utDo {
1402 c = *string;
1403 if(c == '{') {
1404 numBraces++;
1405 } else if(c == '}') {
1406 numBraces--;
1407 }
1408 } utWhile(numBraces != 0) {
1409 string++;
1410 } utRepeat;
1411 return string;
1412 }
1413
1414 /*--------------------------------------------------------------------------------------------------
1415 Find the first non alpha-numeric character.
1416 --------------------------------------------------------------------------------------------------*/
findFirstNonAlnumChar(char * string)1417 static char *findFirstNonAlnumChar(
1418 char *string)
1419 {
1420 while(isalnum(*string)) {
1421 string++;
1422 }
1423 return string;
1424 }
1425
1426 /*--------------------------------------------------------------------------------------------------
1427 Expand the string's environment variable.
1428 --------------------------------------------------------------------------------------------------*/
expandString(char * string,char * varStart)1429 static char *expandString(
1430 char *string,
1431 char *varStart)
1432 {
1433 char *ending;
1434 char *p;
1435
1436 *varStart++ = '\0';
1437 if(*varStart == '{') {
1438 ending = findMatchingBracket(varStart);
1439 varStart++;
1440 if(ending == NULL) {
1441 utWarning("Variable %s does not have a matching '}'" , varStart);
1442 return string;
1443 }
1444 *ending++ = '\0';
1445 } else {
1446 ending = findFirstNonAlnumChar(varStart);
1447 if(ending == NULL) {
1448 ending = "";
1449 } else {
1450 p = ending;
1451 ending = utCopyString(ending);
1452 *p = '\0'; /* To terminate varStart */
1453 }
1454 }
1455 return utSprintf("%s%s%s", string, getenv(varStart), ending);
1456 }
1457
1458 /*--------------------------------------------------------------------------------------------------
1459 Expand the string to replace environment variables with their values.
1460 --------------------------------------------------------------------------------------------------*/
utExpandEnvVariables(char * string)1461 char *utExpandEnvVariables(
1462 char *string)
1463 {
1464 char *p;
1465 bool changed;
1466
1467 string = utCopyString(string); /* To make a writable copy */
1468 if(string == NULL) {
1469 return NULL;
1470 }
1471 do {
1472 changed = false;
1473 p = strchr(string, '$');
1474 if(p != NULL) {
1475 changed = true;
1476 string = expandString(string, p);
1477 }
1478 } while(changed);
1479 return string;
1480 }
1481
1482 /*--------------------------------------------------------------------------------------------------
1483 Create a dynamic array.
1484 --------------------------------------------------------------------------------------------------*/
utDynarrayCreate_(uint16 valueSize)1485 utDynarray utDynarrayCreate_(
1486 uint16 valueSize)
1487 {
1488 utDynarray dynarray = utDynarrayAlloc();
1489
1490 utDynarraySetSize(dynarray, valueSize);
1491 return dynarray;
1492 }
1493
1494 /*--------------------------------------------------------------------------------------------------
1495 Expand the string to replace environment variables with their values.
1496 --------------------------------------------------------------------------------------------------*/
utDynarrayResize(utDynarray dynarray,uint32 newSize)1497 void utDynarrayResize(
1498 utDynarray dynarray,
1499 uint32 newSize)
1500 {
1501 uint32 numValues = newSize*utDynarrayGetSize(dynarray);
1502
1503 if(utDynarrayGetNumValue(dynarray) == 0) {
1504 utDynarrayAllocValues(dynarray, numValues);
1505 } else {
1506 utDynarrayResizeValues(dynarray, numValues);
1507 }
1508 }
1509
1510 /*--------------------------------------------------------------------------------------------------
1511 Build a new symbol, and add it to the symbol table.
1512 --------------------------------------------------------------------------------------------------*/
utUniqueSymCreate(char * name,char * suffix)1513 utSym utUniqueSymCreate(
1514 char *name,
1515 char *suffix)
1516 {
1517 utSym baseSym, sym;
1518 char buf[UTSTRLEN];
1519 char *tail;
1520 uint32 count;
1521 uint32 hashValue;
1522
1523 strcpy(buf, name);
1524 tail = buf + strlen(buf) - 1;
1525 while(isdigit(*tail)) {
1526 tail--;
1527 }
1528 tail++;
1529 strcpy(tail, suffix);
1530 hashValue = utHashString(buf);
1531 baseSym = symtabFindSym(buf, hashValue);
1532 if(baseSym == utSymNull) {
1533 return utSymCreate(buf);
1534 }
1535 tail += strlen(suffix);
1536 count = utSymNextIndex;
1537 do {
1538 sprintf(tail, "%u", count);
1539 count++;
1540 sym = symtabFindSym(buf, hashValue);
1541 } while (sym != utSymNull);
1542 utSymNextIndex = count;
1543 return utSymCreate(buf);
1544 }
1545
1546 /*--------------------------------------------------------------------------------------------------
1547 Convert directory path separation characters from either '\\' or '/' to UTDIRSEP.
1548 --------------------------------------------------------------------------------------------------*/
utConvertDirSepChars(char * path)1549 char *utConvertDirSepChars(
1550 char *path)
1551 {
1552 char *buffer = utCopyString(path);
1553 char *p = buffer;
1554 char c;
1555
1556 utDo {
1557 c = *p;
1558 } utWhile(c != '\0') {
1559 if(c == '\\' || c == '/') {
1560 *p = UTDIRSEP;
1561 }
1562 p++;
1563 } utRepeat;
1564 return buffer;
1565 }
1566