mes_posix.c 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314
  1. /* -*-comment-start: "//";comment-end:""-*-
  2. * GNU Mes --- Maxwell Equations of Software
  3. * Copyright © 2016,2017,2018 Jan (janneke) Nieuwenhuizen <janneke@gnu.org>
  4. * Copyright © 2019 Jeremiah Orians
  5. *
  6. * This file is part of GNU Mes.
  7. *
  8. * GNU Mes is free software; you can redistribute it and/or modify it
  9. * under the terms of the GNU General Public License as published by
  10. * the Free Software Foundation; either version 3 of the License, or (at
  11. * your option) any later version.
  12. *
  13. * GNU Mes is distributed in the hope that it will be useful, but
  14. * WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU General Public License
  19. * along with GNU Mes. If not, see <http://www.gnu.org/licenses/>.
  20. */
  21. #include "mes.h"
  22. /* Imported functions */
  23. int string_size(char* a);
  24. struct cell* make_file(FILE* a, char* name);
  25. struct cell* make_string(char* a, int length);
  26. struct cell* prim_display(struct cell* args, struct cell* out);
  27. struct cell* prim_write(struct cell* args, struct cell* out);
  28. char* ntoab(SCM x, int base, int signed_p)
  29. {
  30. char* p = calloc(13, sizeof(char));
  31. p = p + 11;
  32. p[1] = 0;
  33. int sign_p = 0;
  34. SCM u = x;
  35. SCM i;
  36. if(signed_p && x < 0)
  37. {
  38. sign_p = 1;
  39. u = -x;
  40. }
  41. do
  42. {
  43. i = u % base;
  44. if(i > 9)
  45. {
  46. p[0] = 'a' + i - 10;
  47. }
  48. else
  49. {
  50. p[0] = '0' + i;
  51. }
  52. p = p - 1;
  53. u = u / base;
  54. } while(0 != u);
  55. if(sign_p && p[1] != '0')
  56. {
  57. p[0] = '-';
  58. p = p - 1;
  59. }
  60. return p + 1;
  61. }
  62. struct cell* builtin_display(struct cell* args)
  63. {
  64. require(nil != args, "display requires arguments\n");
  65. if(nil == args->cdr)
  66. {
  67. prim_display(args, __c_stdout);
  68. return cell_unspecified;
  69. }
  70. require(FILE_PORT == args->cdr->car->type, "You passed something that isn't a file pointer to write in position 2\n");
  71. prim_display(args, args->cdr->car);
  72. return cell_unspecified;
  73. }
  74. struct cell* builtin_display_error(struct cell* args)
  75. {
  76. require(nil != args, "display-error requires arguments\n");
  77. if(nil == args->cdr)
  78. {
  79. prim_display(args, __c_stderr);
  80. return cell_unspecified;
  81. }
  82. require(FILE_PORT == args->cdr->car->type, "You passed something that isn't a file pointer to write in position 2\n");
  83. prim_display(args, args->cdr->car);
  84. return cell_unspecified;
  85. }
  86. struct cell* builtin_write(struct cell* args)
  87. {
  88. /* Don't write to files when fuzzing */
  89. if(FUZZING) return cell_unspecified;
  90. require(nil != args, "write requires arguments\n");
  91. if(nil == args->cdr)
  92. {
  93. prim_write(args, __c_stdout);
  94. return cell_unspecified;
  95. }
  96. require(FILE_PORT == args->cdr->car->type, "You passed something that isn't a file pointer to write in position 2\n");
  97. prim_write(args, args->cdr->car);
  98. return cell_unspecified;
  99. }
  100. struct cell* builtin_write_error(struct cell* args)
  101. {
  102. /* Don't write to files when fuzzing */
  103. if(FUZZING) return cell_unspecified;
  104. require(nil != args, "write-error requires arguments\n");
  105. if(nil == args->cdr)
  106. {
  107. return prim_write(args, __c_stderr);
  108. }
  109. require(FILE_PORT == args->cdr->car->type, "You passed something that isn't a file pointer to write in position 2\n");
  110. return prim_write(args, args->cdr->car);
  111. }
  112. FILE* open_file(char* name, char* mode)
  113. {
  114. FILE* f = fopen(name, mode);
  115. if(NULL == f)
  116. {
  117. file_print("Unable to open file ", stderr);
  118. file_print(name, stderr);
  119. if('r' == mode[0])
  120. {
  121. file_print(" for reading\n", stderr);
  122. }
  123. else if('w' == mode[0])
  124. {
  125. file_print(" for writing\n", stderr);
  126. }
  127. else
  128. {
  129. file_print(" with unknown mode\n", stderr);
  130. }
  131. exit(EXIT_FAILURE);
  132. }
  133. return f;
  134. }
  135. struct cell* builtin_close(struct cell* args)
  136. {
  137. require(nil != args, "close-port requires an argument\n");
  138. require(FILE_PORT == args->car->type, "close-port requires a file port\n");
  139. require(nil == args->cdr, "close-port recieved too many arguments\n");
  140. int error = fclose(args->car->file);
  141. if(0 != error) return cell_f;
  142. return cell_t;
  143. }
  144. struct cell* builtin_open(struct cell* args, char* mode)
  145. {
  146. /* Don't open files when fuzzing */
  147. if(FUZZING) return cell_unspecified;
  148. require(nil != args, "Did not recieve a file name\n");
  149. require(STRING == args->car->type, "File name must be a string\n");
  150. return make_file(open_file(args->car->string, mode), args->car->string);
  151. }
  152. struct cell* builtin_open_read(struct cell* args)
  153. {
  154. return builtin_open(args, "r");
  155. }
  156. struct cell* builtin_open_write(struct cell* args)
  157. {
  158. return builtin_open(args, "w");
  159. }
  160. struct cell* builtin_set_current_output_port(struct cell* args)
  161. {
  162. /* When fuzzing write to STDOUT */
  163. if(FUZZING) return cell_unspecified;
  164. require(nil != args, "set-current-output-port requires arguments\n");
  165. require(FILE_PORT == args->car->type, "set-current-output-port expects a port\n");
  166. require(nil == args->cdr, "set-current-output-port expects only a single argument\n");
  167. __c_stdout->file = args->car->file;
  168. __c_stdout->string = args->car->string;
  169. return cell_unspecified;
  170. }
  171. struct cell* builtin_set_current_input_port(struct cell* args)
  172. {
  173. /* When fuzzing don't change input port */
  174. if(FUZZING) return cell_unspecified;
  175. require(nil != args, "set-current-input-port requires arguments\n");
  176. require(FILE_PORT == args->car->type, "set-current-input-port expects a port\n");
  177. require(nil == args->cdr, "set-current-input-port expects only a single argument\n");
  178. __c_stdin->file = args->car->file;
  179. __c_stdin->string = args->car->string;
  180. return cell_unspecified;
  181. }
  182. struct cell* builtin_set_current_error_port(struct cell* args)
  183. {
  184. /* When fuzzing write to STDERR */
  185. if(FUZZING) return cell_unspecified;
  186. require(nil != args, "set-current-error-port requires arguments\n");
  187. require(FILE_PORT == args->car->type, "set-current-error-port expects a port\n");
  188. require(nil == args->cdr, "set-current-error-port expects only a single argument\n");
  189. __c_stderr->file = args->car->file;
  190. __c_stderr->string = args->car->string;
  191. return cell_unspecified;
  192. }
  193. struct cell* builtin_current_input_port(struct cell* args)
  194. {
  195. require(nil == args, "current-input-port does not accept arguments\n");
  196. return __c_stdin;
  197. }
  198. struct cell* builtin_current_output_port(struct cell* args)
  199. {
  200. require(nil == args, "current-output-port does not accept arguments\n");
  201. return __c_stdout;
  202. }
  203. struct cell* builtin_current_error_port(struct cell* args)
  204. {
  205. require(nil == args, "current-error-port does not accept arguments\n");
  206. return __c_stderr;
  207. }
  208. struct cell* builtin_ttyname(struct cell* args)
  209. {
  210. require(nil != args, "ttyname requires an argument\n");
  211. require(nil == args->cdr, "ttyname only accepts a single argument\n");
  212. require(FILE_PORT == args->car->type, "ttyname only accepts ports\n");
  213. return make_string(args->car->string, string_size(args->car->string));
  214. }
  215. struct cell* builtin_port_filename(struct cell* args)
  216. {
  217. require(nil != args, "port-filename requires an argument\n");
  218. require(nil == args->cdr, "port-filename only accepts a single argument\n");
  219. require(FILE_PORT == args->car->type, "port-filename only accepts ports\n");
  220. return make_string(args->car->string, string_size(args->car->string));
  221. }
  222. struct cell* builtin_command_line(struct cell* args)
  223. {
  224. require(nil == args, "command-line does not accept arguments\n");
  225. struct cell* r = nil;
  226. int i = __argc - 1;
  227. while(0 <= i)
  228. {
  229. r = make_cons(make_string(__argv[i], string_size(__argv[i])), r);
  230. i = i - 1;
  231. }
  232. return r;
  233. }
  234. char* prematch(char* search, char* field)
  235. {
  236. do
  237. {
  238. if(search[0] != field[0]) return NULL;
  239. search = search + 1;
  240. field = field + 1;
  241. } while(0 != search[0]);
  242. return field+1;
  243. }
  244. char* env_lookup(char* token, char** envp)
  245. {
  246. if(NULL == envp) return NULL;
  247. int i = 0;
  248. char* ret = NULL;
  249. do
  250. {
  251. ret = prematch(token, envp[i]);
  252. if(NULL != ret) return ret;
  253. i = i + 1;
  254. } while(NULL != envp[i]);
  255. return NULL;
  256. }
  257. struct cell* builtin_get_env(struct cell* args)
  258. {
  259. require(nil != args, "getenv requires an argument\n");
  260. require(nil == args->cdr, "getenv requires only a single argument\n");
  261. require(STRING == args->car->type, "getenv requires a string\n");
  262. char* pass = env_lookup(args->car->string, __envp);
  263. if(NULL == pass) return cell_f;
  264. return make_string(pass, string_size(pass));
  265. }