diff --git a/.github/workflows/esperanto.yml b/.github/workflows/esperanto.yml new file mode 100644 index 000000000..a3539ff15 --- /dev/null +++ b/.github/workflows/esperanto.yml @@ -0,0 +1,102 @@ +name: Esperanto support +on: [ push ] +jobs: + test: + strategy: + matrix: + operating-system: [ ubuntu-latest ] + ocaml-version: [ "4.13.1", "4.14.0" ] + local-packages: + - | + *.opam + !lwt_domain.opam + runs-on: ${{ matrix.operating-system }} + steps: + - uses: actions/checkout@v2 + - uses: ocaml/setup-ocaml@v2 + with: + ocaml-compiler: ${{ matrix.ocaml-version }} + opam-local-packages: ${{ matrix.local-packages }} + - name: Fix binfmt and Cosmopolitan + run: sudo sh -c "echo ':APE:M::MZqFpD::/bin/sh:' >/proc/sys/fs/binfmt_misc/register" + - name: Install Esperanto, Dune & ocamlfind + run: opam install esperanto.0.0.3 dune ocamlfind + - name: Install opam-monorepo + run: opam install opam-monorepo + - name: Add opam-monorepo overlays + run: opam repo add dune-universe git+https://github.com/dune-universe/opam-overlays.git + - name: Example with lwt & esperanto + run: | + mkdir esperanto-example + cd esperanto-example + cat >dune-workspace <dune-project <cat.ml <>= fun len' -> + if len - len' > 0 + then full_write fd buf (off + len') (len - len') + else Lwt.return_unit + + let tmp = Bytes.create 0x1000 + + let rec cat () = + Lwt.catch begin fun () -> + Lwt_unix.read Lwt_unix.stdin tmp 0 (Bytes.length tmp) >>= fun len -> + match len with + | 0 -> Lwt.return_unit + | len -> full_write Lwt_unix.stdout tmp 0 len >>= cat + end @@ function + | End_of_file -> Lwt.return_unit + | exn -> raise exn + + let () = Lwt_main.run (cat ()) + EOF + cat >dune <cat.opam <" ] + authors: [ "Romain Calascibetta " ] + homepage: "https://github.com/dinosaure/esperanto" + bug-reports: "https://github.com/dinosaure/esperanto/issues" + dev-repo: "git+https://github.com/dinosaure/esperanto" + doc: "https://dinosaure.github.io/esperanto/" + license: "MIT" + synopsis: "The cat.com tool produced by esperanto" + description: "The cat.com tool produced by esperanto" + + build: [ + [ "dune" "build" "-p" name "-j" jobs ] + ] + install: [ + [ "dune" "install" "-p" name ] {with-test} + ] + + depends: [ + "ocaml" {>= "4.12.0"} + "dune" {>= "2.8.0"} + "lwt" + ] + EOF + opam monorepo lock --ocaml-version ${{ matrix.ocaml-version }} + opam monorepo pull + opam exec -- dune build -x esperanto ./cat.exe + objcopy -S -O binary _build/default.esperanto/cat.exe cat.com + ./cat.com < cat.ml diff --git a/src/unix/config/discover.ml b/src/unix/config/discover.ml index bd528cad7..eb37ef357 100644 --- a/src/unix/config/discover.ml +++ b/src/unix/config/discover.ml @@ -160,6 +160,8 @@ sig val ws2_32_lib : Configurator.t -> unit + val set_c_flags : string list -> unit + val set_link_flags : string list -> unit val c_flags : unit -> string list val link_flags : unit -> string list val add_link_flags : string list -> unit @@ -249,14 +251,19 @@ struct | None -> try - let path = + let _path = List.find (fun path -> Sys.file_exists (path // "include" // header)) (Lazy.force search_paths) in + (* NOTE: for the cross-compilation sake, we should not arbitrarily + * include ([-I]) some paths which can clash some cross-compilation's + * definitions with host's definitions. The default case about flags + * should always be less than more - and we should put these flags + * only we really require them. *) extend - ["-I" ^ (path // "include")] - ["-L" ^ (path // "lib"); "-l" ^ library] + [] (* ["-I" ^ (path // "include")] *) + [] (* ["-L" ^ (path // "lib"); "-l" ^ library] *) with Not_found -> () @@ -268,6 +275,9 @@ struct else extend unicode ["-lws2_32"] + let set_c_flags lst = c_flags := lst + let set_link_flags lst = link_flags := lst + let c_flags () = !c_flags @@ -368,15 +378,19 @@ struct Output.{name = feature.macro_name; found} end - let compiles ?(werror = false) ?(link_flags = []) context code = - let c_flags = C_library_flags.c_flags () in + let compiles ?(werror = false) ?c_flags ?link_flags context code = + let c_flags = match c_flags with + | None -> C_library_flags.c_flags () + | Some c_flags -> c_flags in let c_flags = if werror then "-Werror"::c_flags else c_flags in - let link_flags = link_flags @ (C_library_flags.link_flags ()) in + let link_flags = match link_flags with + | None -> C_library_flags.link_flags () + | Some link_flags -> link_flags in Configurator.c_test context ~c_flags ~link_flags code |> fun result -> Some result @@ -390,6 +404,76 @@ struct | Some true -> None | _ -> k () + let () = feature { + pretty_name = "pthread"; + macro_name = "HAVE_PTHREAD"; + detect = fun context -> + if !Arguments.use_pthread = Some false then + None + else begin + skip_if_windows context @@ fun () -> + let code = {| + #include + + int main() + { + pthread_create(1, 1, 1, 1); + return 0; + } + |} + in + (* To clarify the semantic of the recognition of [pthread]: + 1) [pthread] can be _standalone_ (included in the standard library) + depending on the C compiler + 1.1) A restrictive context (such as a cross-compilation context) + requires, at least, [-lpthread] but [-I] and [-L] can + disturb the compilation between the host's [pthread] and the + cross-compiled [pthread]. We test above all and for all this + tricky context with **only one** flag [-lpthread] + 1.2) On some platforms, if [pthread] is standalone, the linker + fails when we link with [-lpthread]. So we test our code + with **default** flags (such as [-I/usr/include] and + [-L/usr/lib]) and **without** [-pthread] + 2) On Android, compiling without [-lpthread] is the only way to link + with [pthread], and we don't to search for [pthread.a], because + if we find it, it is likely the host's [pthread] + 3) We finally retest our code with [-lpthread] and basic [-L] and + [-I] flags (from the host system) + + NOTE(dinosaure): + - 2) and 1.1) should be merged, we definitely should try to compile + the code **without any flags** and see results - by this way, we + consider that the _toolchain_ leads us about where is + [pthread]. + - 3) is too ~vague~ and obviously works but it's difficult to really + understand which [pthread] we really use. + - A question remains about priorities: do we want to prioritize + the [dune]'s context or do we prefer a compilation for the host + system first? + - In anyway, [discover.exe] should be less pervasives (no [ref] + about flags) and more strict and reproducible *) + match (* 1.2 *) compiles context code, + (* 1.1 *) compiles ~c_flags:[] ~link_flags:[ "-lpthread" ] context code with + | _, Some true (* prioritize [dune]'s context and cross-compilation *) -> + C_library_flags.set_c_flags [] ; + C_library_flags.set_link_flags [ "-lpthread" ] ; + Some true + | Some true, _ -> Some true + | _no -> + if (* 2 *) !Arguments.android_target = Some true then + Some false + else begin + match (* 3 *) compiles context code ~link_flags:["-lpthread"] with + | Some true -> + C_library_flags.add_link_flags ["-lpthread"]; + Some true + | _ -> + C_library_flags.detect context ~library:"pthread"; + compiles context code + end + end + } + let () = feature { pretty_name = "libev"; macro_name = "HAVE_LIBEV"; @@ -431,61 +515,17 @@ struct } |} in - match compiles context code ~link_flags:["-lev"] with + match compiles context code ~link_flags:("-lev" :: C_library_flags.link_flags ()) with | Some true -> C_library_flags.add_link_flags ["-lev"]; Some true | _ -> + (* C_library_flags.add_link_flags ["-lev"]; *) C_library_flags.detect context ~library:"ev"; compiles context code end } - let () = feature { - pretty_name = "pthread"; - macro_name = "HAVE_PTHREAD"; - detect = fun context -> - if !Arguments.use_pthread = Some false then - None - else begin - skip_if_windows context @@ fun () -> - let code = {| - #include - - int main() - { - pthread_create(0, 0, 0, 0); - return 0; - } - |} - in - (* On some platforms, pthread is included in the standard library, but - linking with -lpthread fails. So, try to link the test code without - any flags first. - - If that fails and we are not targeting Android, try to link with - -lpthread. If *that* fails, search for libpthread in the filesystem. - - When targeting Android, compiling without -lpthread is the only way - to link with pthread, and we don't to search for libpthread, because - if we find it, it is likely the host's libpthread. *) - match compiles context code with - | Some true -> Some true - | no -> - if !Arguments.android_target = Some true then - no - else begin - match compiles context code ~link_flags:["-lpthread"] with - | Some true -> - C_library_flags.add_link_flags ["-lpthread"]; - Some true - | _ -> - C_library_flags.detect context ~library:"pthread"; - compiles context code - end - end - } - let () = feature { pretty_name = "eventfd"; macro_name = "HAVE_EVENTFD"; @@ -516,6 +556,7 @@ struct struct msghdr msg; msg.msg_controllen = 0; msg.msg_control = 0; + unsigned char *data = CMSG_DATA(CMSG_FIRSTHDR(&msg)); return 0; } |} diff --git a/src/unix/unix_c/unix_access_job.c b/src/unix/unix_c/unix_access_job.c index a054fc34c..91a8b0334 100644 --- a/src/unix/unix_c/unix_access_job.c +++ b/src/unix/unix_c/unix_access_job.c @@ -33,21 +33,21 @@ | Converters | +-----------------------------------------------------------------+ */ -/* Table mapping constructors of ocaml type Unix.access_permission to C values. */ -static int access_permission_table[] = { - /* Constructor R_OK. */ - R_OK, - /* Constructor W_OK. */ - W_OK, - /* Constructor X_OK. */ - X_OK, - /* Constructor F_OK. */ - F_OK -}; - /* Convert ocaml values of type Unix.access_permission to a C int. */ static int int_of_access_permissions(value list) { + /* Table mapping constructors of ocaml type Unix.access_permission to C values. */ + int access_permission_table[] = { + /* Constructor R_OK. */ + R_OK, + /* Constructor W_OK. */ + W_OK, + /* Constructor X_OK. */ + X_OK, + /* Constructor F_OK. */ + F_OK + }; + int result = 0; while (list != Val_emptylist) { result |= access_permission_table[Int_val(Field(list, 0))]; diff --git a/src/unix/unix_c/unix_get_network_information_utils.c b/src/unix/unix_c/unix_get_network_information_utils.c index 12248dcd5..ab2fcaf19 100644 --- a/src/unix/unix_c/unix_get_network_information_utils.c +++ b/src/unix/unix_c/unix_get_network_information_utils.c @@ -139,16 +139,12 @@ value alloc_host_entry(struct hostent *entry) res = caml_alloc_small(4, 0); Field(res, 0) = name; Field(res, 1) = aliases; - switch (entry->h_addrtype) { - case PF_UNIX: + if (entry->h_addrtype == PF_UNIX) { Field(res, 2) = Val_int(0); - break; - case PF_INET: + } else if (entry->h_addrtype == PF_INET) { Field(res, 2) = Val_int(1); - break; - default: /*PF_INET6 */ + } else { Field(res, 2) = Val_int(2); - break; } Field(res, 3) = addr_list; End_roots(); diff --git a/src/unix/unix_c/unix_get_pw_gr_nam_id_job.c b/src/unix/unix_c/unix_get_pw_gr_nam_id_job.c index 579686d17..974dbac93 100644 --- a/src/unix/unix_c/unix_get_pw_gr_nam_id_job.c +++ b/src/unix/unix_c/unix_get_pw_gr_nam_id_job.c @@ -20,7 +20,11 @@ #include "lwt_unix.h" -#if !defined(__ANDROID__) +/* NOTE: [__ESPERANTO__] is defined by the cross-compiler if we compile into + * the [esperanto] context (with [arch-esperanto-none-static-cc]). Otherwise, + * nobody should define this macro. The code above can not be compiled with + * Esperanto/Cosmopolitan due to missing [_SC*] macros. */ +#if !defined(__ANDROID__) && !defined(__ESPERANTO__) static value alloc_passwd_entry(struct passwd *entry) { diff --git a/src/unix/unix_c/unix_madvise.c b/src/unix/unix_c/unix_madvise.c index f619a4441..f54987a35 100644 --- a/src/unix/unix_c/unix_madvise.c +++ b/src/unix/unix_c/unix_madvise.c @@ -12,8 +12,11 @@ #include #include -static int advise_table[] = { - MADV_NORMAL, MADV_RANDOM, MADV_SEQUENTIAL, MADV_WILLNEED, MADV_DONTNEED, +CAMLprim value lwt_unix_madvise(value val_buffer, value val_offset, + value val_length, value val_advice) +{ + int advise_table[] = { + MADV_NORMAL, MADV_RANDOM, MADV_SEQUENTIAL, MADV_WILLNEED, MADV_DONTNEED, #if defined(MADV_MERGEABLE) MADV_MERGEABLE, #else @@ -34,11 +37,8 @@ static int advise_table[] = { #else 0, #endif -}; + }; -CAMLprim value lwt_unix_madvise(value val_buffer, value val_offset, - value val_length, value val_advice) -{ int ret = madvise((char *)Caml_ba_data_val(val_buffer) + Long_val(val_offset), Long_val(val_length), advise_table[Int_val(val_advice)]); diff --git a/src/unix/unix_c/unix_mcast_modify_membership.c b/src/unix/unix_c/unix_mcast_modify_membership.c index febb5ac8f..c6c4d076d 100644 --- a/src/unix/unix_c/unix_mcast_modify_membership.c +++ b/src/unix/unix_c/unix_mcast_modify_membership.c @@ -30,8 +30,7 @@ CAMLprim value lwt_unix_mcast_modify_membership(value fd, value v_action, t = socket_domain(fd_sock); r = 0; - switch (t) { - case PF_INET: { + if (t == PF_INET) { struct ip_mreq mreq; if (caml_string_length(group_addr) != 4 || @@ -55,11 +54,10 @@ CAMLprim value lwt_unix_mcast_modify_membership(value fd, value v_action, r = setsockopt(fd_sock, IPPROTO_IP, optname, (void *)&mreq, sizeof(mreq)); - break; } - default: + else { caml_invalid_argument("lwt_unix_mcast_modify_membership"); - }; + } if (r == -1) uerror("setsockopt", Nothing); diff --git a/src/unix/unix_c/unix_mcast_set_loop.c b/src/unix/unix_c/unix_mcast_set_loop.c index bbf423165..34784ba37 100644 --- a/src/unix/unix_c/unix_mcast_set_loop.c +++ b/src/unix/unix_c/unix_mcast_set_loop.c @@ -22,14 +22,12 @@ CAMLprim value lwt_unix_mcast_set_loop(value fd, value flag) f = Bool_val(flag); r = 0; - switch (t) { - case PF_INET: + if (t == PF_INET) { r = setsockopt(Int_val(fd), IPPROTO_IP, IP_MULTICAST_LOOP, (void *)&f, sizeof(f)); - break; - default: + } else { caml_invalid_argument("lwt_unix_mcast_set_loop"); - }; + } if (r == -1) uerror("setsockopt", Nothing); diff --git a/src/unix/unix_c/unix_mcast_set_ttl.c b/src/unix/unix_c/unix_mcast_set_ttl.c index 78cdf2d79..85dfa06df 100644 --- a/src/unix/unix_c/unix_mcast_set_ttl.c +++ b/src/unix/unix_c/unix_mcast_set_ttl.c @@ -24,14 +24,12 @@ CAMLprim value lwt_unix_mcast_set_ttl(value fd, value ttl) v = Int_val(ttl); r = 0; - switch (t) { - case PF_INET: + if (t == PF_INET) { r = setsockopt(fd_sock, IPPROTO_IP, IP_MULTICAST_TTL, (void *)&v, sizeof(v)); - break; - default: + } else { caml_invalid_argument("lwt_unix_mcast_set_ttl"); - }; + } if (r == -1) uerror("setsockopt", Nothing); diff --git a/src/unix/unix_c/unix_mcast_utils.c b/src/unix/unix_c/unix_mcast_utils.c index ef752c977..5fa59402c 100644 --- a/src/unix/unix_c/unix_mcast_utils.c +++ b/src/unix/unix_c/unix_mcast_utils.c @@ -26,12 +26,11 @@ int socket_domain(int fd) l = sizeof(addr); if (getsockname(fd, &addr.s_gen, &l) == -1) uerror("getsockname", Nothing); - switch (addr.s_gen.sa_family) { - case AF_INET: + if (addr.s_gen.sa_family == AF_INET) { return PF_INET; - case AF_INET6: + } else if (addr.s_gen.sa_family == AF_INET6) { return PF_INET6; - default: + } else { caml_invalid_argument("Not an Internet socket"); } diff --git a/src/unix/unix_c/unix_open_job.c b/src/unix/unix_c/unix_open_job.c index a77ad1cab..0c1dc27a8 100644 --- a/src/unix/unix_c/unix_open_job.c +++ b/src/unix/unix_c/unix_open_job.c @@ -35,19 +35,8 @@ #define caml_unix_cloexec_default unix_cloexec_default #endif -static int open_flag_table[] = { - O_RDONLY, O_WRONLY, O_RDWR, O_NONBLOCK, O_APPEND, O_CREAT, O_TRUNC, - O_EXCL, O_NOCTTY, O_DSYNC, O_SYNC, O_RSYNC, 0, /* O_SHARE_DELETE, - Windows-only */ - 0, /* O_CLOEXEC, treated specially */ - 0 /* O_KEEPEXEC, treated specially */ -}; - enum { CLOEXEC = 1, KEEPEXEC = 2 }; -static int open_cloexec_table[15] = {0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, CLOEXEC, KEEPEXEC}; - struct job_open { struct lwt_unix_job job; int flags; @@ -112,6 +101,18 @@ static value result_open(struct job_open *job) CAMLprim value lwt_unix_open_job(value name, value flags, value perms) { + int open_flag_table[] = { + O_RDONLY, O_WRONLY, O_RDWR, O_NONBLOCK, O_APPEND, O_CREAT, O_TRUNC, + O_EXCL, O_NOCTTY, O_DSYNC, O_SYNC, O_RSYNC, 0, /* O_SHARE_DELETE, + Windows-only */ + 0, /* O_CLOEXEC, treated specially */ + 0 /* O_KEEPEXEC, treated specially */ + }; + + + int open_cloexec_table[15] = {0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, CLOEXEC, KEEPEXEC}; + LWT_UNIX_INIT_JOB_STRING(job, open, 0, name); job->fd = caml_convert_flag_list(flags, open_cloexec_table); job->flags = caml_convert_flag_list(flags, open_flag_table); diff --git a/src/unix/unix_c/unix_tcflow_job.c b/src/unix/unix_c/unix_tcflow_job.c index 764fe3c57..f8d783086 100644 --- a/src/unix/unix_c/unix_tcflow_job.c +++ b/src/unix/unix_c/unix_tcflow_job.c @@ -30,22 +30,6 @@ #include #include -/* +-----------------------------------------------------------------+ - | Converters | - +-----------------------------------------------------------------+ */ - -/* Table mapping constructors of ocaml type Unix.flow_action to C values. */ -static int flow_action_table[] = { - /* Constructor TCOOFF. */ - TCOOFF, - /* Constructor TCOON. */ - TCOON, - /* Constructor TCIOFF. */ - TCIOFF, - /* Constructor TCION. */ - TCION -}; - /* +-----------------------------------------------------------------+ | Asynchronous job | +-----------------------------------------------------------------+ */ @@ -94,6 +78,22 @@ static value result_tcflow(struct job_tcflow* job) /* The stub creating the job structure. */ CAMLprim value lwt_unix_tcflow_job(value fd, value action) { +/* +-----------------------------------------------------------------+ + | Converters | + +-----------------------------------------------------------------+ */ + +/* Table mapping constructors of ocaml type Unix.flow_action to C values. */ +int flow_action_table[] = { + /* Constructor TCOOFF. */ + TCOOFF, + /* Constructor TCOON. */ + TCOON, + /* Constructor TCIOFF. */ + TCIOFF, + /* Constructor TCION. */ + TCION +}; + /* Allocate a new job. */ struct job_tcflow* job = lwt_unix_new(struct job_tcflow); /* Initializes function fields. */ diff --git a/src/unix/unix_c/unix_tcflush_job.c b/src/unix/unix_c/unix_tcflush_job.c index 9287ca8e8..c4ce02be3 100644 --- a/src/unix/unix_c/unix_tcflush_job.c +++ b/src/unix/unix_c/unix_tcflush_job.c @@ -30,20 +30,6 @@ #include #include -/* +-----------------------------------------------------------------+ - | Converters | - +-----------------------------------------------------------------+ */ - -/* Table mapping constructors of ocaml type Unix.flush_queue to C values. */ -static int flush_queue_table[] = { - /* Constructor TCIFLUSH. */ - TCIFLUSH, - /* Constructor TCOFLUSH. */ - TCOFLUSH, - /* Constructor TCIOFLUSH. */ - TCIOFLUSH -}; - /* +-----------------------------------------------------------------+ | Asynchronous job | +-----------------------------------------------------------------+ */ @@ -92,6 +78,20 @@ static value result_tcflush(struct job_tcflush* job) /* The stub creating the job structure. */ CAMLprim value lwt_unix_tcflush_job(value fd, value queue) { + /* +-----------------------------------------------------------------+ + | Converters | + +-----------------------------------------------------------------+ */ + + /* Table mapping constructors of ocaml type Unix.flush_queue to C values. */ + int flush_queue_table[] = { + /* Constructor TCIFLUSH. */ + TCIFLUSH, + /* Constructor TCOFLUSH. */ + TCOFLUSH, + /* Constructor TCIOFLUSH. */ + TCIOFLUSH + }; + /* Allocate a new job. */ struct job_tcflush* job = lwt_unix_new(struct job_tcflush); /* Initializes function fields. */ diff --git a/src/unix/unix_c/unix_termios_conversion.c b/src/unix/unix_c/unix_termios_conversion.c index e9b82f8e6..7e292576f 100644 --- a/src/unix/unix_c/unix_termios_conversion.c +++ b/src/unix/unix_c/unix_termios_conversion.c @@ -20,141 +20,169 @@ enum { Iflags, Oflags, Cflags, Lflags }; /* Structure of the terminal_io record. Cf. unix.mli */ -static long terminal_io_descr[] = { - /* Input modes */ - Bool, Iflags, IGNBRK, Bool, Iflags, BRKINT, Bool, Iflags, IGNPAR, Bool, - Iflags, PARMRK, Bool, Iflags, INPCK, Bool, Iflags, ISTRIP, Bool, Iflags, - INLCR, Bool, Iflags, IGNCR, Bool, Iflags, ICRNL, Bool, Iflags, IXON, Bool, - Iflags, IXOFF, - /* Output modes */ - Bool, Oflags, OPOST, - /* Control modes */ - Speed, Output, Speed, Input, Enum, Cflags, 5, 4, CSIZE, CS5, CS6, CS7, CS8, - Enum, Cflags, 1, 2, CSTOPB, 0, CSTOPB, Bool, Cflags, CREAD, Bool, Cflags, - PARENB, Bool, Cflags, PARODD, Bool, Cflags, HUPCL, Bool, Cflags, CLOCAL, - /* Local modes */ - Bool, Lflags, ISIG, Bool, Lflags, ICANON, Bool, Lflags, NOFLSH, Bool, - Lflags, ECHO, Bool, Lflags, ECHOE, Bool, Lflags, ECHOK, Bool, Lflags, - ECHONL, - /* Control characters */ - Char, VINTR, Char, VQUIT, Char, VERASE, Char, VKILL, Char, VEOF, Char, VEOL, - Char, VMIN, Char, VTIME, Char, VSTART, Char, VSTOP, End}; +static tcflag_t *choose_field(struct termios *terminal_status, long field) +{ + switch (field) { + case Iflags: + return &terminal_status->c_iflag; + case Oflags: + return &terminal_status->c_oflag; + case Cflags: + return &terminal_status->c_cflag; + case Lflags: + return &terminal_status->c_lflag; + default: + return 0; + } +} -static struct { +struct speed_t { speed_t speed; int baud; -} speedtable[] = {{B50, 50}, - {B75, 75}, - {B110, 110}, - {B134, 134}, - {B150, 150}, +}; + +/* XXX(dinosaure): esperanto **does not** defines [speed_t] constants. */ + +long _speedtable(struct speed_t dst[]) { + struct speed_t speedtable[] = { +#ifndef __ESPERANTO__ + {B50, 50}, + {B75, 75}, + {B110, 110}, + {B134, 134}, + {B150, 150}, +#endif // __ESPERANTO__ #ifdef B200 - {B200, 200}, + {B200, 200}, #endif - {B300, 300}, - {B600, 600}, - {B1200, 1200}, - {B1800, 1800}, - {B2400, 2400}, - {B4800, 4800}, - {B9600, 9600}, - {B19200, 19200}, - {B38400, 38400}, +#ifndef __ESPERANTO__ + {B300, 300}, + {B600, 600}, + {B1200, 1200}, + {B1800, 1800}, + {B2400, 2400}, + {B4800, 4800}, + {B9600, 9600}, + {B19200, 19200}, + {B38400, 38400}, +#endif // __ESPERANTO__ #ifdef B57600 - {B57600, 57600}, + {B57600, 57600}, #endif #ifdef B115200 - {B115200, 115200}, + {B115200, 115200}, #endif #ifdef B230400 - {B230400, 230400}, + {B230400, 230400}, #endif - {B0, 0}, +#ifndef __ESPERANTO__ + {B0, 0}, +#endif // __ESPERANTO__ /* Linux extensions */ #ifdef B460800 - {B460800, 460800}, + {B460800, 460800}, #endif #ifdef B500000 - {B500000, 500000}, + {B500000, 500000}, #endif #ifdef B576000 - {B576000, 576000}, + {B576000, 576000}, #endif #ifdef B921600 - {B921600, 921600}, + {B921600, 921600}, #endif #ifdef B1000000 - {B1000000, 1000000}, + {B1000000, 1000000}, #endif #ifdef B1152000 - {B1152000, 1152000}, + {B1152000, 1152000}, #endif #ifdef B1500000 - {B1500000, 1500000}, + {B1500000, 1500000}, #endif #ifdef B2000000 - {B2000000, 2000000}, + {B2000000, 2000000}, #endif #ifdef B2500000 - {B2500000, 2500000}, + {B2500000, 2500000}, #endif #ifdef B3000000 - {B3000000, 3000000}, + {B3000000, 3000000}, #endif #ifdef B3500000 - {B3500000, 3500000}, + {B3500000, 3500000}, #endif #ifdef B4000000 - {B4000000, 4000000}, + {B4000000, 4000000}, #endif - /* MacOS extensions */ + /* MacOS extensions */ #ifdef B7200 - {B7200, 7200}, + {B7200, 7200}, #endif #ifdef B14400 - {B14400, 14400}, + {B14400, 14400}, #endif #ifdef B28800 - {B28800, 28800}, + {B28800, 28800}, #endif #ifdef B76800 - {B76800, 76800}, + {B76800, 76800}, #endif /* Cygwin extensions (in addition to the Linux ones) */ #ifdef B128000 - {B128000, 128000}, + {B128000, 128000}, #endif #ifdef B256000 - {B256000, 256000}, + {B256000, 256000}, #endif -}; + }; + + if (dst != NULL) memcpy(dst, speedtable, sizeof(speedtable)); + return (sizeof(speedtable) / sizeof(speedtable[0])); +} -#define NSPEEDS (sizeof(speedtable) / sizeof(speedtable[0])) +long _terminal_io_descr(long dst[]) { + long terminal_io_descr[] = { + /* Input modes */ + Bool, Iflags, IGNBRK, Bool, Iflags, BRKINT, Bool, Iflags, IGNPAR, Bool, + Iflags, PARMRK, Bool, Iflags, INPCK, Bool, Iflags, ISTRIP, Bool, Iflags, + INLCR, Bool, Iflags, IGNCR, Bool, Iflags, ICRNL, Bool, Iflags, IXON, Bool, + Iflags, IXOFF, + /* Output modes */ + Bool, Oflags, OPOST, + /* Control modes */ + Speed, Output, Speed, Input, Enum, Cflags, 5, 4, CSIZE, CS5, CS6, CS7, CS8, + Enum, Cflags, 1, 2, CSTOPB, 0, CSTOPB, Bool, Cflags, CREAD, Bool, Cflags, + PARENB, Bool, Cflags, PARODD, Bool, Cflags, HUPCL, Bool, Cflags, CLOCAL, + /* Local modes */ + Bool, Lflags, ISIG, Bool, Lflags, ICANON, Bool, Lflags, NOFLSH, Bool, + Lflags, ECHO, Bool, Lflags, ECHOE, Bool, Lflags, ECHOK, Bool, Lflags, + ECHONL, + /* Control characters */ + Char, VINTR, Char, VQUIT, Char, VERASE, Char, VKILL, Char, VEOF, Char, VEOL, + Char, VMIN, Char, VTIME, Char, VSTART, Char, VSTOP, End}; -static tcflag_t *choose_field(struct termios *terminal_status, long field) -{ - switch (field) { - case Iflags: - return &terminal_status->c_iflag; - case Oflags: - return &terminal_status->c_oflag; - case Cflags: - return &terminal_status->c_cflag; - case Lflags: - return &terminal_status->c_lflag; - default: - return 0; - } + if (dst != NULL) memcpy(dst, terminal_io_descr, sizeof(terminal_io_descr)); + return (sizeof(terminal_io_descr) / sizeof(long)); } + void encode_terminal_status(struct termios *terminal_status, volatile value *dst) { long *pc; int i; + long _NSPEEDS = _speedtable(NULL); + struct speed_t speedtable[_NSPEEDS]; + _speedtable(speedtable); + + long nterminal_io_descr = _terminal_io_descr(NULL); + long terminal_io_descr[nterminal_io_descr]; + _terminal_io_descr(terminal_io_descr); + for (pc = terminal_io_descr; *pc != End; dst++) { switch (*pc++) { case Bool: { @@ -190,7 +218,7 @@ void encode_terminal_status(struct termios *terminal_status, volatile value *dst speed = cfgetispeed(terminal_status); break; } - for (i = 0; i < NSPEEDS; i++) { + for (i = 0; i < _NSPEEDS; i++) { if (speed == speedtable[i].speed) { *dst = Val_int(speedtable[i].baud); break; @@ -212,6 +240,14 @@ int decode_terminal_status(struct termios *terminal_status, volatile value *src) long *pc; int i; + long _NSPEEDS = _speedtable(NULL); + struct speed_t speedtable[_NSPEEDS]; + _speedtable(speedtable); + + long nterminal_io_descr = _terminal_io_descr(NULL); + long terminal_io_descr[nterminal_io_descr]; + _terminal_io_descr(terminal_io_descr); + for (pc = terminal_io_descr; *pc != End; src++) { switch (*pc++) { case Bool: { @@ -242,7 +278,7 @@ int decode_terminal_status(struct termios *terminal_status, volatile value *src) int which = *pc++; int baud = Int_val(*src); int res = 0; - for (i = 0; i < NSPEEDS; i++) { + for (i = 0; i < _NSPEEDS; i++) { if (baud == speedtable[i].baud) { switch (which) { case Output: diff --git a/src/unix/unix_c/unix_wait4.c b/src/unix/unix_c/unix_wait4.c index daa9ab4f4..c0e86eab5 100644 --- a/src/unix/unix_c/unix_wait4.c +++ b/src/unix/unix_c/unix_wait4.c @@ -58,13 +58,13 @@ static value alloc_process_status(int status) return st; } -static int wait_flag_table[] = {WNOHANG, WUNTRACED}; - value lwt_unix_wait4(value flags, value pid_req) { CAMLparam1(flags); CAMLlocal2(times, res); + int wait_flag_table[] = {WNOHANG, WUNTRACED}; + int pid, status, cv_flags; cv_flags = caml_convert_flag_list(flags, wait_flag_table);