2 * $RCSId: xc/lib/fontconfig/src/fccache.c,v 1.12 2002/08/22 07:36:44 keithp Exp $
4 * Copyright © 2000 Keith Packard
5 * Copyright © 2005 Patrick Lam
7 * Permission to use, copy, modify, distribute, and sell this software and its
8 * documentation for any purpose is hereby granted without fee, provided that
9 * the above copyright notice appear in all copies and that both that
10 * copyright notice and this permission notice appear in supporting
11 * documentation, and that the name of Keith Packard not be used in
12 * advertising or publicity pertaining to distribution of the software without
13 * specific, written prior permission. Keith Packard makes no
14 * representations about the suitability of this software for any purpose. It
15 * is provided "as is" without express or implied warranty.
17 * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
18 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
19 * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
20 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
21 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
22 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
23 * PERFORMANCE OF THIS SOFTWARE.
29 #include <sys/utsname.h>
30 #include <sys/types.h>
34 #define ENDIAN_TEST 0x12345678
35 #define MACHINE_SIGNATURE_SIZE 9 + 5*19 + 1
38 FcCacheSkipToArch (int fd
, const char * arch
);
41 FcCacheCopyOld (int fd
, int fd_orig
, off_t start
);
44 FcDirCacheProduce (FcFontSet
*set
, FcCache
* metadata
);
47 FcDirCacheConsume (int fd
, const char * dir
, FcFontSet
*set
);
50 FcDirCacheRead (FcFontSet
* set
, FcStrSet
* dirs
, const FcChar8
*dir
);
53 FcCacheNextOffset(off_t w
);
56 FcCacheMachineSignature (void);
59 FcCacheHaveBank (int bank
);
62 FcCacheAddBankDir (int bank
, const char * dir
);
64 #define FC_DBG_CACHE_REF 1024
67 FcCacheReadString (int fd
, char *dest
, int len
)
80 while (read (fd
, &c
, 1) == 1)
107 FcCacheWriteString (int fd
, const char *chars
)
109 if (write (fd
, chars
, strlen(chars
)+1) != strlen(chars
)+1)
115 FcGlobalCacheDirDestroy (FcGlobalCacheDir
*d
)
117 FcMemFree (FC_MEM_STRING
, strlen (d
->name
)+1);
119 FcMemFree (FC_MEM_CACHE
, sizeof (FcGlobalCacheDir
));
124 FcGlobalCacheCreate (void)
126 FcGlobalCache
*cache
;
128 cache
= malloc (sizeof (FcGlobalCache
));
131 FcMemAlloc (FC_MEM_CACHE
, sizeof (FcGlobalCache
));
133 cache
->updated
= FcFalse
;
139 FcGlobalCacheDestroy (FcGlobalCache
*cache
)
141 FcGlobalCacheDir
*d
, *next
;
143 for (d
= cache
->dirs
; d
; d
= next
)
146 FcGlobalCacheDirDestroy (d
);
148 FcMemFree (FC_MEM_CACHE
, sizeof (FcGlobalCache
));
153 FcGlobalCacheLoad (FcGlobalCache
*cache
,
155 const FcChar8
*cache_file
,
159 FcGlobalCacheDir
*d
, *next
;
160 FcFileTime config_time
= FcConfigModifiedTime (config
);
161 char * current_arch_machine_name
;
162 char candidate_arch_machine_name
[MACHINE_SIGNATURE_SIZE
+ 9];
163 off_t current_arch_start
;
165 struct stat cache_stat
, dir_stat
;
167 if (stat ((char *) cache_file
, &cache_stat
) < 0)
170 cache
->fd
= open ((char *) cache_file
, O_RDONLY
);
174 cache
->updated
= FcFalse
;
176 current_arch_machine_name
= FcCacheMachineSignature ();
177 current_arch_start
= FcCacheSkipToArch(cache
->fd
,
178 current_arch_machine_name
);
179 if (current_arch_start
< 0)
180 goto bail_and_destroy
;
182 lseek (cache
->fd
, current_arch_start
, SEEK_SET
);
183 FcCacheReadString (cache
->fd
, candidate_arch_machine_name
,
184 sizeof (candidate_arch_machine_name
));
185 if (strlen(candidate_arch_machine_name
) == 0)
186 goto bail_and_destroy
;
192 FcCacheReadString (cache
->fd
, name_buf
, sizeof (name_buf
));
193 if (!strlen(name_buf
))
196 /* Directory must be older than the global cache file; also
197 cache must be newer than the config file. */
198 if (stat ((char *) name_buf
, &dir_stat
) < 0 ||
199 dir_stat
.st_mtime
> cache_stat
.st_mtime
||
200 (config_time
.set
&& cache_stat
.st_mtime
< config_time
.time
))
204 FcStrSetAdd (staleDirs
, FcStrCopy ((FcChar8
*)name_buf
));
205 read (cache
->fd
, &md
, sizeof (FcCache
));
206 lseek (cache
->fd
, FcCacheNextOffset (lseek(cache
->fd
, 0, SEEK_CUR
)) + md
.count
, SEEK_SET
);
210 d
= malloc (sizeof (FcGlobalCacheDir
));
214 d
->next
= cache
->dirs
;
217 d
->name
= (char *)FcStrCopy ((FcChar8
*)name_buf
);
219 d
->offset
= lseek (cache
->fd
, 0, SEEK_CUR
);
220 if (read (cache
->fd
, &d
->metadata
, sizeof (FcCache
)) != sizeof (FcCache
))
222 targ
= FcCacheNextOffset (lseek(cache
->fd
, 0, SEEK_CUR
)) + d
->metadata
.count
;
223 if (lseek (cache
->fd
, targ
, SEEK_SET
) != targ
)
229 for (d
= cache
->dirs
; d
; d
= next
)
244 if (stat ((char *) cache_file
, &cache_stat
) == 0)
245 unlink ((char *)cache_file
);
252 FcGlobalCacheReadDir (FcFontSet
*set
, FcStrSet
*dirs
, FcGlobalCache
* cache
, const char *dir
, FcConfig
*config
)
255 FcBool ret
= FcFalse
;
260 for (d
= cache
->dirs
; d
; d
= d
->next
)
262 if (strncmp (d
->name
, dir
, strlen(dir
)) == 0)
264 lseek (cache
->fd
, d
->offset
, SEEK_SET
);
265 if (!FcDirCacheConsume (cache
->fd
, dir
, set
))
267 if (strcmp (d
->name
, dir
) == 0)
276 FcGlobalCacheUpdate (FcGlobalCache
*cache
,
280 FcGlobalCacheDir
* d
;
285 for (d
= cache
->dirs
; d
; d
= d
->next
)
287 if (strcmp(d
->name
, name
) == 0)
293 d
= malloc (sizeof (FcGlobalCacheDir
));
296 d
->next
= cache
->dirs
;
300 cache
->updated
= FcTrue
;
302 d
->name
= (char *)FcStrCopy ((FcChar8
*)name
);
303 d
->ent
= FcDirCacheProduce (set
, &d
->metadata
);
309 FcGlobalCacheSave (FcGlobalCache
*cache
,
310 const FcChar8
*cache_file
)
313 FcGlobalCacheDir
*dir
;
315 off_t current_arch_start
= 0, truncate_to
;
316 char * current_arch_machine_name
, * header
;
321 #if defined (HAVE_GETUID) && defined (HAVE_GETEUID)
322 /* Set-UID programs can't safely update the cache */
323 if (getuid () != geteuid ())
327 atomic
= FcAtomicCreate (cache_file
);
331 if (!FcAtomicLock (atomic
))
333 fd
= open ((char *) FcAtomicNewFile(atomic
), O_RDWR
| O_CREAT
,
338 fd_orig
= open ((char *) FcAtomicOrigFile(atomic
), O_RDONLY
);
340 current_arch_machine_name
= FcCacheMachineSignature ();
342 current_arch_start
= 0;
344 current_arch_start
= FcCacheSkipToArch (fd_orig
,
345 current_arch_machine_name
);
347 if (current_arch_start
< 0)
348 current_arch_start
= FcCacheNextOffset (lseek(fd_orig
, 0, SEEK_END
));
350 if (!FcCacheCopyOld(fd
, fd_orig
, current_arch_start
))
356 current_arch_start
= lseek(fd
, 0, SEEK_CUR
);
357 if (ftruncate (fd
, current_arch_start
) == -1)
360 header
= malloc (10 + strlen (current_arch_machine_name
));
364 truncate_to
= current_arch_start
+ strlen(current_arch_machine_name
) + 11;
365 for (dir
= cache
->dirs
; dir
; dir
= dir
->next
)
367 truncate_to
+= strlen(dir
->name
) + 1;
368 truncate_to
+= sizeof (FcCache
);
369 truncate_to
= FcCacheNextOffset (current_arch_start
+ truncate_to
);
370 truncate_to
+= dir
->metadata
.count
;
372 truncate_to
-= current_arch_start
;
374 sprintf (header
, "%8x ", (int)truncate_to
);
375 strcat (header
, current_arch_machine_name
);
376 if (!FcCacheWriteString (fd
, header
))
379 for (dir
= cache
->dirs
; dir
; dir
= dir
->next
)
383 FcCacheWriteString (fd
, dir
->name
);
384 write (fd
, &dir
->metadata
, sizeof(FcCache
));
385 lseek (fd
, FcCacheNextOffset (lseek(fd
, 0, SEEK_CUR
)), SEEK_SET
);
386 write (fd
, dir
->ent
, dir
->metadata
.count
);
390 FcCacheWriteString (fd
, "");
392 if (close (fd
) == -1)
395 if (!FcAtomicReplaceOrig (atomic
))
398 FcAtomicUnlock (atomic
);
399 FcAtomicDestroy (atomic
);
401 cache
->updated
= FcFalse
;
412 FcAtomicDeleteNew (atomic
);
414 FcAtomicUnlock (atomic
);
416 FcAtomicDestroy (atomic
);
420 #define PAGESIZE 8192
422 * Find the next presumably-mmapable offset after the supplied file
426 FcCacheNextOffset(off_t w
)
428 if (w
% PAGESIZE
== 0)
431 return ((w
/ PAGESIZE
)+1)*PAGESIZE
;
434 /* return the address of the segment for the provided arch,
435 * or -1 if arch not found */
437 FcCacheSkipToArch (int fd
, const char * arch
)
439 char candidate_arch_machine_name_count
[MACHINE_SIGNATURE_SIZE
+ 9];
440 char * candidate_arch
;
441 off_t current_arch_start
= 0;
443 /* skip arches that are not the current arch */
448 if (lseek (fd
, current_arch_start
, SEEK_SET
) != current_arch_start
)
451 if (FcCacheReadString (fd
, candidate_arch_machine_name_count
,
452 sizeof (candidate_arch_machine_name_count
)) == 0)
454 if (!strlen(candidate_arch_machine_name_count
))
456 bs
= strtol(candidate_arch_machine_name_count
, &candidate_arch
, 16);
458 // count = 0 should probably be distinguished from the !bs condition
459 if (!bs
|| bs
< strlen (candidate_arch_machine_name_count
))
462 candidate_arch
++; /* skip leading space */
464 if (strcmp (candidate_arch
, arch
)==0)
465 return current_arch_start
;
466 current_arch_start
+= bs
;
472 /* Cuts out the segment at the file pointer (moves everything else
473 * down to cover it), and leaves the file pointer at the end of the
476 FcCacheCopyOld (int fd
, int fd_orig
, off_t start
)
478 char * buf
= malloc (8192);
479 char candidate_arch_machine_name
[MACHINE_SIGNATURE_SIZE
+ 9];
481 int c
, bytes_skipped
;
488 lseek (fd
, 0, SEEK_SET
); lseek (fd_orig
, 0, SEEK_SET
);
495 if ((c
= read (fd_orig
, buf
, b
)) <= 0)
497 if (write (fd
, buf
, c
) < 0)
504 lseek (fd
, start
, SEEK_SET
);
505 if (FcCacheReadString (fd
, candidate_arch_machine_name
,
506 sizeof (candidate_arch_machine_name
)) == 0)
508 if (!strlen(candidate_arch_machine_name
))
511 bs
= strtol(candidate_arch_machine_name
, 0, 16);
518 lseek (fd
, start
+bs
+bytes_skipped
, SEEK_SET
);
519 if ((c
= read (fd
, buf
, 8192)) <= 0)
521 lseek (fd
, start
+bytes_skipped
, SEEK_SET
);
522 if (write (fd
, buf
, c
) < 0)
527 lseek (fd
, start
+bytes_skipped
, SEEK_SET
);
538 /* Does not check that the cache has the appropriate arch section. */
540 FcDirCacheValid (const FcChar8
*dir
)
542 FcChar8
*cache_file
= FcStrPlus (dir
, (FcChar8
*) "/" FC_DIR_CACHE_FILE
);
543 struct stat file_stat
, dir_stat
;
545 if (stat ((char *) dir
, &dir_stat
) < 0)
547 FcStrFree (cache_file
);
550 if (stat ((char *) cache_file
, &file_stat
) < 0)
552 FcStrFree (cache_file
);
556 FcStrFree (cache_file
);
558 * If the directory has been modified more recently than
559 * the cache file, the cache is not valid
561 if (dir_stat
.st_mtime
> file_stat
.st_mtime
)
567 /* Assumes that the cache file in 'dir' exists.
568 * Checks that the cache has the appropriate arch section. */
570 FcDirCacheHasCurrentArch (const FcChar8
*dir
)
572 FcChar8
*cache_file
= FcStrPlus (dir
, (FcChar8
*) "/" FC_DIR_CACHE_FILE
);
574 off_t current_arch_start
;
575 char *current_arch_machine_name
;
577 current_arch_machine_name
= FcCacheMachineSignature();
578 fd
= open ((char *)cache_file
, O_RDONLY
);
582 current_arch_start
= FcCacheSkipToArch(fd
, current_arch_machine_name
);
585 if (current_arch_start
< 0)
592 FcDirCacheUnlink (const FcChar8
*dir
)
594 FcChar8
*cache_file
= FcStrPlus (dir
, (FcChar8
*) "/" FC_DIR_CACHE_FILE
);
595 struct stat cache_stat
;
597 if (stat ((char *) cache_file
, &cache_stat
) == 0 &&
598 unlink ((char *)cache_file
) != 0)
600 FcStrFree (cache_file
);
604 FcStrFree (cache_file
);
609 FcCacheReadDirs (FcConfig
* config
, FcGlobalCache
* cache
,
610 FcStrList
*list
, FcFontSet
* set
)
614 FcChar8
*file
, *base
;
620 * Read in the results from 'list'.
622 while ((dir
= FcStrListNext (list
)))
625 file
= (FcChar8
*) malloc (strlen ((char *) dir
) + 1 + FC_MAX_FILE_LEN
+ 1);
629 strcpy ((char *) file
, (char *) dir
);
630 strcat ((char *) file
, "/");
631 base
= file
+ strlen ((char *) file
);
633 subdirs
= FcStrSetCreate ();
636 fprintf (stderr
, "Can't create directory set\n");
642 if (access ((char *) dir
, X_OK
) < 0)
650 fprintf (stderr
, "\"%s\": ", dir
);
654 FcStrSetDestroy (subdirs
);
658 if (stat ((char *) dir
, &statb
) == -1)
660 fprintf (stderr
, "\"%s\": ", dir
);
662 FcStrSetDestroy (subdirs
);
667 if (!S_ISDIR (statb
.st_mode
))
669 fprintf (stderr
, "\"%s\": not a directory, skipping\n", dir
);
670 FcStrSetDestroy (subdirs
);
674 if (!FcDirCacheValid (dir
) || !FcDirCacheRead (set
, subdirs
, dir
))
676 if (FcDebug () & FC_DBG_FONTSET
)
677 printf ("cache scan dir %s\n", dir
);
679 FcDirScanConfig (set
, subdirs
, cache
,
680 config
->blanks
, dir
, FcFalse
, config
);
682 sublist
= FcStrListCreate (subdirs
);
683 FcStrSetDestroy (subdirs
);
686 fprintf (stderr
, "Can't create subdir list in \"%s\"\n", dir
);
691 ret
+= FcCacheReadDirs (config
, cache
, sublist
, set
);
694 FcStrListDone (list
);
699 FcCacheRead (FcConfig
*config
, FcGlobalCache
* cache
)
701 FcFontSet
* s
= FcFontSetCreate();
705 if (FcCacheReadDirs (config
, cache
, FcConfigGetConfigDirs (config
), s
))
711 FcFontSetDestroy (s
);
715 /* read serialized state from the cache file */
717 FcDirCacheRead (FcFontSet
* set
, FcStrSet
* dirs
, const FcChar8
*dir
)
719 char *cache_file
= (char *)FcStrPlus (dir
, (FcChar8
*) "/" FC_DIR_CACHE_FILE
);
721 char * current_arch_machine_name
;
722 char candidate_arch_machine_name
[9+MACHINE_SIGNATURE_SIZE
];
723 off_t current_arch_start
= 0;
724 char subdirName
[FC_MAX_FILE_LEN
+ 1 + 12 + 1];
729 current_arch_machine_name
= FcCacheMachineSignature();
730 fd
= open(cache_file
, O_RDONLY
);
734 current_arch_start
= FcCacheSkipToArch(fd
, current_arch_machine_name
);
735 if (current_arch_start
< 0)
738 lseek (fd
, current_arch_start
, SEEK_SET
);
739 if (FcCacheReadString (fd
, candidate_arch_machine_name
,
740 sizeof (candidate_arch_machine_name
)) == 0)
743 while (strlen(FcCacheReadString (fd
, subdirName
, sizeof (subdirName
))) > 0)
744 FcStrSetAdd (dirs
, (FcChar8
*)subdirName
);
746 if (!FcDirCacheConsume (fd
, (const char *)dir
, set
))
761 FcDirCacheConsume (int fd
, const char * dir
, FcFontSet
*set
)
764 void * current_dir_block
;
767 read(fd
, &metadata
, sizeof(FcCache
));
768 if (metadata
.magic
!= FC_CACHE_MAGIC
)
774 pos
= FcCacheNextOffset (lseek(fd
, 0, SEEK_CUR
));
775 current_dir_block
= mmap (0, metadata
.count
,
776 PROT_READ
, MAP_SHARED
, fd
, pos
);
777 if (current_dir_block
== MAP_FAILED
)
780 if (!FcFontSetUnserialize (metadata
, set
, current_dir_block
))
783 FcCacheAddBankDir (metadata
.bank
, dir
);
789 FcDirCacheProduce (FcFontSet
*set
, FcCache
*metadata
)
791 void * current_dir_block
, * final_dir_block
;
792 static unsigned int rand_state
= 0;
796 rand_state
= time(0L);
797 bank
= rand_r(&rand_state
);
799 while (FcCacheHaveBank(bank
))
800 bank
= rand_r(&rand_state
);
802 memset (metadata
, 0, sizeof(FcCache
));
804 metadata
->count
= FcFontSetNeededBytes (set
);
805 metadata
->magic
= FC_CACHE_MAGIC
;
806 metadata
->bank
= bank
;
808 if (!metadata
->count
) /* not a failure, no fonts to write */
811 current_dir_block
= malloc (metadata
->count
);
812 if (!current_dir_block
)
814 final_dir_block
= FcFontSetDistributeBytes (metadata
, current_dir_block
);
816 if ((char *)current_dir_block
+ metadata
->count
!= final_dir_block
)
819 if (!FcFontSetSerialize (bank
, set
))
822 return current_dir_block
;
825 free (current_dir_block
);
829 /* write serialized state to the cache file */
831 FcDirCacheWrite (FcFontSet
*set
, FcStrSet
*dirs
, const FcChar8
*dir
)
833 FcChar8
*cache_file
= FcStrPlus (dir
, (FcChar8
*) "/" FC_DIR_CACHE_FILE
);
834 int fd
, fd_orig
, i
, dirs_count
;
837 off_t current_arch_start
= 0, truncate_to
;
839 char *current_arch_machine_name
, * header
;
840 void *current_dir_block
;
845 current_dir_block
= FcDirCacheProduce (set
, &metadata
);
847 if (metadata
.count
&& !current_dir_block
)
850 if (FcDebug () & FC_DBG_CACHE
)
851 printf ("FcDirCacheWriteDir cache_file \"%s\"\n", cache_file
);
853 atomic
= FcAtomicCreate (cache_file
);
857 if (!FcAtomicLock (atomic
))
860 fd_orig
= open((char *)FcAtomicOrigFile (atomic
), O_RDONLY
, 0666);
862 fd
= open((char *)FcAtomicNewFile (atomic
), O_RDWR
| O_CREAT
, 0666);
866 current_arch_machine_name
= FcCacheMachineSignature ();
867 current_arch_start
= 0;
871 FcCacheSkipToArch(fd_orig
, current_arch_machine_name
);
873 if (current_arch_start
< 0)
874 current_arch_start
= FcCacheNextOffset (lseek(fd_orig
, 0, SEEK_END
));
876 if (fd_orig
!= -1 && !FcCacheCopyOld(fd
, fd_orig
, current_arch_start
))
882 current_arch_start
= lseek(fd
, 0, SEEK_CUR
);
883 if (ftruncate (fd
, current_arch_start
) == -1)
886 /* allocate space for subdir names in this block */
888 for (i
= 0; i
< dirs
->size
; i
++)
889 dirs_count
+= strlen((char *)dirs
->strs
[i
]) + 1;
892 /* now write the address of the next offset */
893 truncate_to
= FcCacheNextOffset (FcCacheNextOffset (current_arch_start
+ sizeof (FcCache
) + dirs_count
) + metadata
.count
) - current_arch_start
;
894 header
= malloc (10 + strlen (current_arch_machine_name
));
897 sprintf (header
, "%8x ", (int)truncate_to
);
898 strcat (header
, current_arch_machine_name
);
899 if (!FcCacheWriteString (fd
, header
))
902 for (i
= 0; i
< dirs
->size
; i
++)
903 FcCacheWriteString (fd
, (char *)dirs
->strs
[i
]);
904 FcCacheWriteString (fd
, "");
906 write (fd
, &metadata
, sizeof(FcCache
));
909 lseek (fd
, FcCacheNextOffset (lseek(fd
, 0, SEEK_END
)), SEEK_SET
);
910 write (fd
, current_dir_block
, metadata
.count
);
911 free (current_dir_block
);
914 /* this actually serves to pad out the cache file, if needed */
915 if (ftruncate (fd
, current_arch_start
+ truncate_to
) == -1)
919 if (!FcAtomicReplaceOrig(atomic
))
921 FcAtomicUnlock (atomic
);
922 FcAtomicDestroy (atomic
);
930 FcAtomicUnlock (atomic
);
932 FcAtomicDestroy (atomic
);
934 unlink ((char *)cache_file
);
936 if (current_dir_block
)
937 free (current_dir_block
);
943 FcCacheMachineSignature ()
945 static char buf
[MACHINE_SIGNATURE_SIZE
];
946 int magic
= ENDIAN_TEST
;
947 char * m
= (char *)&magic
;
949 sprintf (buf
, "%2x%2x%2x%2x "
950 "%4x %4x %4x %4x %4x %4x %4x %4x %4x %4x %4x %4x "
951 "%4x %4x %4x %4x %4x %4x %4x\n",
952 m
[0], m
[1], m
[2], m
[3],
953 (unsigned int)sizeof (char),
954 (unsigned int)sizeof (char *),
955 (unsigned int)sizeof (int),
956 (unsigned int)sizeof (FcPattern
),
957 (unsigned int)sizeof (FcPatternEltPtr
),
958 (unsigned int)sizeof (struct _FcPatternElt
*),
959 (unsigned int)sizeof (FcPatternElt
),
960 (unsigned int)sizeof (FcObjectPtr
),
961 (unsigned int)sizeof (FcValueListPtr
),
962 (unsigned int)sizeof (FcValue
),
963 (unsigned int)sizeof (FcValueBinding
),
964 (unsigned int)sizeof (struct _FcValueList
*),
965 (unsigned int)sizeof (FcCharSet
),
966 (unsigned int)sizeof (FcCharLeaf
**),
967 (unsigned int)sizeof (FcChar16
*),
968 (unsigned int)sizeof (FcChar16
),
969 (unsigned int)sizeof (FcCharLeaf
),
970 (unsigned int)sizeof (FcChar32
),
971 (unsigned int)sizeof (FcCache
));
976 static int banks_ptr
= 0, banks_alloc
= 0;
977 static int * bankId
= 0, * bankIdx
= 0;
978 static const char ** bankDirs
= 0;
981 FcCacheHaveBank (int bank
)
985 if (bank
< FC_BANK_FIRST
)
988 for (i
= 0; i
< banks_ptr
; i
++)
989 if (bankId
[i
] == bank
)
996 FcCacheBankToIndex (int bank
)
1000 for (i
= 0; i
< banks_ptr
; i
++)
1001 if (bankId
[bankIdx
[i
]] == bank
)
1005 for (j
= i
; j
> 0; j
--)
1006 bankIdx
[j
] = bankIdx
[j
-1];
1011 if (banks_ptr
>= banks_alloc
)
1016 b
= realloc (bankId
, (banks_alloc
+ 4) * sizeof(int));
1021 bidx
= realloc (bankIdx
, (banks_alloc
+ 4) * sizeof(int));
1026 bds
= realloc (bankDirs
, (banks_alloc
+ 4) * sizeof (char *));
1041 FcCacheAddBankDir (int bank
, const char * dir
)
1043 int bi
= FcCacheBankToIndex (bank
);
1048 bankDirs
[bi
] = (const char *)FcStrCopy ((FcChar8
*)dir
);
1052 FcCacheFindBankDir (int bank
)
1054 int bi
= FcCacheBankToIndex (bank
);
1055 return bankDirs
[bi
];