stdlib.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492
  1. /* Copyright (C) 2016 Jeremiah Orians
  2. * This file is part of M2-Planet.
  3. *
  4. * M2-Planet is free software: you can redistribute it and/or modify
  5. * it under the terms of the GNU General Public License as published by
  6. * the Free Software Foundation, either version 3 of the License, or
  7. * (at your option) any later version.
  8. *
  9. * M2-Planet is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with M2-Planet. If not, see <http://www.gnu.org/licenses/>.
  16. */
  17. #include <unistd.h>
  18. #include <sys/stat.h>
  19. #include <fcntl.h>
  20. #define EXIT_FAILURE 1
  21. #define EXIT_SUCCESS 0
  22. #define _IN_USE 1
  23. #define _NOT_IN_USE 0
  24. typedef char wchar_t;
  25. void exit(int value);
  26. struct _malloc_node
  27. {
  28. struct _malloc_node *next;
  29. void* block;
  30. size_t size;
  31. int used;
  32. };
  33. struct _malloc_node* _allocated_list;
  34. struct _malloc_node* _free_list;
  35. /********************************
  36. * The core POSIX malloc *
  37. ********************************/
  38. long _malloc_ptr;
  39. long _brk_ptr;
  40. void* _malloc_brk(unsigned size)
  41. {
  42. if(NULL == _brk_ptr)
  43. {
  44. _brk_ptr = brk(0);
  45. _malloc_ptr = _brk_ptr;
  46. }
  47. if(_brk_ptr < _malloc_ptr + size)
  48. {
  49. _brk_ptr = brk(_malloc_ptr + size);
  50. if(-1 == _brk_ptr) return 0;
  51. }
  52. long old_malloc = _malloc_ptr;
  53. _malloc_ptr = _malloc_ptr + size;
  54. return old_malloc;
  55. }
  56. void __init_malloc()
  57. {
  58. _free_list = NULL;
  59. _allocated_list = NULL;
  60. return;
  61. }
  62. /************************************************************************
  63. * Handle with the tricky insert behaviors for our nodes *
  64. * As free lists must be sorted from smallest to biggest to enable *
  65. * cheap first fit logic *
  66. * The free function however is rarely called, so it can kick sand and *
  67. * do things the hard way *
  68. ************************************************************************/
  69. void _malloc_insert_block(struct _malloc_node* n, int used)
  70. {
  71. /* Allocated block doesn't care about order */
  72. if(_IN_USE == used)
  73. {
  74. /* Literally just be done as fast as possible */
  75. n->next = _allocated_list;
  76. _allocated_list = n;
  77. return;
  78. }
  79. /* sanity check garbage */
  80. if(_NOT_IN_USE != used) exit(EXIT_FAILURE);
  81. if(_NOT_IN_USE != n->used) exit(EXIT_FAILURE);
  82. if(NULL != n->next) exit(EXIT_FAILURE);
  83. /* Free block really does care about order */
  84. struct _malloc_node* i = _free_list;
  85. struct _malloc_node* last = NULL;
  86. while(NULL != i)
  87. {
  88. /* sort smallest to largest */
  89. if(n->size <= i->size)
  90. {
  91. /* Connect */
  92. n->next = i;
  93. /* If smallest yet */
  94. if(NULL == last) _free_list = n;
  95. /* or just another average block */
  96. else last->next = n;
  97. return;
  98. }
  99. /* iterate */
  100. last = i;
  101. i = i->next;
  102. }
  103. /* looks like we are the only one */
  104. if(NULL == last) _free_list = n;
  105. /* or we are the biggest yet */
  106. else last->next = n;
  107. }
  108. /************************************************************************
  109. * We only mark a block as unused, we don't actually deallocate it here *
  110. * But rather shove it into our _free_list *
  111. ************************************************************************/
  112. void free(void* ptr)
  113. {
  114. /* just in case someone needs to quickly turn it off */
  115. #ifndef _MALLOC_DISABLE_FREE
  116. struct _malloc_node* i = _allocated_list;
  117. struct _malloc_node* last = NULL;
  118. /* walk the whole freaking list if needed to do so */
  119. while(NULL != i)
  120. {
  121. /* did we find it? */
  122. if(i->block == ptr)
  123. {
  124. /* detach the block */
  125. if(NULL == last) _allocated_list = i->next;
  126. /* in a way that doesn't break the allocated list */
  127. else last->next = i->next;
  128. /* insert into free'd list */
  129. i->used = _NOT_IN_USE;
  130. i->next = NULL;
  131. _malloc_insert_block(i, _NOT_IN_USE);
  132. return;
  133. }
  134. /* iterate */
  135. last = i;
  136. i = i->next;
  137. }
  138. /* we received a pointer to a block that wasn't allocated */
  139. /* Bail *HARD* because I don't want to cover this edge case */
  140. exit(EXIT_FAILURE);
  141. #endif
  142. /* if free is disabled, there is nothing to do */
  143. return;
  144. }
  145. /************************************************************************
  146. * find if there is any "FREED" blocks big enough to sit on our memory *
  147. * budget's face and ruin its life. Respectfully of course *
  148. ************************************************************************/
  149. void* _malloc_find_free(unsigned size)
  150. {
  151. struct _malloc_node* i = _free_list;
  152. struct _malloc_node* last = NULL;
  153. /* Walk the whole list if need be */
  154. while(NULL != i)
  155. {
  156. /* see if anything in it is equal or bigger than what I need */
  157. if((_NOT_IN_USE == i->used) && (i->size > size))
  158. {
  159. /* disconnect from list ensuring we don't break free doing so */
  160. if(NULL == last) _free_list = i->next;
  161. else last->next = i->next;
  162. /* insert into allocated list */
  163. i->used = _IN_USE;
  164. i->next = NULL;
  165. _malloc_insert_block(i, _IN_USE);
  166. return i->block;
  167. }
  168. /* iterate (will loop forever if you get this wrong) */
  169. last = i;
  170. i = i->next;
  171. }
  172. /* Couldn't find anything big enough */
  173. return NULL;
  174. }
  175. /************************************************************************
  176. * Well we couldn't find any memory good enough to satisfy our needs so *
  177. * we are going to have to go beg for some memory on the street corner *
  178. ************************************************************************/
  179. void* _malloc_add_new(unsigned size)
  180. {
  181. struct _malloc_node* n;
  182. #ifdef __uefi__
  183. n = _malloc_uefi(sizeof(struct _malloc_node));
  184. /* Check if we were beaten */
  185. if(NULL == n) return NULL;
  186. n->block = _malloc_uefi(size);
  187. #else
  188. n = _malloc_brk(sizeof(struct _malloc_node));
  189. /* Check if we were beaten */
  190. if(NULL == n) return NULL;
  191. n->block = _malloc_brk(size);
  192. #endif
  193. /* check if we were robbed */
  194. if(NULL == n->block) return NULL;
  195. /* Looks like we made it home safely */
  196. n->size = size;
  197. n->next = NULL;
  198. n->used = _IN_USE;
  199. /* lets pop the cork and party */
  200. _malloc_insert_block(n, _IN_USE);
  201. return n->block;
  202. }
  203. /************************************************************************
  204. * Safely iterates over all malloc nodes and frees them *
  205. ************************************************************************/
  206. void __malloc_node_iter(struct _malloc_node* node, FUNCTION _free)
  207. {
  208. struct _malloc_node* current;
  209. while(node != NULL)
  210. {
  211. current = node;
  212. node = node->next;
  213. _free(current->block);
  214. _free(current);
  215. }
  216. }
  217. /************************************************************************
  218. * Runs a callback with all previously allocated nodes. *
  219. * This can be useful if operating system does not do any clean up. *
  220. ************************************************************************/
  221. void* _malloc_release_all(FUNCTION _free)
  222. {
  223. __malloc_node_iter(_allocated_list, _free);
  224. __malloc_node_iter(_free_list, _free);
  225. }
  226. /************************************************************************
  227. * Provide a POSIX standardish malloc function to keep things working *
  228. ************************************************************************/
  229. void* malloc(unsigned size)
  230. {
  231. /* skip allocating nothing */
  232. if(0 == size) return NULL;
  233. /* use one of the standard block sizes */
  234. size_t max = 1 << 30;
  235. size_t used = 256;
  236. while(used < size)
  237. {
  238. used = used << 1;
  239. /* fail big allocations */
  240. if(used > max) return NULL;
  241. }
  242. /* try the cabinets around the house */
  243. void* ptr = _malloc_find_free(used);
  244. /* looks like we need to get some more from the street corner */
  245. if(NULL == ptr)
  246. {
  247. ptr = _malloc_add_new(used);
  248. }
  249. /* hopefully you can handle NULL pointers, good luck */
  250. return ptr;
  251. }
  252. /************************************************************************
  253. * Provide a POSIX standardish memset function to keep things working *
  254. ************************************************************************/
  255. void* memset(void* ptr, int value, int num)
  256. {
  257. char* s;
  258. /* basically walk the block 1 byte at a time and set it to any value you want */
  259. for(s = ptr; 0 < num; num = num - 1)
  260. {
  261. s[0] = value;
  262. s = s + 1;
  263. }
  264. return ptr;
  265. }
  266. /************************************************************************
  267. * Provide a POSIX standardish calloc function to keep things working *
  268. ************************************************************************/
  269. void* calloc(int count, int size)
  270. {
  271. /* if things get allocated, we are good*/
  272. void* ret = malloc(count * size);
  273. /* otherwise good luck */
  274. if(NULL == ret) return NULL;
  275. memset(ret, 0, (count * size));
  276. return ret;
  277. }
  278. /* USED EXCLUSIVELY BY MKSTEMP */
  279. void __set_name(char* s, int i)
  280. {
  281. s[5] = '0' + (i % 10);
  282. i = i / 10;
  283. s[4] = '0' + (i % 10);
  284. i = i / 10;
  285. s[3] = '0' + (i % 10);
  286. i = i / 10;
  287. s[2] = '0' + (i % 10);
  288. i = i / 10;
  289. s[1] = '0' + (i % 10);
  290. i = i / 10;
  291. s[0] = '0' + i;
  292. }
  293. /************************************************************************
  294. * Provide a POSIX standardish mkstemp function to keep things working *
  295. ************************************************************************/
  296. int mkstemp(char *template)
  297. {
  298. /* get length of template */
  299. int i = 0;
  300. while(0 != template[i]) i = i + 1;
  301. i = i - 1;
  302. /* String MUST be more than 6 characters in length */
  303. if(i < 6) return -1;
  304. /* Sanity check the string matches the template requirements */
  305. int count = 6;
  306. int c;
  307. while(count > 0)
  308. {
  309. c = template[i];
  310. /* last 6 chars must be X */
  311. if('X' != c) return -1;
  312. template[i] = '0';
  313. i = i - 1;
  314. count = count - 1;
  315. }
  316. int fd = -1;
  317. count = -1;
  318. /* open will return -17 or other values */
  319. while(0 > fd)
  320. {
  321. /* Just give up after the planet has blown up */
  322. if(9000 < count) return -1;
  323. /* Try up to 9000 unique filenames before stopping */
  324. count = count + 1;
  325. __set_name(template+i+1, count);
  326. /* Pray we can */
  327. fd = open(template, O_RDWR | O_CREAT | O_EXCL, 00600);
  328. }
  329. /* well that only took count many tries */
  330. return fd;
  331. }
  332. /************************************************************************
  333. * wcstombs - convert a wide-character string to a multibyte string *
  334. * because seriously UEFI??? UTF-16 is a bad design choice but I guess *
  335. * they were drinking pretty hard when they designed UEFI; it is DOS *
  336. * but somehow they magically found ways of making it worse *
  337. ************************************************************************/
  338. size_t wcstombs(char* dest, char* src, size_t n)
  339. {
  340. int i = 0;
  341. do
  342. {
  343. /* UTF-16 is 2bytes per char and that first byte maps good enough to ASCII */
  344. dest[i] = src[2 * i];
  345. if(dest[i] == 0)
  346. {
  347. break;
  348. }
  349. i = i + 1;
  350. n = n - 1;
  351. } while (n != 0);
  352. return i;
  353. }
  354. /************************************************************************
  355. * getenv - get an environmental variable *
  356. ************************************************************************/
  357. size_t _strlen(char const* str)
  358. {
  359. size_t i = 0;
  360. while(0 != str[i]) i = i + 1;
  361. return i;
  362. }
  363. int _strncmp(char const* lhs, char const* rhs, size_t count)
  364. {
  365. size_t i = 0;
  366. while(count > i)
  367. {
  368. if(0 == lhs[i]) break;
  369. if(lhs[i] != rhs[i]) return lhs[i] - rhs[i];
  370. i = i + 1;
  371. }
  372. return 0;
  373. }
  374. char** _envp;
  375. char* getenv (char const* name)
  376. {
  377. char** p = _envp;
  378. char* q;
  379. int length = _strlen(name);
  380. while (p[0] != 0)
  381. {
  382. if(_strncmp(name, p[0], length) == 0)
  383. {
  384. q = p[0] + length;
  385. if(q[0] == '=')
  386. return q + 1;
  387. }
  388. p += sizeof(char**); /* M2 pointer arithemtic */
  389. }
  390. return 0;
  391. }
  392. /************************************************************************
  393. * setenv - set an environmental variable *
  394. ************************************************************************/
  395. char* _strcpy(char* dest, char const* src)
  396. {
  397. int i = 0;
  398. while (0 != src[i])
  399. {
  400. dest[i] = src[i];
  401. i = i + 1;
  402. }
  403. dest[i] = 0;
  404. return dest;
  405. }
  406. int setenv(char const *s, char const *v, int overwrite_p)
  407. {
  408. char** p = _envp;
  409. int length = _strlen(s);
  410. char* q;
  411. while (p[0] != 0)
  412. {
  413. if (_strncmp (s, p[0], length) == 0)
  414. {
  415. q = p[0] + length;
  416. if (q[0] == '=')
  417. break;
  418. }
  419. p += sizeof(char**); /* M2 pointer arithemtic */
  420. }
  421. char *entry = malloc (length + _strlen(v) + 2);
  422. int end_p = p[0] == 0;
  423. p[0] = entry;
  424. _strcpy(entry, s);
  425. _strcpy(entry + length, "=");
  426. _strcpy(entry + length + 1, v);
  427. entry[length + _strlen(v) + 2] = 0;
  428. if (end_p != 0)
  429. p[1] = 0;
  430. return 0;
  431. }