libc

libc is a module which provides Idio interfaces to C standard library functions.

As things stand, there is enough functionality for Idio to work but there has been limited effort to be any more comprehensive.

API Style

All C names should transliterate exactly into Idio names. The idea, here, is that you can cut’n’paste from manual pages into Idio.

Most Idio interfaces will raise a condition, usually an instance of ^rt-system-error, if the underlying C API reports an error.

In general, values returned from libc functions will be passed opaquely back into other libc functions. Periodically, you may want to print values (which should do something sensible) or pass an original value as an argument. The latter will require some value construction.

Most Idio interfaces will return a C/pointer value where you would have had to allocate some memory and pass a pointer into the C interface. The returned value will be tagged so as to free the memory when it is garbage collected.

Where possible, such C/pointer values will have been tagged with some C Structure Identification (CSI) data which can include structure names and members, accessors and printer.

Portability concerns means that some C structures have limited support. A case in point is libc/struct-rusage which only handles the ru_utime and ru_stime members.

Corresponding standard library typedefs are available (mapping to the underlying C base types) which you should use for portability reasons.

Remember, the C comparison functions require that their arguments be the same type – there is no implicit integer promotion in Idio. Correspondingly, given a frequent comparison with 0 (zero) there are some standard C and libc “zero” values:

  • C/0i and C/0u are C 0 as signed and unsigned integers

  • libc/0pid_t, libc/0uid_t, libc/0git_t are portable values of C 0 as libc/pid_t, libc/uid_t and libc/gid_t respectively

  • you can construct any such convenience value with:

    C/integer-> 0 type

passwd Example

simple-passwd.idio
import libc

printf "EUID is %d, a %s\n" EUID (type->string EUID)

;; C comparisons must be done with like-types
printf "I am %sroot\n" (if (C/== EUID 0uid_t) "" "not ")

pw := getpwuid EUID

if pw {
  ;; We know a non-#f result from getpwuid will be a struct-passwd
  ;; which is a C/pointer but we can do some clarity-inducing double
  ;; checking
  if (C/pointer? pw) {
    printf "pw is a C/pointer to a %s\n"  (C/pointer-name pw)
    printf "members: %@\n" (C/pointer-members pw)
  }

  ;; the accessor is (struct-passwd-ref pw pw_name) but "." can figure
  ;; it out from the CSI
  printf "%s " pw.pw_name

  ;; gecos might be empty
  gecos := pw.pw_gecos
  if ((string-length gecos) gt 0) {
    printf "is %s" gecos
  }
  printf "\n"

  ;; the CSI default printer deliberately uses a passwd(5)-style
  ;; output
  printf "The struct-passwd is %s\n" pw
} {
  printf "No passwd entry\n"
}
$ idio simple-passwd
EUID is 1000, a C/uint
I am not root
pw is a C/pointer to a libc/struct-passwd
members: pw_name pw_passwd pw_uid pw_gid pw_gecos pw_dir pw_shell
idf is Ian Fitchet
The struct-passwd is #<CSI libc/struct-passwd idf:x:1000:1000:Ian Fitchet:/home/idf:/bin/bash>

rlimit Example

Here’s how the test suite reduces the number of file descriptors to something more manageable to test what happens when they run out.

simple-rlimit-1.idio
;; print out the current state using an external command
ulimit -n

;; construct a libc/rlim_t with the value 256
lim := C/integer-> 256 libc/rlim_t

;; get the current rlimit
rl := libc/getrlimit libc/RLIMIT_NOFILE

;; if it's greater than 256, set it to 256
if (C/> (libc/struct-rlimit-ref rl 'rlim_cur) lim) {
  libc/struct-rlimit-set! rl 'rlim_cur lim
  libc/setrlimit libc/RLIMIT_NOFILE rl
}

ulimit -n
$ idio simple-rlimit-1
1024
256

The first example uses the ref and set accessors explicitly as it is “quicker” (by avoiding having to look the accessors up in the CSI information at runtime). Those with fewer bits than time might prefer:

simple-rlimit-2.idio
ulimit -n

lim := C/integer-> 256 libc/rlim_t

rl := libc/getrlimit libc/RLIMIT_NOFILE

if (C/> rl.rlim_cur lim) {
  rl.rlim_cur = lim
  libc/setrlimit libc/RLIMIT_NOFILE rl
}

ulimit -n
$ idio simple-rlimit-2
1024
256

You’ll notice that the “set” has become an assignment.

Last built at 2024-10-13T06:11:42Z+0000 from 77077af (dev) for Idio 0.3