2.3. Writing streams with the write() API

The write() API is used to write bytes to a stream file.

The reason that I say "bytes" as opposed to saying "letters" or "words" is that a byte containing any value can be written. We are not limited to just alphanumeric strings of text. We can write the contents of a packed decimal variable, for example, or an entire data structure.

All you have to tell write() is an area of memory (and again, it doesn't care what's in that area) and length. It copies the bytes from memory to disk.

Here's what the C language prototype of write() looks like, as printed in the UNIX-type APIs manual:

      int(1) write(int fildes(2), const void *buf(3), size_t nbyte(4));

Now that's a sexy looking API!

The return value is an "int", which is a 32-bit signed integer, identical to the RPG "10I 0" data type. The write() API returns the number of bytes written to disk. If something goes wrong, this number will be smaller than the amount we told it to write, so we can use this to detect errors, as well.
The first parameter is also an integer, and this one represents the file descriptor, which is the value that we got from the open() API.
Something new! What the heck could "const void *buf" mean? Well, my friend, it's quite simple. The "const" is just like the RPG "const" keyword. It simply means that the API cannot and will not change the contents of the parameter. But does "void *" mean that it's a pointer to a void? No, not really. It means that this pointer can point to anything. It doesn't have to be a character, a number, or a structure. It can point to any byte value in memory.
And finally, we have "size_t nbyte". It's pretty clear that "nbyte" is short for "number of bytes to write". But what is that funny "size_t" thing?

It's a "user-defined" type. It's similar in some ways to the "like" keyword in RPG. The idea is that on different platforms, the way that a byte size is stored may be different. To write code that's reusable, they have a header member called "sys/types.h" which describes the actual data types of things like "size_t", and then when you change to a different platform and use different header files, the program compiles and works on that platform as well.

On the AS/400, size_t is defined to be a 32-bit unsigned integer. In other words, it's the same as the RPG "10U 0" data type.

Now that we've covered that, here's the RPG version of the prototype. You'll want to add this to the IFSIO_H header member:

     D write           PR            10I 0 extproc('write')  
     D   fildes                      10I 0 value             
     D   buf                           *   value             
     D   nbyte                       10U 0 value             

See? Not so bad. Just a couple of integers and a pointer. no sweat.

Here's a code snippet showing a program that calls the write() API:

     c                   eval      wrdata = 'THE QUICK BROWN FOX JUMP'    
     c                   if        write(fd: %addr(wrdata): %size(wrdata))
     c                                 < %size(wrdata)
     c                   goto      
     c                   endif