intlemu.c (3128B)
1 /* 2 * libintlemu - A Core Foundation libintl emulator 3 * Copyright Copyright (C) 2008 Heikki Lindholm <holin@iki.fi> 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation; either version 2 of the License, or 8 * (at your option) any later version. 9 */ 10 11 #include <CoreFoundation/CoreFoundation.h> 12 #include <stdlib.h> 13 #include <pthread.h> 14 15 static pthread_mutex_t intlemu_lock; 16 static CFMutableDictionaryRef intlemu_dict; 17 18 static void 19 intlemu_cstring_release (CFAllocatorRef allocator, const void *value) 20 { 21 free ((void *) value); 22 } 23 24 25 void __attribute__ ((constructor)) 26 intlemu_init_ () 27 { 28 CFDictionaryValueCallBacks cstring_value_callbacks = { 29 0, /* version */ 30 NULL, /* retain callback */ 31 &intlemu_cstring_release, /* release callback */ 32 NULL, /* copy description */ 33 NULL /* equal */ 34 }; 35 if (pthread_mutex_init (&intlemu_lock, NULL) != 0) 36 abort (); 37 38 intlemu_dict = CFDictionaryCreateMutable ( 39 kCFAllocatorDefault, 40 0, 41 &kCFCopyStringDictionaryKeyCallBacks, 42 &cstring_value_callbacks); 43 if (intlemu_dict == NULL) 44 abort (); 45 } 46 47 48 void __attribute__ ((destructor)) 49 intlemu_fini_ () 50 { 51 if (intlemu_dict) 52 CFRelease (intlemu_dict); 53 54 pthread_mutex_destroy (&intlemu_lock); 55 } 56 57 58 char * 59 intlemu_bgettext (CFBundleRef bundle, const char *msgid) 60 { 61 CFStringRef key; 62 const char *value; 63 CFStringRef s; 64 CFRange r; 65 CFIndex len; 66 CFIndex clen; 67 char *buf; 68 69 if (msgid == NULL) 70 return NULL; 71 if (bundle == NULL) 72 return msgid; 73 74 key = CFStringCreateWithBytes ( 75 kCFAllocatorDefault, 76 (const UInt8 *) msgid, 77 (CFIndex) strlen (msgid), 78 kCFStringEncodingUTF8, 79 false); 80 81 if (pthread_mutex_lock (&intlemu_lock) != 0) 82 abort (); 83 value = (char *) CFDictionaryGetValue (intlemu_dict, key); 84 if (pthread_mutex_unlock (&intlemu_lock) != 0) 85 abort (); 86 if (value != NULL) 87 { 88 CFRelease (key); 89 return (char *) value; 90 } 91 92 /* no cached translaation, so, find one from the bundle */ 93 s = CFBundleCopyLocalizedString ( 94 bundle, 95 key, 96 NULL, 97 NULL); 98 if (s == key) 99 { 100 CFRelease (key); 101 return (char *) msgid; 102 } 103 /* get the length in bytes */ 104 r.location = 0; 105 r.length = CFStringGetLength (s); 106 len = 0; 107 clen = CFStringGetBytes ( 108 s, 109 r, 110 kCFStringEncodingUTF8, 111 0, 112 false, 113 NULL, 114 0, 115 &len); 116 buf = NULL; 117 if (clen == r.length) 118 { 119 buf = malloc (len + 1); 120 } 121 122 if (buf == NULL) 123 { 124 CFRelease (s); 125 CFRelease (key); 126 return (char *) msgid; 127 } 128 129 clen = CFStringGetBytes ( 130 s, 131 r, 132 kCFStringEncodingUTF8, 133 0, 134 false, 135 (UInt8 *) buf, 136 len, 137 &len); 138 buf[len] = '\0'; 139 if (clen == r.length) 140 { 141 if (pthread_mutex_lock (&intlemu_lock) != 0) 142 abort (); 143 CFDictionaryAddValue (intlemu_dict, key, buf); 144 if (pthread_mutex_unlock (&intlemu_lock) != 0) 145 abort (); 146 value = buf; 147 } 148 else 149 { 150 free (buf); 151 value = msgid; 152 } 153 154 CFRelease (s); 155 156 CFRelease (key); 157 158 return (char *) value; 159 }