Leptonica  1.73
Image processing and image analysis suite
utils2.c
Go to the documentation of this file.
1 /*====================================================================*
2  - Copyright (C) 2001 Leptonica. All rights reserved.
3  -
4  - Redistribution and use in source and binary forms, with or without
5  - modification, are permitted provided that the following conditions
6  - are met:
7  - 1. Redistributions of source code must retain the above copyright
8  - notice, this list of conditions and the following disclaimer.
9  - 2. Redistributions in binary form must reproduce the above
10  - copyright notice, this list of conditions and the following
11  - disclaimer in the documentation and/or other materials
12  - provided with the distribution.
13  -
14  - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
15  - ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
16  - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
17  - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ANY
18  - CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19  - EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20  - PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21  - PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22  - OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
23  - NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
24  - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  *====================================================================*/
26 
162 #ifdef HAVE_CONFIG_H
163 #include "config_auto.h"
164 #endif /* HAVE_CONFIG_H */
165 
166 #ifdef _MSC_VER
167 #include <process.h>
168 #include <direct.h>
169 #else
170 #include <unistd.h>
171 #endif /* _MSC_VER */
172 
173 #ifdef _WIN32
174 #include <windows.h>
175 #include <fcntl.h> /* _O_CREAT, ... */
176 #include <io.h> /* _open */
177 #include <sys/stat.h> /* _S_IREAD, _S_IWRITE */
178 #else
179 #include <sys/stat.h> /* for stat, mkdir(2) */
180 #include <sys/types.h>
181 #endif
182 
183 #include <string.h>
184 #include <stddef.h>
185 #include "allheaders.h"
186 
187 /* This is only used to test "/tmp" --> TMPDIR rewriting on Windows,
188  * by emulating it in unix. It should never be on in production. */
189 #define DEBUG_REWRITE 0
190 
191 
192 /*--------------------------------------------------------------------*
193  * Safe string operations *
194  *--------------------------------------------------------------------*/
201 char *
202 stringNew(const char *src)
203 {
204 l_int32 len;
205 char *dest;
206 
207  PROCNAME("stringNew");
208 
209  if (!src) {
210  L_WARNING("src not defined\n", procName);
211  return NULL;
212  }
213 
214  len = strlen(src);
215  if ((dest = (char *)LEPT_CALLOC(len + 1, sizeof(char))) == NULL)
216  return (char *)ERROR_PTR("dest not made", procName, NULL);
217 
218  stringCopy(dest, src, len);
219  return dest;
220 }
221 
222 
241 l_int32
242 stringCopy(char *dest,
243  const char *src,
244  l_int32 n)
245 {
246 l_int32 i;
247 
248  PROCNAME("stringCopy");
249 
250  if (!dest)
251  return ERROR_INT("dest not defined", procName, 1);
252  if (!src || n < 1)
253  return 0;
254 
255  /* Implementation of strncpy that valgrind doesn't complain about */
256  for (i = 0; i < n && src[i] != '\0'; i++)
257  dest[i] = src[i];
258  for (; i < n; i++)
259  dest[i] = '\0';
260  return 0;
261 }
262 
263 
278 l_int32
279 stringReplace(char **pdest,
280  const char *src)
281 {
282  PROCNAME("stringReplace");
283 
284  if (!pdest)
285  return ERROR_INT("pdest not defined", procName, 1);
286 
287  if (*pdest)
288  LEPT_FREE(*pdest);
289 
290  if (src)
291  *pdest = stringNew(src);
292  else
293  *pdest = NULL;
294  return 0;
295 }
296 
297 
314 l_int32
315 stringLength(const char *src,
316  size_t size)
317 {
318 l_int32 i;
319 
320  PROCNAME("stringLength");
321 
322  if (!src)
323  return ERROR_INT("src not defined", procName, 0);
324  if (size < 1)
325  return 0;
326 
327  for (i = 0; i < size; i++) {
328  if (src[i] == '\0')
329  return i;
330  }
331  return size; /* didn't find a NUL byte */
332 }
333 
334 
355 l_int32
356 stringCat(char *dest,
357  size_t size,
358  const char *src)
359 {
360 l_int32 i, n;
361 l_int32 lendest, lensrc;
362 
363  PROCNAME("stringCat");
364 
365  if (!dest)
366  return ERROR_INT("dest not defined", procName, -1);
367  if (size < 1)
368  return ERROR_INT("size < 1; too small", procName, -1);
369  if (!src)
370  return 0;
371 
372  lendest = stringLength(dest, size);
373  if (lendest == size)
374  return ERROR_INT("no terminating nul byte", procName, -1);
375  lensrc = stringLength(src, size);
376  if (lensrc == 0)
377  return 0;
378  n = (lendest + lensrc > size - 1 ? size - lendest - 1 : lensrc);
379  if (n < 1)
380  return ERROR_INT("dest too small for append", procName, -1);
381 
382  for (i = 0; i < n; i++)
383  dest[lendest + i] = src[i];
384  dest[lendest + n] = '\0';
385  return n;
386 }
387 
388 
403 char *
404 stringConcatNew(const char *first, ...)
405 {
406 size_t len;
407 char *result, *ptr;
408 const char *arg;
409 va_list args;
410 
411  if (!first) return NULL;
412 
413  /* Find the length of the output string */
414  va_start(args, first);
415  len = strlen(first);
416  while ((arg = va_arg(args, const char *)) != NULL)
417  len += strlen(arg);
418  va_end(args);
419  result = (char *)LEPT_CALLOC(len + 1, sizeof(char));
420 
421  /* Concatenate the args */
422  va_start(args, first);
423  ptr = result;
424  arg = first;
425  while (*arg)
426  *ptr++ = *arg++;
427  while ((arg = va_arg(args, const char *)) != NULL) {
428  while (*arg)
429  *ptr++ = *arg++;
430  }
431  va_end(args);
432  return result;
433 }
434 
435 
450 char *
451 stringJoin(const char *src1,
452  const char *src2)
453 {
454 char *dest;
455 l_int32 srclen1, srclen2, destlen;
456 
457  PROCNAME("stringJoin");
458 
459  srclen1 = (src1) ? strlen(src1) : 0;
460  srclen2 = (src2) ? strlen(src2) : 0;
461  destlen = srclen1 + srclen2 + 3;
462 
463  if ((dest = (char *)LEPT_CALLOC(destlen, sizeof(char))) == NULL)
464  return (char *)ERROR_PTR("calloc fail for dest", procName, NULL);
465 
466  if (src1)
467  stringCopy(dest, src1, srclen1);
468  if (src2)
469  strncat(dest, src2, srclen2);
470  return dest;
471 }
472 
473 
505 l_int32
506 stringJoinIP(char **psrc1,
507  const char *src2)
508 {
509 char *tmpstr;
510 
511  PROCNAME("stringJoinIP");
512 
513  if (!psrc1)
514  return ERROR_INT("&src1 not defined", procName, 1);
515 
516  tmpstr = stringJoin(*psrc1, src2);
517  LEPT_FREE(*psrc1);
518  *psrc1 = tmpstr;
519  return 0;
520 }
521 
522 
529 char *
530 stringReverse(const char *src)
531 {
532 char *dest;
533 l_int32 i, len;
534 
535  PROCNAME("stringReverse");
536 
537  if (!src)
538  return (char *)ERROR_PTR("src not defined", procName, NULL);
539  len = strlen(src);
540  if ((dest = (char *)LEPT_CALLOC(len + 1, sizeof(char))) == NULL)
541  return (char *)ERROR_PTR("calloc fail for dest", procName, NULL);
542  for (i = 0; i < len; i++)
543  dest[i] = src[len - 1 - i];
544 
545  return dest;
546 }
547 
548 
581 char *
582 strtokSafe(char *cstr,
583  const char *seps,
584  char **psaveptr)
585 {
586 char nextc;
587 char *start, *substr;
588 l_int32 istart, i, j, nchars;
589 
590  PROCNAME("strtokSafe");
591 
592  if (!seps)
593  return (char *)ERROR_PTR("seps not defined", procName, NULL);
594  if (!psaveptr)
595  return (char *)ERROR_PTR("&saveptr not defined", procName, NULL);
596 
597  if (!cstr) {
598  start = *psaveptr;
599  } else {
600  start = cstr;
601  *psaveptr = NULL;
602  }
603  if (!start) /* nothing to do */
604  return NULL;
605 
606  /* First time, scan for the first non-sep character */
607  istart = 0;
608  if (cstr) {
609  for (istart = 0;; istart++) {
610  if ((nextc = start[istart]) == '\0') {
611  *psaveptr = NULL; /* in case caller doesn't check ret value */
612  return NULL;
613  }
614  if (!strchr(seps, nextc))
615  break;
616  }
617  }
618 
619  /* Scan through, looking for a sep character; if none is
620  * found, 'i' will be at the end of the string. */
621  for (i = istart;; i++) {
622  if ((nextc = start[i]) == '\0')
623  break;
624  if (strchr(seps, nextc))
625  break;
626  }
627 
628  /* Save the substring */
629  nchars = i - istart;
630  substr = (char *)LEPT_CALLOC(nchars + 1, sizeof(char));
631  stringCopy(substr, start + istart, nchars);
632 
633  /* Look for the next non-sep character.
634  * If this is the last substring, return a null saveptr. */
635  for (j = i;; j++) {
636  if ((nextc = start[j]) == '\0') {
637  *psaveptr = NULL; /* no more non-sep characters */
638  break;
639  }
640  if (!strchr(seps, nextc)) {
641  *psaveptr = start + j; /* start here on next call */
642  break;
643  }
644  }
645 
646  return substr;
647 }
648 
649 
675 l_int32
677  const char *seps,
678  char **phead,
679  char **ptail)
680 {
681 char *saveptr;
682 
683  PROCNAME("stringSplitOnToken");
684 
685  if (!phead)
686  return ERROR_INT("&head not defined", procName, 1);
687  if (!ptail)
688  return ERROR_INT("&tail not defined", procName, 1);
689  *phead = *ptail = NULL;
690  if (!cstr)
691  return ERROR_INT("cstr not defined", procName, 1);
692  if (!seps)
693  return ERROR_INT("seps not defined", procName, 1);
694 
695  *phead = strtokSafe(cstr, seps, &saveptr);
696  if (saveptr)
697  *ptail = stringNew(saveptr);
698  return 0;
699 }
700 
701 
702 /*--------------------------------------------------------------------*
703  * Find and replace procs *
704  *--------------------------------------------------------------------*/
719 l_int32
720 stringCheckForChars(const char *src,
721  const char *chars,
722  l_int32 *pfound)
723 {
724 char ch;
725 l_int32 i, n;
726 
727  PROCNAME("stringCheckForChars");
728 
729  if (!pfound)
730  return ERROR_INT("&found not defined", procName, 1);
731  *pfound = FALSE;
732  if (!src || !chars)
733  return ERROR_INT("src and chars not both defined", procName, 1);
734 
735  n = strlen(src);
736  for (i = 0; i < n; i++) {
737  ch = src[i];
738  if (strchr(chars, ch)) {
739  *pfound = TRUE;
740  break;
741  }
742  }
743  return 0;
744 }
745 
746 
754 char *
755 stringRemoveChars(const char *src,
756  const char *remchars)
757 {
758 char ch;
759 char *dest;
760 l_int32 nsrc, i, k;
761 
762  PROCNAME("stringRemoveChars");
763 
764  if (!src)
765  return (char *)ERROR_PTR("src not defined", procName, NULL);
766  if (!remchars)
767  return stringNew(src);
768 
769  if ((dest = (char *)LEPT_CALLOC(strlen(src) + 1, sizeof(char))) == NULL)
770  return (char *)ERROR_PTR("dest not made", procName, NULL);
771  nsrc = strlen(src);
772  for (i = 0, k = 0; i < nsrc; i++) {
773  ch = src[i];
774  if (!strchr(remchars, ch))
775  dest[k++] = ch;
776  }
777 
778  return dest;
779 }
780 
781 
799 l_int32
800 stringFindSubstr(const char *src,
801  const char *sub,
802  l_int32 *ploc)
803 {
804 char *ptr;
805 
806  PROCNAME("stringFindSubstr");
807 
808  if (!src)
809  return ERROR_INT("src not defined", procName, 0);
810  if (!sub)
811  return ERROR_INT("sub not defined", procName, 0);
812  if (ploc) *ploc = -1;
813  if (strlen(sub) == 0)
814  return ERROR_INT("substring length 0", procName, 0);
815  if (strlen(src) == 0)
816  return 0;
817 
818  if ((ptr = (char *)strstr(src, sub)) == NULL) /* not found */
819  return 0;
820 
821  if (ploc)
822  *ploc = ptr - src;
823  return 1;
824 }
825 
826 
851 char *
852 stringReplaceSubstr(const char *src,
853  const char *sub1,
854  const char *sub2,
855  l_int32 *pfound,
856  l_int32 *ploc)
857 {
858 char *ptr, *dest;
859 l_int32 nsrc, nsub1, nsub2, len, npre, loc;
860 
861  PROCNAME("stringReplaceSubstr");
862 
863  if (!src)
864  return (char *)ERROR_PTR("src not defined", procName, NULL);
865  if (!sub1)
866  return (char *)ERROR_PTR("sub1 not defined", procName, NULL);
867  if (!sub2)
868  return (char *)ERROR_PTR("sub2 not defined", procName, NULL);
869 
870  if (pfound)
871  *pfound = 0;
872  if (ploc)
873  loc = *ploc;
874  else
875  loc = 0;
876  if ((ptr = (char *)strstr(src + loc, sub1)) == NULL) {
877  return NULL;
878  }
879 
880  if (pfound)
881  *pfound = 1;
882  nsrc = strlen(src);
883  nsub1 = strlen(sub1);
884  nsub2 = strlen(sub2);
885  len = nsrc + nsub2 - nsub1;
886  if ((dest = (char *)LEPT_CALLOC(len + 1, sizeof(char))) == NULL)
887  return (char *)ERROR_PTR("dest not made", procName, NULL);
888  npre = ptr - src;
889  memcpy(dest, src, npre);
890  strcpy(dest + npre, sub2);
891  strcpy(dest + npre + nsub2, ptr + nsub1);
892  if (ploc)
893  *ploc = npre + nsub2;
894 
895  return dest;
896 }
897 
898 
917 char *
918 stringReplaceEachSubstr(const char *src,
919  const char *sub1,
920  const char *sub2,
921  l_int32 *pcount)
922 {
923 char *currstr, *newstr;
924 l_int32 loc;
925 
926  PROCNAME("stringReplaceEachSubstr");
927 
928  if (pcount) *pcount = 0;
929  if (!src)
930  return (char *)ERROR_PTR("src not defined", procName, NULL);
931  if (!sub1)
932  return (char *)ERROR_PTR("sub1 not defined", procName, NULL);
933  if (!sub2)
934  return (char *)ERROR_PTR("sub2 not defined", procName, NULL);
935 
936  loc = 0;
937  if ((newstr = stringReplaceSubstr(src, sub1, sub2, NULL, &loc)) == NULL)
938  return NULL;
939 
940  if (pcount)
941  (*pcount)++;
942  while (1) {
943  currstr = newstr;
944  newstr = stringReplaceSubstr(currstr, sub1, sub2, NULL, &loc);
945  if (!newstr)
946  return currstr;
947  LEPT_FREE(currstr);
948  if (pcount)
949  (*pcount)++;
950  }
951 }
952 
953 
972 L_DNA *
973 arrayFindEachSequence(const l_uint8 *data,
974  size_t datalen,
975  const l_uint8 *sequence,
976  size_t seqlen)
977 {
978 l_int32 start, offset, realoffset, found;
979 L_DNA *da;
980 
981  PROCNAME("arrayFindEachSequence");
982 
983  if (!data || !sequence)
984  return (L_DNA *)ERROR_PTR("data & sequence not both defined",
985  procName, NULL);
986 
987  da = l_dnaCreate(0);
988  start = 0;
989  while (1) {
990  arrayFindSequence(data + start, datalen - start, sequence, seqlen,
991  &offset, &found);
992  if (found == FALSE)
993  break;
994 
995  realoffset = start + offset;
996  l_dnaAddNumber(da, realoffset);
997  start = realoffset + seqlen;
998  if (start >= datalen)
999  break;
1000  }
1001 
1002  if (l_dnaGetCount(da) == 0)
1003  l_dnaDestroy(&da);
1004  return da;
1005 }
1006 
1007 
1032 l_int32
1033 arrayFindSequence(const l_uint8 *data,
1034  size_t datalen,
1035  const l_uint8 *sequence,
1036  size_t seqlen,
1037  l_int32 *poffset,
1038  l_int32 *pfound)
1039 {
1040 l_int32 i, j, found, lastpos;
1041 
1042  PROCNAME("arrayFindSequence");
1043 
1044  if (poffset) *poffset = 0;
1045  if (pfound) *pfound = FALSE;
1046  if (!data || !sequence)
1047  return ERROR_INT("data & sequence not both defined", procName, 1);
1048  if (!poffset || !pfound)
1049  return ERROR_INT("&offset and &found not defined", procName, 1);
1050 
1051  lastpos = datalen - seqlen + 1;
1052  found = FALSE;
1053  for (i = 0; i < lastpos; i++) {
1054  for (j = 0; j < seqlen; j++) {
1055  if (data[i + j] != sequence[j])
1056  break;
1057  if (j == seqlen - 1)
1058  found = TRUE;
1059  }
1060  if (found == TRUE)
1061  break;
1062  }
1063 
1064  if (found == TRUE) {
1065  *poffset = i;
1066  *pfound = TRUE;
1067  }
1068  return 0;
1069 }
1070 
1071 
1072 /*--------------------------------------------------------------------*
1073  * Safe realloc *
1074  *--------------------------------------------------------------------*/
1101 void *
1102 reallocNew(void **pindata,
1103  l_int32 oldsize,
1104  l_int32 newsize)
1105 {
1106 l_int32 minsize;
1107 void *indata;
1108 void *newdata;
1109 
1110  PROCNAME("reallocNew");
1111 
1112  if (!pindata)
1113  return ERROR_PTR("input data not defined", procName, NULL);
1114  indata = *pindata;
1115 
1116  if (newsize <= 0) { /* nonstandard usage */
1117  if (indata) {
1118  LEPT_FREE(indata);
1119  *pindata = NULL;
1120  }
1121  return NULL;
1122  }
1123 
1124  if (!indata) { /* nonstandard usage */
1125  if ((newdata = (void *)LEPT_CALLOC(1, newsize)) == NULL)
1126  return ERROR_PTR("newdata not made", procName, NULL);
1127  return newdata;
1128  }
1129 
1130  /* Standard usage */
1131  if ((newdata = (void *)LEPT_CALLOC(1, newsize)) == NULL)
1132  return ERROR_PTR("newdata not made", procName, NULL);
1133  minsize = L_MIN(oldsize, newsize);
1134  memcpy((char *)newdata, (char *)indata, minsize);
1135 
1136  LEPT_FREE(indata);
1137  *pindata = NULL;
1138 
1139  return newdata;
1140 }
1141 
1142 
1143 /*--------------------------------------------------------------------*
1144  * Read and write between file and memory *
1145  *--------------------------------------------------------------------*/
1153 l_uint8 *
1154 l_binaryRead(const char *filename,
1155  size_t *pnbytes)
1156 {
1157 l_uint8 *data;
1158 FILE *fp;
1159 
1160  PROCNAME("l_binaryRead");
1161 
1162  if (!pnbytes)
1163  return (l_uint8 *)ERROR_PTR("pnbytes not defined", procName, NULL);
1164  *pnbytes = 0;
1165  if (!filename)
1166  return (l_uint8 *)ERROR_PTR("filename not defined", procName, NULL);
1167 
1168  if ((fp = fopenReadStream(filename)) == NULL)
1169  return (l_uint8 *)ERROR_PTR("file stream not opened", procName, NULL);
1170  data = l_binaryReadStream(fp, pnbytes);
1171  fclose(fp);
1172  return data;
1173 }
1174 
1175 
1199 l_uint8 *
1201  size_t *pnbytes)
1202 {
1203 l_uint8 *data;
1204 l_int32 seekable, navail, nadd, nread;
1205 L_BBUFFER *bb;
1206 
1207  PROCNAME("l_binaryReadStream");
1208 
1209  if (!pnbytes)
1210  return (l_uint8 *)ERROR_PTR("&nbytes not defined", procName, NULL);
1211  *pnbytes = 0;
1212  if (!fp)
1213  return (l_uint8 *)ERROR_PTR("fp not defined", procName, NULL);
1214 
1215  /* Test if the stream is seekable, by attempting to seek to
1216  * the start of data. This is a no-op. If it is seekable, use
1217  * l_binaryReadSelectStream() to determine the size of the
1218  * data to be read in advance. */
1219  seekable = (ftell(fp) == 0) ? 1 : 0;
1220  if (seekable)
1221  return l_binaryReadSelectStream(fp, 0, 0, pnbytes);
1222 
1223  /* If it is not seekable, use the bbuffer to realloc memory
1224  * as needed during reading. */
1225  bb = bbufferCreate(NULL, 4096);
1226  while (1) {
1227  navail = bb->nalloc - bb->n;
1228  if (navail < 4096) {
1229  nadd = L_MAX(bb->nalloc, 4096);
1230  bbufferExtendArray(bb, nadd);
1231  }
1232  nread = fread((void *)(bb->array + bb->n), 1, 4096, fp);
1233  bb->n += nread;
1234  if (nread != 4096) break;
1235  }
1236 
1237  /* Copy the data to a new array sized for the data, because
1238  * the bbuffer array can be nearly twice the size we need. */
1239  if ((data = (l_uint8 *)LEPT_CALLOC(bb->n + 1, sizeof(l_uint8))) != NULL) {
1240  memcpy(data, bb->array, bb->n);
1241  *pnbytes = bb->n;
1242  } else {
1243  L_ERROR("calloc fail for data\n", procName);
1244  }
1245 
1246  bbufferDestroy(&bb);
1247  return data;
1248 }
1249 
1250 
1266 l_uint8 *
1267 l_binaryReadSelect(const char *filename,
1268  size_t start,
1269  size_t nbytes,
1270  size_t *pnread)
1271 {
1272 l_uint8 *data;
1273 FILE *fp;
1274 
1275  PROCNAME("l_binaryReadSelect");
1276 
1277  if (!pnread)
1278  return (l_uint8 *)ERROR_PTR("pnread not defined", procName, NULL);
1279  *pnread = 0;
1280  if (!filename)
1281  return (l_uint8 *)ERROR_PTR("filename not defined", procName, NULL);
1282 
1283  if ((fp = fopenReadStream(filename)) == NULL)
1284  return (l_uint8 *)ERROR_PTR("file stream not opened", procName, NULL);
1285  data = l_binaryReadSelectStream(fp, start, nbytes, pnread);
1286  fclose(fp);
1287  return data;
1288 }
1289 
1290 
1311 l_uint8 *
1313  size_t start,
1314  size_t nbytes,
1315  size_t *pnread)
1316 {
1317 l_uint8 *data;
1318 size_t bytesleft, bytestoread, nread, filebytes;
1319 
1320  PROCNAME("l_binaryReadSelectStream");
1321 
1322  if (!pnread)
1323  return (l_uint8 *)ERROR_PTR("&nread not defined", procName, NULL);
1324  *pnread = 0;
1325  if (!fp)
1326  return (l_uint8 *)ERROR_PTR("stream not defined", procName, NULL);
1327 
1328  /* Verify and adjust the parameters if necessary */
1329  fseek(fp, 0, SEEK_END); /* EOF */
1330  filebytes = ftell(fp);
1331  fseek(fp, 0, SEEK_SET);
1332  if (start > filebytes) {
1333  L_ERROR("start = %lu but filebytes = %lu\n", procName,
1334  (unsigned long)start, (unsigned long)filebytes);
1335  return NULL;
1336  }
1337  if (filebytes == 0) /* start == 0; nothing to read; return null byte */
1338  return (l_uint8 *)LEPT_CALLOC(1, 1);
1339  bytesleft = filebytes - start; /* greater than 0 */
1340  if (nbytes == 0) nbytes = bytesleft;
1341  bytestoread = (bytesleft >= nbytes) ? nbytes : bytesleft;
1342 
1343  /* Read the data */
1344  if ((data = (l_uint8 *)LEPT_CALLOC(1, bytestoread + 1)) == NULL)
1345  return (l_uint8 *)ERROR_PTR("calloc fail for data", procName, NULL);
1346  fseek(fp, start, SEEK_SET);
1347  nread = fread(data, 1, bytestoread, fp);
1348  if (nbytes != nread)
1349  L_INFO("%lu bytes requested; %lu bytes read\n", procName,
1350  (unsigned long)nbytes, (unsigned long)nread);
1351  *pnread = nread;
1352  fseek(fp, 0, SEEK_SET);
1353  return data;
1354 }
1355 
1356 
1366 l_int32
1367 l_binaryWrite(const char *filename,
1368  const char *operation,
1369  void *data,
1370  size_t nbytes)
1371 {
1372 char actualOperation[20];
1373 FILE *fp;
1374 
1375  PROCNAME("l_binaryWrite");
1376 
1377  if (!filename)
1378  return ERROR_INT("filename not defined", procName, 1);
1379  if (!operation)
1380  return ERROR_INT("operation not defined", procName, 1);
1381  if (!data)
1382  return ERROR_INT("data not defined", procName, 1);
1383  if (nbytes <= 0)
1384  return ERROR_INT("nbytes must be > 0", procName, 1);
1385 
1386  if (strcmp(operation, "w") && strcmp(operation, "a"))
1387  return ERROR_INT("operation not one of {'w','a'}", procName, 1);
1388 
1389  /* The 'b' flag to fopen() is ignored for all POSIX
1390  * conforming systems. However, Windows needs the 'b' flag. */
1391  stringCopy(actualOperation, operation, 2);
1392  strncat(actualOperation, "b", 2);
1393 
1394  if ((fp = fopenWriteStream(filename, actualOperation)) == NULL)
1395  return ERROR_INT("stream not opened", procName, 1);
1396  fwrite(data, 1, nbytes, fp);
1397  fclose(fp);
1398  return 0;
1399 }
1400 
1401 
1408 size_t
1409 nbytesInFile(const char *filename)
1410 {
1411 size_t nbytes;
1412 FILE *fp;
1413 
1414  PROCNAME("nbytesInFile");
1415 
1416  if (!filename)
1417  return ERROR_INT("filename not defined", procName, 0);
1418  if ((fp = fopenReadStream(filename)) == NULL)
1419  return ERROR_INT("stream not opened", procName, 0);
1420  nbytes = fnbytesInFile(fp);
1421  fclose(fp);
1422  return nbytes;
1423 }
1424 
1425 
1432 size_t
1433 fnbytesInFile(FILE *fp)
1434 {
1435 l_int64 pos, nbytes;
1436 
1437  PROCNAME("fnbytesInFile");
1438 
1439  if (!fp)
1440  return ERROR_INT("stream not open", procName, 0);
1441 
1442  pos = ftell(fp); /* initial position */
1443  fseek(fp, 0, SEEK_END); /* EOF */
1444  nbytes = ftell(fp);
1445  fseek(fp, pos, SEEK_SET); /* back to initial position */
1446  return nbytes;
1447 }
1448 
1449 
1450 /*--------------------------------------------------------------------*
1451  * Copy in memory *
1452  *--------------------------------------------------------------------*/
1468 l_uint8 *
1469 l_binaryCopy(l_uint8 *datas,
1470  size_t size)
1471 {
1472 l_uint8 *datad;
1473 
1474  PROCNAME("l_binaryCopy");
1475 
1476  if (!datas)
1477  return (l_uint8 *)ERROR_PTR("datas not defined", procName, NULL);
1478 
1479  if ((datad = (l_uint8 *)LEPT_CALLOC(size + 4, sizeof(l_uint8))) == NULL)
1480  return (l_uint8 *)ERROR_PTR("datad not made", procName, NULL);
1481  memcpy(datad, datas, size);
1482  return datad;
1483 }
1484 
1485 
1486 /*--------------------------------------------------------------------*
1487  * File copy operations *
1488  *--------------------------------------------------------------------*/
1496 l_int32
1497 fileCopy(const char *srcfile,
1498  const char *newfile)
1499 {
1500 l_int32 ret;
1501 size_t nbytes;
1502 l_uint8 *data;
1503 
1504  PROCNAME("fileCopy");
1505 
1506  if (!srcfile)
1507  return ERROR_INT("srcfile not defined", procName, 1);
1508  if (!newfile)
1509  return ERROR_INT("newfile not defined", procName, 1);
1510 
1511  if ((data = l_binaryRead(srcfile, &nbytes)) == NULL)
1512  return ERROR_INT("data not returned", procName, 1);
1513  ret = l_binaryWrite(newfile, "w", data, nbytes);
1514  LEPT_FREE(data);
1515  return ret;
1516 }
1517 
1518 
1526 l_int32
1527 fileConcatenate(const char *srcfile,
1528  const char *destfile)
1529 {
1530 size_t nbytes;
1531 l_uint8 *data;
1532 
1533  PROCNAME("fileConcatenate");
1534 
1535  if (!srcfile)
1536  return ERROR_INT("srcfile not defined", procName, 1);
1537  if (!destfile)
1538  return ERROR_INT("destfile not defined", procName, 1);
1539 
1540  data = l_binaryRead(srcfile, &nbytes);
1541  l_binaryWrite(destfile, "a", data, nbytes);
1542  LEPT_FREE(data);
1543  return 0;
1544 }
1545 
1546 
1554 l_int32
1555 fileAppendString(const char *filename,
1556  const char *str)
1557 {
1558 FILE *fp;
1559 
1560  PROCNAME("fileAppendString");
1561 
1562  if (!filename)
1563  return ERROR_INT("filename not defined", procName, 1);
1564  if (!str)
1565  return ERROR_INT("str not defined", procName, 1);
1566 
1567  if ((fp = fopenWriteStream(filename, "a")) == NULL)
1568  return ERROR_INT("stream not opened", procName, 1);
1569  fprintf(fp, "%s", str);
1570  fclose(fp);
1571  return 0;
1572 }
1573 
1574 
1575 /*--------------------------------------------------------------------*
1576  * Multi-platform functions for opening file streams *
1577  *--------------------------------------------------------------------*/
1592 FILE *
1593 fopenReadStream(const char *filename)
1594 {
1595 char *fname, *tail;
1596 FILE *fp;
1597 
1598  PROCNAME("fopenReadStream");
1599 
1600  if (!filename)
1601  return (FILE *)ERROR_PTR("filename not defined", procName, NULL);
1602 
1603  /* Try input filename */
1604  fname = genPathname(filename, NULL);
1605  fp = fopen(fname, "rb");
1606  LEPT_FREE(fname);
1607  if (fp) return fp;
1608 
1609  /* Else, strip directory and try locally */
1610  splitPathAtDirectory(filename, NULL, &tail);
1611  fp = fopen(tail, "rb");
1612  LEPT_FREE(tail);
1613 
1614  if (!fp)
1615  return (FILE *)ERROR_PTR("file not found", procName, NULL);
1616  return fp;
1617 }
1618 
1619 
1635 FILE *
1636 fopenWriteStream(const char *filename,
1637  const char *modestring)
1638 {
1639 char *fname;
1640 FILE *fp;
1641 
1642  PROCNAME("fopenWriteStream");
1643 
1644  if (!filename)
1645  return (FILE *)ERROR_PTR("filename not defined", procName, NULL);
1646 
1647  fname = genPathname(filename, NULL);
1648  fp = fopen(fname, modestring);
1649  LEPT_FREE(fname);
1650  if (!fp)
1651  return (FILE *)ERROR_PTR("stream not opened", procName, NULL);
1652  return fp;
1653 }
1654 
1655 
1669 FILE *
1670 fopenReadFromMemory(const l_uint8 *data,
1671  size_t size)
1672 {
1673 FILE *fp;
1674 
1675  PROCNAME("fopenReadFromMemory");
1676 
1677  if (!data)
1678  return (FILE *)ERROR_PTR("data not defined", procName, NULL);
1679 
1680 #if HAVE_FMEMOPEN
1681  if ((fp = fmemopen((void *)data, size, "rb")) == NULL)
1682  return (FILE *)ERROR_PTR("stream not opened", procName, NULL);
1683 #else /* write to tmp file */
1684  L_INFO("work-around: writing to a temp file\n", procName);
1685  #ifdef _WIN32
1686  if ((fp = fopenWriteWinTempfile()) == NULL)
1687  return (FILE *)ERROR_PTR("tmpfile stream not opened", procName, NULL);
1688  #else
1689  if ((fp = tmpfile()) == NULL)
1690  return (FILE *)ERROR_PTR("tmpfile stream not opened", procName, NULL);
1691  #endif /* _WIN32 */
1692  fwrite(data, 1, size, fp);
1693  rewind(fp);
1694 #endif /* HAVE_FMEMOPEN */
1695 
1696  return fp;
1697 }
1698 
1699 
1700 /*--------------------------------------------------------------------*
1701  * Opening a windows tmpfile for writing *
1702  *--------------------------------------------------------------------*/
1715 FILE *
1717 {
1718 #ifdef _WIN32
1719 l_int32 handle;
1720 FILE *fp;
1721 char *filename;
1722 
1723  PROCNAME("fopenWriteWinTempfile");
1724 
1725  if ((filename = l_makeTempFilename()) == NULL) {
1726  L_ERROR("l_makeTempFilename failed, %s\n", procName, strerror(errno));
1727  return NULL;
1728  }
1729 
1730  handle = _open(filename, _O_CREAT | _O_RDWR | _O_SHORT_LIVED |
1731  _O_TEMPORARY | _O_BINARY, _S_IREAD | _S_IWRITE);
1732  lept_free(filename);
1733  if (handle == -1) {
1734  L_ERROR("_open failed, %s\n", procName, strerror(errno));
1735  return NULL;
1736  }
1737 
1738  if ((fp = _fdopen(handle, "r+b")) == NULL) {
1739  L_ERROR("_fdopen failed, %s\n", procName, strerror(errno));
1740  return NULL;
1741  }
1742 
1743  return fp;
1744 #else
1745  return NULL;
1746 #endif /* _WIN32 */
1747 }
1748 
1749 
1750 /*--------------------------------------------------------------------*
1751  * Multi-platform functions that avoid C-runtime boundary *
1752  * crossing for applications with Windows DLLs *
1753  *--------------------------------------------------------------------*/
1754 /*
1755  * Problems arise when pointers to streams and data are passed
1756  * between two Windows DLLs that have been generated with different
1757  * C runtimes. To avoid this, leptonica provides wrappers for
1758  * several C library calls.
1759  */
1773 FILE *
1774 lept_fopen(const char *filename,
1775  const char *mode)
1776 {
1777  PROCNAME("lept_fopen");
1778 
1779  if (!filename)
1780  return (FILE *)ERROR_PTR("filename not defined", procName, NULL);
1781  if (!mode)
1782  return (FILE *)ERROR_PTR("mode not defined", procName, NULL);
1783 
1784  if (stringFindSubstr(mode, "r", NULL))
1785  return fopenReadStream(filename);
1786  else
1787  return fopenWriteStream(filename, mode);
1788 }
1789 
1790 
1803 l_int32
1804 lept_fclose(FILE *fp)
1805 {
1806  PROCNAME("lept_fclose");
1807 
1808  if (!fp)
1809  return ERROR_INT("stream not defined", procName, 1);
1810 
1811  return fclose(fp);
1812 }
1813 
1814 
1829 void *
1830 lept_calloc(size_t nmemb,
1831  size_t size)
1832 {
1833  if (nmemb <= 0 || size <= 0)
1834  return NULL;
1835  return LEPT_CALLOC(nmemb, size);
1836 }
1837 
1838 
1850 void
1851 lept_free(void *ptr)
1852 {
1853  if (!ptr) return;
1854  LEPT_FREE(ptr);
1855  return;
1856 }
1857 
1858 
1859 /*--------------------------------------------------------------------*
1860  * Multi-platform file system operations *
1861  * [ These only write to /tmp or its subdirectories ] *
1862  *--------------------------------------------------------------------*/
1879 l_int32
1880 lept_mkdir(const char *subdir)
1881 {
1882 char *dir, *tmpdir;
1883 l_int32 i, n;
1884 l_int32 ret = 0;
1885 SARRAY *sa;
1886 #ifdef _WIN32
1887 l_uint32 attributes;
1888 #endif /* _WIN32 */
1889 
1890  PROCNAME("lept_mkdir");
1891 
1892  if (!subdir)
1893  return ERROR_INT("subdir not defined", procName, 1);
1894  if ((strlen(subdir) == 0) || (subdir[0] == '.') || (subdir[0] == '/'))
1895  return ERROR_INT("subdir not an actual subdirectory", procName, 1);
1896 
1897  sa = sarrayCreate(0);
1898  sarraySplitString(sa, subdir, "/");
1899  n = sarrayGetCount(sa);
1900  dir = genPathname("/tmp", NULL);
1901  /* Make sure the tmp directory exists */
1902 #ifndef _WIN32
1903  ret = mkdir(dir, 0777);
1904 #else
1905  attributes = GetFileAttributes(dir);
1906  if (attributes == INVALID_FILE_ATTRIBUTES)
1907  ret = (CreateDirectory(dir, NULL) ? 0 : 1);
1908 #endif
1909  /* Make all the subdirectories */
1910  for (i = 0; i < n; i++) {
1911  tmpdir = pathJoin(dir, sarrayGetString(sa, i, L_NOCOPY));
1912 #ifndef _WIN32
1913  ret += mkdir(tmpdir, 0777);
1914 #else
1915  if (CreateDirectory(tmpdir, NULL) == 0)
1916  ret += (GetLastError () != ERROR_ALREADY_EXISTS);
1917 #endif
1918  LEPT_FREE(dir);
1919  dir = tmpdir;
1920  }
1921  LEPT_FREE(dir);
1922  sarrayDestroy(&sa);
1923  if (ret > 0)
1924  L_ERROR("failure to create %d directories\n", procName, ret);
1925  return ret;
1926 }
1927 
1928 
1950 l_int32
1951 lept_rmdir(const char *subdir)
1952 {
1953 char *dir, *realdir, *fname, *fullname;
1954 l_int32 exists, ret, i, nfiles;
1955 SARRAY *sa;
1956 #ifdef _WIN32
1957 char *newpath;
1958 #endif /* _WIN32 */
1959 
1960  PROCNAME("lept_rmdir");
1961 
1962  if (!subdir)
1963  return ERROR_INT("subdir not defined", procName, 1);
1964  if ((strlen(subdir) == 0) || (subdir[0] == '.') || (subdir[0] == '/'))
1965  return ERROR_INT("subdir not an actual subdirectory", procName, 1);
1966 
1967  /* Find the temp subdirectory */
1968  dir = pathJoin("/tmp", subdir);
1969  if (!dir)
1970  return ERROR_INT("directory name not made", procName, 1);
1971  lept_direxists(dir, &exists);
1972  if (!exists) { /* fail silently */
1973  LEPT_FREE(dir);
1974  return 0;
1975  }
1976 
1977  /* List all the files in that directory */
1978  if ((sa = getFilenamesInDirectory(dir)) == NULL) {
1979  L_ERROR("directory %s does not exist!\n", procName, dir);
1980  LEPT_FREE(dir);
1981  return 1;
1982  }
1983  nfiles = sarrayGetCount(sa);
1984 
1985  for (i = 0; i < nfiles; i++) {
1986  fname = sarrayGetString(sa, i, L_NOCOPY);
1987  fullname = genPathname(dir, fname);
1988  remove(fullname);
1989  LEPT_FREE(fullname);
1990  }
1991 
1992 #ifndef _WIN32
1993  realdir = genPathname("/tmp", subdir);
1994  ret = rmdir(realdir);
1995  LEPT_FREE(realdir);
1996 #else
1997  newpath = genPathname(dir, NULL);
1998  ret = (RemoveDirectory(newpath) ? 0 : 1);
1999  LEPT_FREE(newpath);
2000 #endif /* !_WIN32 */
2001 
2002  sarrayDestroy(&sa);
2003  LEPT_FREE(dir);
2004  return ret;
2005 }
2006 
2007 
2024 void
2025 lept_direxists(const char *dir,
2026  l_int32 *pexists)
2027 {
2028 char *realdir;
2029 
2030  if (!pexists) return;
2031  *pexists = 0;
2032  if (!dir) return;
2033  if ((realdir = genPathname(dir, NULL)) == NULL)
2034  return;
2035 
2036 #ifndef _WIN32
2037  {
2038  struct stat s;
2039  l_int32 err = stat(realdir, &s);
2040  if (err != -1 && S_ISDIR(s.st_mode))
2041  *pexists = 1;
2042  }
2043 #else /* _WIN32 */
2044  l_uint32 attributes;
2045  attributes = GetFileAttributes(realdir);
2046  if (attributes != INVALID_FILE_ATTRIBUTES &&
2047  (attributes & FILE_ATTRIBUTE_DIRECTORY)) {
2048  *pexists = 1;
2049  }
2050 #endif /* _WIN32 */
2051 
2052  LEPT_FREE(realdir);
2053  return;
2054 }
2055 
2056 
2082 l_int32
2083 lept_rm_match(const char *subdir,
2084  const char *substr)
2085 {
2086 char *path, *fname;
2087 char tempdir[256];
2088 l_int32 i, n, ret;
2089 SARRAY *sa;
2090 
2091  PROCNAME("lept_rm_match");
2092 
2093  makeTempDirname(tempdir, 256, subdir);
2094  if ((sa = getSortedPathnamesInDirectory(tempdir, substr, 0, 0)) == NULL)
2095  return ERROR_INT("sa not made", procName, -1);
2096  n = sarrayGetCount(sa);
2097  if (n == 0) {
2098  L_WARNING("no matching files found\n", procName);
2099  sarrayDestroy(&sa);
2100  return 0;
2101  }
2102 
2103  ret = 0;
2104  for (i = 0; i < n; i++) {
2105  fname = sarrayGetString(sa, i, L_NOCOPY);
2106  path = genPathname(fname, NULL);
2107  if (lept_rmfile(path) != 0) {
2108  L_ERROR("failed to remove %s\n", procName, path);
2109  ret++;
2110  }
2111  LEPT_FREE(path);
2112  }
2113  sarrayDestroy(&sa);
2114  return ret;
2115 }
2116 
2117 
2132 l_int32
2133 lept_rm(const char *subdir,
2134  const char *tail)
2135 {
2136 char *path;
2137 char newtemp[256];
2138 l_int32 ret;
2139 
2140  PROCNAME("lept_rm");
2141 
2142  if (!tail || strlen(tail) == 0)
2143  return ERROR_INT("tail undefined or empty", procName, 1);
2144 
2145  if (makeTempDirname(newtemp, 256, subdir))
2146  return ERROR_INT("temp dirname not made", procName, 1);
2147  path = genPathname(newtemp, tail);
2148  ret = lept_rmfile(path);
2149  LEPT_FREE(path);
2150  return ret;
2151 }
2152 
2153 
2172 l_int32
2173 lept_rmfile(const char *filepath)
2174 {
2175 l_int32 ret;
2176 
2177  PROCNAME("lept_rmfile");
2178 
2179  if (!filepath || strlen(filepath) == 0)
2180  return ERROR_INT("filepath undefined or empty", procName, 1);
2181 
2182 #ifndef _WIN32
2183  ret = remove(filepath);
2184 #else
2185  /* Set attributes to allow deletion of read-only files */
2186  SetFileAttributes(filepath, FILE_ATTRIBUTE_NORMAL);
2187  ret = DeleteFile(filepath) ? 0 : 1;
2188 #endif /* !_WIN32 */
2189 
2190  return ret;
2191 }
2192 
2193 
2227 l_int32
2228 lept_mv(const char *srcfile,
2229  const char *newdir,
2230  const char *newtail,
2231  char **pnewpath)
2232 {
2233 char *srcpath, *newpath, *realpath, *dir, *srctail;
2234 char newtemp[256];
2235 l_int32 ret;
2236 
2237  PROCNAME("lept_mv");
2238 
2239  if (!srcfile)
2240  return ERROR_INT("srcfile not defined", procName, 1);
2241 
2242  /* Require output pathname to be in /tmp/ or a subdirectory */
2243  if (makeTempDirname(newtemp, 256, newdir) == 1)
2244  return ERROR_INT("newdir not NULL or a subdir of /tmp", procName, 1);
2245 
2246  /* Get canonical src pathname */
2247  splitPathAtDirectory(srcfile, &dir, &srctail);
2248 
2249 #ifndef _WIN32
2250  srcpath = pathJoin(dir, srctail);
2251  LEPT_FREE(dir);
2252 
2253  /* Generate output pathname */
2254  if (!newtail || newtail[0] == '\0')
2255  newpath = pathJoin(newtemp, srctail);
2256  else
2257  newpath = pathJoin(newtemp, newtail);
2258  LEPT_FREE(srctail);
2259 
2260  /* Overwrite any existing file at 'newpath' */
2261  ret = fileCopy(srcpath, newpath);
2262  if (!ret) {
2263  realpath = genPathname(srcpath, NULL);
2264  remove(realpath);
2265  LEPT_FREE(realpath);
2266  }
2267 #else
2268  srcpath = genPathname(dir, srctail);
2269  LEPT_FREE(dir);
2270 
2271  /* Generate output pathname */
2272  if (!newtail || newtail[0] == '\0')
2273  newpath = genPathname(newtemp, srctail);
2274  else
2275  newpath = genPathname(newtemp, newtail);
2276  LEPT_FREE(srctail);
2277 
2278  /* Overwrite any existing file at 'newpath' */
2279  ret = MoveFileEx(srcpath, newpath,
2280  MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING) ? 0 : 1;
2281 #endif /* ! _WIN32 */
2282 
2283  LEPT_FREE(srcpath);
2284  if (pnewpath)
2285  *pnewpath = newpath;
2286  else
2287  LEPT_FREE(newpath);
2288  return ret;
2289 }
2290 
2291 
2326 l_int32
2327 lept_cp(const char *srcfile,
2328  const char *newdir,
2329  const char *newtail,
2330  char **pnewpath)
2331 {
2332 char *srcpath, *newpath, *dir, *srctail;
2333 char newtemp[256];
2334 l_int32 ret;
2335 
2336  PROCNAME("lept_cp");
2337 
2338  if (!srcfile)
2339  return ERROR_INT("srcfile not defined", procName, 1);
2340 
2341  /* Require output pathname to be in /tmp or a subdirectory */
2342  if (makeTempDirname(newtemp, 256, newdir) == 1)
2343  return ERROR_INT("newdir not NULL or a subdir of /tmp", procName, 1);
2344 
2345  /* Get canonical src pathname */
2346  splitPathAtDirectory(srcfile, &dir, &srctail);
2347 
2348 #ifndef _WIN32
2349  srcpath = pathJoin(dir, srctail);
2350  LEPT_FREE(dir);
2351 
2352  /* Generate output pathname */
2353  if (!newtail || newtail[0] == '\0')
2354  newpath = pathJoin(newtemp, srctail);
2355  else
2356  newpath = pathJoin(newtemp, newtail);
2357  LEPT_FREE(srctail);
2358 
2359  /* Overwrite any existing file at 'newpath' */
2360  ret = fileCopy(srcpath, newpath);
2361 #else
2362  srcpath = genPathname(dir, srctail);
2363  LEPT_FREE(dir);
2364 
2365  /* Generate output pathname */
2366  if (!newtail || newtail[0] == '\0')
2367  newpath = genPathname(newtemp, srctail);
2368  else
2369  newpath = genPathname(newtemp, newtail);
2370  LEPT_FREE(srctail);
2371 
2372  /* Overwrite any existing file at 'newpath' */
2373  ret = CopyFile(srcpath, newpath, FALSE) ? 0 : 1;
2374 #endif /* !_WIN32 */
2375 
2376  LEPT_FREE(srcpath);
2377  if (pnewpath)
2378  *pnewpath = newpath;
2379  else
2380  LEPT_FREE(newpath);
2381  return ret;
2382 }
2383 
2384 
2385 /*--------------------------------------------------------------------*
2386  * General file name operations *
2387  *--------------------------------------------------------------------*/
2418 l_int32
2419 splitPathAtDirectory(const char *pathname,
2420  char **pdir,
2421  char **ptail)
2422 {
2423 char *cpathname, *lastslash;
2424 
2425  PROCNAME("splitPathAtDirectory");
2426 
2427  if (!pdir && !ptail)
2428  return ERROR_INT("null input for both strings", procName, 1);
2429  if (pdir) *pdir = NULL;
2430  if (ptail) *ptail = NULL;
2431  if (!pathname)
2432  return ERROR_INT("pathname not defined", procName, 1);
2433 
2434  cpathname = stringNew(pathname);
2435  convertSepCharsInPath(cpathname, UNIX_PATH_SEPCHAR);
2436  lastslash = strrchr(cpathname, '/');
2437  if (lastslash) {
2438  if (ptail)
2439  *ptail = stringNew(lastslash + 1);
2440  if (pdir) {
2441  *(lastslash + 1) = '\0';
2442  *pdir = cpathname;
2443  } else {
2444  LEPT_FREE(cpathname);
2445  }
2446  } else { /* no directory */
2447  if (pdir)
2448  *pdir = stringNew("");
2449  if (ptail)
2450  *ptail = cpathname;
2451  else
2452  LEPT_FREE(cpathname);
2453  }
2454 
2455  return 0;
2456 }
2457 
2458 
2485 l_int32
2486 splitPathAtExtension(const char *pathname,
2487  char **pbasename,
2488  char **pextension)
2489 {
2490 char *tail, *dir, *lastdot;
2491 char empty[4] = "";
2492 
2493  PROCNAME("splitPathExtension");
2494 
2495  if (!pbasename && !pextension)
2496  return ERROR_INT("null input for both strings", procName, 1);
2497  if (pbasename) *pbasename = NULL;
2498  if (pextension) *pextension = NULL;
2499  if (!pathname)
2500  return ERROR_INT("pathname not defined", procName, 1);
2501 
2502  /* Split out the directory first */
2503  splitPathAtDirectory(pathname, &dir, &tail);
2504 
2505  /* Then look for a "." in the tail part.
2506  * This way we ignore all "." in the directory. */
2507  if ((lastdot = strrchr(tail, '.'))) {
2508  if (pextension)
2509  *pextension = stringNew(lastdot);
2510  if (pbasename) {
2511  *lastdot = '\0';
2512  *pbasename = stringJoin(dir, tail);
2513  }
2514  } else {
2515  if (pextension)
2516  *pextension = stringNew(empty);
2517  if (pbasename)
2518  *pbasename = stringNew(pathname);
2519  }
2520  LEPT_FREE(dir);
2521  LEPT_FREE(tail);
2522  return 0;
2523 }
2524 
2525 
2564 char *
2565 pathJoin(const char *dir,
2566  const char *fname)
2567 {
2568 char *slash = (char *)"/";
2569 char *str, *dest;
2570 l_int32 i, n1, n2, emptydir;
2571 size_t size;
2572 SARRAY *sa1, *sa2;
2573 L_BYTEA *ba;
2574 
2575  PROCNAME("pathJoin");
2576 
2577  if (!dir && !fname)
2578  return stringNew("");
2579  if (dir && strlen(dir) >= 2 && dir[0] == '.' && dir[1] == '.')
2580  return (char *)ERROR_PTR("dir starts with '..'", procName, NULL);
2581  if (fname && strlen(fname) >= 2 && fname[0] == '.' && fname[1] == '.')
2582  return (char *)ERROR_PTR("fname starts with '..'", procName, NULL);
2583 
2584  sa1 = sarrayCreate(0);
2585  sa2 = sarrayCreate(0);
2586  ba = l_byteaCreate(4);
2587 
2588  /* Process %dir */
2589  if (dir && strlen(dir) > 0) {
2590  if (dir[0] == '/')
2591  l_byteaAppendString(ba, slash);
2592  sarraySplitString(sa1, dir, "/"); /* removes all slashes */
2593  n1 = sarrayGetCount(sa1);
2594  for (i = 0; i < n1; i++) {
2595  str = sarrayGetString(sa1, i, L_NOCOPY);
2596  l_byteaAppendString(ba, str);
2597  l_byteaAppendString(ba, slash);
2598  }
2599  }
2600 
2601  /* Special case to add leading slash: dir NULL or empty string */
2602  emptydir = dir && strlen(dir) == 0;
2603  if ((!dir || emptydir) && fname && strlen(fname) > 0 && fname[0] == '/')
2604  l_byteaAppendString(ba, slash);
2605 
2606  /* Process %fname */
2607  if (fname && strlen(fname) > 0) {
2608  sarraySplitString(sa2, fname, "/");
2609  n2 = sarrayGetCount(sa2);
2610  for (i = 0; i < n2; i++) {
2611  str = sarrayGetString(sa2, i, L_NOCOPY);
2612  l_byteaAppendString(ba, str);
2613  l_byteaAppendString(ba, slash);
2614  }
2615  }
2616 
2617  /* Remove trailing slash */
2618  dest = (char *)l_byteaCopyData(ba, &size);
2619  if (size > 1 && dest[size - 1] == '/')
2620  dest[size - 1] = '\0';
2621 
2622  sarrayDestroy(&sa1);
2623  sarrayDestroy(&sa2);
2624  l_byteaDestroy(&ba);
2625  return dest;
2626 }
2627 
2628 
2643 char *
2644 appendSubdirs(const char *basedir,
2645  const char *subdirs)
2646 {
2647 char *newdir;
2648 size_t len1, len2, len3, len4;
2649 
2650  PROCNAME("appendSubdirs");
2651 
2652  if (!basedir || !subdirs)
2653  return (char *)ERROR_PTR("basedir and subdirs not both defined",
2654  procName, NULL);
2655 
2656  len1 = strlen(basedir);
2657  len2 = strlen(subdirs);
2658  len3 = len1 + len2 + 6;
2659  if ((newdir = (char *)LEPT_CALLOC(len3 + 1, 1)) == NULL)
2660  return (char *)ERROR_PTR("newdir not made", procName, NULL);
2661  strncat(newdir, basedir, len3); /* add basedir */
2662  if (newdir[len1 - 1] != '/') /* add '/' if necessary */
2663  newdir[len1] = '/';
2664  if (subdirs[0] == '/') /* add subdirs, stripping leading '/' */
2665  strncat(newdir, subdirs + 1, len3);
2666  else
2667  strncat(newdir, subdirs, len3);
2668  len4 = strlen(newdir);
2669  if (newdir[len4 - 1] == '/') /* strip trailing '/' */
2670  newdir[len4 - 1] = '\0';
2671 
2672  return newdir;
2673 }
2674 
2675 
2676 /*--------------------------------------------------------------------*
2677  * Special file name operations *
2678  *--------------------------------------------------------------------*/
2695 l_int32
2697  l_int32 type)
2698 {
2699 l_int32 i;
2700 size_t len;
2701 
2702  PROCNAME("convertSepCharsInPath");
2703  if (!path)
2704  return ERROR_INT("path not defined", procName, 1);
2705  if (type != UNIX_PATH_SEPCHAR && type != WIN_PATH_SEPCHAR)
2706  return ERROR_INT("invalid type", procName, 1);
2707 
2708  len = strlen(path);
2709  if (type == UNIX_PATH_SEPCHAR) {
2710  for (i = 0; i < len; i++) {
2711  if (path[i] == '\\')
2712  path[i] = '/';
2713  }
2714  } else { /* WIN_PATH_SEPCHAR */
2715  for (i = 0; i < len; i++) {
2716  if (path[i] == '/')
2717  path[i] = '\\';
2718  }
2719  }
2720  return 0;
2721 }
2722 
2723 
2758 char *
2759 genPathname(const char *dir,
2760  const char *fname)
2761 {
2762 l_int32 is_win32 = FALSE;
2763 char *cdir, *pathout;
2764 l_int32 dirlen, namelen, size;
2765 
2766  PROCNAME("genPathname");
2767 
2768  if (!dir && !fname)
2769  return (char *)ERROR_PTR("no input", procName, NULL);
2770 
2771  /* Handle the case where we start from the current directory */
2772  if (!dir || dir[0] == '\0') {
2773  if ((cdir = getcwd(NULL, 0)) == NULL)
2774  return (char *)ERROR_PTR("no current dir found", procName, NULL);
2775  } else {
2776  cdir = stringNew(dir);
2777  }
2778 
2779  /* Convert to unix path separators, and remove the trailing
2780  * slash in the directory, except when dir == "/" */
2781  convertSepCharsInPath(cdir, UNIX_PATH_SEPCHAR);
2782  dirlen = strlen(cdir);
2783  if (cdir[dirlen - 1] == '/' && dirlen != 1) {
2784  cdir[dirlen - 1] = '\0';
2785  dirlen--;
2786  }
2787 
2788  namelen = (fname) ? strlen(fname) : 0;
2789  size = dirlen + namelen + 256;
2790  if ((pathout = (char *)LEPT_CALLOC(size, sizeof(char))) == NULL) {
2791  LEPT_FREE(cdir);
2792  return (char *)ERROR_PTR("pathout not made", procName, NULL);
2793  }
2794 
2795 #ifdef _WIN32
2796  is_win32 = TRUE;
2797 #endif /* _WIN32 */
2798 
2799  /* First handle %dir (which may be a full pathname).
2800  * There is no path rewriting on unix, and on win32, we do not
2801  * rewrite unless the specified directory is /tmp or
2802  * a subdirectory of /tmp */
2803  if (!is_win32 || dirlen < 4 ||
2804  (dirlen == 4 && strncmp(cdir, "/tmp", 4) != 0) || /* not in "/tmp" */
2805  (dirlen > 4 && strncmp(cdir, "/tmp/", 5) != 0)) { /* not in "/tmp/" */
2806  stringCopy(pathout, cdir, dirlen);
2807  } else { /* Rewrite for win32 with "/tmp" specified for the directory. */
2808 #ifdef _WIN32
2809  l_int32 tmpdirlen;
2810  char tmpdir[MAX_PATH];
2811  GetTempPath(sizeof(tmpdir), tmpdir); /* get the windows temp dir */
2812  tmpdirlen = strlen(tmpdir);
2813  if (tmpdirlen > 0 && tmpdir[tmpdirlen - 1] == '\\') {
2814  tmpdir[tmpdirlen - 1] = '\0'; /* trim the trailing '\' */
2815  }
2816  tmpdirlen = strlen(tmpdir);
2817  stringCopy(pathout, tmpdir, tmpdirlen);
2818 
2819  /* Add the rest of cdir */
2820  if (dirlen > 4)
2821  stringCat(pathout, size, cdir + 4);
2822 #endif /* _WIN32 */
2823  }
2824 
2825  /* Now handle %fname */
2826  if (fname && strlen(fname) > 0) {
2827  dirlen = strlen(pathout);
2828  pathout[dirlen] = '/';
2829  strncat(pathout, fname, namelen);
2830  }
2831 
2832  LEPT_FREE(cdir);
2833  return pathout;
2834 }
2835 
2836 
2864 l_int32
2865 makeTempDirname(char *result,
2866  size_t nbytes,
2867  const char *subdir)
2868 {
2869 char *dir, *path;
2870 l_int32 ret = 0;
2871 size_t pathlen;
2872 
2873  PROCNAME("makeTempDirname");
2874 
2875  if (!result)
2876  return ERROR_INT("result not defined", procName, 1);
2877  if (subdir && ((subdir[0] == '.') || (subdir[0] == '/')))
2878  return ERROR_INT("subdir not an actual subdirectory", procName, 1);
2879 
2880  memset(result, 0, nbytes);
2881  dir = pathJoin("/tmp", subdir);
2882 #ifndef _WIN32
2883  path = stringNew(dir);
2884 #else
2885  path = genPathname(dir, NULL);
2886 #endif /* ~ _WIN32 */
2887  pathlen = strlen(path);
2888  if (pathlen < nbytes - 1) {
2889  strncpy(result, path, pathlen);
2890  } else {
2891  L_ERROR("result array too small for path\n", procName);
2892  ret = 1;
2893  }
2894 
2895  LEPT_FREE(dir);
2896  LEPT_FREE(path);
2897  return ret;
2898 }
2899 
2900 
2914 l_int32
2916  size_t nbytes,
2917  l_int32 flag)
2918 {
2919 char lastchar;
2920 size_t len;
2921 
2922  PROCNAME("modifyTrailingSlash");
2923 
2924  if (!path)
2925  return ERROR_INT("path not defined", procName, 1);
2926  if (flag != L_ADD_TRAIL_SLASH && flag != L_REMOVE_TRAIL_SLASH)
2927  return ERROR_INT("invalid flag", procName, 1);
2928 
2929  len = strlen(path);
2930  lastchar = path[len - 1];
2931  if (flag == L_ADD_TRAIL_SLASH && lastchar != '/' && len < nbytes - 2) {
2932  path[len] = '/';
2933  path[len + 1] = '\0';
2934  } else if (flag == L_REMOVE_TRAIL_SLASH && lastchar == '/') {
2935  path[len - 1] = '\0';
2936  }
2937  return 0;
2938 }
2939 
2940 
2963 char *
2964 l_makeTempFilename()
2965 {
2966 char dirname[240];
2967 
2968  PROCNAME("l_makeTempFilename");
2969 
2970  if (makeTempDirname(dirname, sizeof(dirname), NULL) == 1)
2971  return (char *)ERROR_PTR("failed to make dirname", procName, NULL);
2972 
2973 #ifndef _WIN32
2974 {
2975  char *pattern;
2976  l_int32 fd;
2977  pattern = stringConcatNew(dirname, "/lept.XXXXXX", NULL);
2978  fd = mkstemp(pattern);
2979  if (fd == -1) {
2980  LEPT_FREE(pattern);
2981  return (char *)ERROR_PTR("mkstemp failed", procName, NULL);
2982  }
2983  close(fd);
2984  return pattern;
2985 }
2986 #else
2987 {
2988  char fname[MAX_PATH];
2989  FILE *fp;
2990  if (GetTempFileName(dirname, "lp.", 0, fname) == 0)
2991  return (char *)ERROR_PTR("GetTempFileName failed", procName, NULL);
2992  if ((fp = fopen(fname, "wb")) == NULL)
2993  return (char *)ERROR_PTR("file cannot be written to", procName, NULL);
2994  fclose(fp);
2995  return stringNew(fname);
2996 }
2997 #endif /* ~ _WIN32 */
2998 }
2999 
3000 
3019 l_int32
3020 extractNumberFromFilename(const char *fname,
3021  l_int32 numpre,
3022  l_int32 numpost)
3023 {
3024 char *tail, *basename;
3025 l_int32 len, nret, num;
3026 
3027  PROCNAME("extractNumberFromFilename");
3028 
3029  if (!fname)
3030  return ERROR_INT("fname not defined", procName, -1);
3031 
3032  splitPathAtDirectory(fname, NULL, &tail);
3033  splitPathAtExtension(tail, &basename, NULL);
3034  LEPT_FREE(tail);
3035 
3036  len = strlen(basename);
3037  if (numpre + numpost > len - 1) {
3038  LEPT_FREE(basename);
3039  return ERROR_INT("numpre + numpost too big", procName, -1);
3040  }
3041 
3042  basename[len - numpost] = '\0';
3043  nret = sscanf(basename + numpre, "%d", &num);
3044  LEPT_FREE(basename);
3045 
3046  if (nret == 1)
3047  return num;
3048  else
3049  return -1; /* not found */
3050 }
l_uint8 * l_binaryReadSelectStream(FILE *fp, size_t start, size_t nbytes, size_t *pnread)
l_binaryReadSelectStream()
Definition: utils2.c:1312
size_t nbytesInFile(const char *filename)
nbytesInFile()
Definition: utils2.c:1409
l_int32 lept_mv(const char *srcfile, const char *newdir, const char *newtail, char **pnewpath)
lept_mv()
Definition: utils2.c:2228
l_int32 n
Definition: bbuffer.h:53
l_int32 lept_mkdir(const char *subdir)
lept_mkdir()
Definition: utils2.c:1880
l_int32 l_dnaGetCount(L_DNA *da)
l_dnaGetCount()
Definition: dnabasic.c:597
l_int32 stringLength(const char *src, size_t size)
stringLength()
Definition: utils2.c:315
l_int32 stringCopy(char *dest, const char *src, l_int32 n)
stringCopy()
Definition: utils2.c:242
l_int32 stringReplace(char **pdest, const char *src)
stringReplace()
Definition: utils2.c:279
char * genPathname(const char *dir, const char *fname)
genPathname()
Definition: utils2.c:2759
l_int32 l_dnaAddNumber(L_DNA *da, l_float64 val)
l_dnaAddNumber()
Definition: dnabasic.c:439
l_int32 stringSplitOnToken(char *cstr, const char *seps, char **phead, char **ptail)
stringSplitOnToken()
Definition: utils2.c:676
L_DNA * arrayFindEachSequence(const l_uint8 *data, size_t datalen, const l_uint8 *sequence, size_t seqlen)
arrayFindEachSequence()
Definition: utils2.c:973
L_BYTEA * l_byteaCreate(size_t nbytes)
l_byteaCreate()
Definition: bytearray.c:93
void l_dnaDestroy(L_DNA **pda)
l_dnaDestroy()
Definition: dnabasic.c:321
l_int32 fileCopy(const char *srcfile, const char *newfile)
fileCopy()
Definition: utils2.c:1497
Definition: pix.h:704
char * stringNew(const char *src)
stringNew()
Definition: utils2.c:202
l_int32 modifyTrailingSlash(char *path, size_t nbytes, l_int32 flag)
modifyTrailingSlash()
Definition: utils2.c:2915
char * appendSubdirs(const char *basedir, const char *subdirs)
appendSubdirs()
Definition: utils2.c:2644
l_uint8 * l_binaryReadSelect(const char *filename, size_t start, size_t nbytes, size_t *pnread)
l_binaryReadSelect()
Definition: utils2.c:1267
void * lept_calloc(size_t nmemb, size_t size)
lept_calloc()
Definition: utils2.c:1830
l_int32 splitPathAtDirectory(const char *pathname, char **pdir, char **ptail)
splitPathAtDirectory()
Definition: utils2.c:2419
char * stringRemoveChars(const char *src, const char *remchars)
stringRemoveChars()
Definition: utils2.c:755
SARRAY * sarrayCreate(l_int32 n)
sarrayCreate()
Definition: sarray1.c:157
Definition: array.h:83
SARRAY * getFilenamesInDirectory(const char *dirname)
getFilenamesInDirectory()
Definition: sarray1.c:1851
FILE * fopenReadFromMemory(const l_uint8 *data, size_t size)
fopenReadFromMemory()
Definition: utils2.c:1670
l_int32 lept_cp(const char *srcfile, const char *newdir, const char *newtail, char **pnewpath)
lept_cp()
Definition: utils2.c:2327
l_uint8 * l_binaryCopy(l_uint8 *datas, size_t size)
l_binaryCopy()
Definition: utils2.c:1469
l_int32 lept_rm_match(const char *subdir, const char *substr)
lept_rm_match()
Definition: utils2.c:2083
void * reallocNew(void **pindata, l_int32 oldsize, l_int32 newsize)
reallocNew()
Definition: utils2.c:1102
Definition: array.h:116
l_int32 lept_fclose(FILE *fp)
lept_fclose()
Definition: utils2.c:1804
l_int32 stringCat(char *dest, size_t size, const char *src)
stringCat()
Definition: utils2.c:356
l_uint8 * l_binaryRead(const char *filename, size_t *pnbytes)
l_binaryRead()
Definition: utils2.c:1154
l_int32 splitPathAtExtension(const char *pathname, char **pbasename, char **pextension)
splitPathAtExtension()
Definition: utils2.c:2486
l_int32 stringJoinIP(char **psrc1, const char *src2)
stringJoinIP()
Definition: utils2.c:506
l_int32 fileAppendString(const char *filename, const char *str)
fileAppendString()
Definition: utils2.c:1555
l_int32 nalloc
Definition: bbuffer.h:52
l_uint8 * array
Definition: bbuffer.h:55
l_int32 l_byteaAppendString(L_BYTEA *ba, char *str)
l_byteaAppendString()
Definition: bytearray.c:396
void lept_free(void *ptr)
lept_free()
Definition: utils2.c:1851
size_t fnbytesInFile(FILE *fp)
fnbytesInFile()
Definition: utils2.c:1433
l_int32 bbufferExtendArray(L_BBUFFER *bb, l_int32 nbytes)
bbufferExtendArray()
Definition: bbuffer.c:361
FILE * fopenWriteWinTempfile()
fopenWriteWinTempfile()
Definition: utils2.c:1716
char * sarrayGetString(SARRAY *sa, l_int32 index, l_int32 copyflag)
sarrayGetString()
Definition: sarray1.c:675
char * stringReplaceEachSubstr(const char *src, const char *sub1, const char *sub2, l_int32 *pcount)
stringReplaceEachSubstr()
Definition: utils2.c:918
void lept_direxists(const char *dir, l_int32 *pexists)
lept_direxists()
Definition: utils2.c:2025
SARRAY * getSortedPathnamesInDirectory(const char *dirname, const char *substr, l_int32 first, l_int32 nfiles)
getSortedPathnamesInDirectory()
Definition: sarray1.c:1710
l_int32 extractNumberFromFilename(const char *fname, l_int32 numpre, l_int32 numpost)
l_makeTempFilename()
Definition: utils2.c:3020
void bbufferDestroy(L_BBUFFER **pbb)
bbufferDestroy()
Definition: bbuffer.c:167
FILE * fopenWriteStream(const char *filename, const char *modestring)
fopenWriteStream()
Definition: utils2.c:1636
FILE * fopenReadStream(const char *filename)
fopenReadStream()
Definition: utils2.c:1593
l_uint8 * l_binaryReadStream(FILE *fp, size_t *pnbytes)
l_binaryReadStream()
Definition: utils2.c:1200
l_int32 stringCheckForChars(const char *src, const char *chars, l_int32 *pfound)
stringCheckForChars()
Definition: utils2.c:720
l_int32 makeTempDirname(char *result, size_t nbytes, const char *subdir)
makeTempDirname()
Definition: utils2.c:2865
l_int32 sarrayGetCount(SARRAY *sa)
sarrayGetCount()
Definition: sarray1.c:615
FILE * lept_fopen(const char *filename, const char *mode)
lept_fopen()
Definition: utils2.c:1774
l_int32 l_binaryWrite(const char *filename, const char *operation, void *data, size_t nbytes)
l_binaryWrite()
Definition: utils2.c:1367
l_int32 convertSepCharsInPath(char *path, l_int32 type)
convertSepCharsInPath()
Definition: utils2.c:2696
char * pathJoin(const char *dir, const char *fname)
pathJoin()
Definition: utils2.c:2565
L_DNA * l_dnaCreate(l_int32 n)
l_dnaCreate()
Definition: dnabasic.c:169
char * stringJoin(const char *src1, const char *src2)
stringJoin()
Definition: utils2.c:451
char * strtokSafe(char *cstr, const char *seps, char **psaveptr)
strtokSafe()
Definition: utils2.c:582
void l_byteaDestroy(L_BYTEA **pba)
l_byteaDestroy()
Definition: bytearray.c:245
l_int32 fileConcatenate(const char *srcfile, const char *destfile)
fileConcatenate()
Definition: utils2.c:1527
l_int32 stringFindSubstr(const char *src, const char *sub, l_int32 *ploc)
stringFindSubstr()
Definition: utils2.c:800
l_int32 lept_rmdir(const char *subdir)
lept_rmdir()
Definition: utils2.c:1951
char * stringReverse(const char *src)
stringReverse()
Definition: utils2.c:530
L_BBUFFER * bbufferCreate(l_uint8 *indata, l_int32 nalloc)
bbufferCreate()
Definition: bbuffer.c:124
char * stringReplaceSubstr(const char *src, const char *sub1, const char *sub2, l_int32 *pfound, l_int32 *ploc)
stringReplaceSubstr()
Definition: utils2.c:852
l_int32 lept_rm(const char *subdir, const char *tail)
lept_rm()
Definition: utils2.c:2133
char * stringConcatNew(const char *first,...)
stringConcatNew()
Definition: utils2.c:404
l_uint8 * l_byteaCopyData(L_BYTEA *ba, size_t *psize)
l_byteaCopyData()
Definition: bytearray.c:333
l_int32 arrayFindSequence(const l_uint8 *data, size_t datalen, const l_uint8 *sequence, size_t seqlen, l_int32 *poffset, l_int32 *pfound)
arrayFindSequence()
Definition: utils2.c:1033
l_int32 lept_rmfile(const char *filepath)
lept_rmfile()
Definition: utils2.c:2173
void sarrayDestroy(SARRAY **psa)
sarrayDestroy()
Definition: sarray1.c:349
Definition: array.h:126