1 /*---------------------------------------------------------------------------*
2   Project:  TwlSDK - tools - defval
3   File:     misc.c
4 
5   Copyright 2005-2008 Nintendo. All rights reserved.
6 
7   These coded instructions, statements, and computer programs contain
8   proprietary information of Nintendo of America Inc. and/or Nintendo
9   Company Ltd., and are protected by Federal copyright law. They may
10   not be disclosed to third parties or copied or duplicated in any form,
11   in whole or in part, without the prior written consent of Nintendo.
12 
13   $Date:: 2008-09-17#$
14   $Rev: 8556 $
15   $Author: okubata_ryoma $
16  *---------------------------------------------------------------------------*/
17 #include "misc.h"
18 
19 /*---------------------------------------------------------------------------*
20   Name:         StrDup
21 
22   Description:  Error handling version of strdup
23 
24   Arguments:    str     String to copy
25 
26   Returns:      String that was copied
27  *---------------------------------------------------------------------------*/
StrDup(const char * str)28 char   *StrDup(const char *str)
29 {
30     char   *cp;
31 
32     if (NULL == (cp = strdup(str ? str : "")))
33     {
34         fprintf(stderr, "Error: No memory.");
35         exit(2);
36     }
37     return cp;
38 }
39 
40 /*---------------------------------------------------------------------------*
41   Name:         StrNDup
42 
43   Description:  Error-handling version of strdup with character length specification.
44 
45   Arguments:    str     String to copy
46                 len     String to copy (Not including '\0')
47 
48   Returns:      String that was copied
49  *---------------------------------------------------------------------------*/
StrNDup(const char * str,int len)50 char   *StrNDup(const char *str, int len)
51 {
52     char   *cp;
53 
54     cp = Calloc(len + 1);
55     if (str && len)
56         (void)strncpy(cp, str, len);
57     return cp;
58 
59     // Area having len+1 bytes was allocated with malloc, so there is no need to add  '\0' after strncpy.
60     //
61     // Can also support cases where str is NULL
62 }
63 
64 /*---------------------------------------------------------------------------*
65   Name:         StrCatDup
66 
67   Description:  Allocates room for a concatenated string from the heap area.
68 
69   Arguments:    str1    String 1 (When str1 == NULL, treated as "")
70                 str2    String 2 (When str2 == NULL, treated as "")
71 
72   Returns:      Concatenated string
73  *---------------------------------------------------------------------------*/
StrCatDup(const char * str1,const char * str2)74 char   *StrCatDup(const char *str1, const char *str2)
75 {
76     int     len1, len2;
77     char   *cp;
78 
79     len1 = str1 ? strlen(str1) : 0;
80     len2 = str2 ? strlen(str2) : 0;
81 
82     cp = Calloc(len1 + len2 + 1);
83 
84     if (str1)
85         (void)strcpy(cp, str1);
86     if (str2)
87         (void)strcat(cp, str2);
88 
89     return cp;
90 }
91 
92 /*---------------------------------------------------------------------------*
93   Name:         Calloc
94 
95   Description:  Error-handling version of calloc (only one argument)
96 
97   Arguments:    size    Length of area to allocate
98 
99   Returns:      Allocated area
100  *---------------------------------------------------------------------------*/
Calloc(int size)101 void   *Calloc(int size)
102 {
103     void   *cp;
104 
105     if (NULL == (cp = calloc(1, size)))
106     {
107         fprintf(stderr, "Error: No memory.");
108         exit(2);
109     }
110     return cp;
111 }
112 
113 /*---------------------------------------------------------------------------*
114   Name:         Free
115 
116   Description:  NULL-handling version of free
117                 Variable *ptr is cleared to NULL
118 
119   Arguments:    ptr  Area to free
120 
121   Returns:      None.
122  *---------------------------------------------------------------------------*/
Free(void ** ptr)123 void Free(void **ptr)
124 {
125     if (NULL != *ptr)
126     {
127         free(*ptr);
128         *ptr = NULL;
129     }
130     return;
131 }
132 
133 /*---------------------------------------------------------------------------*
134   Name:         Realloc
135 
136   Description:  Error-handling version of realloc
137 
138   Arguments:    buffer  Original size
139                 size    Length of area to allocate
140 
141   Returns:      Allocated area
142  *---------------------------------------------------------------------------*/
Realloc(void * buffer,int size)143 void   *Realloc(void *buffer, int size)
144 {
145     void   *cp;
146 
147     cp = Calloc(size);
148     if (buffer)
149     {
150         strcpy(cp, buffer);
151         free(buffer);
152     }
153     return cp;
154 }
155 
156 /*---------------------------------------------------------------------------*
157   Name:         Fopen
158 
159   Description:  Version of fopen with stdin/stdout taken into account.
160                 If '-' is specified and also access mode is 'r', set to stdin.
161                                     If the access mode is 'w', set to stdout.
162 
163   Arguments:    name   (Pointer to) the pointer to the file buffer
164                 mode   (Pointer to) the file buffer size
165 
166   Returns:      fp               File pointer
167  *---------------------------------------------------------------------------*/
Fopen(const char * filename,const char * mode)168 FILE   *Fopen(const char *filename, const char *mode)
169 {
170     FILE   *fp;
171 
172     DebugPrintf("filename=[%s] mode=[%s]\n", filename, mode);
173 
174     if ('-' == filename[0] && '\0' == filename[1])
175     {
176         fp = (mode[0] == 'r') ? stdin : stdout;
177     }
178     else
179     {
180         if (NULL == (fp = fopen(filename, mode)))
181         {
182             fprintf(stderr, "Error: cannot open %s\n", filename);
183             return NULL;
184         }
185     }
186 
187     DebugPrintf("fp=[%x] stdin=[%x] stdout=[%x]\n", fp, stdin, stdout);
188 
189     return fp;
190 }
191 
192 /*---------------------------------------------------------------------------*
193   Name:         Fclose
194 
195   Description:  Version of fclose with stdin/stdout taken into account.
196                 If NULL, stdin, stdout or stderr, does not close
197 
198   Arguments:    fp               File pointer
199 
200   Returns:      None.
201  *---------------------------------------------------------------------------*/
Fclose(FILE * fp)202 void Fclose(FILE * fp)
203 {
204     if (fp != NULL && fp != stdin && fp != stdout && fp != stderr)
205     {
206         fclose(fp);
207     }
208     return;
209 }
210 
211 /*---------------------------------------------------------------------------*
212   Name:         Fgets
213 
214   Description:  Reads the file one line at a time.
215                 Unlike the normal fgets, uses dynamic control of the buffer size to precisely read just one line.
216 
217 
218   Arguments:    *buffer  (Pointer to) the pointer to the file buffer
219                 *size   (Pointer to) the file buffer size
220                 fp        The file (If =NULL, reads from stdin)
221 
222       'buffer' and 'size' are realloc'ed as necessary inside Fgets.
223       Passing 'size' as an argument reuses 'buffer' so that alloc/free processing is reduced.
224 
225       It is expected that the first call will be to set *buffer to NULL.
226 
227   Returns:      If successful, returns *buffer. If it fails at the end of file, etc., returns NULL.
228  *---------------------------------------------------------------------------*/
Fgets(char ** pbuffer,int * pbuffer_size,FILE * fp)229 char   *Fgets(char **pbuffer, int *pbuffer_size, FILE * fp)
230 {
231     char   *buffer;
232     int     buffer_size;
233     int     buffer_gets;
234 
235     assert(pbuffer);
236     assert(pbuffer_size);
237 
238     buffer = *pbuffer;
239     buffer_size = *pbuffer_size;
240 
241     if (buffer == NULL || buffer_size == 0)
242     {
243         buffer_size = DEFAULT_LINE_BUFFER_SIZE;
244         buffer = Calloc(buffer_size);
245     }
246 
247     buffer_gets = 0;
248 
249     while (NULL != fgets(buffer + buffer_gets, buffer_size - buffer_gets, fp))
250     {
251         //
252         //  If the loaded line reaches the line-end, register the definition value
253         //    In loading done by fgets, the end of a line is determined when:
254         //      1) Data could not be loaded up to the very end of the buffer area;
255         //      2) Data could be loaded fully, but the line ends exactly at that location.
256         //
257         buffer_gets = strlen(buffer);
258         if (buffer_gets < buffer_size - 1 || buffer[buffer_gets - 1] == '\n')
259         {
260             *pbuffer = buffer;
261             *pbuffer_size = buffer_size;
262             return buffer;
263         }
264         //
265         //  If the loaded line does not reach the end of the line, double the buffer size, and continue reading.
266         //
267         //
268         else
269         {
270             buffer_size *= 2;
271             buffer = Realloc(buffer, buffer_size);
272         }
273     }
274 
275     // Processing at the end of file
276     free(*pbuffer);
277     *pbuffer = NULL;
278     *pbuffer_size = 0;
279     return NULL;
280 }
281 
282 /*---------------------------------------------------------------------------*
283   Name:         UnpackFileName
284 
285   Description:  Analyzes the file name and divides it into parts: (directory, file base name, file extension)
286 
287 
288   Arguments:    path   Full path name
289                 dir    Directory  (Including '/' etc.)
290                 base   File's base name
291                 ext    File extension (including '.')
292 
293                 * * Because dir, base, and ext are allocated from the heap, they must be freed
294                 * * When dir, base or ext is NULL, no value is assigned
295 
296   Returns:      None.
297  *---------------------------------------------------------------------------*/
UnpackFileName(const char * path,char ** dir,char ** base,char ** ext)298 void UnpackFileName(const char *path, char **dir, char **base, char **ext)
299 {
300     int     i, base_top, ext_top;
301     int     path_len = strlen(path);
302 
303     // Search for the position of the final '.' and the path delimiters
304     ext_top = path_len;
305     base_top = 0;
306 
307     for (i = path_len - 1; i >= 0; i--)
308     {
309         if (path[i] == '.' && ext_top == path_len)
310         {
311             ext_top = i;
312         }
313         if (path[i] == '/' || path[i] == '\\' || path[i] == ':')
314         {
315             base_top = i + 1;
316             break;
317         }
318     }
319 
320     // Processing of "." and ".." (In this case, the base is "." or "..", with no extension)
321     if (!strcmp(path + base_top, ".") || !strcmp(path + base_top, ".."))
322     {
323         ext_top = path_len;
324     }
325 
326     // Assign
327     if (dir)
328         *dir = StrNDup(path, base_top);
329     if (base)
330         *base = StrNDup(path + base_top, ext_top - base_top);
331     if (ext)
332         *ext = StrDup(path + ext_top);
333     return;
334 }
335 
336 /*---------------------------------------------------------------------------*
337   Name:         SetDebugMode
338 
339   Description:  Sets debug mode.
340 
341   Arguments:    mode   The mode
342 
343   Returns:      None.
344  *---------------------------------------------------------------------------*/
345 static BOOL sDebugMode = FALSE;
346 
SetDebugMode(BOOL mode)347 void SetDebugMode(BOOL mode)
348 {
349     sDebugMode = mode;
350 }
351 
352 /*---------------------------------------------------------------------------*
353   Name:         DebugPrintf
354 
355   Description:  Debug print
356 
357   Arguments:    fmt   Printf format
358                 ...   Variables to print
359 
360   Returns:      None.
361  *---------------------------------------------------------------------------*/
DebugPrintf(const char * fmt,...)362 void DebugPrintf(const char *fmt, ...)
363 {
364     va_list va;
365 
366     if (sDebugMode)
367     {
368         va_start(va, fmt);
369         vfprintf(stderr, fmt, va);
370         va_end(va);
371     }
372 }
373