• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*====================================================================*
2  -  Copyright (C) 2001 Leptonica.  All rights reserved.
3  -  This software is distributed in the hope that it will be
4  -  useful, but with NO WARRANTY OF ANY KIND.
5  -  No author or distributor accepts responsibility to anyone for the
6  -  consequences of using this software, or for whether it serves any
7  -  particular purpose or works at all, unless he or she says so in
8  -  writing.  Everyone is granted permission to copy, modify and
9  -  redistribute this source code, for commercial or non-commercial
10  -  purposes, with the following restrictions: (1) the origin of this
11  -  source code must not be misrepresented; (2) modified versions must
12  -  be plainly marked as such; and (3) this notice may not be removed
13  -  or altered from any source or modified source distribution.
14  *====================================================================*/
15 
16 
17 /*
18  *  utils.c
19  *
20  *       error, warning and info procs; all invoked by macros
21  *           l_int32    returnErrorInt()
22  *           l_float32  returnErrorFloat()
23  *           void      *returnErrorPtr()
24  *           void       returnErrorVoid()
25  *           void       l_error()
26  *           void       l_errorString()
27  *           void       l_errorInt()
28  *           void       l_errorFloat()
29  *           void       l_warning()
30  *           void       l_warningString()
31  *           void       l_warningInt()
32  *           void       l_warningFloat()
33  *           void       l_info()
34  *           void       l_infoString()
35  *           void       l_infoInt()
36  *           void       l_infoInt2()
37  *           void       l_infoFloat()
38  *           void       l_infoFloat2()
39  *
40  *       safe string procs
41  *           char      *stringNew()
42  *           l_int32    stringReplace()
43  *           char      *stringJoin()
44  *           char      *stringReverse()
45  *           char      *strtokSafe()
46  *           l_int32    stringSplitOnToken()
47  *
48  *       find and replace procs
49  *           char      *stringRemoveChars()
50  *           l_int32    stringFindSubstr()
51  *           char      *stringReplaceSubstr()
52  *           char      *stringReplaceEachSubstr()
53  *           l_int32    arrayFindSequence()
54  *
55  *       safe realloc
56  *           void      *reallocNew()
57  *
58  *       read file to memory
59  *           l_uint8   *arrayRead()
60  *           l_uint8   *arrayReadStream()
61  *           l_int32    nbytesInFile()
62  *           l_int32    fnbytesInFile()
63  *
64  *       write memory to file
65  *           l_int32    arrayWrite()
66  *
67  *       byte-swapping data conversion
68  *           l_uint16   convertOnBigEnd16()
69  *           l_uint32   convertOnBigEnd32()
70  *           l_uint16   convertOnLittleEnd16()
71  *           l_uint32   convertOnLittleEnd32()
72  *
73  *       file opening
74  *           FILE      *fopenReadStream()
75  *
76  *       file name operations
77  *           l_int32    splitPathAtDirectory()
78  *           l_int32    splitPathAtExtension()
79  *           char      *genPathname()
80  *           char      *genTempFilename()
81  *           l_int32    extractNumberFromFilename()
82  *
83  *       timing
84  *           void       startTimer()
85  *           l_float32  stopTimer()
86  */
87 
88 #include <stdio.h>
89 #include <string.h>
90 #include <stdlib.h>
91 #include <unistd.h>
92 #include "allheaders.h"
93 
94 #if COMPILER_MSVC
95 static const char sepchar = '\\';
96 #else
97 static const char sepchar = '/';
98 #endif
99 
100 
101 /*----------------------------------------------------------------------*
102  *                 Error, warning and info message procs                *
103  *                                                                      *
104  *            ---------------------  N.B. ---------------------         *
105  *                                                                      *
106  *    (1) These functions all print messages to stderr.                 *
107  *                                                                      *
108  *    (2) They must be invoked only by macros, which are in             *
109  *        environ.h, so that the print output can be disabled           *
110  *        at compile time, using -DNO_CONSOLE_IO.                       *
111  *                                                                      *
112  *----------------------------------------------------------------------*/
113 /*!
114  *  returnErrorInt()
115  *
116  *      Input:  msg (error message)
117  *              procname
118  *              ival (return val)
119  *      Return: ival (typically 1)
120  */
121 l_int32
returnErrorInt(const char * msg,const char * procname,l_int32 ival)122 returnErrorInt(const char  *msg,
123                const char  *procname,
124                l_int32      ival)
125 {
126     fprintf(stderr, "Error in %s: %s\n", procname, msg);
127     return ival;
128 }
129 
130 
131 /*!
132  *  returnErrorFloat()
133  *
134  *      Input:  msg (error message)
135  *              procname
136  *              fval (return val)
137  *      Return: fval
138  */
139 l_float32
returnErrorFloat(const char * msg,const char * procname,l_float32 fval)140 returnErrorFloat(const char  *msg,
141                  const char  *procname,
142                  l_float32    fval)
143 {
144     fprintf(stderr, "Error in %s: %s\n", procname, msg);
145     return fval;
146 }
147 
148 
149 /*!
150  *  returnErrorPtr()
151  *
152  *      Input:  msg (error message)
153  *              procname
154  *              pval  (return val)
155  *      Return: pval (typically null)
156  */
157 void *
returnErrorPtr(const char * msg,const char * procname,void * pval)158 returnErrorPtr(const char  *msg,
159                const char  *procname,
160                void        *pval)
161 {
162     fprintf(stderr, "Error in %s: %s\n", procname, msg);
163     return pval;
164 }
165 
166 
167 /*!
168  *  returnErrorVoid()
169  *
170  *      Input: msg (error message)
171  *             procname
172  */
173 void
returnErrorVoid(const char * msg,const char * procname)174 returnErrorVoid(const char  *msg,
175                 const char  *procname)
176 {
177     fprintf(stderr, "Error in %s: %s\n", procname, msg);
178     return;
179 }
180 
181 
182 /*!
183  *  l_error()
184  *
185  *      Input: msg (error message)
186  *             procname
187  */
188 void
l_error(const char * msg,const char * procname)189 l_error(const char  *msg,
190         const char  *procname)
191 {
192     fprintf(stderr, "Error in %s: %s\n", procname, msg);
193     return;
194 }
195 
196 
197 /*!
198  *  l_errorString()
199  *
200  *      Input: msg (error message; must include '%s')
201  *             procname
202  *             str (embedded in error message via %s)
203  */
204 void
l_errorString(const char * msg,const char * procname,const char * str)205 l_errorString(const char  *msg,
206               const char  *procname,
207               const char  *str)
208 {
209 l_int32  bufsize;
210 char    *charbuf;
211 
212     if (!msg || !procname || !str) {
213         ERROR_VOID("msg, procname or str not defined in l_errorString()",
214                    procname);
215         return;
216     }
217 
218     bufsize = strlen(msg) + strlen(procname) + 128;
219     if ((charbuf = (char *)CALLOC(bufsize, sizeof(char))) == NULL) {
220         ERROR_VOID("charbuf not made in l_errorString()", procname);
221         return;
222     }
223 
224     sprintf(charbuf, "Error in %s: %s\n", procname, msg);
225     fprintf(stderr, charbuf, str);
226 
227     FREE(charbuf);
228     return;
229 }
230 
231 
232 /*!
233  *  l_errorInt()
234  *
235  *      Input: msg (error message; must include '%d')
236  *             procname
237  *             ival (embedded in error message via %d)
238  */
239 void
l_errorInt(const char * msg,const char * procname,l_int32 ival)240 l_errorInt(const char  *msg,
241            const char  *procname,
242            l_int32      ival)
243 {
244 l_int32  bufsize;
245 char    *charbuf;
246 
247     if (!msg || !procname) {
248         ERROR_VOID("msg or procname not defined in l_errorInt()", procname);
249         return;
250     }
251 
252     bufsize = strlen(msg) + strlen(procname) + 128;
253     if ((charbuf = (char *)CALLOC(bufsize, sizeof(char))) == NULL) {
254         ERROR_VOID("charbuf not made in l_errorInt()", procname);
255         return;
256     }
257 
258     sprintf(charbuf, "Error in %s: %s\n", procname, msg);
259     fprintf(stderr, charbuf, ival);
260 
261     FREE(charbuf);
262     return;
263 }
264 
265 
266 /*!
267  *  l_errorFloat()
268  *
269  *      Input: msg (error message; must include '%f')
270  *             procname
271  *             fval (embedded in error message via %f)
272  */
273 void
l_errorFloat(const char * msg,const char * procname,l_float32 fval)274 l_errorFloat(const char  *msg,
275              const char  *procname,
276              l_float32    fval)
277 {
278 l_int32  bufsize;
279 char    *charbuf;
280 
281     if (!msg || !procname) {
282         ERROR_VOID("msg or procname not defined in l_errorFloat()", procname);
283         return;
284     }
285 
286     bufsize = strlen(msg) + strlen(procname) + 128;
287     if ((charbuf = (char *)CALLOC(bufsize, sizeof(char))) == NULL) {
288         ERROR_VOID("charbuf not made in l_errorFloat()", procname);
289         return;
290     }
291 
292     sprintf(charbuf, "Error in %s: %s\n", procname, msg);
293     fprintf(stderr, charbuf, fval);
294 
295     FREE(charbuf);
296     return;
297 }
298 
299 
300 /*!
301  *  l_warning()
302  *
303  *      Input: msg (warning message)
304  *             procname
305  */
306 void
l_warning(const char * msg,const char * procname)307 l_warning(const char  *msg,
308           const char  *procname)
309 {
310     fprintf(stderr, "Warning in %s: %s\n", procname, msg);
311     return;
312 }
313 
314 
315 /*!
316  *  l_warningString()
317  *
318  *      Input: msg (warning message; must include '%s')
319  *             procname
320  *             str (embedded in warning message via %s)
321  */
322 void
l_warningString(const char * msg,const char * procname,const char * str)323 l_warningString(const char  *msg,
324                 const char  *procname,
325                 const char  *str)
326 {
327 l_int32  bufsize;
328 char    *charbuf;
329 
330     if (!msg || !procname || !str) {
331         ERROR_VOID("msg, procname or str not defined in l_warningString()",
332                    procname);
333         return;
334     }
335 
336     bufsize = strlen(msg) + strlen(procname) + 128;
337     if ((charbuf = (char *)CALLOC(bufsize, sizeof(char))) == NULL) {
338         ERROR_VOID("charbuf not made in l_warningString()", procname);
339         return;
340     }
341 
342     sprintf(charbuf, "Warning in %s: %s\n", procname, msg);
343     fprintf(stderr, charbuf, str);
344 
345     FREE(charbuf);
346     return;
347 }
348 
349 
350 /*!
351  *  l_warningInt()
352  *
353  *      Input: msg (warning message; must include '%d')
354  *             procname
355  *             ival (embedded in warning message via %d)
356  */
357 void
l_warningInt(const char * msg,const char * procname,l_int32 ival)358 l_warningInt(const char  *msg,
359              const char  *procname,
360              l_int32      ival)
361 {
362 l_int32  bufsize;
363 char    *charbuf;
364 
365     if (!msg || !procname) {
366         ERROR_VOID("msg or procname not defined in l_warningInt()", procname);
367         return;
368     }
369 
370     bufsize = strlen(msg) + strlen(procname) + 128;
371     if ((charbuf = (char *)CALLOC(bufsize, sizeof(char))) == NULL) {
372         ERROR_VOID("charbuf not made in l_warningInt()", procname);
373         return;
374     }
375 
376     sprintf(charbuf, "Warning in %s: %s\n", procname, msg);
377     fprintf(stderr, charbuf, ival);
378 
379     FREE(charbuf);
380     return;
381 }
382 
383 
384 /*!
385  *  l_warningFloat()
386  *
387  *      Input: msg (warning message; must include '%f')
388  *             procname
389  *             fval (embedded in warning message via %f)
390  */
391 void
l_warningFloat(const char * msg,const char * procname,l_float32 fval)392 l_warningFloat(const char  *msg,
393                const char  *procname,
394                l_float32    fval)
395 {
396 l_int32  bufsize;
397 char    *charbuf;
398 
399     if (!msg || !procname) {
400         ERROR_VOID("msg or procname not defined in l_warningFloat()", procname);
401         return;
402     }
403 
404     bufsize = strlen(msg) + strlen(procname) + 128;
405     if ((charbuf = (char *)CALLOC(bufsize, sizeof(char))) == NULL) {
406         ERROR_VOID("charbuf not made in l_warningFloat()", procname);
407         return;
408     }
409 
410     sprintf(charbuf, "Warning in %s: %s\n", procname, msg);
411     fprintf(stderr, charbuf, fval);
412 
413     FREE(charbuf);
414     return;
415 }
416 
417 
418 /*!
419  *  l_info()
420  *
421  *      Input: msg (info message)
422  *             procname
423  */
424 void
l_info(const char * msg,const char * procname)425 l_info(const char  *msg,
426        const char  *procname)
427 {
428     fprintf(stderr, "Info in %s: %s\n", procname, msg);
429     return;
430 }
431 
432 
433 /*!
434  *  l_infoString()
435  *
436  *      Input: msg (info message; must include '%s')
437  *             procname
438  *             str (embedded in warning message via %s)
439  */
440 void
l_infoString(const char * msg,const char * procname,const char * str)441 l_infoString(const char  *msg,
442              const char  *procname,
443              const char  *str)
444 {
445 l_int32  bufsize;
446 char    *charbuf;
447 
448     if (!msg || !procname || !str) {
449         ERROR_VOID("msg, procname or str not defined in l_infoString()",
450                    procname);
451         return;
452     }
453 
454     bufsize = strlen(msg) + strlen(procname) + 128;
455     if ((charbuf = (char *)CALLOC(bufsize, sizeof(char))) == NULL) {
456         ERROR_VOID("charbuf not made in l_infoString()", procname);
457         return;
458     }
459 
460     sprintf(charbuf, "Info in %s: %s\n", procname, msg);
461     fprintf(stderr, charbuf, str);
462 
463     FREE(charbuf);
464     return;
465 }
466 
467 
468 /*!
469  *  l_infoInt()
470  *
471  *      Input: msg (info message; must include '%d')
472  *             procname
473  *             ival (embedded in info message via %d)
474  */
475 void
l_infoInt(const char * msg,const char * procname,l_int32 ival)476 l_infoInt(const char  *msg,
477           const char  *procname,
478           l_int32      ival)
479 {
480 l_int32  bufsize;
481 char    *charbuf;
482 
483     if (!msg || !procname) {
484         ERROR_VOID("msg or procname not defined in l_infoInt()", procname);
485         return;
486     }
487 
488     bufsize = strlen(msg) + strlen(procname) + 128;
489     if ((charbuf = (char *)CALLOC(bufsize, sizeof(char))) == NULL) {
490         ERROR_VOID("charbuf not made in l_infoInt()", procname);
491         return;
492     }
493 
494     sprintf(charbuf, "Info in %s: %s\n", procname, msg);
495     fprintf(stderr, charbuf, ival);
496 
497     FREE(charbuf);
498     return;
499 }
500 
501 
502 /*!
503  *  l_infoInt2()
504  *
505  *      Input: msg (info message; must include two '%d')
506  *             procname
507  *             ival1, ival2 (two args, embedded in info message via %d)
508  */
509 void
l_infoInt2(const char * msg,const char * procname,l_int32 ival1,l_int32 ival2)510 l_infoInt2(const char  *msg,
511            const char  *procname,
512            l_int32      ival1,
513            l_int32      ival2)
514 {
515 l_int32  bufsize;
516 char    *charbuf;
517 
518     if (!msg || !procname) {
519         ERROR_VOID("msg or procname not defined in l_infoInt2()", procname);
520         return;
521     }
522 
523     bufsize = strlen(msg) + strlen(procname) + 128;
524     if ((charbuf = (char *)CALLOC(bufsize, sizeof(char))) == NULL) {
525         ERROR_VOID("charbuf not made in l_infoInt2()", procname);
526         return;
527     }
528 
529     sprintf(charbuf, "Info in %s: %s\n", procname, msg);
530     fprintf(stderr, charbuf, ival1, ival2);
531 
532     FREE(charbuf);
533     return;
534 }
535 
536 
537 /*!
538  *  l_infoFloat()
539  *
540  *      Input: msg (info message; must include '%f')
541  *             procname
542  *             fval (embedded in info message via %f)
543  */
544 void
l_infoFloat(const char * msg,const char * procname,l_float32 fval)545 l_infoFloat(const char  *msg,
546             const char  *procname,
547             l_float32    fval)
548 {
549 l_int32  bufsize;
550 char    *charbuf;
551 
552     if (!msg || !procname) {
553         ERROR_VOID("msg or procname not defined in l_infoFloat()", procname);
554         return;
555     }
556 
557     bufsize = strlen(msg) + strlen(procname) + 128;
558     if ((charbuf = (char *)CALLOC(bufsize, sizeof(char))) == NULL) {
559         ERROR_VOID("charbuf not made in l_infoFloat()", procname);
560         return;
561     }
562 
563     sprintf(charbuf, "Info in %s: %s\n", procname, msg);
564     fprintf(stderr, charbuf, fval);
565 
566     FREE(charbuf);
567     return;
568 }
569 
570 
571 /*!
572  *  l_infoFloat2()
573  *
574  *      Input: msg (info message; must include two '%f')
575  *             procname
576  *             fval1, fval2 (two args, embedded in info message via %f)
577  */
578 void
l_infoFloat2(const char * msg,const char * procname,l_float32 fval1,l_float32 fval2)579 l_infoFloat2(const char  *msg,
580              const char  *procname,
581              l_float32    fval1,
582              l_float32    fval2)
583 {
584 l_int32  bufsize;
585 char    *charbuf;
586 
587     if (!msg || !procname) {
588         ERROR_VOID("msg or procname not defined in l_infoFloat2()", procname);
589         return;
590     }
591 
592     bufsize = strlen(msg) + strlen(procname) + 128;
593     if ((charbuf = (char *)CALLOC(bufsize, sizeof(char))) == NULL) {
594         ERROR_VOID("charbuf not made in l_infoFloat()", procname);
595         return;
596     }
597 
598     sprintf(charbuf, "Info in %s: %s\n", procname, msg);
599     fprintf(stderr, charbuf, fval1, fval2);
600 
601     FREE(charbuf);
602     return;
603 }
604 
605 
606 
607 /*--------------------------------------------------------------------*
608  *                       Safe string operations                       *
609  *--------------------------------------------------------------------*/
610 /*!
611  *  stringNew()
612  *
613  *      Input:  src string
614  *      Return: dest copy of src string, or null on error
615  */
616 char *
stringNew(const char * src)617 stringNew(const char  *src)
618 {
619 char  *dest;
620 
621     PROCNAME("stringNew");
622 
623     if (!src)
624         return (char *)ERROR_PTR("src not defined", procName, NULL);
625 
626     if ((dest = (char *)CALLOC(strlen(src) + 2, sizeof(char))) == NULL)
627         return (char *)ERROR_PTR("dest not made", procName, NULL);
628     strcpy(dest, src);
629 
630     return dest;
631 }
632 
633 
634 /*!
635  *  stringReplace()
636  *
637  *      Input:  &dest string (<return> copy)
638  *              src string
639  *      Return: 0 if OK; 1 on error
640  *
641  *  Notes:
642  *      (1) Frees any existing dest string
643  *      (2) Puts a copy of src string in the dest
644  *      (3) If either or both strings are null, does the reasonable thing.
645  */
646 l_int32
stringReplace(char ** pdest,const char * src)647 stringReplace(char       **pdest,
648               const char  *src)
649 {
650 char  *scopy;
651 
652     PROCNAME("stringReplace");
653 
654     if (!pdest)
655         return ERROR_INT("pdest not defined", procName, 1);
656 
657     if (*pdest)
658         FREE(*pdest);
659 
660     if (src) {
661         if ((scopy = (char *)CALLOC(strlen(src) + 2, sizeof(char))) == NULL)
662             return ERROR_INT("scopy not made", procName, 1);
663         strcpy(scopy, src);
664         *pdest = scopy;
665     }
666     else
667         *pdest = NULL;
668 
669     return 0;
670 }
671 
672 
673 /*!
674  *  stringJoin()
675  *
676  *      Input:  src1 string (<optional>)
677  *              src2 string (<optional>)
678  *      Return: concatenated string, or null on error
679  *
680  *  Notes:
681  *      (1) This is the safe version of strcat; it makes a new string.
682  *      (2) It is not an error if either or both of the strings
683  *          are empty, or if either or both the pointers are null.
684  */
685 char *
stringJoin(const char * src1,const char * src2)686 stringJoin(const char  *src1,
687            const char  *src2)
688 {
689 char    *dest;
690 l_int32  srclen1, srclen2, destlen;
691 
692     PROCNAME("stringJoin");
693 
694     srclen1 = srclen2 = 0;
695     if (src1)
696         srclen1 = strlen(src1);
697     if (src2)
698         srclen2 = strlen(src2);
699     destlen = srclen1 + srclen2 + 3;
700 
701     if ((dest = (char *)CALLOC(destlen, sizeof(char))) == NULL)
702         return (char *)ERROR_PTR("calloc fail for dest", procName, NULL);
703 
704     if (src1)
705         strcpy(dest, src1);
706     if (src2)
707         strcat(dest, src2);
708     return dest;
709 }
710 
711 
712 /*!
713  *  stringReverse()
714  *
715  *      Input:  src (string)
716  *      Return: dest (newly-allocated reversed string)
717  */
718 char *
stringReverse(const char * src)719 stringReverse(const char  *src)
720 {
721 char    *dest;
722 l_int32  i, len;
723 
724     PROCNAME("stringReverse");
725 
726     if (!src)
727         return (char *)ERROR_PTR("src not defined", procName, NULL);
728     len = strlen(src);
729     if ((dest = (char *)CALLOC(len + 1, sizeof(char))) == NULL)
730         return (char *)ERROR_PTR("calloc fail for dest", procName, NULL);
731     for (i = 0; i < len; i++)
732         dest[i] = src[len - 1 - i];
733 
734     return dest;
735 }
736 
737 
738 /*!
739  *  strtokSafe()
740  *
741  *      Input:  cstr (input string to be sequentially parsed;
742  *                    use NULL after the first call)
743  *              seps (a string of character separators)
744  *              &saveptr (<return> ptr to the next char after
745  *                        the last encountered separator)
746  *      Return: substr (a new string that is copied from the previous
747  *                      saveptr up to but not including the next
748  *                      separator character), or NULL if end of cstr.
749  *
750  *  Notes:
751  *      (1) This is a thread-safe implementation of strtok.
752  *      (2) It has the same interface as strtok_r.
753  *      (3) It differs from strtok_r in usage in two respects:
754  *          (a) the input string is not altered
755  *          (b) each returned substring is newly allocated and must
756  *              be freed after use.
757  *      (4) Let me repeat that.  This is "safe" because the input
758  *          string is not altered and because each returned string
759  *          is newly allocated on the heap.
760  *      (5) It is here because, surprisingly, some C libraries don't
761  *          include strtok_r.
762  *      (6) Important usage points:
763  *          - Input the string to be parsed on the first invocation.
764  *          - Then input NULL after that; the value returned in saveptr
765  *            is used in all subsequent calls.
766  *      (7) This is only slightly slower than strtok_k.
767  */
768 char *
strtokSafe(char * cstr,const char * seps,char ** psaveptr)769 strtokSafe(char        *cstr,
770            const char  *seps,
771            char       **psaveptr)
772 {
773 char     nextc;
774 char    *start, *substr;
775 l_int32  istart, i, j, nchars;
776 
777     PROCNAME("strtokSafe");
778 
779     if (!seps)
780         return (char *)ERROR_PTR("seps not defined", procName, NULL);
781     if (!psaveptr)
782         return (char *)ERROR_PTR("&saveptr not defined", procName, NULL);
783 
784     if (!cstr)
785         start = *psaveptr;
786     else
787         start = cstr;
788     if (!start)  /* nothing to do */
789         return NULL;
790 
791         /* First time, scan for the first non-sep character */
792     istart = 0;
793     if (cstr) {
794         for (istart = 0;; istart++) {
795             if ((nextc = start[istart]) == '\0') {
796                 *psaveptr = NULL;  /* in case caller doesn't check ret value */
797                 return NULL;
798             }
799             if (!strchr(seps, nextc))
800                 break;
801         }
802     }
803 
804         /* Scan through, looking for a sep character; if none is
805          * found, 'i' will be at the end of the string. */
806     for (i = istart;; i++) {
807         if ((nextc = start[i]) == '\0')
808             break;
809         if (strchr(seps, nextc))
810             break;
811     }
812 
813         /* Save the substring */
814     nchars = i - istart;
815     substr = (char *)CALLOC(nchars + 1, sizeof(char));
816     strncpy(substr, start + istart, nchars);
817 
818         /* Look for the next non-sep character.
819          * If this is the last substring, return a null saveptr. */
820     for (j = i;; j++) {
821         if ((nextc = start[j]) == '\0') {
822             *psaveptr = NULL;  /* no more non-sep characters */
823             break;
824         }
825         if (!strchr(seps, nextc)) {
826             *psaveptr = start + j;  /* start here on next call */
827                 break;
828         }
829     }
830 
831     return substr;
832 }
833 
834 
835 /*!
836  *  stringSplitOnToken()
837  *
838  *      Input:  cstr (input string to be split; not altered)
839  *              seps (a string of character separators)
840  *              &head (<return> ptr to copy of the input string, up to
841  *                     the first separator token encountered)
842  *              &tail (<return> ptr to copy of the part of the input string
843  *                     starting with the first non-separator character
844  *                     that occurs after the first separator is found)
845  *      Return: 0 if OK, 1 on error
846  *
847  *  Notes:
848  *      (1) The input string is not altered; all split parts are new strings.
849  *      (2) The split occurs around the first consecutive sequence of
850  *          tokens encountered.
851  *      (3) The head goes from the beginning of the string up to
852  *          but not including the first token found.
853  *      (4) The tail contains the second part of the string, starting
854  *          with the first char in that part that is NOT a token.
855  *      (5) If no separator token is found, 'head' contains a copy
856  *          of the input string and 'tail' is null.
857  */
858 l_int32
stringSplitOnToken(char * cstr,const char * seps,char ** phead,char ** ptail)859 stringSplitOnToken(char        *cstr,
860                    const char  *seps,
861                    char       **phead,
862                    char       **ptail)
863 {
864 char  *saveptr;
865 
866     PROCNAME("stringSplitOnToken");
867 
868     if (!phead)
869         return ERROR_INT("&head not defined", procName, 1);
870     if (!ptail)
871         return ERROR_INT("&tail not defined", procName, 1);
872     *phead = *ptail = NULL;
873     if (!cstr)
874         return ERROR_INT("cstr not defined", procName, 1);
875     if (!seps)
876         return ERROR_INT("seps not defined", procName, 1);
877 
878     *phead = strtokSafe(cstr, seps, &saveptr);
879     if (saveptr)
880         *ptail = stringNew(saveptr);
881     return 0;
882 }
883 
884 
885 /*--------------------------------------------------------------------*
886  *                       Find and replace procs                       *
887  *--------------------------------------------------------------------*/
888 /*!
889  *  stringRemoveChars()
890  *
891  *      Input:  src (input string; can be of zero length)
892  *              remchars  (string of chars to be removed from src)
893  *      Return: dest (string with specified chars removed), or null on error
894  */
895 char *
stringRemoveChars(const char * src,const char * remchars)896 stringRemoveChars(const char  *src,
897                   const char  *remchars)
898 {
899 char     ch;
900 char    *dest;
901 l_int32  nsrc, i, k;
902 
903     PROCNAME("stringRemoveChars");
904 
905     if (!src)
906         return (char *)ERROR_PTR("src not defined", procName, NULL);
907     if (!remchars)
908         return stringNew(src);
909 
910     if ((dest = (char *)CALLOC(strlen(src) + 1, sizeof(char))) == NULL)
911         return (char *)ERROR_PTR("dest not made", procName, NULL);
912     nsrc = strlen(src);
913     for (i = 0, k = 0; i < nsrc; i++) {
914         ch = src[i];
915         if (!strchr(remchars, ch))
916             dest[k++] = ch;
917     }
918 
919     return dest;
920 }
921 
922 
923 /*!
924  *  stringFindSubstr()
925  *
926  *      Input:  src (input string; can be of zero length)
927  *              sub (substring to be searched for)
928  *              &loc (<return optional> location of substring in src)
929  *      Return: 1 if found; 0 if not found or on error
930  *
931  *  Notes:
932  *      (1) This is a wrapper around strstr().
933  *      (2) Both @src and @sub must be defined, and @sub must have
934  *          length of at least 1.
935  *      (3) If the substring is not found and loc is returned, it has
936  *          the value -1.
937  */
938 l_int32
stringFindSubstr(const char * src,const char * sub,l_int32 * ploc)939 stringFindSubstr(const char  *src,
940                  const char  *sub,
941                  l_int32     *ploc)
942 {
943 char  *ptr;
944 
945     PROCNAME("stringFindSubstr");
946 
947     if (!src)
948         return ERROR_INT("src not defined", procName, 0);
949     if (!sub)
950         return ERROR_INT("sub not defined", procName, 0);
951     if (ploc) *ploc = -1;
952     if (strlen(sub) == 0)
953         return ERROR_INT("substring length 0", procName, 0);
954     if (strlen(src) == 0)
955         return 0;
956 
957     if ((ptr = (char *)strstr(src, sub)) == NULL)  /* not found */
958         return 0;
959 
960     if (*ploc)
961         *ploc = ptr - src;
962     return 1;
963 }
964 
965 
966 /*!
967  *  stringReplaceSubstr()
968  *
969  *      Input:  src (input string; can be of zero length)
970  *              sub1 (substring to be replaced)
971  *              sub2 (substring to put in; can be "")
972  *              &found (<return optional> 1 if sub1 is found; 0 otherwise)
973  *              &loc (<return optional> location of ptr after replacement)
974  *      Return: dest (string with substring replaced), or null if the
975  *              substring not found or on error.
976  *
977  *  Notes:
978  *      (1) Replaces the first instance.
979  *      (2) To only remove sub1, use "" for sub2
980  *      (3) Returns a new string if sub1 and sub2 are the same.
981  *      (4) The optional loc is input as the byte offset within the src
982  *          from which the search starts, and after the search it is the
983  *          char position in the string of the next character after
984  *          the substituted string.
985  *      (5) N.B. If ploc is not null, loc must always be initialized.
986  *          To search the string from the beginning, set loc = 0.
987  */
988 char *
stringReplaceSubstr(const char * src,const char * sub1,const char * sub2,l_int32 * pfound,l_int32 * ploc)989 stringReplaceSubstr(const char  *src,
990                     const char  *sub1,
991                     const char  *sub2,
992                     l_int32     *pfound,
993                     l_int32     *ploc)
994 {
995 char    *ptr, *dest;
996 l_int32  nsrc, nsub1, nsub2, len, npre, loc;
997 
998     PROCNAME("stringReplaceSubstr");
999 
1000     if (!src)
1001         return (char *)ERROR_PTR("src not defined", procName, NULL);
1002     if (!sub1)
1003         return (char *)ERROR_PTR("sub1 not defined", procName, NULL);
1004     if (!sub2)
1005         return (char *)ERROR_PTR("sub2 not defined", procName, NULL);
1006 
1007     if (pfound)
1008         *pfound = 0;
1009     if (ploc)
1010         loc = *ploc;
1011     else
1012         loc = 0;
1013     if ((ptr = (char *)strstr(src + loc, sub1)) == NULL) {
1014         return NULL;
1015     }
1016 
1017     if (pfound)
1018         *pfound = 1;
1019     nsrc = strlen(src);
1020     nsub1 = strlen(sub1);
1021     nsub2 = strlen(sub2);
1022     len = nsrc + nsub2 - nsub1;
1023     if ((dest = (char *)CALLOC(len + 1, sizeof(char))) == NULL)
1024         return (char *)ERROR_PTR("dest not made", procName, NULL);
1025     npre = ptr - src;
1026     memcpy(dest, src, npre);
1027     strcpy(dest + npre, sub2);
1028     strcpy(dest + npre + nsub2, ptr + nsub1);
1029     if (ploc)
1030         *ploc = npre + nsub2;
1031 
1032     return dest;
1033 }
1034 
1035 
1036 /*!
1037  *  stringReplaceEachSubstr()
1038  *
1039  *      Input:  src (input string; can be of zero length)
1040  *              sub1 (substring to be replaced)
1041  *              sub2 (substring to put in; can be "")
1042  *              &count (<optional return > the number of times that sub1
1043  *                      is found in src; 0 if not found)
1044  *      Return: dest (string with substring replaced), or null if the
1045  *              substring not found or on error.
1046  *
1047  *  Notes:
1048  *      (1) Replaces every instance.
1049  *      (2) To only remove each instance of sub1, use "" for sub2
1050  *      (3) Returns NULL if sub1 and sub2 are the same.
1051  */
1052 char *
stringReplaceEachSubstr(const char * src,const char * sub1,const char * sub2,l_int32 * pcount)1053 stringReplaceEachSubstr(const char  *src,
1054                         const char  *sub1,
1055                         const char  *sub2,
1056                         l_int32     *pcount)
1057 {
1058 char    *currstr, *newstr;
1059 l_int32  loc;
1060 
1061     PROCNAME("stringReplaceEachSubstr");
1062 
1063     if (!src)
1064         return (char *)ERROR_PTR("src not defined", procName, NULL);
1065     if (!sub1)
1066         return (char *)ERROR_PTR("sub1 not defined", procName, NULL);
1067     if (!sub2)
1068         return (char *)ERROR_PTR("sub2 not defined", procName, NULL);
1069 
1070     if (pcount)
1071         *pcount = 0;
1072     loc = 0;
1073     if ((newstr = stringReplaceSubstr(src, sub1, sub2, NULL, &loc)) == NULL)
1074         return NULL;
1075 
1076     if (pcount)
1077         (*pcount)++;
1078     while (1) {
1079         currstr = newstr;
1080         newstr = stringReplaceSubstr(currstr, sub1, sub2, NULL, &loc);
1081         if (!newstr)
1082             return currstr;
1083         FREE(currstr);
1084         if (pcount)
1085             (*pcount)++;
1086     }
1087 }
1088 
1089 
1090 /*!
1091  *  arrayFindSequence()
1092  *
1093  *      Input:  data (byte array)
1094  *              datalen (length of data, in bytes)
1095  *              sequence (subarray of bytes to find in data)
1096  *              seqlen (length of sequence, in bytes)
1097  *              &offset (return> offset from beginning of
1098  *                       data where the sequence begins)
1099  *              &found (<return> 1 if sequence is found; 0 otherwise)
1100  *      Return: 0 if OK, 1 on error
1101  *
1102  *  Notes:
1103  *      (1) The byte arrays 'data' and 'sequence' are not C strings,
1104  *          as they can contain null bytes.  Therefore, for each
1105  *          we must give the length of the array.
1106  *      (2) This searches for the first occurrence in 'data' of
1107  *          the first 'seqlen' bytes of 'sequence'.  The parameter 'seqlen'
1108  *          must not exceed the actual length of the 'sequence' byte array.
1109  *      (3) If the sequence is not found, the offset will be set to -1.
1110  */
1111 l_int32
arrayFindSequence(const l_uint8 * data,l_int32 datalen,const l_uint8 * sequence,l_int32 seqlen,l_int32 * poffset,l_int32 * pfound)1112 arrayFindSequence(const l_uint8  *data,
1113                   l_int32         datalen,
1114                   const l_uint8  *sequence,
1115                   l_int32         seqlen,
1116                   l_int32        *poffset,
1117                   l_int32        *pfound)
1118 {
1119 l_int32  i, j, found, lastpos;
1120 
1121     PROCNAME("arrayFindSequence");
1122 
1123     if (!data || !sequence)
1124         return ERROR_INT("data & sequence not both defined", procName, 1);
1125     if (!poffset || !pfound)
1126         return ERROR_INT("&offset and &found not both defined", procName, 1);
1127 
1128     *pfound = 0;
1129     *poffset = -1;
1130     lastpos = datalen - seqlen + 1;
1131     found = 0;
1132     for (i = 0; i < lastpos; i++) {
1133         for (j = 0; j < seqlen; j++) {
1134             if (data[i + j] != sequence[j])
1135                  break;
1136             if (j == seqlen - 1)
1137                  found = 1;
1138         }
1139         if (found)
1140             break;
1141     }
1142 
1143     if (found) {
1144         *pfound = 1;
1145         *poffset = i;
1146     }
1147 
1148     return 0;
1149 }
1150 
1151 
1152 /*--------------------------------------------------------------------*
1153  *                             Safe realloc                           *
1154  *--------------------------------------------------------------------*/
1155 /*!
1156  *  reallocNew()
1157  *
1158  *      Input:  &indata (<optional>; nulls indata)
1159  *              size of input data to be copied (bytes)
1160  *              size of data to be reallocated (bytes)
1161  *      Return: ptr to new data, or null on error
1162  *
1163  *  Action: !N.B. (3) and (4)!
1164  *      (1) Allocates memory, initialized to 0
1165  *      (2) Copies as much of the input data as possible
1166  *          to the new block, truncating the copy if necessary
1167  *      (3) Frees the input data
1168  *      (4) Zeroes the input data ptr
1169  *
1170  *  Notes:
1171  *      (1) If newsize <=0, just frees input data and nulls ptr
1172  *      (2) If input ptr is null, just callocs new memory
1173  *      (3) This differs from realloc in that it always allocates
1174  *          new memory (if newsize > 0) and initializes it to 0,
1175  *          it requires the amount of old data to be copied,
1176  *          and it takes the address of the input ptr and
1177  *          nulls the handle.
1178  */
1179 void *
reallocNew(void ** pindata,l_int32 oldsize,l_int32 newsize)1180 reallocNew(void   **pindata,
1181            l_int32  oldsize,
1182            l_int32  newsize)
1183 {
1184 l_int32  minsize;
1185 void    *indata;
1186 void    *newdata;
1187 
1188     PROCNAME("reallocNew");
1189 
1190     if (!pindata)
1191         return ERROR_PTR("input data not defined", procName, NULL);
1192     indata = *pindata;
1193 
1194     if (newsize <= 0) {   /* nonstandard usage */
1195         if (indata) {
1196             FREE(indata);
1197             *pindata = NULL;
1198         }
1199         return NULL;
1200     }
1201 
1202     if (!indata)   /* nonstandard usage */
1203     {
1204         if ((newdata = (void *)CALLOC(1, newsize)) == NULL)
1205             return ERROR_PTR("newdata not made", procName, NULL);
1206         return newdata;
1207     }
1208 
1209         /* Standard usage */
1210     if ((newdata = (void *)CALLOC(1, newsize)) == NULL)
1211         return ERROR_PTR("newdata not made", procName, NULL);
1212     minsize = L_MIN(oldsize, newsize);
1213     memcpy((char *)newdata, (char *)indata, minsize);
1214 
1215     FREE(indata);
1216     *pindata = NULL;
1217 
1218     return newdata;
1219 }
1220 
1221 
1222 
1223 /*--------------------------------------------------------------------*
1224  *                       Reading bytes from file                      *
1225  *--------------------------------------------------------------------*/
1226 /*!
1227  *  arrayRead()
1228  *
1229  *      Input:  filename
1230  *              &nbytes (<return> number of bytes read)
1231  *      Return: array, or null on error
1232  */
1233 l_uint8 *
arrayRead(const char * fname,l_int32 * pnbytes)1234 arrayRead(const char  *fname,
1235            l_int32     *pnbytes)
1236 {
1237 l_uint8  *data;
1238 FILE     *fp;
1239 
1240     PROCNAME("arrayRead");
1241 
1242     if (!fname)
1243         return (l_uint8 *)ERROR_PTR("fname not defined", procName, NULL);
1244     if (!pnbytes)
1245         return (l_uint8 *)ERROR_PTR("pnbytes not defined", procName, NULL);
1246     *pnbytes = 0;
1247 
1248     if ((fp = fopen(fname, "r")) == NULL)
1249         return (l_uint8 *)ERROR_PTR("file stream not opened", procName, NULL);
1250 
1251     data = arrayReadStream(fp, pnbytes);
1252     fclose(fp);
1253 
1254     return data;
1255 }
1256 
1257 
1258 /*!
1259  *  arrayReadStream()
1260  *
1261  *      Input:  stream
1262  *              &nbytes (<return> number of bytes read)
1263  *      Return: null-terminated array, or null on error
1264  *              (reading 0 bytes is not an error)
1265  *
1266  *  Notes:
1267  *      (1) N.B.: as a side effect, this always re-positions the
1268  *          stream ptr to the beginning of the file.
1269  */
1270 l_uint8 *
arrayReadStream(FILE * fp,l_int32 * pnbytes)1271 arrayReadStream(FILE     *fp,
1272                 l_int32  *pnbytes)
1273 {
1274 l_uint8  *data;
1275 
1276     PROCNAME("arrayReadStream");
1277 
1278     if (!fp)
1279         return (l_uint8 *)ERROR_PTR("stream not defined", procName, NULL);
1280     if (!pnbytes)
1281         return (l_uint8 *)ERROR_PTR("ptr to nbytes not defined", procName, NULL);
1282 
1283     *pnbytes = fnbytesInFile(fp);
1284 
1285     if ((data = (l_uint8 *)CALLOC(1, *pnbytes + 1)) == NULL)
1286         return (l_uint8 *)ERROR_PTR("CALLOC fail for data", procName, NULL);
1287     fread(data, *pnbytes, 1, fp);
1288 
1289     return data;
1290 }
1291 
1292 
1293 /*!
1294  *  nbytesInFile()
1295  *
1296  *      Input:  filename
1297  *      Return: nbytes in file; 0 on error
1298  */
1299 l_int32
nbytesInFile(const char * filename)1300 nbytesInFile(const char  *filename)
1301 {
1302 l_int32  nbytes;
1303 FILE    *fp;
1304 
1305     PROCNAME("nbytesInFile");
1306 
1307     if (!filename)
1308         return ERROR_INT("filename not defined", procName, 0);
1309     fp = fopen(filename, "r");
1310     nbytes = fnbytesInFile(fp);
1311     fclose(fp);
1312     return nbytes;
1313 }
1314 
1315 
1316 /*!
1317  *  fnbytesInFile()
1318  *
1319  *      Input:  file stream
1320  *      Return: nbytes in file; 0 on error
1321  */
1322 l_int32
fnbytesInFile(FILE * fp)1323 fnbytesInFile(FILE  *fp)
1324 {
1325 l_int32  nbytes, pos;
1326 
1327     PROCNAME("fnbytesInFile");
1328 
1329     if (!fp)
1330         return ERROR_INT("stream not open", procName, 0);
1331 
1332     pos = ftell(fp);          /* initial position */
1333     fseek(fp, 0, SEEK_END);   /* EOF */
1334     nbytes = ftell(fp);
1335     fseek(fp, 0, pos);        /* back to initial position */
1336     return nbytes;
1337 }
1338 
1339 
1340 
1341 /*--------------------------------------------------------------------*
1342  *                          Writing bytes to file                     *
1343  *--------------------------------------------------------------------*/
1344 /*!
1345  *  arrayWrite()
1346  *
1347  *      Input:  filename (output)
1348  *              operation  ("w" for write; "a" for append)
1349  *              data  (binary data to be written)
1350  *              nbytes  (size of data array)
1351  *      Return: 0 if OK; 1 on error
1352  */
1353 l_int32
arrayWrite(const char * filename,const char * operation,void * data,l_int32 nbytes)1354 arrayWrite(const char  *filename,
1355            const char  *operation,
1356            void        *data,
1357            l_int32      nbytes)
1358 {
1359 FILE  *fp;
1360 
1361     PROCNAME("arrayWrite");
1362 
1363     if (!filename)
1364         return ERROR_INT("filename not defined", procName, 1);
1365     if (!operation)
1366         return ERROR_INT("operation not defined", procName, 1);
1367     if (!data)
1368         return ERROR_INT("data not defined", procName, 1);
1369     if (nbytes <= 0)
1370         return ERROR_INT("nbytes must be > 0", procName, 1);
1371 
1372     if (!strcmp(operation, "w") && !strcmp(operation, "a"))
1373         return ERROR_INT("operation not one of {'w','a'}", procName, 1);
1374 
1375     if ((fp = fopen(filename, operation)) == NULL)
1376         return ERROR_INT("stream not opened", procName, 1);
1377     fwrite(data, 1, nbytes, fp);
1378     fclose(fp);
1379 
1380     return 0;
1381 }
1382 
1383 
1384 /*--------------------------------------------------------------------------*
1385  *   16 and 32 bit byte-swapping on big endian and little  endian machines  *
1386  *                                                                          *
1387  *   These are typically used for I/O conversions:                          *
1388  *      (1) endian conversion for data that was read from a file            *
1389  *      (2) endian conversion on data before it is written to a file        *
1390  *--------------------------------------------------------------------------*/
1391 
1392 /*--------------------------------------------------------------------*
1393  *                        16-bit byte swapping                        *
1394  *--------------------------------------------------------------------*/
1395 #ifdef L_BIG_ENDIAN
1396 
1397 l_uint16
convertOnBigEnd16(l_uint16 shortin)1398 convertOnBigEnd16(l_uint16  shortin)
1399 {
1400     return ((shortin << 8) | (shortin >> 8));
1401 }
1402 
1403 l_uint16
convertOnLittleEnd16(l_uint16 shortin)1404 convertOnLittleEnd16(l_uint16  shortin)
1405 {
1406     return  shortin;
1407 }
1408 
1409 #else     /* L_LITTLE_ENDIAN */
1410 
1411 l_uint16
convertOnLittleEnd16(l_uint16 shortin)1412 convertOnLittleEnd16(l_uint16  shortin)
1413 {
1414     return ((shortin << 8) | (shortin >> 8));
1415 }
1416 
1417 l_uint16
convertOnBigEnd16(l_uint16 shortin)1418 convertOnBigEnd16(l_uint16  shortin)
1419 {
1420     return  shortin;
1421 }
1422 
1423 #endif  /* L_BIG_ENDIAN */
1424 
1425 
1426 /*--------------------------------------------------------------------*
1427  *                        32-bit byte swapping                        *
1428  *--------------------------------------------------------------------*/
1429 #ifdef L_BIG_ENDIAN
1430 
1431 l_uint32
convertOnBigEnd32(l_uint32 wordin)1432 convertOnBigEnd32(l_uint32  wordin)
1433 {
1434     return ((wordin << 24) | ((wordin << 8) & 0x00ff0000) |
1435             ((wordin >> 8) & 0x0000ff00) | (wordin >> 24));
1436 }
1437 
1438 l_uint32
convertOnLittleEnd32(l_uint32 wordin)1439 convertOnLittleEnd32(l_uint32  wordin)
1440 {
1441     return wordin;
1442 }
1443 
1444 #else  /*  L_LITTLE_ENDIAN */
1445 
1446 l_uint32
convertOnLittleEnd32(l_uint32 wordin)1447 convertOnLittleEnd32(l_uint32  wordin)
1448 {
1449     return ((wordin << 24) | ((wordin << 8) & 0x00ff0000) |
1450             ((wordin >> 8) & 0x0000ff00) | (wordin >> 24));
1451 }
1452 
1453 l_uint32
convertOnBigEnd32(l_uint32 wordin)1454 convertOnBigEnd32(l_uint32  wordin)
1455 {
1456     return wordin;
1457 }
1458 
1459 #endif  /* L_BIG_ENDIAN */
1460 
1461 
1462 
1463 /*--------------------------------------------------------------------*
1464  *                         Opening read stream                        *
1465  *--------------------------------------------------------------------*/
1466 /*!
1467  *  fopenReadStream()
1468  *
1469  *      Input:  filename
1470  *      Return: stream or null on error
1471  */
1472 FILE *
fopenReadStream(const char * filename)1473 fopenReadStream(const char  *filename)
1474 {
1475 char  *tail;
1476 FILE  *fp;
1477 
1478     PROCNAME("fopenReadStream");
1479 
1480     if (!filename)
1481         return (FILE *)ERROR_PTR("filename not defined", procName, NULL);
1482 
1483         /* Try input filename */
1484     if ((fp = fopen(filename, "rb")))
1485         return fp;
1486 
1487         /* Else, strip directory and try locally */
1488     splitPathAtDirectory(filename, NULL, &tail);
1489     if ((fp = fopen(tail, "rb"))) {
1490         FREE(tail);
1491         return fp;
1492     }
1493     FREE(tail);
1494 
1495     return (FILE *)ERROR_PTR("file not found", procName, NULL);
1496 }
1497 
1498 
1499 /*--------------------------------------------------------------------*
1500  *                         File name operations                       *
1501  *--------------------------------------------------------------------*/
1502 /*!
1503  *  splitPathAtDirectory()
1504  *
1505  *      Input:  pathname  (full path; can be a directory)
1506  *              &dir  (<optional return> root directory name of
1507  *                     input path, including trailing '/')
1508  *              &tail (<optional return> path tail, which is either
1509  *                     the file name within the root directory or
1510  *                     the last sub-directory in the path)
1511  *      Return: 0 if OK, 1 on error
1512  *
1513  *  Note: (1) if you only want the tail, input null for
1514  *            the root directory ptr.
1515  *        (2) if you only want the root directory name,
1516  *            input null for the tail ptr.
1517  *        (3) This function makes decisions based only on the lexical
1518  *            structure of the input.  Examples:
1519  *              /usr/tmp/abc  -->  dir: /usr/tmp/   tail: abc
1520  *              /usr/tmp/  -->  dir: /usr/tmp/   tail: [empty string]
1521  *              /usr/tmp  -->  dir: /usr/   tail: tmp
1522  */
1523 l_int32
splitPathAtDirectory(const char * pathname,char ** pdir,char ** ptail)1524 splitPathAtDirectory(const char  *pathname,
1525                      char       **pdir,
1526                      char       **ptail)
1527 {
1528 char  *cpathname, *lastslash;
1529 
1530     PROCNAME("splitPathAtDirectory");
1531 
1532     if (!pdir && !ptail)
1533         return ERROR_INT("null input for both strings", procName, 1);
1534     if (pdir) *pdir = NULL;
1535     if (ptail) *ptail = NULL;
1536     if (!pathname)
1537         return ERROR_INT("pathname not defined", procName, 1);
1538 
1539     cpathname = stringNew(pathname);
1540     if ((lastslash = strrchr(cpathname, '/'))) {
1541         if (ptail)
1542             *ptail = stringNew(lastslash + 1);
1543         if (pdir) {
1544             *(lastslash + 1) = '\0';
1545             *pdir = cpathname;
1546         }
1547         else
1548             FREE(cpathname);
1549     }
1550     else {  /* no directory */
1551         if (pdir)
1552             *pdir = stringNew("");
1553         if (ptail)
1554             *ptail = cpathname;
1555         else
1556             FREE(cpathname);
1557     }
1558 
1559     return 0;
1560 }
1561 
1562 
1563 /*!
1564  *  splitPathAtExtension()
1565  *
1566  *      Input:  pathname (full path; can be a directory)
1567  *              &basename (<optional return> pathname not including the
1568  *                        last dot and characters after that)
1569  *              &extension (<optional return> path extension, which is
1570  *                        the last dot and the characters after it.  If
1571  *                        there is no extension, it returns the empty string)
1572  *      Return: 0 if OK, 1 on error
1573  *
1574  *  Notes:
1575  *      (1) If you only want the extension, input null for the basename ptr.
1576  *      (2) If you only want the basename without extension, input null
1577  *          for the extension ptr.
1578  *      (3) This function makes decisions based only on the lexical
1579  *          structure of the input.  Examples:
1580  *            /usr/tmp/abc.jpg  -->  basename: /usr/tmp/abc   ext: .jpg
1581  *            /usr/tmp/.jpg  -->  basename: /usr/tmp/   tail: .jpg
1582  *            /usr/tmp.jpg/  -->  basename: /usr/tmp.jpg/   tail: [empty str]
1583  *            ./.jpg  -->  basename: ./   tail: .jpg
1584  */
1585 l_int32
splitPathAtExtension(const char * pathname,char ** pbasename,char ** pextension)1586 splitPathAtExtension(const char  *pathname,
1587                      char       **pbasename,
1588                      char       **pextension)
1589 {
1590 char  *tail, *dir, *lastdot;
1591 char   empty[4] = "";
1592 
1593     PROCNAME("splitPathExtension");
1594 
1595     if (!pbasename && !pextension)
1596         return ERROR_INT("null input for both strings", procName, 1);
1597     if (pbasename) *pbasename = NULL;
1598     if (pextension) *pextension = NULL;
1599     if (!pathname)
1600         return ERROR_INT("pathname not defined", procName, 1);
1601 
1602         /* Split out the directory first */
1603     splitPathAtDirectory(pathname, &dir, &tail);
1604 
1605         /* Then look for a "." in the tail part.
1606          * This way we ignore all "." in the directory. */
1607     if ((lastdot = strrchr(tail, '.'))) {
1608         if (pextension)
1609             *pextension = stringNew(lastdot);
1610         if (pbasename) {
1611             *lastdot = '\0';
1612             *pbasename = stringJoin(dir, tail);
1613         }
1614     }
1615     else {
1616         if (pextension)
1617             *pextension = stringNew(empty);
1618         if (pbasename)
1619             *pbasename = stringNew(pathname);
1620     }
1621     FREE(dir);
1622     FREE(tail);
1623     return 0;
1624 }
1625 
1626 
1627 /*!
1628  *  genPathname()
1629  *
1630  *      Input:  dir (directory name, with or without trailing '/')
1631  *              fname (file name within the directory)
1632  *      Return: full pathname, or null on error
1633  */
1634 char *
genPathname(const char * dir,const char * fname)1635 genPathname(const char  *dir,
1636             const char  *fname)
1637 {
1638 char    *charbuf;
1639 l_int32  dirlen, namelen;
1640 
1641     PROCNAME("genPathname");
1642 
1643     if (!dir)
1644         return (char *)ERROR_PTR("dir not defined", procName, NULL);
1645     if (!fname)
1646         return (char *)ERROR_PTR("fname not defined", procName, NULL);
1647 
1648     dirlen = strlen(dir);
1649     namelen = strlen(fname);
1650     if ((charbuf = (char *)CALLOC(dirlen + namelen + 10, sizeof(char)))
1651             == NULL)
1652         return (char *)ERROR_PTR("charbuf not made", procName, NULL);
1653 
1654     if (dir[dirlen - 1] != sepchar)
1655 #if COMPILER_MSVC
1656         sprintf(charbuf, "%s\\", dir);
1657 #else
1658         sprintf(charbuf, "%s/", dir);
1659 #endif
1660     else
1661         strcpy(charbuf, dir);
1662     strcat(charbuf, fname);
1663     return charbuf;
1664 }
1665 
1666 
1667 /*!
1668  *  genTempFilename()
1669  *
1670  *      Input:  dir (directory name; use '.' for local dir; no trailing '/')
1671  *              extension (<optional> filename extention with '.'; can be null)
1672  *      Return: tempname (with pid embedded in file name), or null on error
1673  *
1674  *  Notes:
1675  *      (1) This function is useful when there can be more than one
1676  *          process writing and reading temporary files.  It will not
1677  *          work properly when multiple threads from a single process call
1678  *          this function.  Furthermore, as with any function that
1679  *          provides easily guessed temporary filenames, it is not designed
1680  *          to be safe from an attack where the intruder is logged onto
1681  *          the server.
1682  */
1683 char *
genTempFilename(const char * dir,const char * extension)1684 genTempFilename(const char  *dir,
1685                 const char  *extension)
1686 {
1687 char     buf[256];
1688 char    *tempname;
1689 l_int32  pid, nchars;
1690 
1691     PROCNAME("genTempFilename");
1692 
1693     if (!dir)
1694         return (char *)ERROR_PTR("dir not defined", procName, NULL);
1695     pid = getpid();
1696     if (extension)
1697         nchars = strlen(extension);
1698     else
1699         nchars = 0;
1700 
1701 #if COMPILER_MSVC
1702     snprintf(buf, 255 - nchars, "%s\\%d", dir, pid);
1703 #else
1704     snprintf(buf, 25 - nchars, "%s/%d", dir, pid);
1705 #endif
1706 
1707     tempname = stringJoin(buf, extension);
1708     return tempname;
1709 }
1710 
1711 
1712 /*!
1713  *  extractNumberFromFilename()
1714  *
1715  *      Input:  fname
1716  *              numpre (number of characters before the digits to be found)
1717  *              numpost (number of characters after the digits to be found)
1718  *      Return: num (number embedded in the filename); -1 on error or if
1719  *                   not found
1720  */
1721 l_int32
extractNumberFromFilename(const char * fname,l_int32 numpre,l_int32 numpost)1722 extractNumberFromFilename(const char  *fname,
1723                           l_int32      numpre,
1724                           l_int32      numpost)
1725 {
1726 char    *tail, *basename;
1727 l_int32  len, nret, num;
1728 
1729     PROCNAME("extractNumberFromFilename");
1730 
1731     if (!fname)
1732         return ERROR_INT("fname not defined", procName, -1);
1733 
1734     splitPathAtDirectory(fname, NULL, &tail);
1735     splitPathAtExtension(tail, &basename, NULL);
1736     FREE(tail);
1737 
1738     len = strlen(basename);
1739     if (numpre + numpost > len - 1) {
1740         FREE(basename);
1741         return ERROR_INT("numpre + numpost too big", procName, -1);
1742     }
1743 
1744     basename[len - numpost] = '\n';
1745     nret = sscanf(basename + numpre, "%d", &num);
1746     FREE(basename);
1747 
1748     if (nret == 1)
1749         return num;
1750     else
1751         return ERROR_INT("no number found", procName, -1);
1752 }
1753 
1754 
1755 
1756 /*---------------------------------------------------------------------*
1757  *                           Timing procs                              *
1758  *---------------------------------------------------------------------*/
1759 /*
1760  *  Example of use:
1761  *
1762  *      startTimer();
1763  *      ....
1764  *      fprintf(stderr, "Elapsed time = %7.3f sec\n", stopTimer());
1765  */
1766 #if !defined(__MINGW32__) && !defined(_WIN32)
1767 
1768 #include <sys/time.h>
1769 #include <sys/resource.h>
1770 
1771 static struct rusage rusage_before;
1772 static struct rusage rusage_after;
1773 
1774 void
startTimer(void)1775 startTimer(void)
1776 {
1777     getrusage(RUSAGE_SELF, &rusage_before);
1778 }
1779 
1780 
1781 l_float32
stopTimer(void)1782 stopTimer(void)
1783 {
1784 l_int32  tsec, tusec;
1785 
1786     getrusage(RUSAGE_SELF, &rusage_after);
1787 
1788     tsec = rusage_after.ru_utime.tv_sec - rusage_before.ru_utime.tv_sec;
1789     tusec = rusage_after.ru_utime.tv_usec - rusage_before.ru_utime.tv_usec;
1790 
1791     return (tsec + ((l_float32)tusec) / 1000000.0);
1792 }
1793 
1794 #else   /* __MINGW32__ : resource.h not implemented under MINGW */
1795 
1796 #include <windows.h>
1797 
1798 static ULARGE_INTEGER utime_before;
1799 static ULARGE_INTEGER utime_after;
1800 
1801 void
startTimer(void)1802 startTimer(void)
1803 {
1804 HANDLE    this_process;
1805 FILETIME  start, stop, kernel, user;
1806 
1807     this_process = GetCurrentProcess ();
1808 
1809     GetProcessTimes (this_process, &start, &stop, &kernel, &user);
1810 
1811     utime_before.LowPart  = user.dwLowDateTime;
1812     utime_before.HighPart = user.dwHighDateTime;
1813 }
1814 
1815 l_float32
stopTimer(void)1816 stopTimer(void)
1817 {
1818 HANDLE    this_process;
1819 FILETIME  start, stop, kernel, user;
1820 
1821     this_process = GetCurrentProcess ();
1822 
1823     GetProcessTimes (this_process, &start, &stop, &kernel, &user);
1824 
1825     utime_after.LowPart  = user.dwLowDateTime;
1826     utime_after.HighPart = user.dwHighDateTime;
1827 
1828     return ((l_float32)(signed)(utime_after.QuadPart - utime_before.QuadPart) /
1829              10000000.0);
1830 }
1831 
1832 #endif
1833