1 /*-------------------------------------------------------------------------
2 SDCCutil.c - Small utility functions.
4 Written By - Sandeep Dutta . sandeep.dutta@usa.net (1999)
6 This program is free software; you can redistribute it and/or modify it
7 under the terms of the GNU General Public License as published by the
8 Free Software Foundation; either version 2, or (at your option) any
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 In other words, you are welcome to use, share and improve this program.
21 You are forbidden to forbid anyone else to use, share and improve
22 what you give them. Help stamp out software-hoarding!
23 -------------------------------------------------------------------------*/
36 #include "SDCCglobl.h"
37 #include "SDCCmacro.h"
40 #include "dbuf_string.h"
47 /** Given an array of name, value string pairs creates a new hash
48 containing all of the pairs.
51 populateStringHash (const char **pin
)
57 shash_add (&pret
, pin
[0], pin
[1]);
65 /** shell escape string
66 returns dynamically allocated string, which should be free-ed
69 shell_escape (const char *str
)
72 /* see http://www.autohotkey.net/~deleyd/parameters/parameters.htm */
76 const char *begin
= str
;
80 dbuf_init (&dbuf
, 128);
82 /* opening double quotes */
83 dbuf_append_char(&dbuf
, '"');
95 /* append the remaining characters */
97 dbuf_append (&dbuf
, begin
, str
- begin
);
99 /* append additional backslash */
102 /* special handling if last chars before double quote are backslashes */
107 if (sizeof (backslbuf
) == backslp
- backslbuf
)
109 dbuf_append (&dbuf
, backslbuf
, sizeof (backslbuf
));
113 if (backslp
> backslbuf
)
114 dbuf_append (&dbuf
, backslbuf
, backslp
- backslbuf
);
118 else if ('%' == *str
)
120 /* disable env. variable expansion */
121 /* append the remaining characters */
122 if (begin
&& str
> begin
)
123 dbuf_append (&dbuf
, begin
, str
- begin
);
125 /* special handling if last chars before double quote are backslashes */
130 if (sizeof (backslbuf
) == backslp
- backslbuf
)
132 dbuf_append (&dbuf
, backslbuf
, sizeof (backslbuf
));
136 if (backslp
> backslbuf
)
137 dbuf_append (&dbuf
, backslbuf
, backslp
- backslbuf
);
139 /* closing doube quotes */
142 /* re opening double quotes */
144 dbuf_append (&dbuf
, backslbuf
, 3);
151 /* append the remaining characters */
152 if (begin
&& str
> begin
)
153 dbuf_append (&dbuf
, begin
, str
- begin
);
155 /* special handling if last chars before double quote are backslashes */
160 if (sizeof (backslbuf
) == backslp
- backslbuf
)
162 dbuf_append (&dbuf
, backslbuf
, sizeof (backslbuf
));
166 if (backslp
> backslbuf
)
167 dbuf_append (&dbuf
, backslbuf
, backslp
- backslbuf
);
169 /* closing doube quotes */
170 dbuf_append_char (&dbuf
, '"');
172 return dbuf_detach_c_str (&dbuf
);
176 const char *begin
= str
;
178 dbuf_init (&dbuf
, 128);
184 case ' ': case '\t': case '\n': /* IFS white space */
185 case '\'': case '"': case '\\': /* quoting chars */
186 case '|': case '&': case ';': /* shell metacharacters */
187 case '(': case ')': case '<': case '>':
188 case '!': case '{': case '}': /* reserved words */
189 case '*': case '[': case '?': case ']': /* globbing chars */
191 case '$': case '`': /* expansion chars */
192 case ',': /* brace expansion */
195 dbuf_append (&dbuf
, begin
, s
- begin
);
197 dbuf_append_char (&dbuf
, '\\');
201 case '~': /* tilde expansion */
202 if (s
== str
|| s
[-1] == '=' || s
[-1] == ':')
206 dbuf_append (&dbuf
, begin
, s
- begin
);
208 dbuf_append_char (&dbuf
, '\\');
213 case '#': /* comment char */
217 dbuf_append (&dbuf
, begin
, s
- begin
);
219 dbuf_append_char (&dbuf
, '\\');
230 dbuf_append (&dbuf
, begin
, s
- begin
);
232 return dbuf_detach_c_str (&dbuf
);
237 /** Escape string for string constants.
238 Returns dynamically allocated string, which should be free-ed.
239 TODO: Maybe handle other non-printable characters.
242 string_escape (const char *str
)
246 dbuf_init (&dbuf
, 128);
253 dbuf_append_char (&dbuf
, '\\');
254 dbuf_append_char (&dbuf
, *str
);
258 dbuf_append_str (&dbuf
, "\\n");
262 dbuf_append_char (&dbuf
, *str
);
268 return dbuf_detach_c_str (&dbuf
);
272 /** Prints elements of the set to the file, each element on new line
275 fputStrSet (FILE * fp
, set
* list
)
279 for (s
= setFirstItem (list
); s
!= NULL
; s
= setNextItem (list
))
286 /** Prepend / append / process given strings to each item of string set.
287 The result is in a new string set.
290 processStrSet (set
* list
, const char *pre
, const char *post
, char *(*func
)(const char *))
292 set
*new_list
= NULL
;
296 for (item
= setFirstItem (list
); item
!= NULL
; item
= setNextItem (list
))
298 dbuf_init (&dbuf
, PATH_MAX
);
301 dbuf_append_str (&dbuf
, pre
);
305 char *s
= func (item
);
307 dbuf_append_str (&dbuf
, s
);
311 dbuf_append_str (&dbuf
, item
);
314 dbuf_append_str (&dbuf
, post
);
316 addSet (&new_list
, dbuf_detach_c_str (&dbuf
));
322 /** Given a set returns a string containing all of the strings separated
323 by spaces. The returned string is on the heap.
326 joinStrSet (set
* list
)
331 dbuf_init (&dbuf
, PATH_MAX
);
333 for (s
= setFirstItem (list
); s
!= NULL
; s
= setNextItem (list
))
335 dbuf_append_str (&dbuf
, s
);
336 dbuf_append_char (&dbuf
, ' ');
339 return dbuf_detach_c_str (&dbuf
);
342 /** Split the path string to the directory and file name (including extension) components.
343 The directory component doesn't contain trailing directory separator.
344 Returns true if the path contains the directory separator. */
346 dbuf_splitPath (const char *path
, struct dbuf_s
*dir
, struct dbuf_s
*file
)
350 const char *end
= &path
[strlen (path
)];
352 for (p
= end
- 1; p
>= path
&& !IS_DIR_SEPARATOR (*p
); --p
)
362 dbuf_append (dir
, path
, len
);
373 dbuf_append (file
, p
, len
);
379 /** Split the path string to the file name (including directory) and file extension components.
380 File extension component contains the extension separator.
381 Returns true if the path contains the extension separator. */
383 dbuf_splitFile (const char *path
, struct dbuf_s
*file
, struct dbuf_s
*ext
)
386 const char *end
= &path
[strlen (path
)];
388 for (p
= end
- 1; p
>= path
&& !IS_DIR_SEPARATOR (*p
) && '.' != *p
; --p
)
391 if (p
< path
|| '.' != *p
)
393 dbuf_append_str (file
, path
);
404 dbuf_append (file
, path
, len
);
412 dbuf_append (ext
, p
, len
);
419 /** Combine directory and the file name to a path string using the DIR_SEPARATOR_CHAR.
422 dbuf_makePath (struct dbuf_s
*path
, const char *dir
, const char *file
)
425 dbuf_append_str (path
, dir
);
427 dbuf_append_char (path
, DIR_SEPARATOR_CHAR
);
430 dbuf_append_str (path
, file
);
433 /** Given a file with path information in the binary files directory,
434 returns the directory component. Used for discovery of bin
435 directory of SDCC installation. Returns NULL if the path is
440 getBinPath (const char *prel
)
445 dbuf_init (&path
, 128);
446 dbuf_splitPath (prel
, &path
, NULL
);
448 p
= dbuf_c_str (&path
);
453 char module
[PATH_MAX
];
455 dbuf_destroy (&path
);
457 /* not enough info in prel; do it with module name */
458 if (0 != GetModuleFileName (NULL
, module
, sizeof (module
)))
460 dbuf_init (&path
, 128);
462 dbuf_splitPath (module
, &path
, NULL
);
463 return dbuf_detach_c_str (&path
);
471 getBinPath (const char *prel
)
473 const char *ret_path
;
475 if (NULL
!= (ret_path
= findProgramPath (prel
)))
479 dbuf_init (&path
, 128);
481 dbuf_splitPath (ret_path
, &path
, NULL
);
482 free ((void *) ret_path
);
483 return dbuf_detach_c_str (&path
);
490 /** Returns true if the given path exists.
493 pathExists (const char *ppath
)
497 return stat (ppath
, &s
) == 0;
500 static hTab
*_mainValues
;
503 setMainValue (const char *pname
, const char *pvalue
)
507 shash_add (&_mainValues
, pname
, pvalue
);
511 buildMacros (const char *cmd
)
513 return eval_macros (_mainValues
, cmd
);
517 buildCmdLine (const char **cmds
, const char *p1
, const char *p2
, const char *p3
, set
* list
, set
* list2
)
522 assert (cmds
!= NULL
);
524 dbuf_init (&dbuf
, 256);
528 const char *p
, *from
, *par
;
534 /* See if it has a '$' anywhere - if not, just copy */
535 if ((p
= strchr (from
, '$')))
537 /* include first part of cmd */
541 dbuf_append_char (&dbuf
, ' ');
542 dbuf_append (&dbuf
, from
, p
- from
);
547 /* include parameter */
568 for (tmp
= setFirstItem (list
); tmp
; tmp
= setNextItem (list
))
573 dbuf_append_char (&dbuf
, ' '); /* separate it */
574 dbuf_append_str (&dbuf
, tmp
);
586 for (tmp
= setFirstItem (list2
); tmp
; tmp
= setNextItem (list2
))
591 dbuf_append_char (&dbuf
, ' '); /* separate it */
592 dbuf_append_str (&dbuf
, tmp
);
604 if (par
&& *par
!= '\0')
607 dbuf_append_char (&dbuf
, ' '); /* separate it */
608 dbuf_append_str (&dbuf
, par
);
613 /* include the rest of cmd, e.g. ".asm" from "$1.asm" */
617 dbuf_append_char (&dbuf
, ' '); /* separate it */
618 dbuf_append_str (&dbuf
, from
);
625 return dbuf_detach_c_str (&dbuf
);
629 buildCmdLine2 (const char *pcmd
, ...)
635 assert (_mainValues
);
639 poutcmd
= mvsprintf (_mainValues
, pcmd
, ap
);
647 populateMainValues (const char **ppin
)
649 _mainValues
= populateStringHash (ppin
);
652 /** Returns true if sz starts with the string given in key.
655 startsWith (const char *sz
, const char *key
)
657 return !strncmp (sz
, key
, strlen (key
));
660 /** Removes any newline characters from the string. Not strictly the
661 same as perl's chomp.
667 while ((nl
= strrchr (sz
, '\n')))
672 getRuntimeVariables (void)
677 /* strncpy() with guaranteed NULL termination. */
679 strncpyz (char *dest
, const char *src
, size_t n
)
685 if (strlen (src
) > n
)
687 fprintf (stderr
, "strncpyz prevented buffer overrun!\n");
690 strncpy (dest
, src
, n
);
695 /* like strncat() with guaranteed NULL termination
696 * The passed size should be the size of the dest buffer, not the number of
700 strncatz (char *dest
, const char *src
, size_t n
)
703 size_t destLen
= strlen (dest
);
706 assert (n
> destLen
);
708 maxToCopy
= n
- destLen
- 1;
711 if (strlen (src
) + destLen
>= n
)
713 fprintf (stderr
, "strncatz prevented buffer overrun!\n");
716 strncat (dest
, src
, maxToCopy
);
721 /*-----------------------------------------------------------------*/
722 /* getBuildNumber - return build number */
723 /*-----------------------------------------------------------------*/
725 getBuildNumber (void)
727 return (SDCC_BUILD_NUMBER
);
730 /*-----------------------------------------------------------------*/
731 /* getBuildEnvironment - return environment used to build SDCC */
732 /*-----------------------------------------------------------------*/
734 getBuildEnvironment (void)
738 #elif defined __MINGW64__
740 #elif defined __MINGW32__
742 #elif defined __DJGPP__
744 #elif defined(_MSC_VER)
746 #elif defined(__BORLANDC__)
748 #elif defined(__APPLE__)
749 #if defined(__i386__)
750 return "Mac OS X i386";
751 #elif defined(__x86_64__)
752 return "Mac OS X x86_64";
754 return "Mac OS X ppc";
756 #elif defined(__linux__)
758 #elif defined(__NetBSD__)
760 #elif defined(__FreeBSD__)
762 #elif defined(__OpenBSD__)
766 return "Solaris i386";
767 #elif defined(__amd64)
768 return "Solaris amd64";
770 return "Solaris SPARC";
778 SDCCsnprintf (char *dst
, size_t n
, const char *fmt
, ...)
783 va_start (args
, fmt
);
785 len
= vsnprintf (dst
, n
, fmt
, args
);
789 /* on some gnu systems, vsnprintf returns -1 if output is truncated.
790 * In the C99 spec, vsnprintf returns the number of characters that
791 * would have been written, were space available.
793 if ((len
< 0) || (size_t) len
>= n
)
795 fprintf (stderr
, "internal error: sprintf truncated.\n");
804 init_pragma_token (struct pragma_token_s
*token
)
806 dbuf_init (&token
->dbuf
, 16);
807 token
->type
= TOKEN_UNKNOWN
;
811 get_pragma_token (const char *s
, struct pragma_token_s
*token
)
813 dbuf_set_length (&token
->dbuf
, 0);
815 /* skip leading spaces */
816 while ('\n' != *s
&& isspace (*s
))
819 if ('\0' == *s
|| '\n' == *s
)
821 token
->type
= TOKEN_EOL
;
827 long val
= strtol (s
, &end
, 0);
829 if (end
!= s
&& ('\0' == *end
|| isspace (*end
)))
831 token
->val
.int_val
= val
;
832 token
->type
= TOKEN_INT
;
833 dbuf_append (&token
->dbuf
, s
, end
- s
);
838 while ('\0' != *s
&& !isspace (*s
))
840 dbuf_append_char (&token
->dbuf
, *s
);
844 token
->type
= TOKEN_STR
;
852 get_pragma_string (struct pragma_token_s
*token
)
854 return dbuf_c_str (&token
->dbuf
);
858 free_pragma_token (struct pragma_token_s
*token
)
860 dbuf_destroy (&token
->dbuf
);
863 /*! /fn char hexEscape(char **src)
865 /param src Pointer to 'x' from start of hex character value
869 hexEscape (const char **src
)
874 ++*src
; /* Skip over the 'x' */
876 value
= strtoul (*src
, &s
, 16);
880 /* no valid hex found */
881 werror (E_INVALID_HEX
);
889 /*------------------------------------------------------------------*/
890 /* universalEscape - process an hex constant of exactly four digits */
891 /* return the hex value, throw an error warning for invalid hex */
892 /* adjust src to point at the last processed char */
893 /*------------------------------------------------------------------*/
896 universalEscape (const char **str
, unsigned int n
)
899 unsigned long value
= 0;
900 const char *s
= *str
;
902 if (!options
.std_c95
)
904 werror (W_UNIVERSAL_C95
);
907 ++*str
; /* Skip over the 'u' or 'U' */
909 for (digits
= 0; digits
< n
; ++digits
)
911 if (**str
>= '0' && **str
<= '9')
913 value
= (value
<< 4) + (**str
- '0');
916 else if (tolower((unsigned char)(**str
)) >= 'a' && (tolower((unsigned char)(**str
)) <= 'f'))
918 value
= (value
<< 4) + (tolower((unsigned char)(**str
)) - 'a' + 10);
924 if (digits
!= n
|| value
< 0x00a0 && value
!= 0x0024 && value
!= 0x0040 && value
!= 0x0060 || value
>= 0xd800 && 0xdfff >= value
||
925 value
> 0x10ffff) // Additional diagnostic required in C23, but since it is just a warning, we enable it even for older standards.
927 werror (W_INVALID_UNIVERSAL
, s
);
933 /*------------------------------------------------------------------*/
934 /* octalEscape - process an octal constant of max three digits */
935 /* return the octal value, throw a warning for illegal octal */
936 /* adjust src to point at the last processed char */
937 /*------------------------------------------------------------------*/
940 octalEscape (const char **str
)
945 for (digits
= 0; digits
< 3; ++digits
)
947 if (**str
>= '0' && **str
<= '7')
949 value
= value
* 8 + (**str
- '0');
962 /fn const char *copyStr (const char *src, size_t *size)
964 Copies source string to a dynamically allocated buffer interpreting
965 escape sequences and special characters
967 /param src Buffer containing the source string with escape sequences
968 /param size Pointer to location where the resulting buffer length is written
969 /return Dynamically allocated resulting buffer
973 copyStr (const char *src
, size_t *size
)
975 const char *begin
= NULL
;
978 dbuf_init(&dbuf
, 128);
986 /* copy what we have until now */
987 dbuf_append (&dbuf
, begin
, src
- begin
);
992 else if (*src
== '\\')
995 bool universal
= FALSE
;
999 /* copy what we have until now */
1000 dbuf_append (&dbuf
, begin
, src
- begin
);
1042 c
= octalEscape (&src
);
1047 c
= hexEscape (&src
);
1052 c
= universalEscape (&src
, 4);
1058 c
= universalEscape (&src
, 8);
1071 if (universal
) // Encode one utf-32 character to utf-8
1073 char s
[5] = "\0\0\0\0";
1078 s
[0] = (c
>> 6) & 0x1f | 0xc0;
1079 s
[1] = (c
>> 0) & 0x3f | 0x80;
1081 else if (c
< 0x10000)
1083 s
[0] = (c
>> 12) & 0x0f | 0xe0;
1084 s
[1] = (c
>> 6) & 0x3f | 0x80;
1085 s
[2] = (c
>> 0) & 0x3f | 0x80;
1087 else if (c
< 0x110000)
1089 s
[0] = (c
>> 18) & 0x07 | 0xf0;
1090 s
[1] = (c
>> 12) & 0x3f | 0x80;
1091 s
[2] = (c
>> 6) & 0x3f | 0x80;
1092 s
[3] = (c
>> 0) & 0x3f | 0x80;
1096 dbuf_append_str (&dbuf
, s
);
1099 dbuf_append_char (&dbuf
, (char)c
);
1113 /* copy what we have until now */
1114 dbuf_append (&dbuf
, begin
, src
- begin
);
1120 /* include null terminator character
1121 appended by dbuf_detach_c_str() */
1122 *size
= dbuf_get_length (&dbuf
) + 1;
1125 return dbuf_detach_c_str (&dbuf
);
1128 static char prefix
[256] = "";
1129 static char suffix
[256] = "";
1130 static char cmd
[4096] = "";
1132 void getPrefixSuffix(const char *arg
)
1135 const char sdcc
[] = "sdcc";
1140 p
= arg
+ strlen (arg
);
1141 while (p
!= arg
&& *(p
- 1) != '\\' && *(p
- 1) != '/')
1145 /* found no "sdcc" in command line argv[0] */
1146 if ((p
= strstr (arg
, sdcc
)) == NULL
)
1149 /* found more than one "sdcc" in command line argv[0] */
1150 if (strstr (p
+ strlen (sdcc
), sdcc
) != NULL
)
1153 /* copy prefix and suffix */
1154 strncpy (prefix
, arg
, p
- arg
);
1155 strcpy (suffix
, p
+ strlen (sdcc
));
1158 char *setPrefixSuffix(const char *arg
)
1165 memset (cmd
, 0x00, sizeof (cmd
));
1167 /* find the core name of command line */
1168 for (p
= arg
; (*p
) && isblank (*p
); p
++);
1170 assert (strstr (arg
, ".exe") == NULL
);
1171 for (p
= arg
; (*p
) && !isblank (*p
); p
++);
1173 /* compose new command line with prefix and suffix */
1174 strcpy (cmd
, prefix
);
1175 strncat (cmd
, arg
, p
- arg
);
1176 strcat (cmd
, suffix
);
1182 char *formatInlineAsm (char *asmStr
)
1193 // omit leading space or tab
1194 while (*q
== '\t' || *q
== ' ')
1196 // then record the head of current line
1198 // search for CL or reach the end
1199 while (*q
!= '\n' && *q
!= '\r' && *q
!= 0)
1201 // omit more CL characters
1202 while (*q
== '\n' || *q
== '\r')
1204 // replace the first with tab
1206 if (*p
== '\t') // '\t' appears first then no need to do
1210 else if (*p
== ' ') // find the first space then replace it with tab
1215 else // go on to search