mojoshader_common.c 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987
  1. #define __MOJOSHADER_INTERNAL__ 1
  2. #include "mojoshader_internal.h"
  3. typedef struct HashItem
  4. {
  5. const void *key;
  6. const void *value;
  7. struct HashItem *next;
  8. } HashItem;
  9. struct HashTable
  10. {
  11. HashItem **table;
  12. uint32 table_len;
  13. int stackable;
  14. void *data;
  15. HashTable_HashFn hash;
  16. HashTable_KeyMatchFn keymatch;
  17. HashTable_NukeFn nuke;
  18. MOJOSHADER_malloc m;
  19. MOJOSHADER_free f;
  20. void *d;
  21. };
  22. static inline uint32 calc_hash(const HashTable *table, const void *key)
  23. {
  24. return table->hash(key, table->data) & (table->table_len-1);
  25. } // calc_hash
  26. int hash_find(const HashTable *table, const void *key, const void **_value)
  27. {
  28. HashItem *i;
  29. void *data = table->data;
  30. const uint32 hash = calc_hash(table, key);
  31. HashItem *prev = NULL;
  32. for (i = table->table[hash]; i != NULL; i = i->next)
  33. {
  34. if (table->keymatch(key, i->key, data))
  35. {
  36. if (_value != NULL)
  37. *_value = i->value;
  38. // Matched! Move to the front of list for faster lookup next time.
  39. // (stackable tables have to remain in the same order, though!)
  40. if ((!table->stackable) && (prev != NULL))
  41. {
  42. assert(prev->next == i);
  43. prev->next = i->next;
  44. i->next = table->table[hash];
  45. table->table[hash] = i;
  46. } // if
  47. return 1;
  48. } // if
  49. prev = i;
  50. } // for
  51. return 0;
  52. } // hash_find
  53. int hash_iter(const HashTable *table, const void *key,
  54. const void **_value, void **iter)
  55. {
  56. HashItem *item = (HashItem *)*iter;
  57. if (item == NULL)
  58. item = table->table[calc_hash(table, key)];
  59. else
  60. item = item->next;
  61. while (item != NULL)
  62. {
  63. if (table->keymatch(key, item->key, table->data))
  64. {
  65. *_value = item->value;
  66. *iter = item;
  67. return 1;
  68. } // if
  69. item = item->next;
  70. } // while
  71. // no more matches.
  72. *_value = NULL;
  73. *iter = NULL;
  74. return 0;
  75. } // hash_iter
  76. int hash_iter_keys(const HashTable *table, const void **_key, void **iter)
  77. {
  78. HashItem *item = (HashItem *)*iter;
  79. int idx = 0;
  80. if (item != NULL)
  81. {
  82. const HashItem *orig = item;
  83. item = item->next;
  84. if (item == NULL)
  85. idx = calc_hash(table, orig->key) + 1;
  86. } // if
  87. while (!item && (idx < table->table_len))
  88. item = table->table[idx++]; // skip empty buckets...
  89. if (item == NULL) // no more matches?
  90. {
  91. *_key = NULL;
  92. *iter = NULL;
  93. return 0;
  94. } // if
  95. *_key = item->key;
  96. *iter = item;
  97. return 1;
  98. } // hash_iter_keys
  99. int hash_insert(HashTable *table, const void *key, const void *value)
  100. {
  101. HashItem *item = NULL;
  102. const uint32 hash = calc_hash(table, key);
  103. if ( (!table->stackable) && (hash_find(table, key, NULL)) )
  104. return 0;
  105. // !!! FIXME: grow and rehash table if it gets too saturated.
  106. item = (HashItem *) table->m(sizeof (HashItem), table->d);
  107. if (item == NULL)
  108. return -1;
  109. item->key = key;
  110. item->value = value;
  111. item->next = table->table[hash];
  112. table->table[hash] = item;
  113. return 1;
  114. } // hash_insert
  115. HashTable *hash_create(void *data, const HashTable_HashFn hashfn,
  116. const HashTable_KeyMatchFn keymatchfn,
  117. const HashTable_NukeFn nukefn,
  118. const int stackable,
  119. MOJOSHADER_malloc m, MOJOSHADER_free f, void *d)
  120. {
  121. const uint32 initial_table_size = 256;
  122. const uint32 alloc_len = sizeof (HashItem *) * initial_table_size;
  123. HashTable *table = (HashTable *) m(sizeof (HashTable), d);
  124. if (table == NULL)
  125. return NULL;
  126. memset(table, '\0', sizeof (HashTable));
  127. table->table = (HashItem **) m(alloc_len, d);
  128. if (table->table == NULL)
  129. {
  130. f(table, d);
  131. return NULL;
  132. } // if
  133. memset(table->table, '\0', alloc_len);
  134. table->table_len = initial_table_size;
  135. table->stackable = stackable;
  136. table->data = data;
  137. table->hash = hashfn;
  138. table->keymatch = keymatchfn;
  139. table->nuke = nukefn;
  140. table->m = m;
  141. table->f = f;
  142. table->d = d;
  143. return table;
  144. } // hash_create
  145. void hash_destroy(HashTable *table)
  146. {
  147. uint32 i;
  148. void *data = table->data;
  149. MOJOSHADER_free f = table->f;
  150. void *d = table->d;
  151. for (i = 0; i < table->table_len; i++)
  152. {
  153. HashItem *item = table->table[i];
  154. while (item != NULL)
  155. {
  156. HashItem *next = item->next;
  157. table->nuke(item->key, item->value, data);
  158. f(item, d);
  159. item = next;
  160. } // while
  161. } // for
  162. f(table->table, d);
  163. f(table, d);
  164. } // hash_destroy
  165. int hash_remove(HashTable *table, const void *key)
  166. {
  167. HashItem *item = NULL;
  168. HashItem *prev = NULL;
  169. void *data = table->data;
  170. const uint32 hash = calc_hash(table, key);
  171. for (item = table->table[hash]; item != NULL; item = item->next)
  172. {
  173. if (table->keymatch(key, item->key, data))
  174. {
  175. if (prev != NULL)
  176. prev->next = item->next;
  177. else
  178. table->table[hash] = item->next;
  179. table->nuke(item->key, item->value, data);
  180. table->f(item, table->d);
  181. return 1;
  182. } // if
  183. prev = item;
  184. } // for
  185. return 0;
  186. } // hash_remove
  187. // this is djb's xor hashing function.
  188. static inline uint32 hash_string_djbxor(const char *str, size_t len)
  189. {
  190. register uint32 hash = 5381;
  191. while (len--)
  192. hash = ((hash << 5) + hash) ^ *(str++);
  193. return hash;
  194. } // hash_string_djbxor
  195. static inline uint32 hash_string(const char *str, size_t len)
  196. {
  197. return hash_string_djbxor(str, len);
  198. } // hash_string
  199. uint32 hash_hash_string(const void *sym, void *data)
  200. {
  201. (void) data;
  202. return hash_string((const char*) sym, strlen((const char *) sym));
  203. } // hash_hash_string
  204. int hash_keymatch_string(const void *a, const void *b, void *data)
  205. {
  206. (void) data;
  207. return (strcmp((const char *) a, (const char *) b) == 0);
  208. } // hash_keymatch_string
  209. // string -> string map...
  210. static void stringmap_nuke_noop(const void *key, const void *val, void *d) {}
  211. static void stringmap_nuke(const void *key, const void *val, void *d)
  212. {
  213. StringMap *smap = (StringMap *) d;
  214. smap->f((void *) key, smap->d);
  215. smap->f((void *) val, smap->d);
  216. } // stringmap_nuke
  217. StringMap *stringmap_create(const int copy, MOJOSHADER_malloc m,
  218. MOJOSHADER_free f, void *d)
  219. {
  220. HashTable_NukeFn nuke = copy ? stringmap_nuke : stringmap_nuke_noop;
  221. StringMap *smap;
  222. smap = hash_create(0,hash_hash_string,hash_keymatch_string,nuke,0,m,f,d);
  223. if (smap != NULL)
  224. smap->data = smap;
  225. return smap;
  226. } // stringmap_create
  227. void stringmap_destroy(StringMap *smap)
  228. {
  229. hash_destroy(smap);
  230. } // stringmap_destroy
  231. int stringmap_insert(StringMap *smap, const char *key, const char *value)
  232. {
  233. assert(key != NULL);
  234. if (smap->nuke == stringmap_nuke_noop) // no copy?
  235. return hash_insert(smap, key, value);
  236. int rc = -1;
  237. char *k = (char *) smap->m(strlen(key) + 1, smap->d);
  238. char *v = (char *) (value ? smap->m(strlen(value) + 1, smap->d) : NULL);
  239. int failed = ( (!k) || ((!v) && (value)) );
  240. if (!failed)
  241. {
  242. strcpy(k, key);
  243. if (value != NULL)
  244. strcpy(v, value);
  245. failed = ((rc = hash_insert(smap, k, v)) <= 0);
  246. } // if
  247. if (failed)
  248. {
  249. smap->f(k, smap->d);
  250. smap->f(v, smap->d);
  251. } // if
  252. return rc;
  253. } // stringmap_insert
  254. int stringmap_remove(StringMap *smap, const char *key)
  255. {
  256. return hash_remove(smap, key);
  257. } // stringmap_remove
  258. int stringmap_find(const StringMap *smap, const char *key, const char **_value)
  259. {
  260. const void *value = NULL;
  261. const int retval = hash_find(smap, key, &value);
  262. *_value = (const char *) value;
  263. return retval;
  264. } // stringmap_find
  265. // The string cache... !!! FIXME: use StringMap internally for this.
  266. typedef struct StringBucket
  267. {
  268. char *string;
  269. struct StringBucket *next;
  270. } StringBucket;
  271. struct StringCache
  272. {
  273. StringBucket **hashtable;
  274. uint32 table_size;
  275. MOJOSHADER_malloc m;
  276. MOJOSHADER_free f;
  277. void *d;
  278. };
  279. const char *stringcache(StringCache *cache, const char *str)
  280. {
  281. return stringcache_len(cache, str, strlen(str));
  282. } // stringcache
  283. const char *stringcache_len(StringCache *cache, const char *str,
  284. const unsigned int len)
  285. {
  286. const uint8 hash = hash_string(str, len) & (cache->table_size-1);
  287. StringBucket *bucket = cache->hashtable[hash];
  288. StringBucket *prev = NULL;
  289. while (bucket)
  290. {
  291. const char *bstr = bucket->string;
  292. if ((strncmp(bstr, str, len) == 0) && (bstr[len] == 0))
  293. {
  294. // Matched! Move this to the front of the list.
  295. if (prev != NULL)
  296. {
  297. assert(prev->next == bucket);
  298. prev->next = bucket->next;
  299. bucket->next = cache->hashtable[hash];
  300. cache->hashtable[hash] = bucket;
  301. } // if
  302. return bstr; // already cached
  303. } // if
  304. prev = bucket;
  305. bucket = bucket->next;
  306. } // while
  307. // no match, add to the table.
  308. bucket = (StringBucket *) cache->m(sizeof (StringBucket), cache->d);
  309. if (bucket == NULL)
  310. return NULL;
  311. bucket->string = (char *) cache->m(len + 1, cache->d);
  312. if (bucket->string == NULL)
  313. {
  314. cache->f(bucket, cache->d);
  315. return NULL;
  316. } // if
  317. memcpy(bucket->string, str, len);
  318. bucket->string[len] = '\0';
  319. bucket->next = cache->hashtable[hash];
  320. cache->hashtable[hash] = bucket;
  321. return bucket->string;
  322. } // stringcache_len
  323. const char *stringcache_fmt(StringCache *cache, const char *fmt, ...)
  324. {
  325. char buf[128]; // use the stack if reasonable.
  326. char *ptr = NULL;
  327. int len = 0; // number of chars, NOT counting null-terminator!
  328. va_list ap;
  329. va_start(ap, fmt);
  330. len = vsnprintf(buf, sizeof (buf), fmt, ap);
  331. va_end(ap);
  332. if (len > sizeof (buf))
  333. {
  334. ptr = (char *) cache->m(len, cache->d);
  335. if (ptr == NULL)
  336. return NULL;
  337. va_start(ap, fmt);
  338. vsnprintf(ptr, len, fmt, ap);
  339. va_end(ap);
  340. } // if
  341. const char *retval = stringcache_len(cache, ptr ? ptr : buf, len);
  342. if (ptr != NULL)
  343. cache->f(ptr, cache->d);
  344. return retval;
  345. } // stringcache_fmt
  346. StringCache *stringcache_create(MOJOSHADER_malloc m, MOJOSHADER_free f, void *d)
  347. {
  348. const uint32 initial_table_size = 256;
  349. const size_t tablelen = sizeof (StringBucket *) * initial_table_size;
  350. StringCache *cache = (StringCache *) m(sizeof (StringCache), d);
  351. if (!cache)
  352. return NULL;
  353. memset(cache, '\0', sizeof (StringCache));
  354. cache->hashtable = (StringBucket **) m(tablelen, d);
  355. if (!cache->hashtable)
  356. {
  357. f(cache, d);
  358. return NULL;
  359. } // if
  360. memset(cache->hashtable, '\0', tablelen);
  361. cache->table_size = initial_table_size;
  362. cache->m = m;
  363. cache->f = f;
  364. cache->d = d;
  365. return cache;
  366. } // stringcache_create
  367. void stringcache_destroy(StringCache *cache)
  368. {
  369. if (cache == NULL)
  370. return;
  371. MOJOSHADER_free f = cache->f;
  372. void *d = cache->d;
  373. size_t i;
  374. for (i = 0; i < cache->table_size; i++)
  375. {
  376. StringBucket *bucket = cache->hashtable[i];
  377. cache->hashtable[i] = NULL;
  378. while (bucket)
  379. {
  380. StringBucket *next = bucket->next;
  381. f(bucket->string, d);
  382. f(bucket, d);
  383. bucket = next;
  384. } // while
  385. } // for
  386. f(cache->hashtable, d);
  387. f(cache, d);
  388. } // stringcache_destroy
  389. // We chain errors as a linked list with a head/tail for easy appending.
  390. // These get flattened before passing to the application.
  391. typedef struct ErrorItem
  392. {
  393. MOJOSHADER_error error;
  394. struct ErrorItem *next;
  395. } ErrorItem;
  396. struct ErrorList
  397. {
  398. ErrorItem head;
  399. ErrorItem *tail;
  400. int count;
  401. MOJOSHADER_malloc m;
  402. MOJOSHADER_free f;
  403. void *d;
  404. };
  405. ErrorList *errorlist_create(MOJOSHADER_malloc m, MOJOSHADER_free f, void *d)
  406. {
  407. ErrorList *retval = (ErrorList *) m(sizeof (ErrorList), d);
  408. if (retval != NULL)
  409. {
  410. memset(retval, '\0', sizeof (ErrorList));
  411. retval->tail = &retval->head;
  412. retval->m = m;
  413. retval->f = f;
  414. retval->d = d;
  415. } // if
  416. return retval;
  417. } // errorlist_create
  418. int errorlist_add(ErrorList *list, const char *fname,
  419. const int errpos, const char *str)
  420. {
  421. return errorlist_add_fmt(list, fname, errpos, "%s", str);
  422. } // errorlist_add
  423. int errorlist_add_fmt(ErrorList *list, const char *fname,
  424. const int errpos, const char *fmt, ...)
  425. {
  426. va_list ap;
  427. va_start(ap, fmt);
  428. const int retval = errorlist_add_va(list, fname, errpos, fmt, ap);
  429. va_end(ap);
  430. return retval;
  431. } // errorlist_add_fmt
  432. int errorlist_add_va(ErrorList *list, const char *_fname,
  433. const int errpos, const char *fmt, va_list va)
  434. {
  435. ErrorItem *error = (ErrorItem *) list->m(sizeof (ErrorItem), list->d);
  436. if (error == NULL)
  437. return 0;
  438. char *fname = NULL;
  439. if (_fname != NULL)
  440. {
  441. fname = (char *) list->m(strlen(_fname) + 1, list->d);
  442. if (fname == NULL)
  443. {
  444. list->f(error, list->d);
  445. return 0;
  446. } // if
  447. strcpy(fname, _fname);
  448. } // if
  449. char scratch[128];
  450. va_list ap;
  451. va_copy(ap, va);
  452. const int len = vsnprintf(scratch, sizeof (scratch), fmt, ap);
  453. va_end(ap);
  454. char *failstr = (char *) list->m(len + 1, list->d);
  455. if (failstr == NULL)
  456. {
  457. list->f(error, list->d);
  458. list->f(fname, list->d);
  459. return 0;
  460. } // if
  461. // If we overflowed our scratch buffer, that's okay. We were going to
  462. // allocate anyhow...the scratch buffer just lets us avoid a second
  463. // run of vsnprintf().
  464. if (len < sizeof (scratch))
  465. strcpy(failstr, scratch); // copy it over.
  466. else
  467. {
  468. va_copy(ap, va);
  469. vsnprintf(failstr, len + 1, fmt, ap); // rebuild it.
  470. va_end(ap);
  471. } // else
  472. error->error.error = failstr;
  473. error->error.filename = fname;
  474. error->error.error_position = errpos;
  475. error->next = NULL;
  476. list->tail->next = error;
  477. list->tail = error;
  478. list->count++;
  479. return 1;
  480. } // errorlist_add_va
  481. int errorlist_count(ErrorList *list)
  482. {
  483. return list->count;
  484. } // errorlist_count
  485. MOJOSHADER_error *errorlist_flatten(ErrorList *list)
  486. {
  487. if (list->count == 0)
  488. return NULL;
  489. int total = 0;
  490. MOJOSHADER_error *retval = (MOJOSHADER_error *)
  491. list->m(sizeof (MOJOSHADER_error) * list->count, list->d);
  492. if (retval == NULL)
  493. return NULL;
  494. ErrorItem *item = list->head.next;
  495. while (item != NULL)
  496. {
  497. ErrorItem *next = item->next;
  498. // reuse the string allocations
  499. memcpy(&retval[total], &item->error, sizeof (MOJOSHADER_error));
  500. list->f(item, list->d);
  501. item = next;
  502. total++;
  503. } // while
  504. assert(total == list->count);
  505. list->count = 0;
  506. list->head.next = NULL;
  507. list->tail = &list->head;
  508. return retval;
  509. } // errorlist_flatten
  510. void errorlist_destroy(ErrorList *list)
  511. {
  512. if (list == NULL)
  513. return;
  514. MOJOSHADER_free f = list->f;
  515. void *d = list->d;
  516. ErrorItem *item = list->head.next;
  517. while (item != NULL)
  518. {
  519. ErrorItem *next = item->next;
  520. f((void *) item->error.error, d);
  521. f((void *) item->error.filename, d);
  522. f(item, d);
  523. item = next;
  524. } // while
  525. f(list, d);
  526. } // errorlist_destroy
  527. typedef struct BufferBlock
  528. {
  529. uint8 *data;
  530. size_t bytes;
  531. struct BufferBlock *next;
  532. } BufferBlock;
  533. struct Buffer
  534. {
  535. size_t total_bytes;
  536. BufferBlock *head;
  537. BufferBlock *tail;
  538. size_t block_size;
  539. MOJOSHADER_malloc m;
  540. MOJOSHADER_free f;
  541. void *d;
  542. };
  543. Buffer *buffer_create(size_t blksz, MOJOSHADER_malloc m,
  544. MOJOSHADER_free f, void *d)
  545. {
  546. Buffer *buffer = (Buffer *) m(sizeof (Buffer), d);
  547. if (buffer != NULL)
  548. {
  549. memset(buffer, '\0', sizeof (Buffer));
  550. buffer->block_size = blksz;
  551. buffer->m = m;
  552. buffer->f = f;
  553. buffer->d = d;
  554. } // if
  555. return buffer;
  556. } // buffer_create
  557. char *buffer_reserve(Buffer *buffer, const size_t len)
  558. {
  559. // note that we make the blocks bigger than blocksize when we have enough
  560. // data to overfill a fresh block, to reduce allocations.
  561. const size_t blocksize = buffer->block_size;
  562. if (len == 0)
  563. return NULL;
  564. if (buffer->tail != NULL)
  565. {
  566. const size_t tailbytes = buffer->tail->bytes;
  567. const size_t avail = (tailbytes >= blocksize) ? 0 : blocksize - tailbytes;
  568. if (len <= avail)
  569. {
  570. buffer->tail->bytes += len;
  571. buffer->total_bytes += len;
  572. assert(buffer->tail->bytes <= blocksize);
  573. return (char *) buffer->tail->data + tailbytes;
  574. } // if
  575. } // if
  576. // need to allocate a new block (even if a previous block wasn't filled,
  577. // so this buffer is contiguous).
  578. const size_t bytecount = len > blocksize ? len : blocksize;
  579. const size_t malloc_len = sizeof (BufferBlock) + bytecount;
  580. BufferBlock *item = (BufferBlock *) buffer->m(malloc_len, buffer->d);
  581. if (item == NULL)
  582. return NULL;
  583. item->data = ((uint8 *) item) + sizeof (BufferBlock);
  584. item->bytes = len;
  585. item->next = NULL;
  586. if (buffer->tail != NULL)
  587. buffer->tail->next = item;
  588. else
  589. buffer->head = item;
  590. buffer->tail = item;
  591. buffer->total_bytes += len;
  592. return (char *) item->data;
  593. } // buffer_reserve
  594. int buffer_append(Buffer *buffer, const void *_data, size_t len)
  595. {
  596. const uint8 *data = (const uint8 *) _data;
  597. // note that we make the blocks bigger than blocksize when we have enough
  598. // data to overfill a fresh block, to reduce allocations.
  599. const size_t blocksize = buffer->block_size;
  600. if (len == 0)
  601. return 1;
  602. if (buffer->tail != NULL)
  603. {
  604. const size_t tailbytes = buffer->tail->bytes;
  605. const size_t avail = (tailbytes >= blocksize) ? 0 : blocksize - tailbytes;
  606. const size_t cpy = (avail > len) ? len : avail;
  607. if (cpy > 0)
  608. {
  609. memcpy(buffer->tail->data + tailbytes, data, cpy);
  610. len -= cpy;
  611. data += cpy;
  612. buffer->tail->bytes += cpy;
  613. buffer->total_bytes += cpy;
  614. assert(buffer->tail->bytes <= blocksize);
  615. } // if
  616. } // if
  617. if (len > 0)
  618. {
  619. assert((!buffer->tail) || (buffer->tail->bytes == blocksize));
  620. const size_t bytecount = len > blocksize ? len : blocksize;
  621. const size_t malloc_len = sizeof (BufferBlock) + bytecount;
  622. BufferBlock *item = (BufferBlock *) buffer->m(malloc_len, buffer->d);
  623. if (item == NULL)
  624. return 0;
  625. item->data = ((uint8 *) item) + sizeof (BufferBlock);
  626. item->bytes = len;
  627. item->next = NULL;
  628. if (buffer->tail != NULL)
  629. buffer->tail->next = item;
  630. else
  631. buffer->head = item;
  632. buffer->tail = item;
  633. memcpy(item->data, data, len);
  634. buffer->total_bytes += len;
  635. } // if
  636. return 1;
  637. } // buffer_append
  638. int buffer_append_fmt(Buffer *buffer, const char *fmt, ...)
  639. {
  640. va_list ap;
  641. va_start(ap, fmt);
  642. const int retval = buffer_append_va(buffer, fmt, ap);
  643. va_end(ap);
  644. return retval;
  645. } // buffer_append_fmt
  646. int buffer_append_va(Buffer *buffer, const char *fmt, va_list va)
  647. {
  648. char scratch[256];
  649. va_list ap;
  650. va_copy(ap, va);
  651. const int len = vsnprintf(scratch, sizeof (scratch), fmt, ap);
  652. va_end(ap);
  653. // If we overflowed our scratch buffer, heap allocate and try again.
  654. if (len == 0)
  655. return 1; // nothing to do.
  656. else if (len < sizeof (scratch))
  657. return buffer_append(buffer, scratch, len);
  658. char *buf = (char *) buffer->m(len + 1, buffer->d);
  659. if (buf == NULL)
  660. return 0;
  661. va_copy(ap, va);
  662. vsnprintf(buf, len + 1, fmt, ap); // rebuild it.
  663. va_end(ap);
  664. const int retval = buffer_append(buffer, scratch, len);
  665. buffer->f(buf, buffer->d);
  666. return retval;
  667. } // buffer_append_va
  668. size_t buffer_size(Buffer *buffer)
  669. {
  670. return buffer->total_bytes;
  671. } // buffer_size
  672. void buffer_empty(Buffer *buffer)
  673. {
  674. BufferBlock *item = buffer->head;
  675. while (item != NULL)
  676. {
  677. BufferBlock *next = item->next;
  678. buffer->f(item, buffer->d);
  679. item = next;
  680. } // while
  681. buffer->head = buffer->tail = NULL;
  682. buffer->total_bytes = 0;
  683. } // buffer_empty
  684. char *buffer_flatten(Buffer *buffer)
  685. {
  686. char *retval = (char *) buffer->m(buffer->total_bytes + 1, buffer->d);
  687. if (retval == NULL)
  688. return NULL;
  689. BufferBlock *item = buffer->head;
  690. char *ptr = retval;
  691. while (item != NULL)
  692. {
  693. BufferBlock *next = item->next;
  694. memcpy(ptr, item->data, item->bytes);
  695. ptr += item->bytes;
  696. buffer->f(item, buffer->d);
  697. item = next;
  698. } // while
  699. *ptr = '\0';
  700. assert(ptr == (retval + buffer->total_bytes));
  701. buffer->head = buffer->tail = NULL;
  702. buffer->total_bytes = 0;
  703. return retval;
  704. } // buffer_flatten
  705. char *buffer_merge(Buffer **buffers, const size_t n, size_t *_len)
  706. {
  707. Buffer *first = NULL;
  708. size_t len = 0;
  709. size_t i;
  710. for (i = 0; i < n; i++)
  711. {
  712. Buffer *buffer = buffers[i];
  713. if (buffer == NULL)
  714. continue;
  715. if (first == NULL)
  716. first = buffer;
  717. len += buffer->total_bytes;
  718. } // for
  719. char *retval = (char *) (first ? first->m(len + 1, first->d) : NULL);
  720. if (retval == NULL)
  721. {
  722. *_len = 0;
  723. return NULL;
  724. } // if
  725. *_len = len;
  726. char *ptr = retval;
  727. for (i = 0; i < n; i++)
  728. {
  729. Buffer *buffer = buffers[i];
  730. if (buffer == NULL)
  731. continue;
  732. BufferBlock *item = buffer->head;
  733. while (item != NULL)
  734. {
  735. BufferBlock *next = item->next;
  736. memcpy(ptr, item->data, item->bytes);
  737. ptr += item->bytes;
  738. buffer->f(item, buffer->d);
  739. item = next;
  740. } // while
  741. buffer->head = buffer->tail = NULL;
  742. buffer->total_bytes = 0;
  743. } // for
  744. *ptr = '\0';
  745. assert(ptr == (retval + len));
  746. return retval;
  747. } // buffer_merge
  748. void buffer_destroy(Buffer *buffer)
  749. {
  750. if (buffer != NULL)
  751. {
  752. MOJOSHADER_free f = buffer->f;
  753. void *d = buffer->d;
  754. buffer_empty(buffer);
  755. f(buffer, d);
  756. } // if
  757. } // buffer_destroy
  758. static int blockscmp(BufferBlock *item, const uint8 *data, size_t len)
  759. {
  760. if (len == 0)
  761. return 1; // "match"
  762. while (item != NULL)
  763. {
  764. const size_t itemremain = item->bytes;
  765. const size_t avail = len < itemremain ? len : itemremain;
  766. if (memcmp(item->data, data, avail) != 0)
  767. return 0; // not a match.
  768. if (len == avail)
  769. return 1; // complete match!
  770. len -= avail;
  771. data += avail;
  772. item = item->next;
  773. } // while
  774. return 0; // not a complete match.
  775. } // blockscmp
  776. ssize_t buffer_find(Buffer *buffer, const size_t start,
  777. const void *_data, const size_t len)
  778. {
  779. if (len == 0)
  780. return 0; // I guess that's right.
  781. if (start >= buffer->total_bytes)
  782. return -1; // definitely can't match.
  783. if (len > (buffer->total_bytes - start))
  784. return -1; // definitely can't match.
  785. // Find the start point somewhere in the center of a buffer.
  786. BufferBlock *item = buffer->head;
  787. const uint8 *ptr = item->data;
  788. size_t pos = 0;
  789. if (start > 0)
  790. {
  791. while (1)
  792. {
  793. assert(item != NULL);
  794. if ((pos + item->bytes) > start) // start is in this block.
  795. {
  796. ptr = item->data + (start - pos);
  797. break;
  798. } // if
  799. pos += item->bytes;
  800. item = item->next;
  801. } // while
  802. } // if
  803. // okay, we're at the origin of the search.
  804. assert(item != NULL);
  805. assert(ptr != NULL);
  806. const uint8 *data = (const uint8 *) _data;
  807. const uint8 first = *data;
  808. while (item != NULL)
  809. {
  810. const size_t itemremain = item->bytes - ((size_t)(ptr-item->data));
  811. ptr = (uint8 *) memchr(ptr, first, itemremain);
  812. while (ptr != NULL)
  813. {
  814. const size_t retval = pos + ((size_t) (ptr - item->data));
  815. if (len == 1)
  816. return retval; // we're done, here it is!
  817. const size_t itemremain = item->bytes - ((size_t)(ptr-item->data));
  818. const size_t avail = len < itemremain ? len : itemremain;
  819. if ((avail == 0) || (memcmp(ptr, data, avail) == 0))
  820. {
  821. // okay, we've got a (sub)string match! Move to the next block.
  822. // check all blocks until we get a complete match or a failure.
  823. if (blockscmp(item->next, data+avail, len-avail))
  824. return (ssize_t) retval;
  825. } // if
  826. // try again, further in this block.
  827. ptr = (uint8 *) memchr(ptr + 1, first, itemremain - 1);
  828. } // while
  829. pos += item->bytes;
  830. item = item->next;
  831. if (item != NULL)
  832. ptr = item->data;
  833. } // while
  834. return -1; // no match found.
  835. } // buffer_find
  836. // end of mojoshader_common.c ...