Transput RFC - early version based on POSIX

chris hermansen clhermansen@gmail.com
Mon Jun 1 19:42:12 GMT 2026


Perfectly clear, thank you!

On Mon, Jun 1, 2026 at 12:41 PM Jose E. Marchesi <jemarch@gnu.org> wrote:

>
> > Thanks, Jose.
> >
> > I have "just one more little question" below...
> >
> > On Thu, May 28, 2026 at 1:15 AM Jose E. Marchesi <jemarch@gnu.org>
> wrote:
> >
> >>
> >> Hi Chris.
> >>
> >> > Wow, I'm feeling so much better having the text for van Vliet's part 2
> >> now
> >> > (see my other email today).
> >> >
> >> > On Thu, May 21, 2026 at 2:42 PM Jose E. Marchesi <jemarch@gnu.org>
> >> wrote:
> >> >
> >> >>
> >> >> The fstat interface involves a struct stat, which in principle would
> not
> >> >> be a problem to interact directly using the Algol 68 FFI, because our
> >> >> structs are like C structs ABI wise.
> >> >>
> >> >> However, it looks like:
> >> >>
> >> >>        struct stat {
> >> >>            dev_t      st_dev;      /* ID of device containing file */
> >> >>            ino_t      st_ino;      /* Inode number */
> >> >>            mode_t     st_mode;     /* File type and mode */
> >> >>            nlink_t    st_nlink;    /* Number of hard links */
> >> >>            uid_t      st_uid;      /* User ID of owner */
> >> >>            gid_t      st_gid;      /* Group ID of owner */
> >> >>            dev_t      st_rdev;     /* Device ID (if special file) */
> >> >>            off_t      st_size;     /* Total size, in bytes */
> >> >>            blksize_t  st_blksize;  /* Block size for filesystem I/O
> */
> >> >>            blkcnt_t   st_blocks;   /* Number of 512 B blocks
> allocated
> >> */
> >> >>
> >> >>            /* Since POSIX.1-2008, this structure supports nanosecond
> >> >>               precision for the following timestamp fields.
> >> >>               For the details before POSIX.1-2008, see VERSIONS. */
> >> >>
> >> >>            struct timespec  st_atim;  /* Time of last access */
> >> >>            struct timespec  st_mtim;  /* Time of last modification */
> >> >>            struct timespec  st_ctim;  /* Time of last status change
> */
> >> >>
> >> >>        #define st_atime  st_atim.tv_sec  /* Backward compatibility */
> >> >>        #define st_mtine  st_mtim.tv_sec
> >> >>        #define st_ctime  st_ctim.tv_sec
> >> >>        };
> >> >>
> >> >> And there are plenty of fields there that have different sizes
> depending
> >> >> on target, system, etc.  Even the signedness of some of these types
> may
> >> >> no be fully defined by POSIX.
> >> >>
> >> >> So, in this case, we will need an intermediate C wrapper in
> ga68-posix.c
> >> >> with definite types, something like:
> >> >>
> >> >>   struct _ga68_stat
> >> >>   {
> >> >>     int st_uid;
> >> >>     int st_gid;
> >> >>     /* ... other fields we want.  */
> >> >>   };
> >> >>
> >> >> Then the getter that translates from struct stat to struct
> _ga68_stat:
> >> >>
> >> >>   int _ga68_fstat (struct _ga68_stat *stat)
> >> >>   {
> >> >>     /* Call fstat, translate from struct stat to struct _gat6*_stat
> */
> >> >>   }
> >> >>
> >> >> And then you can FFI this wrapper in libga68/posix.a68, something
> like:
> >> >>
> >> >>   mode Stat = struct (int uid, gid, ...);
> >> >>
> >> >>   pub fstat = (ref Stat stat): nest C "_ga68_fstat";
> >> >>
> >> >>
> >> >> That should work.  Of course tests shall be added to
> >> >> libga68/configure.ac to check for the availability of stat, etc.
> >> >>
> >> >> > On Thu, May 21, 2026, at 1:39 PM, chris hermansen wrote:
> >> >> >> Good morning everyone,
> >> >> >>
> >> >> >> Jose, thanks for the comments you provided.  One more question
> below:
> >> >> >> On Thu, May 21, 2026 at 2:16 AM Jose E. Marchesi <jemarch@gnu.org
> >
> >> >> wrote:
> >> >> >>>
> >> >> >>> Hello Chris.
> >> >> >>>
> >> >> >>> > Good afternoon everyone,
> >> >> >>> >
> >> >> >>> > After monkeying around far too long trying to pull out bits of
> van
> >> >> >>> > Vliet's transput so I could implement it piece by piece, I have
> >> >> given up on
> >> >> >>> > that approach (way too many dependencies between things in
> there)
> >> >> and am
> >> >> >>> > gritting my teeth and starting back at the beginning.
> >> >> >>> >
> >> >> >>> > To facilitate getting as much as possible working, I'd like to
> put
> >> >> van
> >> >> >>> > Vliet's code and ideas on top of Algol 68 POSIX for now,
> >> forgetting
> >> >> about
> >> >> >>> > reading and writing binary for the first go-around.
> >> >> >>> >
> >> >> >>> > Does that make sense?
> >> >> >>>
> >> >> >>> To me, it makes 100% sense.  In my experience, once you get
> >> something
> >> >> >>> working it becomes easier to reason about it.  There is a lot to
> >> learn
> >> >> >>> in the process too.
> >> >> >>>
> >> >> >>> > Assuming it's not too crazy an idea, the first bump on the road
> >> I've
> >> >> >>> > encountered is dealing with system file status.  As far as I
> can
> >> >> tell, the
> >> >> >>> > only pathway in Algol 68 POSIX for this type of thing is to
> call
> >> >> fopen() or
> >> >> >>> > fcreate() with various flags as documented here:
> >> >> >>> >
> >> >> >>> > https://gcc.gnu.org/onlinedocs/ga68/POSIX-files.html
> >> >> >>> >
> >> >> >>> > and then, based on what works and what doesn't, I can resolve
> many
> >> >> of van
> >> >> >>> > Vliet's "possibles":
> >> >> >>> > - get_possible(f) { true if fopen(filename, bits file o rdonly)
> >> >> returns ≥ 0
> >> >> >>> > }
> >> >> >>> > - put_possible(f) { true if fopen(filename, bits file o wronly)
> >> >> returns ≥ 0
> >> >> >>> > }
> >> >> >>> > - bin_possible(f) { always false for now }
> >> >> >>> > - compressible(f) { always true - indicates variable length
> lines
> >> }
> >> >> >>> > - reset_possible(f) { always true for now }
> >> >> >>> > - set_possible(f) { always true for now because lseek() }
> >> >> >>> > - backspace_possible(f) { always true for now because lseek() }
> >> >> >>> > - reidf_possible(f) { always false for now because Algol 68
> >> transput
> >> >> >>> > doesn't provide rename() }
> >> >> >>> >
> >> >> >>> > Does this sound like an acceptable start?
> >> >> >>>
> >> >> >>> I think it would be better to call to the system's fstat, a
> wrapper
> >> for
> >> >> >>> which needs to be added to the POSIX prelude.
> >> >> >>
> >> >> >> Are you suggesting here that (gasp) I add this in and create a
> patch?
> >> >> >>
> >> >> >> Am I too old a dog to learn a new trick?
> >> >> >
> >> >> > Since Jose added support for writing libga68 preludes in Algol 68
> this
> >> >> became much easier.
> >> >> > If it's an easy mapping from C you just need to add it to
> >> >> libga68/posix.a68.
> >> >> > If not, you need a add a C wrapper in libga68/ga68-posix.c and
> then in
> >> >> libga68/posix.a68.
> >> >> >
> >> >> > Don't forget to add docs in gcc/algol68/ga68.texi and tests in
> >> >> gcc/testsuite/algol68/compile
> >> >> > or gcc/testsuite/algol68/execute
> >> >>
> >> >> Not ready to create a patch yet!
> >> >
> >> > But reading van Vliet (as opposed to studying his code) I see this
> >> comment
> >> > on p. 21 of
> >> >
> >> > ALGOL 68 TRANSPUT PART II:  AN IMPLEMENTATION MODEL
> >> >
> >> > "The access properties of a book opened via such a channel are
> obtained
> >> by
> >> > the intersection of the properties of the book and the channel.  For
> >> > example, reading is possible if both the book and the channel allow
> >> reading"
> >> >
> >> > So fstat - not to start a big argument, but I think it's wrong
> because it
> >> > uses a file descriptor, meaning (says me) the file has to be open
> first.
> >>
> >> Oh ok.
> >>
> >> > Therefore, I think I want to implement Algol 68 open as:
> >> >
> >> > 1. figure out what the Channel wants - read? write? both? binary? not
> >> > binary? etc?
> >> > 2. translate the Channel 'wants' into a POSIX "mode"
> >>
> >> Yep.
> >>
> >> > 3. use the POSIX routine access(idf, mode) to see if I can do what the
> >> > Channel wants to the operating system file
> >>
> >> Yep.
> >>
> >> > 4. assuming all is good, then use POSIX routine fopen(idf, mode) to
> open
> >> > the file
> >>
> >> Yep.
> >>
> >> > 5. put the file descriptor and other stuff in the File structure and
> >> maybe
> >> > some stuff in the Book structure
> >>
> >> Makes sense.
> >>
> >> > One of the things I don't believe to be necessary in the whole Algol
> 68
> >> > transput, so long as we are basing it on POSIX anyway, is all the
> Buffer
> >> > stuff that van Vliet sets up; instead we can use his procedures
> >> write_char,
> >> > write_bin_char, read_char, read_bin_char (that are copied from the
> >> Channel
> >> > to the File when it is successfully opened) to call POSIX fputc(),
> >> > something for binary, fgetc(), something for binary.
> >>
> >> The POSIX f* functions are buffered themselves, so it makes sense to me,
> >> to not replicate the buffering at the Transput level.
> >>
> >> > Here I say "something" because for now I'm ignoring binary but I'm
> pretty
> >> > sure I will need some other pair of POSIX functions to handle the
> stuff
> >> van
> >> > Vliet refers to as BINCHAR.
> >> >
> >> > Maybe we can even replace his procedure components of File with the
> POSIX
> >> > routines.
> >> >
> >> > Hoping for more comments here!
> >>
> >
> > Following on with the idea of using POSIX:
> >
> > int access(const char *path, int amode);
> >
> > to determine whether my Channel access requirements are congruent with
> the
> > operating system file access permissions, I looked in
> gcc/libga68/posix.a68
> > to find:
> >
> > pub proc(string,bits)int fopen = nest C "_libga68_posixfopen",
> >
> > and then in gcc/libga68/ga68-posix.c to find:
> >
> > int
> > _libga68_posixfopen (const uint32_t *pathname, size_t len, size_t stride,
> >              unsigned int flags)
> > {
> >   int fd;
> >   int openflags = 0;
> >   size_t u8len;
> >   char *filepath = _libga68_u32_to_u8 (pathname, len, stride, &u8len);
> >
> >   /* Default mode: try read-write initially.
> >      If that fails, then try read-only.
> >      If that fails, then try write-only.  */
> >   if (flags == _libga68_file_o_default)
> >     {
> >       openflags = O_RDWR;
> >       if ((fd = _libga68_open (filepath, openflags)) < 0)
> >     {
> >       openflags = O_RDONLY;
> >       if ((fd = _libga68_open (filepath, openflags)) < 0)
> >         {
> >           openflags = O_WRONLY;
> >           fd = _libga68_open (filepath, openflags);
> >           _libga68_free_internal (filepath);
> >           return fd;
> >         }
> >     }
> >       _libga68_free_internal (filepath);
> >       return fd;
> >     }
> >
> >   if (flags & _libga68_file_o_rdonly)
> >     openflags |= O_RDONLY;
> >   if (flags & _libga68_file_o_wronly)
> >     openflags |= O_WRONLY;
> >   if (flags & _libga68_file_o_rdwr)
> >     openflags |= O_RDWR;
> >   if (flags & _libga68_file_o_trunc)
> >     openflags |= O_TRUNC;
> >
> >   fd = _libga68_open (filepath, openflags);
> >   _libga68_free_internal (filepath);
> >   return fd;
> > }
> >
> > But the declaration of _libga68_posixfopen does not seem to match the
> Algol
> > 68 procedure that is the caller.
> >
> > I hope one of you can enlighten me about this...
>
> Ok, so we have:
>
>   pub proc(string,bits)int fopen = nest C "_libga68_posixfopen",
>
> The procedure yields an int, that translates directly to a C int.
>
> The first formal parameter is a string.  That translates into three C
> arguments: a const uint32_t* with the characters, a size_t size with the
> number of uint32_t pointed, and a size_t stride with the stride of the
> elements stored in the string (which is a multiple).
>
> The second formal parameter is a bits, which corresponds to a C unsigned
> int.
>
>

-- 
Chris Hermansen · clhermansen "at" gmail "dot" com

C'est ma façon de parler.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://gcc.gnu.org/pipermail/algol68/attachments/20260601/08e4669c/attachment-0001.htm>


More information about the Algol68 mailing list