On Tuesday 11 October 2005 06:26 pm, Geo Carncross wrote: > On Tue, 2005-10-11 at 17:45 -0400, Paul Alfille wrote: > > Ok, Geo. I'm convinced. > > > > Look in the CVS for owcapi. (libowcapi.so.0.0.0) > > > > Very simple library: > > int OW_init( const char * device ) ; > > What's device? Why is the programmer concerned? Isn't it a target-system > specified thing?
It's the same "device" used in owfs and owhttpd and owserver (and owperl,...) Something like "/dev/ttyS0" or "3333" or "u" for serial, tcp and USB respectively. It seems no different than using a device name in an "open" or "fopen" call in C for file or serial device access. We could certainly use a default environment variable. Hell, we could do that for owfs and owhttpd as well. Or the user of the C library could pull the variable. The whole code for owcapi.c is about 160 lines, including 3 different syntaxes for the init call, comments, spaces, etc. For instance OW_put is: int OW_put( const char * path, const char * buffer, size_t buffer_length ) { /* Check the parameters */ if ( buffer==NULL || buffer_length==0 ) return -EINVAL ; if ( path==NULL ) return -EINVAL ; return FS_write(path,buffer,buffer_length,0) ; } The advantage is it's simplicity. > > Perhaps the environment variable OWDEVICE would be more appropriate. > > If you're really intent on letting the user set it here, perhaps making > device==NULL should use getenv("OWDEVICE") - and if that's not > specified, perhaps some automatic hunting? > > If hunting is really inappropriate, have OW_init() simply fail. > > > int OW_get( const char * path, char * buffer, int buffer_length ) ; > > Don't let the programmer specify a buffer length for gets. It's prone to > programming errors. The extra malloc() isn't going to cause any real > problems, but if you're worried, a: > We could do that, and demand the programmer "free" the buffer. The length would be problematic, since some "get" values are binary rather than ascii so can't be handled by normal string functions. > int OW_get_buffer(const char *path,char*buffer,int buffer_length); > > in addition to: > > int OW_get(const char *path,char**buffer); > > > int OW_put( const char * path, const char * buffer, int buffer_length ) ; > > void OW_finish( void ) ; > > Most of my programs are small. I write them small so I can avoid bugs > (security or otherwise), so I have wrappers that look like this: > > void*memalloc(unsigned int s) { > void*q; > if (!(q = malloc(s))) { perror("malloc");exit(255); } > return q; > } > > This does the right thing 99% of the time, so I'd recommend some > additional api: > > void OW_errhandle(int(*f)(int e)); > > that sets up global error handling for OW: > f == function > this calls the function when an error occurs- > useful for emulating (or using) real exceptions > in gcc, OBJC, or C++. if it returns, this is > the "real" return code used. > Some supplied functions: > > int _OW_err_ansi(int e) { return e; } > use error reporting like ANSI/POSIX C does. This means > the user is expected to check return codes. > > int _OW_err_throw(int e) { > if (e > CRITICAL) { perror("whatever"); exit(255); } > return e; > } > this should be the default. > > automatically exits on critical errors. Note this isn't > the same as nonrecoverable errors- those should ALWAYS > kill the current process (preferably with abort()) > > critical errors are the kind that it's probably the USER > that wants to recover from them and not the programmer. > good examples are: > * out of memory > * invalid or nonfunctioning device spec (OW_init) > * put format specification violation > > I also recommend: > > void OW_blocking(int f); > if f is true, OW blocks. this is the default. > if f is false, OW will return OW_BUSY instead of blocking. It will also > setjmp() a special buffer. Until OW_completion() > is called, all other OW_* operations generate a critical error, > OW_NOSTACK > > int OW_completion(void); > when called, the stack will be guaranteed to be equal-to > or deeper in depth than when the last blocking call that > returned OW_BUSY. It then performs a longjmp() to the > last operation to complete it. > > if it returns (and it returns if still busy, or if no > operation is pending), it returns a file descriptor that > can be select()d on to determine whether or not an operation > will block. > > > APIs do NOT need to be complicated in order to be useful. The trick is > to make sure the user can step up the API as they need it. > > Btw, specify in documentation: > OW_* calls aren't reetrant or thread-safe. Serialize yourself. > Actually, I think OW_get and OW_put are thread safe. They use only the stack, and libow is thread-safe. ------------------ I guess my question, Geo, is how much effort and complexity is warranted. The memory allocation choice is purely a matter of style. OW_put will need to know the buffer length, however, since some field can get null bytes in their binary data. The "char ** buffer" parameter in OW_get can scare people, too. libowcapi currently mirrors the owperl API rather closely. It is an admittedly sparse API, but targetted at programs where 1-wire performance and features are secondary to ease of use. For me, the big advantage is that keeping a simple and similar API makes maintainance and documentation far easier. There is no reason why a C program can't call libow itself, rather than using libowcapi as a wrapper. In fact, libowcapi shows how to get started. If you have interest and a need for the C-API, feel free to modify or start another C wrapper targetted at a different set of users. Serg and Peter have taken owtcl and owpython under their respective wings . ------------------------------------------------------- This SF.Net email is sponsored by: Power Architecture Resource Center: Free content, downloads, discussions, and more. http://solutions.newsforge.com/ibmarch.tmpl _______________________________________________ Owfs-developers mailing list Owfs-developers@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/owfs-developers