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