From: sproven@uk.ac.strath.cs Subject: docs for gstream Date: Tue, 06 Jul 93 13:13:54 +0100 Here is some documentation for gstream, which was missing from the gstream code on newcastle. Hopefuly this will enable people to make use of it. I've fixed some bugs in savebox, but the code is in Manchester and I'm in Scotland, so it looks as though you'll need to wait 'till october when Uni starts again before I can send a new version. gstream provides a uniform means of communicating with various devices or applications in RISC OS. It provides a range of functions similar to the stdio functions (eg fprintf == gsprintf ). However, streams are opened differently - via a number of bolt on extensions which implement the low level access to a given type of stream. This makes it possible for users of gstream to add their own types of stream without needing to make any changes to gstream itself. This is advantageous in that the gstream code will not get hacked up by a million different people, which would make updates to newer versions very difficult. Most of the functions exported by gstream can be understood by looking at their stdio equivalents - where differences occur these are documented in the sources. It is hoped that these differences will be removed when I can be bothered. The only other functions which need explaining to the user of gstream are: gsopeninternalw gsopeninternalr gsdiscardinternal gsgetbuf The first three of these provide a means to hold data in flex blocks. The system is write once, read many - ie you first of all open a flex block to write to with gsopeninternalw, write your data to it, then gsclose it. Then, you can open the same stream with gsopeninternalr and read the data back, then gsclose it. If you then use gsopeninternalr again will be able to read the data back again. gsdiscardinternal frees the memory used by the internal stream, really losing the data. After it has been called you can then call gsopeninternalw again. gsgetbuf is a function which tries to claim a flex block between minsize and maxsize bytes in size, returing the size of block claimed (0 if no block was claimed). See examples of its use in gstream, osstream and ramstream. The gstream module provides the following stdio-like functions: int gsflush(gstream *to) int gsclose(gstream *stream) int gsgetc(gstream *stream) int gsputc(int c, gstream *stream) size_t gsread(void *ptr, size_t size, size_t nmemb, gstream *stream) size_t gswrite(void *ptr, size_t size, size_t nmemb, gstream *stream) int gsputs(const char *s, gstream *stream) char *gsgets(char *s, int n, gstream *stream) int gsprintf(gstream *stream, const char *format, ...) int gsungetc(int c, gstream *stream) int gseof(gstream *stream) int gserror(gstream *stream) Then, the other modules provide: osstream.c: int gsopenosr(char *fname, gstream *stream) - opens a file for read int gsopenosw(char *fname, gstream *stream) - opens a file for write ramstream.c int gsopenramsend(wimp_msgstr *msg, gstream *stream) int gsopenramfetch(wimp_msgstr *msg, gstream *stream) - for the ram data transfer protocol xferstream.c int gsopenxferrecv(wimp_eventstr *e, gstream *stream) int gsopenxfersend( char *leafname, int filetype, int estsize, int *safeptr, gstream *stream) The module savebox.c has one or two bugs (template handling), but it does show how to implement save boxes using gstream. Things to do ------------ * Add stream types for Acorn's Cut/Copy/Paste protocol * Add stream types to handle RISC OS 3 pipes - so that a m/tasking app can not only write to a pipe but also read from one without hanging. * Add stream types to write to screen and read from keyboard. If in m/tasking app, these stream types will open a window on the screen for I/O. Suggestions wanted. * Try to allow saving back to sending task (currently won't work - has to be trapped by xferrecv to avoid crash) * Improve the comments Example code ------------ Here is a little bit of code to show how gstream can be used. It should be regsistered with as a handler for win_ICONBARLOAD What it does is when a file is dragged to the app, the function will use gsopenxferrecv to open a read stream (thus responding to the dataload or datasave message), then open an internal write stream, and copy the incoming data into the internal stream. After closing the internal write stream and the xferrecv stream, it opens a xfersend stream (using savebox()) and opens the internal buffer, copying the data from the internal buffer to the write stream. I bet that's a *lot* simpler than it is using RISC_OSLib's xfersend, xferrecv and saveas modules. :-) static void icon_load_handler(wimp_eventstr *e, void *handle) { gstream stream, internal_buffer; int safe, type, load_succeded=TRUE; char name[256]="File"; switch(e->data.msg.hdr.action) { case wimp_MDATALOAD: strcpy(name,e->data.msg.data.dataload.name); type=e->data.msg.data.dataload.type; break; case wimp_MDATASAVE: strcpy(name,e->data.msg.data.datasave.leaf); type=e->data.msg.data.datasave.type; break; } visdelay_begin(); if (gsopenxferrecv(e,&stream)) { if (gsopeninternalw(&internal_buffer)) { char dummy[256]; int c; while((c=gsread((void *) dummy, 1, 256, &stream))!=0) { gswrite(dummy,1,c,&internal_buffer); if (gserror(&stream) || gserror(&internal_buffer)) { werr(FALSE,"Error in load"); break; } } gsclose(&internal_buffer); if (gserror(&stream) || gserror(&internal_buffer)) { load_succeded=FALSE; gsdiscardinternal(&internal_buffer); } } else load_succeded=FALSE; gsclose(&stream); } else load_succeded=FALSE; visdelay_end(); if (load_succeded) { if (gsopeninternalr(&internal_buffer)) { if (savebox(name,1024,type,&safe,&stream)) { char dummy[256]; int c; visdelay_begin(); while((c=gsread((void *) dummy, 1, 256, &internal_buffer))!=0) { gswrite(dummy,1,c,&stream); if (gserror(&stream)) break; } visdelay_end(); gsclose(&stream); } gsclose(&internal_buffer); } gsdiscardinternal(&internal_buffer); } } Simon Proven - sproven@cs.strath.ac.uk