genie-unix.c
1 //! @file genie-unix.c
2 //! @author J. Marcel van der Veer
3
4 //! @section Copyright
5 //!
6 //! This file is part of Algol68G - an Algol 68 compiler-interpreter.
7 //! Copyright 2001-2024 J. Marcel van der Veer [algol68g@xs4all.nl].
8
9 //! @section License
10 //!
11 //! This program is free software; you can redistribute it and/or modify it
12 //! under the terms of the GNU General Public License as published by the
13 //! Free Software Foundation; either version 3 of the License, or
14 //! (at your option) any later version.
15 //!
16 //! This program is distributed in the hope that it will be useful, but
17 //! WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
18 //! or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
19 //! more details. You should have received a copy of the GNU General Public
20 //! License along with this program. If not, see [http://www.gnu.org/licenses/].
21
22 //! @section Synopsis
23 //!
24 //! Low-level UNIX routines.
25
26 #include "a68g.h"
27 #include "a68g-genie.h"
28 #include "a68g-prelude.h"
29 #include "a68g-transput.h"
30
31 #define VECTOR_SIZE 512
32 #define FD_READ 0
33 #define FD_WRITE 1
34
35 #if defined (HAVE_DIRENT_H)
36
37 //! @brief PROC (STRING) [] STRING directory
38
39 void genie_directory (NODE_T * p)
40 {
41 errno = 0;
42 A68_REF name;
43 POP_REF (p, &name);
44 CHECK_INIT (p, INITIALISED (&name), M_STRING);
45 char *buffer = (char *) a68_alloc ((size_t) (1 + a68_string_size (p, name)), __func__, __LINE__);
46 if (buffer == NO_TEXT) {
47 diagnostic (A68_RUNTIME_ERROR, p, ERROR_OUT_OF_CORE);
48 exit_genie (p, A68_RUNTIME_ERROR);
49 PUSH_VALUE (p, A68_MAX_INT, A68_INT);
50 } else {
51 char *dir_name = a_to_c_string (p, buffer, name);
52 DIR *dir = opendir (dir_name);
53 if (dir == NULL) {
54 diagnostic (A68_RUNTIME_ERROR, p, ERROR_FILE_ACCESS);
55 exit_genie (p, A68_RUNTIME_ERROR);
56 }
57 int n = 0;
58 struct dirent *entry;
59 do {
60 entry = readdir (dir);
61 if (errno != 0) {
62 diagnostic (A68_RUNTIME_ERROR, p, ERROR_FILE_ACCESS);
63 exit_genie (p, A68_RUNTIME_ERROR);
64 }
65 if (entry != NULL) {
66 n++;
67 }
68 } while (entry != NULL);
69 rewinddir (dir);
70 if (errno != 0) {
71 diagnostic (A68_RUNTIME_ERROR, p, ERROR_FILE_ACCESS);
72 exit_genie (p, A68_RUNTIME_ERROR);
73 }
74 A68_REF z, row; A68_ARRAY arr; A68_TUPLE tup;
75 NEW_ROW_1D (z, row, arr, tup, M_ROW_STRING, M_STRING, n);
76 A68_REF *base = DEREF (A68_REF, &row);
77 for (int k = 0; k < n; k++) {
78 entry = readdir (dir);
79 if (errno != 0) {
80 diagnostic (A68_RUNTIME_ERROR, p, ERROR_FILE_ACCESS);
81 exit_genie (p, A68_RUNTIME_ERROR);
82 }
83 base[k] = c_to_a_string (p, D_NAME (entry), DEFAULT_WIDTH);
84 }
85 if (closedir (dir) != 0) {
86 diagnostic (A68_RUNTIME_ERROR, p, ERROR_FILE_ACCESS);
87 exit_genie (p, A68_RUNTIME_ERROR);
88 }
89 PUSH_REF (p, z);
90 a68_free (buffer);
91 }
92 }
93
94 #endif
95
96 //! @brief PROC [] INT utc time
97
98 void genie_utctime (NODE_T * p)
99 {
100 time_t dt;
101 if (time (&dt) == (time_t) - 1) {
102 (void) empty_row (p, M_ROW_INT);
103 } else {
104 ADDR_T pop_sp = A68_SP;
105 struct tm *tod = gmtime (&dt);
106 PUSH_VALUE (p, TM_YEAR (tod) + 1900, A68_INT);
107 PUSH_VALUE (p, TM_MON (tod) + 1, A68_INT);
108 PUSH_VALUE (p, TM_MDAY (tod), A68_INT);
109 PUSH_VALUE (p, TM_HOUR (tod), A68_INT);
110 PUSH_VALUE (p, TM_MIN (tod), A68_INT);
111 PUSH_VALUE (p, TM_SEC (tod), A68_INT);
112 PUSH_VALUE (p, TM_WDAY (tod) + 1, A68_INT);
113 PUSH_VALUE (p, TM_ISDST (tod), A68_INT);
114 A68_REF row = genie_make_row (p, M_INT, 8, pop_sp);
115 A68_SP = pop_sp;
116 PUSH_REF (p, row);
117 }
118 }
119
120 //! @brief PROC [] INT local time
121
122 void genie_localtime (NODE_T * p)
123 {
124 time_t dt;
125 if (time (&dt) == (time_t) - 1) {
126 (void) empty_row (p, M_ROW_INT);
127 } else {
128 ADDR_T pop_sp = A68_SP;
129 struct tm *tod = localtime (&dt);
130 PUSH_VALUE (p, TM_YEAR (tod) + 1900, A68_INT);
131 PUSH_VALUE (p, TM_MON (tod) + 1, A68_INT);
132 PUSH_VALUE (p, TM_MDAY (tod), A68_INT);
133 PUSH_VALUE (p, TM_HOUR (tod), A68_INT);
134 PUSH_VALUE (p, TM_MIN (tod), A68_INT);
135 PUSH_VALUE (p, TM_SEC (tod), A68_INT);
136 PUSH_VALUE (p, TM_WDAY (tod) + 1, A68_INT);
137 PUSH_VALUE (p, TM_ISDST (tod), A68_INT);
138 A68_REF row = genie_make_row (p, M_INT, 8, pop_sp);
139 A68_SP = pop_sp;
140 PUSH_REF (p, row);
141 }
142 }
143
144 //! @brief PROC INT rows
145
146 void genie_rows (NODE_T * p)
147 {
148 errno = 0;
149 PUSH_VALUE (p, A68 (term_heigth), A68_INT);
150 }
151
152 //! @brief PROC INT columns
153
154 void genie_columns (NODE_T * p)
155 {
156 errno = 0;
157 PUSH_VALUE (p, A68 (term_width), A68_INT);
158 }
159
160 //! @brief PROC INT argc
161
162 void genie_argc (NODE_T * p)
163 {
164 errno = 0;
165 PUSH_VALUE (p, A68 (argc), A68_INT);
166 }
167
168 //! @brief PROC (INT) STRING argv
169
170 void genie_argv (NODE_T * p)
171 {
172 errno = 0;
173 A68_INT a68_index;
174 POP_OBJECT (p, &a68_index, A68_INT);
175 if (VALUE (&a68_index) >= 1 && VALUE (&a68_index) <= A68 (argc)) {
176 char *q = A68 (argv)[VALUE (&a68_index) - 1];
177 int n = (int) strlen (q);
178 // Allow for spaces ending in # to have A68 comment syntax with '#!'.
179 while (n > 0 && (IS_SPACE (q[n - 1]) || q[n - 1] == '#')) {
180 q[--n] = NULL_CHAR;
181 }
182 PUSH_REF (p, c_to_a_string (p, q, DEFAULT_WIDTH));
183 } else {
184 PUSH_REF (p, empty_string (p));
185 }
186 }
187
188 //! @brief Find good argument
189
190 int find_good_arg (void)
191 {
192 for (int i = 0; i < A68 (argc); i++) {
193 char *q = A68 (argv)[i];
194 if (strncmp (q, "--script", 8) == 0) {
195 return i + 1;
196 }
197 if (strncmp (q, "--run-script", 12) == 0) {
198 return i + 1;
199 }
200 if (strcmp (q, "--") == 0) {
201 return i;
202 }
203 if (strcmp (q, "--exit") == 0) {
204 return i;
205 }
206 }
207 return 0;
208 }
209
210 //! @brief PROC INT a68g argc
211
212 void genie_a68g_argc (NODE_T * p)
213 {
214 errno = 0;
215 PUSH_VALUE (p, A68 (argc) - find_good_arg (), A68_INT);
216 }
217
218 //! @brief PROC (INT) STRING a68_argv
219
220 void genie_a68g_argv (NODE_T * p)
221 {
222 errno = 0;
223 A68_INT a68_index;
224 POP_OBJECT (p, &a68_index, A68_INT);
225 int k = VALUE (&a68_index);
226 if (k > 1) {
227 k += find_good_arg ();
228 }
229 if (k >= 1 && k <= A68 (argc)) {
230 char *q = A68 (argv)[k - 1];
231 int n = (int) strlen (q);
232 // Allow for spaces ending in # to have A68 comment syntax with '#!'.
233 while (n > 0 && (IS_SPACE (q[n - 1]) || q[n - 1] == '#')) {
234 q[--n] = NULL_CHAR;
235 }
236 PUSH_REF (p, c_to_a_string (p, q, DEFAULT_WIDTH));
237 } else {
238 PUSH_REF (p, empty_string (p));
239 }
240 }
241
242 //! @brief PROC STRING pwd
243
244 void genie_pwd (NODE_T * p)
245 {
246 errno = 0;
247 char *buffer = NO_TEXT;
248 BOOL_T cont = A68_TRUE;
249 size_t size = BUFFER_SIZE;
250 while (cont) {
251 buffer = (char *) a68_alloc (size, __func__, __LINE__);
252 if (buffer == NO_TEXT) {
253 diagnostic (A68_RUNTIME_ERROR, p, ERROR_OUT_OF_CORE);
254 exit_genie (p, A68_RUNTIME_ERROR);
255 }
256 if (getcwd (buffer, size) == buffer) {
257 cont = A68_FALSE;
258 } else {
259 a68_free (buffer);
260 cont = (BOOL_T) (errno == 0);
261 size *= 2;
262 }
263 }
264 if (buffer != NO_TEXT && errno == 0) {
265 PUSH_REF (p, c_to_a_string (p, buffer, DEFAULT_WIDTH));
266 a68_free (buffer);
267 } else {
268 PUSH_REF (p, empty_string (p));
269 }
270 }
271
272 //! @brief PROC (STRING) INT cd
273
274 void genie_cd (NODE_T * p)
275 {
276 errno = 0;
277 A68_REF dir;
278 POP_REF (p, &dir);
279 CHECK_INIT (p, INITIALISED (&dir), M_STRING);
280 char *buffer = (char *) a68_alloc ((size_t) (1 + a68_string_size (p, dir)), __func__, __LINE__);
281 if (buffer == NO_TEXT) {
282 diagnostic (A68_RUNTIME_ERROR, p, ERROR_OUT_OF_CORE);
283 exit_genie (p, A68_RUNTIME_ERROR);
284 } else {
285 int ret = chdir (a_to_c_string (p, buffer, dir));
286 if (ret == 0) {
287 PUSH_VALUE (p, 0, A68_INT);
288 } else {
289 diagnostic (A68_RUNTIME_ERROR, p, ERROR_FILE_ACCESS);
290 exit_genie (p, A68_RUNTIME_ERROR);
291 }
292 a68_free (buffer);
293 }
294 }
295
296 //! @brief PROC (STRING) BITS
297
298 void genie_file_mode (NODE_T * p)
299 {
300 errno = 0;
301 A68_REF name;
302 POP_REF (p, &name);
303 CHECK_INIT (p, INITIALISED (&name), M_STRING);
304 char *buffer = (char *) a68_alloc ((size_t) (1 + a68_string_size (p, name)), __func__, __LINE__);
305 if (buffer == NO_TEXT) {
306 diagnostic (A68_RUNTIME_ERROR, p, ERROR_OUT_OF_CORE);
307 exit_genie (p, A68_RUNTIME_ERROR);
308 } else {
309 struct stat status;
310 if (stat (a_to_c_string (p, buffer, name), &status) == 0) {
311 PUSH_VALUE (p, (unt) (ST_MODE (&status)), A68_BITS);
312 } else {
313 PUSH_VALUE (p, 0x0, A68_BITS);
314 }
315 a68_free (buffer);
316 }
317 }
318
319 //! @brief PROC (STRING) BOOL file is block device
320
321 void genie_file_is_block_device (NODE_T * p)
322 {
323 errno = 0;
324 A68_REF name;
325 POP_REF (p, &name);
326 CHECK_INIT (p, INITIALISED (&name), M_STRING);
327 char *buffer = (char *) a68_alloc ((size_t) (1 + a68_string_size (p, name)), __func__, __LINE__);
328 if (buffer == NO_TEXT) {
329 diagnostic (A68_RUNTIME_ERROR, p, ERROR_OUT_OF_CORE);
330 exit_genie (p, A68_RUNTIME_ERROR);
331 } else {
332 struct stat status;
333 if (stat (a_to_c_string (p, buffer, name), &status) == 0) {
334 PUSH_VALUE (p, (BOOL_T) (S_ISBLK (ST_MODE (&status)) != 0 ? A68_TRUE : A68_FALSE), A68_BOOL);
335 } else {
336 PUSH_VALUE (p, A68_FALSE, A68_BOOL);
337 }
338 a68_free (buffer);
339 }
340 }
341
342 //! @brief PROC (STRING) BOOL file is char device
343
344 void genie_file_is_char_device (NODE_T * p)
345 {
346 errno = 0;
347 A68_REF name;
348 POP_REF (p, &name);
349 CHECK_INIT (p, INITIALISED (&name), M_STRING);
350 char *buffer = (char *) a68_alloc ((size_t) (1 + a68_string_size (p, name)), __func__, __LINE__);
351 if (buffer == NO_TEXT) {
352 diagnostic (A68_RUNTIME_ERROR, p, ERROR_OUT_OF_CORE);
353 exit_genie (p, A68_RUNTIME_ERROR);
354 } else {
355 struct stat status;
356 if (stat (a_to_c_string (p, buffer, name), &status) == 0) {
357 PUSH_VALUE (p, (BOOL_T) (S_ISCHR (ST_MODE (&status)) != 0 ? A68_TRUE : A68_FALSE), A68_BOOL);
358 } else {
359 PUSH_VALUE (p, A68_FALSE, A68_BOOL);
360 }
361 a68_free (buffer);
362 }
363 }
364
365 //! @brief PROC (STRING) BOOL file is directory
366
367 void genie_file_is_directory (NODE_T * p)
368 {
369 errno = 0;
370 A68_REF name;
371 POP_REF (p, &name);
372 CHECK_INIT (p, INITIALISED (&name), M_STRING);
373 char *buffer = (char *) a68_alloc ((size_t) (1 + a68_string_size (p, name)), __func__, __LINE__);
374 if (buffer == NO_TEXT) {
375 diagnostic (A68_RUNTIME_ERROR, p, ERROR_OUT_OF_CORE);
376 exit_genie (p, A68_RUNTIME_ERROR);
377 } else {
378 struct stat status;
379 if (stat (a_to_c_string (p, buffer, name), &status) == 0) {
380 PUSH_VALUE (p, (BOOL_T) (S_ISDIR (ST_MODE (&status)) != 0 ? A68_TRUE : A68_FALSE), A68_BOOL);
381 } else {
382 PUSH_VALUE (p, A68_FALSE, A68_BOOL);
383 }
384 a68_free (buffer);
385 }
386 }
387
388 //! @brief PROC (STRING) BOOL file is regular
389
390 void genie_file_is_regular (NODE_T * p)
391 {
392 errno = 0;
393 A68_REF name;
394 POP_REF (p, &name);
395 CHECK_INIT (p, INITIALISED (&name), M_STRING);
396 char *buffer = (char *) a68_alloc ((size_t) (1 + a68_string_size (p, name)), __func__, __LINE__);
397 if (buffer == NO_TEXT) {
398 diagnostic (A68_RUNTIME_ERROR, p, ERROR_OUT_OF_CORE);
399 exit_genie (p, A68_RUNTIME_ERROR);
400 } else {
401 struct stat status;
402 if (stat (a_to_c_string (p, buffer, name), &status) == 0) {
403 PUSH_VALUE (p, (BOOL_T) (S_ISREG (ST_MODE (&status)) != 0 ? A68_TRUE : A68_FALSE), A68_BOOL);
404 } else {
405 PUSH_VALUE (p, A68_FALSE, A68_BOOL);
406 }
407 a68_free (buffer);
408 }
409 }
410
411 #if defined (S_ISFIFO)
412
413 //! @brief PROC (STRING) BOOL file is fifo
414
415 void genie_file_is_fifo (NODE_T * p)
416 {
417 errno = 0;
418 A68_REF name;
419 POP_REF (p, &name);
420 CHECK_INIT (p, INITIALISED (&name), M_STRING);
421 char *buffer = (char *) a68_alloc ((size_t) (1 + a68_string_size (p, name)), __func__, __LINE__);
422 if (buffer == NO_TEXT) {
423 diagnostic (A68_RUNTIME_ERROR, p, ERROR_OUT_OF_CORE);
424 exit_genie (p, A68_RUNTIME_ERROR);
425 } else {
426 struct stat status;
427 if (stat (a_to_c_string (p, buffer, name), &status) == 0) {
428 PUSH_VALUE (p, (BOOL_T) (S_ISFIFO (ST_MODE (&status)) != 0 ? A68_TRUE : A68_FALSE), A68_BOOL);
429 } else {
430 PUSH_VALUE (p, A68_FALSE, A68_BOOL);
431 }
432 a68_free (buffer);
433 }
434 }
435
436 #endif
437
438 #if defined (S_ISLNK)
439
440 //! @brief PROC (STRING) BOOL file is link
441
442 void genie_file_is_link (NODE_T * p)
443 {
444 errno = 0;
445 A68_REF name;
446 POP_REF (p, &name);
447 CHECK_INIT (p, INITIALISED (&name), M_STRING);
448 char *buffer = (char *) a68_alloc ((size_t) (1 + a68_string_size (p, name)), __func__, __LINE__);
449 if (buffer == NO_TEXT) {
450 diagnostic (A68_RUNTIME_ERROR, p, ERROR_OUT_OF_CORE);
451 exit_genie (p, A68_RUNTIME_ERROR);
452 } else {
453 struct stat status;
454 if (stat (a_to_c_string (p, buffer, name), &status) == 0) {
455 PUSH_VALUE (p, (BOOL_T) (S_ISLNK (ST_MODE (&status)) != 0 ? A68_TRUE : A68_FALSE), A68_BOOL);
456 } else {
457 PUSH_VALUE (p, A68_FALSE, A68_BOOL);
458 }
459 a68_free (buffer);
460 }
461 }
462
463 #endif
464
465 //! @brief Convert [] STRING row to char *vec[].
466
467 void convert_string_vector (NODE_T * p, char *vec[], A68_REF row)
468 {
469 BYTE_T *z = ADDRESS (&row);
470 A68_ARRAY *arr = (A68_ARRAY *) & z[0];
471 A68_TUPLE *tup = (A68_TUPLE *) & z[SIZE_ALIGNED (A68_ARRAY)];
472 int k = 0;
473 if (get_row_size (tup, DIM (arr)) > 0) {
474 BYTE_T *base_addr = DEREF (BYTE_T, &ARRAY (arr));
475 BOOL_T done = A68_FALSE;
476 initialise_internal_index (tup, DIM (arr));
477 while (!done) {
478 ADDR_T a68_index = calculate_internal_index (tup, DIM (arr));
479 ADDR_T elem_addr = (a68_index + SLICE_OFFSET (arr)) * ELEM_SIZE (arr) + FIELD_OFFSET (arr);
480 BYTE_T *elem = &base_addr[elem_addr];
481 int size = a68_string_size (p, *(A68_REF *) elem);
482 CHECK_INIT (p, INITIALISED ((A68_REF *) elem), M_STRING);
483 vec[k] = (char *) get_heap_space ((size_t) (1 + size));
484 ASSERT (a_to_c_string (p, vec[k], *(A68_REF *) elem) != NO_TEXT);
485 if (k == VECTOR_SIZE - 1) {
486 diagnostic (A68_RUNTIME_ERROR, p, ERROR_TOO_MANY_ARGUMENTS);
487 exit_genie (p, A68_RUNTIME_ERROR);
488 }
489 if (strlen (vec[k]) > 0) {
490 k++;
491 }
492 done = increment_internal_index (tup, DIM (arr));
493 }
494 }
495 vec[k] = NO_TEXT;
496 }
497
498 //! @brief Free char *vec[].
499
500 void free_vector (char *vec[])
501 {
502 int k = 0;
503 while (vec[k] != NO_TEXT) {
504 a68_free (vec[k]);
505 k++;
506 }
507 }
508
509 //! @brief Reset error number.
510
511 void genie_reset_errno (NODE_T * p)
512 {
513 (void) *p;
514 errno = 0;
515 }
516
517 //! @brief Error number.
518
519 void genie_errno (NODE_T * p)
520 {
521 PUSH_VALUE (p, errno, A68_INT);
522 }
523
524 //! @brief PROC strerror = (INT) STRING
525
526 void genie_strerror (NODE_T * p)
527 {
528 A68_INT i;
529 POP_OBJECT (p, &i, A68_INT);
530 PUSH_REF (p, c_to_a_string (p, strerror (VALUE (&i)), DEFAULT_WIDTH));
531 }
532
533 //! @brief Set up file for usage in pipe.
534
535 void set_up_file (NODE_T * p, A68_REF * z, int fd, A68_CHANNEL chan, BOOL_T r_mood, BOOL_T w_mood, int pid)
536 {
537 *z = heap_generator (p, M_REF_FILE, SIZE (M_FILE));
538 A68_FILE *f = FILE_DEREF (z);
539 STATUS (f) = (STATUS_MASK_T) ((pid < 0) ? 0 : INIT_MASK);
540 IDENTIFICATION (f) = nil_ref;
541 TERMINATOR (f) = nil_ref;
542 CHANNEL (f) = chan;
543 FD (f) = fd;
544 STREAM (&DEVICE (f)) = NO_STREAM;
545 OPENED (f) = A68_TRUE;
546 OPEN_EXCLUSIVE (f) = A68_FALSE;
547 READ_MOOD (f) = r_mood;
548 WRITE_MOOD (f) = w_mood;
549 CHAR_MOOD (f) = A68_TRUE;
550 DRAW_MOOD (f) = A68_FALSE;
551 FORMAT (f) = nil_format;
552 TRANSPUT_BUFFER (f) = get_unblocked_transput_buffer (p);
553 STRING (f) = nil_ref;
554 reset_transput_buffer (TRANSPUT_BUFFER (f));
555 set_default_event_procedures (f);
556 }
557
558 //! @brief Create and push a pipe.
559
560 void genie_mkpipe (NODE_T * p, int fd_r, int fd_w, int pid)
561 {
562 errno = 0;
563 A68_REF r, w;
564 set_up_file (p, &r, fd_r, A68 (stand_in_channel), A68_TRUE, A68_FALSE, pid);
565 set_up_file (p, &w, fd_w, A68 (stand_out_channel), A68_FALSE, A68_TRUE, pid);
566 PUSH_REF (p, r);
567 PUSH_REF (p, w);
568 PUSH_VALUE (p, pid, A68_INT);
569 }
570
571 //! @brief Push an environment string.
572
573 void genie_getenv (NODE_T * p)
574 {
575 errno = 0;
576 A68_REF a_env;
577 POP_REF (p, &a_env);
578 CHECK_INIT (p, INITIALISED (&a_env), M_STRING);
579 char *z_env = (char *) get_heap_space ((size_t) (1 + a68_string_size (p, a_env)));
580 char *z = a_to_c_string (p, z_env, a_env);
581 char *val = getenv (z);
582 if (val == NO_TEXT) {
583 a_env = empty_string (p);
584 } else {
585 a_env = tmp_to_a68_string (p, val);
586 }
587 PUSH_REF (p, a_env);
588 }
589
590 //! @brief PROC fork = INT
591
592 void genie_fork (NODE_T * p)
593 {
594 #if defined (BUILD_WIN32)
595 PUSH_VALUE (p, -1, A68_INT);
596 #else
597 errno = 0;
598 int pid = (int) fork ();
599 PUSH_VALUE (p, pid, A68_INT);
600 #endif
601 }
602
603 //! @brief PROC execve = (STRING, [] STRING, [] STRING) INT
604
605 void genie_exec (NODE_T * p)
606 {
607 errno = 0;
608 // Pop parameters.
609 A68_REF a_prog, a_args, a_env;
610 POP_REF (p, &a_env);
611 POP_REF (p, &a_args);
612 POP_REF (p, &a_prog);
613 // Convert strings and hasta el infinito.
614 char *prog = (char *) get_heap_space ((size_t) (1 + a68_string_size (p, a_prog)));
615 ASSERT (a_to_c_string (p, prog, a_prog) != NO_TEXT);
616 char *argv[VECTOR_SIZE], *envp[VECTOR_SIZE];
617 convert_string_vector (p, argv, a_args);
618 convert_string_vector (p, envp, a_env);
619 if (argv[0] == NO_TEXT) {
620 diagnostic (A68_RUNTIME_ERROR, p, ERROR_EMPTY_ARGUMENT);
621 exit_genie (p, A68_RUNTIME_ERROR);
622 }
623 int ret = execve (prog, argv, envp);
624 // execve only returns if it fails.
625 free_vector (argv);
626 free_vector (envp);
627 a68_free (prog);
628 PUSH_VALUE (p, ret, A68_INT);
629 }
630
631 //! @brief PROC execve child = (STRING, [] STRING, [] STRING) INT
632
633 void genie_exec_sub (NODE_T * p)
634 {
635 errno = 0;
636 A68_REF a_prog, a_args, a_env;
637 // Pop parameters.
638 POP_REF (p, &a_env);
639 POP_REF (p, &a_args);
640 POP_REF (p, &a_prog);
641 // Now create the pipes and fork.
642 #if defined (BUILD_WIN32)
643 int pid = -1;
644 (void) pid;
645 PUSH_VALUE (p, -1, A68_INT);
646 return;
647 #else
648 int pid = (int) fork ();
649 if (pid == -1) {
650 PUSH_VALUE (p, -1, A68_INT);
651 } else if (pid == 0) {
652 // Child process.
653 char *prog = (char *) get_heap_space ((size_t) (1 + a68_string_size (p, a_prog)));
654 ASSERT (a_to_c_string (p, prog, a_prog) != NO_TEXT);
655 char *argv[VECTOR_SIZE], *envp[VECTOR_SIZE];
656 convert_string_vector (p, argv, a_args);
657 convert_string_vector (p, envp, a_env);
658 if (argv[0] == NO_TEXT) {
659 diagnostic (A68_RUNTIME_ERROR, p, ERROR_EMPTY_ARGUMENT);
660 exit_genie (p, A68_RUNTIME_ERROR);
661 }
662 (void) execve (prog, argv, envp);
663 // execve only returns if it fails - end child process.
664 a68_exit (EXIT_FAILURE);
665 PUSH_VALUE (p, 0, A68_INT);
666 } else {
667 // parent process.
668 PUSH_VALUE (p, pid, A68_INT);
669 }
670 #endif
671 }
672
673 //! @brief PROC execve child pipe = (STRING, [] STRING, [] STRING) PIPE
674
675 void genie_exec_sub_pipeline (NODE_T * p)
676 {
677 // Child redirects STDIN and STDOUT.
678 // Return a PIPE that contains the descriptors for the parent.
679 //
680 // pipe ptoc
681 // ->W...R->
682 // PARENT CHILD
683 // <-R...W<-
684 // pipe ctop
685 errno = 0;
686 A68_REF a_prog, a_args, a_env;
687 POP_REF (p, &a_env);
688 POP_REF (p, &a_args);
689 POP_REF (p, &a_prog);
690 #if !defined (BUILD_UNIX)
691 int pid = -1;
692 (void) pid;
693 genie_mkpipe (p, -1, -1, -1);
694 return;
695 #else
696 // Create the pipes and fork.
697 int ptoc_fd[2], ctop_fd[2];
698 if ((pipe (ptoc_fd) == -1) || (pipe (ctop_fd) == -1)) {
699 genie_mkpipe (p, -1, -1, -1);
700 return;
701 }
702 int pid = (int) fork ();
703 if (pid == -1) {
704 // Fork failure.
705 genie_mkpipe (p, -1, -1, -1);
706 return;
707 }
708 if (pid == 0) {
709 // Child process.
710 // Convert strings.
711 char *prog = (char *) get_heap_space ((size_t) (1 + a68_string_size (p, a_prog)));
712 ASSERT (a_to_c_string (p, prog, a_prog) != NO_TEXT);
713 char *argv[VECTOR_SIZE], *envp[VECTOR_SIZE];
714 convert_string_vector (p, argv, a_args);
715 convert_string_vector (p, envp, a_env);
716 // Set up redirection.
717 ASSERT (close (ctop_fd[FD_READ]) == 0);
718 ASSERT (close (ptoc_fd[FD_WRITE]) == 0);
719 ASSERT (close (A68_STDIN) == 0);
720 ASSERT (close (A68_STDOUT) == 0);
721 ASSERT (dup2 (ptoc_fd[FD_READ], A68_STDIN) != -1);
722 ASSERT (dup2 (ctop_fd[FD_WRITE], A68_STDOUT) != -1);
723 if (argv[0] == NO_TEXT) {
724 diagnostic (A68_RUNTIME_ERROR, p, ERROR_EMPTY_ARGUMENT);
725 exit_genie (p, A68_RUNTIME_ERROR);
726 }
727 (void) execve (prog, argv, envp);
728 // execve only returns if it fails - end child process.
729 a68_exit (EXIT_FAILURE);
730 genie_mkpipe (p, -1, -1, -1);
731 } else {
732 // Parent process.
733 ASSERT (close (ptoc_fd[FD_READ]) == 0);
734 ASSERT (close (ctop_fd[FD_WRITE]) == 0);
735 genie_mkpipe (p, ctop_fd[FD_READ], ptoc_fd[FD_WRITE], pid);
736 }
737 #endif
738 }
739
740 //! @brief PROC execve output = (STRING, [] STRING, [] STRING, REF_STRING) INT
741
742 void genie_exec_sub_output (NODE_T * p)
743 {
744 // Child redirects STDIN and STDOUT.
745 //
746 // pipe ptoc
747 // ->W...R->
748 // PARENT CHILD
749 // <-R...W<-
750 // pipe ctop
751 errno = 0;
752 A68_REF a_prog, a_args, a_env, dest;
753 POP_REF (p, &dest);
754 POP_REF (p, &a_env);
755 POP_REF (p, &a_args);
756 POP_REF (p, &a_prog);
757 #if !defined (BUILD_UNIX)
758 int pid = -1;
759 (void) pid;
760 PUSH_VALUE (p, -1, A68_INT);
761 return;
762 #else
763 // Create the pipes and fork.
764 int ptoc_fd[2], ctop_fd[2];
765 if ((pipe (ptoc_fd) == -1) || (pipe (ctop_fd) == -1)) {
766 PUSH_VALUE (p, -1, A68_INT);
767 return;
768 }
769 int pid = (int) fork ();
770 if (pid == -1) {
771 // Fork failure.
772 PUSH_VALUE (p, -1, A68_INT);
773 return;
774 }
775 if (pid == 0) {
776 char *prog = (char *) get_heap_space ((size_t) (1 + a68_string_size (p, a_prog)));
777 ASSERT (a_to_c_string (p, prog, a_prog) != NO_TEXT);
778 char *argv[VECTOR_SIZE], *envp[VECTOR_SIZE];
779 convert_string_vector (p, argv, a_args);
780 convert_string_vector (p, envp, a_env);
781 // Set up redirection.
782 ASSERT (close (ctop_fd[FD_READ]) == 0);
783 ASSERT (close (ptoc_fd[FD_WRITE]) == 0);
784 ASSERT (close (A68_STDIN) == 0);
785 ASSERT (close (A68_STDOUT) == 0);
786 ASSERT (dup2 (ptoc_fd[FD_READ], A68_STDIN) != -1);
787 ASSERT (dup2 (ctop_fd[FD_WRITE], A68_STDOUT) != -1);
788 if (argv[0] == NO_TEXT) {
789 diagnostic (A68_RUNTIME_ERROR, p, ERROR_EMPTY_ARGUMENT);
790 exit_genie (p, A68_RUNTIME_ERROR);
791 }
792 (void) execve (prog, argv, envp);
793 // execve only returns if it fails - end child process.
794 a68_exit (EXIT_FAILURE);
795 PUSH_VALUE (p, -1, A68_INT);
796 } else {
797 // Parent process.
798 char ch;
799 ASSERT (close (ptoc_fd[FD_READ]) == 0);
800 ASSERT (close (ctop_fd[FD_WRITE]) == 0);
801 reset_transput_buffer (INPUT_BUFFER);
802 int pipe_read, ret, status;
803 do {
804 pipe_read = (int) io_read_conv (ctop_fd[FD_READ], &ch, 1);
805 if (pipe_read > 0) {
806 plusab_transput_buffer (p, INPUT_BUFFER, ch);
807 }
808 } while (pipe_read > 0);
809 do {
810 ret = (int) waitpid ((a68_pid_t) pid, &status, 0);
811 } while (ret == -1 && errno == EINTR);
812 if (ret != pid) {
813 status = -1;
814 }
815 if (!IS_NIL (dest)) {
816 *DEREF (A68_REF, &dest) = c_to_a_string (p, get_transput_buffer (INPUT_BUFFER), get_transput_buffer_index (INPUT_BUFFER));
817 }
818 ASSERT (close (ptoc_fd[FD_WRITE]) == 0);
819 ASSERT (close (ctop_fd[FD_READ]) == 0);
820 PUSH_VALUE (p, ret, A68_INT);
821 }
822 #endif
823 }
824
825 //! @brief PROC create pipe = PIPE
826
827 void genie_create_pipe (NODE_T * p)
828 {
829 errno = 0;
830 genie_stand_in (p);
831 genie_stand_out (p);
832 PUSH_VALUE (p, -1, A68_INT);
833 }
834
835 //! @brief PROC wait pid = (INT) VOID
836
837 void genie_waitpid (NODE_T * p)
838 {
839 errno = 0;
840 A68_INT k;
841 POP_OBJECT (p, &k, A68_INT);
842 #if defined (BUILD_UNIX)
843 ASSERT (waitpid ((a68_pid_t) VALUE (&k), NULL, 0) != -1);
844 #endif
845 }
© 2002-2024 J.M. van der Veer (jmvdveer@xs4all.nl)
|