2 * lmo - Lua Machine Objects - Base functions
4 * Copyright (C) 2009-2010 Jo-Philipp Wich <xm@subsignal.org>
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
19 #include "template_lmo.h"
22 * Hash function from http://www.azillionmonkeys.com/qed/hash.html
23 * Copyright (C) 2004-2008 by Paul Hsieh
26 uint32_t sfh_hash(const char *data
, int len
)
28 uint32_t hash
= len
, tmp
;
31 if (len
<= 0 || data
== NULL
) return 0;
37 for (;len
> 0; len
--) {
38 hash
+= sfh_get16(data
);
39 tmp
= (sfh_get16(data
+2) << 11) ^ hash
;
40 hash
= (hash
<< 16) ^ tmp
;
41 data
+= 2*sizeof(uint16_t);
45 /* Handle end cases */
47 case 3: hash
+= sfh_get16(data
);
49 hash
^= data
[sizeof(uint16_t)] << 18;
52 case 2: hash
+= sfh_get16(data
);
56 case 1: hash
+= *data
;
61 /* Force "avalanching" of final 127 bits */
72 uint32_t lmo_canon_hash(const char *str
, int len
)
78 if (!str
|| len
>= sizeof(res
))
81 for (prev
= ' ', ptr
= res
, off
= 0; off
< len
; prev
= *str
, off
++, str
++)
94 if ((ptr
> res
) && isspace(*(ptr
-1)))
97 return sfh_hash(res
, ptr
- res
);
100 lmo_archive_t
* lmo_open(const char *file
)
103 uint32_t idx_offset
= 0;
106 lmo_archive_t
*ar
= NULL
;
108 if (stat(file
, &s
) == -1)
111 if ((in
= open(file
, O_RDONLY
)) == -1)
114 if ((ar
= (lmo_archive_t
*)malloc(sizeof(*ar
))) != NULL
)
116 memset(ar
, 0, sizeof(*ar
));
119 ar
->size
= s
.st_size
;
121 fcntl(ar
->fd
, F_SETFD
, fcntl(ar
->fd
, F_GETFD
) | FD_CLOEXEC
);
123 if ((ar
->mmap
= mmap(NULL
, ar
->size
, PROT_READ
, MAP_SHARED
, ar
->fd
, 0)) == MAP_FAILED
)
126 idx_offset
= *((const uint32_t *)
127 (ar
->mmap
+ ar
->size
- sizeof(uint32_t)));
129 if (idx_offset
>= ar
->size
)
132 ar
->index
= (lmo_entry_t
*)(ar
->mmap
+ idx_offset
);
133 ar
->length
= (ar
->size
- idx_offset
- sizeof(uint32_t)) / sizeof(lmo_entry_t
);
134 ar
->end
= ar
->mmap
+ ar
->size
;
145 if ((ar
->mmap
!= NULL
) && (ar
->mmap
!= MAP_FAILED
))
146 munmap(ar
->mmap
, ar
->size
);
154 void lmo_close(lmo_archive_t
*ar
)
158 if ((ar
->mmap
!= NULL
) && (ar
->mmap
!= MAP_FAILED
))
159 munmap(ar
->mmap
, ar
->size
);
169 lmo_catalog_t
*_lmo_catalogs
= NULL
;
170 lmo_catalog_t
*_lmo_active_catalog
= NULL
;
172 int lmo_load_catalog(const char *lang
, const char *dir
)
177 struct dirent
*de
= NULL
;
179 lmo_archive_t
*ar
= NULL
;
180 lmo_catalog_t
*cat
= NULL
;
182 if (!lmo_change_catalog(lang
))
185 if (!dir
|| !(dh
= opendir(dir
)))
188 if (!(cat
= malloc(sizeof(*cat
))))
191 memset(cat
, 0, sizeof(*cat
));
193 snprintf(cat
->lang
, sizeof(cat
->lang
), "%s", lang
);
194 snprintf(pattern
, sizeof(pattern
), "*.%s.lmo", lang
);
196 while ((de
= readdir(dh
)) != NULL
)
198 if (!fnmatch(pattern
, de
->d_name
, 0))
200 snprintf(path
, sizeof(path
), "%s/%s", dir
, de
->d_name
);
205 ar
->next
= cat
->archives
;
213 cat
->next
= _lmo_catalogs
;
216 if (!_lmo_active_catalog
)
217 _lmo_active_catalog
= cat
;
222 if (dh
) closedir(dh
);
228 int lmo_change_catalog(const char *lang
)
232 for (cat
= _lmo_catalogs
; cat
; cat
= cat
->next
)
234 if (!strncmp(cat
->lang
, lang
, sizeof(cat
->lang
)))
236 _lmo_active_catalog
= cat
;
244 static lmo_entry_t
* lmo_find_entry(lmo_archive_t
*ar
, uint32_t hash
)
246 unsigned int m
, l
, r
;
253 m
= l
+ ((r
- l
) / 2);
258 if (ar
->index
[m
].key_id
== hash
)
259 return &ar
->index
[m
];
261 if (ar
->index
[m
].key_id
> hash
)
277 int lmo_translate(const char *key
, int keylen
, char **out
, int *outlen
)
283 if (!key
|| !_lmo_active_catalog
)
286 hash
= htonl(lmo_canon_hash(key
, keylen
));
288 for (ar
= _lmo_active_catalog
->archives
; ar
; ar
= ar
->next
)
290 if ((e
= lmo_find_entry(ar
, hash
)) != NULL
)
292 *out
= ar
->mmap
+ e
->offset
;
301 void lmo_close_catalog(const char *lang
)
303 lmo_archive_t
*ar
, *next
;
304 lmo_catalog_t
*cat
, *prev
;
306 for (prev
= NULL
, cat
= _lmo_catalogs
; cat
; prev
= cat
, cat
= cat
->next
)
308 if (!strncmp(cat
->lang
, lang
, sizeof(cat
->lang
)))
311 prev
->next
= cat
->next
;
313 _lmo_catalogs
= cat
->next
;
315 for (ar
= cat
->archives
; ar
; ar
= next
)