/[webpac]/trunk2/openisis/lio.c
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Annotation of /trunk2/openisis/lio.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 239 - (hide annotations)
Mon Mar 8 17:49:13 2004 UTC (20 years ago) by dpavlin
Original Path: trunk/openisis/lio.c
File MIME type: text/plain
File size: 25424 byte(s)
including openisis 0.9.0 into webpac tree

1 dpavlin 237 /*
2     openisis - an open implementation of the CDS/ISIS database
3     Version 0.8.x (patchlevel see file Version)
4     Copyright (C) 2001-2003 by Erik Grziwotz, erik@openisis.org
5    
6     This library is free software; you can redistribute it and/or
7     modify it under the terms of the GNU Lesser General Public
8     License as published by the Free Software Foundation; either
9     version 2.1 of the License, or (at your option) any later version.
10    
11     This library is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14     Lesser General Public License for more details.
15    
16     You should have received a copy of the GNU Lesser General Public
17     License along with this library; if not, write to the Free Software
18     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19    
20     see README for more information
21     EOH */
22    
23     /*
24     $Id: lio.c,v 1.43 2003/06/11 14:53:08 kripke Exp $
25     I/O support for the openisis library.
26     */
27     #include <stdlib.h>
28     #include <stdio.h> /* vsnprintf */
29     #include <stdarg.h>
30     #include <string.h>
31     #include <errno.h>
32     #include <limits.h> /* PATH_MAX */
33     #include <sys/types.h>
34    
35     #ifdef WIN32
36     #define WIN32_LEAN_AND_MEAN
37     #define NONAMELESSUNION
38     # include <windows.h>
39     # include <winsock.h>
40     # define SHUT_RD SD_RECEIVE
41     # define SHUT_WR SD_SEND
42     # define SHUT_RDWR SD_BOTH
43     # define snprintf _snprintf
44     # define vsnprintf _vsnprintf
45     # include <sys/timeb.h>
46     #else /* have operating system */
47     # define __USE_UNIX98
48     /*
49     # define _POSIX_MAPPED_FILES
50     # define _POSIX_SYNCHRONIZED_IO
51     */
52     # include <fcntl.h> /* or try unixio */
53     # ifndef O_SYNC
54     # if defined( __FreeBSD__ )
55     # define O_SYNC O_FSYNC
56     # else
57     # define O_SYNC 0
58     # endif
59     # endif
60     # include <sys/stat.h>
61     # include <sys/file.h> /* flock */
62     # include <sys/mman.h>
63     # include <sys/socket.h>
64     # include <unistd.h>
65     #endif /* WIN32 */
66     #include <sys/time.h> /* gettimeofday */
67     #include <time.h> /* localtime */
68    
69     #include "luti.h" /* logging */
70     #include "lses.h"
71     #include "lstr.h" /* log_str */
72     #include "lio.h"
73    
74    
75    
76     /* ************************************************************
77     private data
78     */
79     static int init;
80    
81     #ifdef WIN32
82     /* it's not thread-safe, anyway */
83     static HANDLE hand[128];
84     #endif
85    
86     /* ************************************************************
87     private functions
88     */
89     #ifndef WIN32
90     static int lerrno ( int errno_ )
91     {
92     switch ( errno_ ) {
93     case EINTR:
94     case EAGAIN:
95     return ERR_OK;
96     case EFAULT: /* structurally bad address */
97     case ENAMETOOLONG:
98     case ELOOP:
99     return ERR_FAULT;
100     case EBADF: /* file "does not exist" */
101     case ENOENT:
102     case ENOTDIR:
103     return ERR_BADF;
104     case EIO: /* file "is not accessible" */
105     case EEXIST:
106     case EISDIR:
107     case EACCES:
108     case ENXIO:
109     case ENODEV:
110     case EROFS:
111     case ETXTBSY:
112     case ENOSPC:
113     case EPIPE:
114     case ESPIPE:
115     return ERR_IO;
116     case ENOMEM:
117     case EMFILE:
118     case ENFILE:
119     return ERR_NOMEM;
120     case EBUSY:
121     return ERR_BUSY;
122     }
123     return ERR_INVAL;
124     } /* lerrno */
125    
126     /**
127     check unixio errno.
128     if harmless, return != 0 (is ok).
129     else return 0, possibly closing the file
130     */
131     int unixio_ok ( int *file, int io )
132     {
133     switch ( errno ) {
134     case EINTR:
135     case EAGAIN:
136     return !0;
137     case EFAULT:
138     case ESPIPE:
139     break;
140     default:
141     log_msg( LOG_IOERR, "closing file %x for %x on %d", *file, io, errno );
142     lio_close( file, io );
143     }
144     return 0;
145     } /* unixio_err */
146     #endif
147    
148    
149     /**
150     return wether printing should be skipped
151     */
152     static int seterrlev ( int *err, int *level, int code )
153     {
154     *level = LOG_MASK & code;
155     *err = ERR_MASK & code;
156     if ( ! code )
157     return 0;
158     if ( ! *err )
159     switch ( *level ) {
160     case LOG_FATAL: *err = ERR_IDIOT; break;
161     case LOG_ERROR: *err = ERR_INVAL; break;
162     case LOG_IOERR:
163     #ifndef WIN32
164     if ( EAGAIN == errno || EINTR == errno ) /* no error */
165     return !0;
166     case LOG_SYSERR:
167     *err = lerrno( errno );
168     #else
169     case LOG_SYSERR:
170     *err = ERR_INVAL;
171     #endif
172     break;
173     default:
174     *err = 0;
175     }
176     else if ( ! *level ) {
177     if ( ERR_TRASH <= *err )
178     *level = LOG_FATAL;
179     else if ( ERR_IO <= *err )
180     *level = LOG_SYSERR;
181     else if ( ERR_FAULT <= *err )
182     *level = LOG_ERROR;
183     else
184     *level = LOG_VERBOSE;
185     }
186     return *level > (int)log_lev;
187     } /* seterrlev */
188    
189    
190     /* ************************************************************
191     package data
192     */
193    
194     CLockFunc *lio_lock;
195     LogLevel log_lev = LOG_ERROR;
196     int log_flush = 1;
197    
198     #ifndef WIN32
199     # define LIO_STATICFD( nm, flg ) int nm = flg
200     #else
201     # define LIO_STATICFD( nm, flg ) int nm
202     #endif
203     LIO_STATICFD( lio_in , LIO_IN | 0 );
204     LIO_STATICFD( lio_out, LIO_OUT | 1 );
205     LIO_STATICFD( lio_err, LIO_OUT | 2 );
206    
207     /* ************************************************************
208     package functions
209     */
210     static void lio_init ()
211     {
212     #ifndef WIN32
213     /* static */
214     #else
215     lio_in = lio_open( "CONIN$", LIO_RD );
216     lio_out = lio_open( "CONOUT$", LIO_WR );
217     lio_err = lio_open( "oisiserr.txt", LIO_WR|LIO_CREAT );
218     #endif
219     } /* lio_init */
220    
221    
222     /*
223     has "official" name, since visible to linker
224     use ld -init openIsisInit for shared object
225     */
226     void openIsisInit ()
227     {
228     static const char inimsg[] = "openIsisInit\n";
229     const char *ll = getenv("OPENISIS_LOGLEVEL");
230    
231     if ( init )
232     return;
233     init = 42;
234     lio_init();
235     if ( ll ) {
236     cLog( ll[0], 0 );
237     #ifndef NDEBUG
238     if ( LOG_DEBUG <= log_lev )
239     lio_write( &lio_err, inimsg, sizeof(inimsg)-1 );
240     #endif
241     }
242     if ( getenv("OPENISIS_LOGBUFFERED") )
243     log_flush = 0;
244     lses_init();
245     } /* openIsisInit */
246    
247    
248     /*
249     use ld -fini openIsisFini for shared object
250     */
251     void openIsisFini ()
252     {
253     static const char finimsg[] = "openIsisFini\n";
254    
255     lses_fini();
256     #ifndef NDEBUG
257     if ( LOG_DEBUG <= log_lev )
258     lio_write( &lio_err, finimsg, sizeof(finimsg)-1 );
259     #endif
260     } /* openIsisFini */
261    
262    
263     void linit () /* called by cOpen() */
264     {
265     if ( init ) /* we're an .so -- implicitly initialized */
266     return;
267     /* we're statically linked */
268     openIsisInit();
269     atexit( openIsisFini );
270     }
271    
272    
273    
274    
275     int lio_open ( const char *name, int flags )
276     {
277     int fd = -1;
278     int faillvl = (LIO_TRY == ((LIO_TRY|LIO_WR)&flags))
279     ? (LOG_VERBOSE|ERR_BADF) : LOG_INFO|ERR_BADF /* LOG_IOERR too annoying ... */;
280    
281     if ( '&' == name[0] ) {
282     int i = 1;
283     fd = 0;
284     while ( '0' <= name[i] && name[i] <= '9' )
285     fd = 10*fd + name[i++] - '0';
286     }
287    
288     #ifndef WIN32
289     if ( 0 > fd ) {
290     int f = !(LIO_WR&flags) ? O_RDONLY
291     : ((LIO_RD&flags) ? O_RDWR : O_WRONLY);
292     if ( LIO_CREAT & flags && LIO_WR & flags ) f |= O_CREAT;
293     if ( LIO_NBLK & flags ) f |= O_NONBLOCK;
294     if ( LIO_SYNC & flags ) f |= O_SYNC;
295     if ( LIO_TRUNC & flags ) f |= O_TRUNC;
296     if ( ! (LIO_SEEK & flags) ) f |= O_APPEND;
297     fd = open( name, f, 00664 ); /* let umask finetune */
298     if ( LIO_FD < fd ) {
299     log_msg( LOG_ERROR, "got big fd %d", fd );
300     fd = -1;
301     }
302     if ( 0 > fd )
303     return log_msg( faillvl, "could not open '%s' %x", name, flags );
304     if ( LIO_FLOCK & flags ) {
305     const char *lck = LIO_WR&flags ? "exclusive" : "shared";
306     /*
307     we want an advisory lock, so that tail -f can read changes.
308     SYSV/POSIX fcntl might be mandatory, depending on files mode bits
309     (and filesystem). Therefore prefer BSD style flock, if available.
310    
311     under linux, flock is never mandatory, while lockf/fcntl may be.
312     /usr/src/linux/Documentation/mandatory.txt
313     moreover fcntl attempts to lock over NFS, which is a very feeble idea.
314     */
315     #ifndef LOCK_SH
316     /*
317     on solaris, LOCK_SH is declared only with the /usr/ucb/cc includes.
318     their flock on fcntl emulation "must not be used in MT environments".
319     */
320     struct flock fl;
321     memset( &fl, 0, sizeof(fl) );
322     fl.l_type = LIO_WR&flags ? F_WRLCK : F_RDLCK;
323     fl.l_whence = SEEK_SET;
324     fl.l_start = 0;
325     fl.l_len = 1; /* 0 locks the whole file -- could be mandatory :( */
326     #endif
327     log_msg( LOG_VERBOSE, "attempting %s lock on '%s'", lck, name );
328     if (
329     #ifndef LOCK_SH
330     /* hmm .. at least this is "POSIX" */
331     fcntl( fd, LIO_WLOCK&flags ? F_SETLKW : F_SETLK, &fl )
332     #else
333     flock( fd,
334     (LIO_WR&flags ? LOCK_EX : LOCK_SH) | (LIO_WLOCK&flags ? 0 : LOCK_NB) )
335     #endif
336     ) {
337     close( fd );
338     return log_msg( ERR_BADF, "could not get %s lock on '%s'", lck, name );
339     }
340     }
341     } else if ( -1 == fcntl( fd, F_GETFL ) ) /* check open */
342     return -ERR_BADF;
343     #else
344     if ( 0 > fd ) {
345     HANDLE h;
346     int acc = 0;
347     int shr = FILE_SHARE_READ | (LIO_FLOCK&flags ? 0 : FILE_SHARE_WRITE);
348     int cre = (LIO_CREAT & flags && LIO_WR & flags)
349     ? (LIO_TRUNC & flags) ? CREATE_ALWAYS : OPEN_ALWAYS
350     : (LIO_TRUNC & flags) ? TRUNCATE_EXISTING : OPEN_EXISTING;
351     int f = (LIO_WR&flags) ? FILE_ATTRIBUTE_ARCHIVE : FILE_ATTRIBUTE_NORMAL;
352    
353     if ( LIO_RD & flags ) acc |= GENERIC_READ; /* FILE_READ_DATA; */
354     if ( LIO_WR & flags ) acc |= GENERIC_WRITE;
355     /* some routines like GetFileSize are "documented" to require
356     GENERIC_READ/GENERIC_WRITE, so it may not be sufficient to use:
357     (LIO_SEEK & flags) ? FILE_WRITE_DATA : FILE_APPEND_DATA */;
358     /* if ( LIO_NBLK & flags ) f |= FILE_FLAG_OVERLAPPED; */
359     if ( LIO_SYNC & flags ) f |= FILE_FLAG_WRITE_THROUGH;
360     f |= (LIO_SEEK & flags) ? FILE_FLAG_RANDOM_ACCESS
361     : FILE_FLAG_SEQUENTIAL_SCAN;
362    
363     for ( fd=0; hand[fd]; )
364     if ( sizeof(hand)/sizeof(hand[0]) == ++fd )
365     return -EMFILE;
366     h = CreateFile( name, acc, shr, 0, cre, f, 0 );
367     if ( INVALID_HANDLE_VALUE == h )
368     return log_msg( faillvl, "could not open '%s' %x", name, flags );
369     hand[fd] = h;
370     if ( (LIO_WR & flags) && ! (LIO_SEEK & flags) )
371     SetFilePointer( hand[fd], 0, 0, FILE_END );
372     } else if ( (int)(sizeof(hand)/sizeof(hand[0])) <= fd || ! hand[fd] )
373     return -ERR_BADF;
374     #endif
375     fd |= flags & LIO_WANT;
376     /* add status flags */
377     if ( LIO_RD & flags ) fd |= LIO_IN;
378     if ( LIO_WR & flags ) fd |= LIO_OUT;
379     return fd;
380     } /* lio_open */
381    
382    
383     int lio_close ( int *file, int flags )
384     {
385     int fd = 0xffff & *file;
386     int op = LIO_INOUT & *file;
387     int cl = LIO_INOUT & flags;
388     if ( ! op || ! cl )
389     return 0;
390     if ( 0 > *file ) { /* probably failed open */
391     *file = 0;
392     return 0;
393     }
394     *file &= ~cl;
395     if ( op & ~cl ) { /* remains partly open */
396     int how = (LIO_IN & cl) ? SHUT_RD : SHUT_WR;
397     if ( !(LIO_SOCK & fd) )
398     return 0;
399     #ifndef WIN32
400     if ( ! shutdown( fd, how ) )
401     return 0;
402     #else
403     /* TODO */
404     #endif
405     log_msg( LOG_SYSERR, "could not shutdown sock %d %d", fd, how );
406     return errno ? -errno : -1;
407     }
408     #ifndef WIN32
409     for ( fsync( fd ); close( fd ); errno = 0 )
410     if ( EINTR != errno ) {
411     log_msg( LOG_SYSERR, "could not close file %d", fd );
412     return errno ? -errno : -1;
413     }
414     #else
415     if ( (int)(sizeof(hand)/sizeof(hand[0])) <= fd )
416     return -ERR_BADF;
417     CloseHandle( hand[fd] );
418     hand[fd] = 0;
419     #endif
420     return 0;
421     } /* lio_close */
422    
423    
424     int lio_size ( int file )
425     {
426     if ( !((LIO_IN|LIO_OUT) & file) )
427     return log_msg( ERR_BADF, "*file 0x%x not open for stat", file );
428     {
429     int fd = LIO_FD & file;
430     #ifndef WIN32
431     struct stat s;
432     return fstat( fd, &s ) ? 0 : s.st_size;
433     #else
434     return GetFileSize( hand[fd], 0 );
435     #endif
436     }
437     } /* lio_size */
438    
439    
440     unsigned lio_time ( int file )
441     {
442     if ( !((LIO_IN|LIO_OUT) & file) )
443     return log_msg( ERR_BADF, "*file 0x%x not open for stat", file );
444     {
445     int fd = LIO_FD & file;
446     #ifndef WIN32
447     struct stat s;
448     return fstat( fd, &s ) ? 0 : (unsigned)s.st_mtime;
449     #else
450     FILETIME foo; /* time since 160101011200 UTC in hundred nanoseconds !!! */
451     ull bar;
452     if ( ! GetFileTime( hand[fd], 0, 0, &foo ) )
453     return 0;
454     bar = ((ull)foo.dwHighDateTime<<32 | (ull)foo.dwLowDateTime) / ULL(10000000);
455     return (unsigned)(bar - ULL(11644473600));
456     #endif
457     }
458     } /* lio_size */
459    
460    
461     int lio_read ( int *file, void *buf, unsigned count )
462     {
463     if ( !(LIO_IN & *file) )
464     return log_msg( ERR_BADF, "*file 0x%x not open for reading", *file );
465     {
466     int fd = LIO_FD & *file;
467     #ifndef WIN32
468     int got = read( fd, buf, count );
469     /* log_msg( LOG_ERROR, "read 0x%x got %d", *file, got ); */
470     if ( got )
471     return 0 < got ? got
472     : unixio_ok( file, LIO_IN ) ? 0
473     : log_msg( LOG_IOERR, "could not read %d bytes from %d", count, fd );
474     else if ( LIO_SEEK & *file ) /* special EOF treatment */
475     return 0;
476     else {
477     lio_close( file, LIO_IN );
478     return -ERR_EOF;
479     }
480     #else
481     DWORD got = 0;
482     int ok = ReadFile( hand[fd], buf, count, &got, 0 );
483     return ok ? got
484     : log_msg( LOG_IOERR, "could not read %d bytes from %d", count, fd );
485     #endif
486     }
487     } /* lio_read */
488    
489    
490     int lio_write ( int *file, const void *buf, unsigned count )
491     {
492     if ( !(LIO_OUT & *file) )
493     return log_msg( ERR_BADF, "*file 0x%x not open for writing", *file );
494     {
495     int fd = LIO_FD & *file;
496     #ifndef WIN32
497     int got = write( fd, buf, count );
498     return 0 <= got ? got
499     : unixio_ok( file, LIO_OUT ) ? 0
500     : log_msg( LOG_IOERR, "could not read %d bytes from %d", count, fd );
501     #else
502     DWORD got = 0;
503     int ok = WriteFile( hand[fd], buf, count, &got, 0 );
504     return ok ? got
505     : log_msg( LOG_IOERR, "could not read %d bytes from %d", count, fd );
506     #endif
507     }
508     } /* lio_write */
509    
510    
511    
512     int lio_seek ( int *file, int offset )
513     {
514     if ( !(LIO_INOUT & *file) )
515     return log_msg( ERR_BADF, "*file 0x%x not open", *file );
516     {
517     int fd = LIO_FD & *file;
518     #ifndef WIN32
519     int got = (int)lseek( fd, offset, SEEK_SET );
520     return offset == got ? 0
521     : log_msg( LOG_IOERR, "could not seek to %d", offset );
522     #else
523     return 0xffffffff /* "INVALID_SET_FILE_POINTER" */
524     == SetFilePointer( hand[fd], offset, 0, FILE_BEGIN )
525     ? -1 : 0;
526     #endif
527     }
528     } /* lio_seek */
529    
530    
531     int lio_pread ( int *file, void *buf, unsigned count, int offset )
532     {
533     if ( !(LIO_IN & *file) )
534     return log_msg( ERR_BADF, "*file 0x%x not open for reading", *file );
535     {
536     int fd = LIO_FD & *file;
537     #ifndef WIN32
538     int got = pread( fd, buf, count, offset );
539     return 0 <= got ? got
540     : unixio_ok( file, LIO_IN ) ? 0
541     : log_msg( LOG_IOERR, "could not read %d bytes from %d at %d",
542     count, fd, offset );
543     #else
544     return 0xffffffff /* "INVALID_SET_FILE_POINTER" */
545     == SetFilePointer( hand[fd], offset, 0, FILE_BEGIN )
546     ? -1 : lio_read( file, buf, count );
547     #endif
548     }
549     } /* lio_pread */
550    
551    
552     int lio_pwrite ( int *file, const void *buf, unsigned count, int offset )
553     {
554     if ( !(LIO_OUT & *file) )
555     return log_msg( ERR_BADF, "*file 0x%x not open for writing", *file );
556     {
557     int fd = LIO_FD & *file;
558     #ifndef WIN32
559     int got = pwrite( fd, buf, count, offset );
560     return 0 <= got ? got
561     : unixio_ok( file, LIO_OUT ) ? 0
562     : log_msg( LOG_IOERR, "could not read %d bytes from %d at %d",
563     count, fd, offset );
564     #else
565     return 0xffffffff /* "INVALID_SET_FILE_POINTER" */
566     == SetFilePointer( hand[fd], offset, 0, FILE_BEGIN )
567     ? -1 : lio_write( file, buf, count );
568     #endif
569     }
570     } /* lio_pwrite */
571    
572    
573     int lio_trunc ( int *file, int offset )
574     {
575     int fd = LIO_FD & *file;
576     #ifndef WIN32
577     ftruncate( fd, offset );
578     #else
579     /* SetFileValidData( hand[fd], offset ); XP only */
580     return 0xffffffff /* "INVALID_SET_FILE_POINTER" */
581     == SetFilePointer( hand[fd], offset, 0, FILE_BEGIN )
582     ? -1 : SetEndOfFile( hand[fd] )
583     ? 0 : log_msg( LOG_IOERR, "could not truncate %d to %d", fd, offset );
584     #endif
585     return 0;
586     } /* lio_trunc */
587    
588    
589     int lio_mmap ( int *file, void **map, int length )
590     {
591     if ( ! map )
592     return log_msg( ERR_INVAL, "no map" );
593     if ( 0 >= length && 0 >= (length = lio_size( *file )) ) {
594     *map = 0;
595     return length;
596     }
597     #ifndef WIN32
598     #if 0 /* solaris states it will round up itself, and linux does */
599     {
600     static int ps = 0;
601     if ( !ps )
602     ps = sysconf(_SC_PAGESIZE); /* getpagesize(); */
603     }
604     #endif
605     if ( file ) {
606     if ( *map )
607     return msync( *map, length, (LIO_SYNC & *file)
608     ? (MS_SYNC|MS_INVALIDATE) : MS_ASYNC )
609     ? log_msg( LOG_IOERR, "msync" ) : 0;
610     *map = mmap( 0, length, PROT_READ | ((LIO_OUT&*file) ? PROT_WRITE : 0),
611     MAP_SHARED, LIO_FD&*file, 0 );
612     if ( MAP_FAILED != *map )
613     return length;
614     *map = 0;
615     return log_msg( ERR_NOMEM, "mmap failed on fd %08x", *file );
616     }
617     if ( ! *map )
618     return log_msg( ERR_INVAL, "no *map" );
619     munmap( *map, length );
620     *map = 0;
621     return 0;
622     #else
623     /* awfully complicated here
624     -- need CreateFileMapping, MapViewOfFile
625     stupid piece of shrott
626     true mapping supported in NT family only, 9x copies to swap
627     */
628     *map = 0;
629     return 0;
630     #endif
631     } /* lio_mmap */
632    
633    
634     int lio_slurp ( char **buf, int sz, const char *name, int opt )
635     {
636     int file = lio_open( name, LIO_RD|LIO_SEEK|(opt ? LIO_TRY : 0) );
637     int size;
638     int ret = -ERR_NOMEM;
639     char *p = *buf;
640     /* log_msg( LOG_IOERR, "open '%s' = %d", name, file ); */
641     if ( 0 > file )
642     return file;
643     size = lio_size( file );
644     if ( 0 >= size )
645     return size;
646     if ( size > sz )
647     LOG_OTO( done, ( ERR_INVAL, "file '%.30s' too big: %d > %d",
648     name, size, sz ) );
649     if ( ! p && !(p = mAlloc(size)) )
650     goto done;
651     ret = lio_read( &file, p, size );
652     if ( size == ret )
653     *buf = p;
654     else {
655     if ( ret >= 0 )
656     ret = log_msg( ERR_IO, "OOPS! got %d of %d bytes from '%.30s'",
657     ret, size, name );
658     if ( ! *buf )
659     free( p );
660     }
661     done:
662     lio_close( &file, LIO_INOUT );
663     return ret;
664     } /* lio_slurp */
665    
666    
667     int log_msg ( int code, const char *fmt, ... )
668     {
669     static const char toolong[] = ": message too long !!!\n";
670     int err, level;
671     va_list ap;
672     va_start( ap, fmt );
673     #if 0
674     ret = sMsg( MSG_VA|code, fmt, ap );
675     make log_msg unbuffered, use sMsg for buffered logging
676     #else
677     if ( ! seterrlev( &err, &level, code ) && (LIO_OUT & lio_err) ) {
678     char buf[4096];
679     int len = vsnprintf( (char*)buf, sizeof(buf), fmt, ap );
680     if ( 0 < len && len < (int)sizeof(buf) ) {
681     buf[len++] = '\n';
682     lio_write( &lio_err, buf, len );
683     } else {
684     lio_write( &lio_err, fmt, strlen(fmt) );
685     lio_write( &lio_err, toolong, sizeof(toolong)-1 );
686     }
687     }
688     #endif
689     va_end( ap );
690     return -err;
691     } /* log_msg */
692    
693    
694     void log_str ( LogLevel level, int *rec, const char **desc )
695     {
696     int occ = -1;
697     int nmbrs = LSTRFIX(*rec);
698     int *mbr = rec+1;
699     char *base = (char*)rec;
700    
701     if ( level > log_lev || ! desc )
702     return;
703    
704     sMsg( 2, "record %.20s\n", *desc++ );
705     /* dump the fixed part (occ==-1) and each occurrence of repeated part. */
706     for ( ;/* occ < LSTROCC(*dst) */; ) { /* dump one part */
707     int i;
708     for ( i=0; i<nmbrs; i++, mbr++ ) { /* dump one mbr */
709     if ( '\'' == *desc[i] )
710     sMsg( 2, "%3d.%2d %4.4s %.67s<\n",
711     occ, i, desc[i], base+*mbr );
712     else
713     sMsg( 2, "%3d.%2d %4.4s 0x%08x = %d\n",
714     occ, i, desc[i], *mbr, *mbr );
715     } /* for mbrs */
716    
717     if ( ++occ >= LSTROCC(*rec) )
718     break;
719     if ( ! occ ) { /* was the fixed part, setup for repeated */
720     nmbrs = LSTRREP(*rec);
721     desc += i;
722     }
723     }
724     } /* log_str */
725    
726    
727     void log_hex ( LogLevel level, const void *mem, int len )
728     {
729     const char *p = (const char *)mem;
730     char buf[82];
731     int i = 0;
732    
733     if ( level > log_lev )
734     return;
735     for ( ; i<len; i+=16, p+=16 ) {
736     int j = 0;
737     int left = len -i;
738     int pos = 10;
739     sprintf( buf, "%08x ", i );
740     if ( left > 16 )
741     left = 16;
742     for ( ; j < left; j++ ) {
743     sprintf( buf+pos, "%02x", p[j] );
744     pos += 2;
745     if ( 3 == j%4 ) { buf[pos++] = ' '; buf[pos++] = ' '; }
746     }
747     for ( ; j < 16; j++ ) {
748     buf[pos++] = ' '; buf[pos++] = ' ';
749     if ( 3 == j%4 ) { buf[pos++] = ' '; buf[pos++] = ' '; }
750     }
751     /* got 50 = 10 + 16*2 + 4*2 */
752     for ( j=0; j < left; j++ ) /* add up to 16 */
753     buf[pos++] = (0x60 & p[j]) ? p[j] : '.';
754     buf[pos++] = '\n';
755     buf[pos] = 0;
756     sMsg( 2, "%.*s", pos, buf );
757     }
758     } /* log_hex */
759    
760    
761     /* ************************************************************
762     public functions
763     */
764     int timeUpd ( Tm *tm )
765     {
766     Tm o;
767     #ifdef WIN32
768     struct _timeb tb;
769     _ftime( &tb );
770     if ( !tm )
771     return tb.time;
772     o = *tm;
773     tm->millis = tb.time*LLL(1000) + tb.millitm;
774     #else
775     struct timeval tv;
776     gettimeofday( &tv, 0 );
777     if ( !tm )
778     return tv.tv_sec;
779     o = *tm;
780     tm->millis = tv.tv_sec*LLL(1000) + tv.tv_usec/1000;
781     #endif
782     return (int)(tm->millis - o.millis);
783     } /* timeUpd */
784    
785    
786     static int timeLoc ( struct tm *t, Tm *tm )
787     {
788     Tm x;
789     time_t tt;
790     if ( !tm || !tm->millis )
791     timeUpd( tm ? tm : (tm = &x) );
792     tt = (time_t)(tm->millis / 1000);
793     #ifdef WIN32 /* did I mention it's not threadsafe ? */
794     *t = *localtime( &tt );
795     #else
796     localtime_r( &tt, t );
797     #endif
798     return (int)(tm->millis % 1000);
799     } /* timeLoc */
800    
801     char *timeGtf ( char *buf, Tm *tm )
802     {
803     struct tm t;
804     timeLoc( &t, tm );
805     snprintf( buf, 15, "%04u%02u%02u%02u%02u%02u",
806     1900+t.tm_year, 1+t.tm_mon, t.tm_mday,
807     t.tm_hour, t.tm_min, t.tm_sec );
808     buf[14] = 0;
809     return buf;
810     } /* timeGtf */
811    
812    
813     char *timeGtfm ( char *buf, Tm *tm )
814     {
815     struct tm t;
816     int millis = timeLoc( &t, tm );
817     snprintf( buf, 19, "%04u%02u%02u%02u%02u%02u%03u",
818     1900+t.tm_year, 1+t.tm_mon, t.tm_mday,
819     t.tm_hour, t.tm_min, t.tm_sec, millis );
820     buf[18] = 0;
821     return buf;
822     } /* timeGtfm */
823    
824    
825     void timeSleep ( Tm *tm )
826     {
827     #ifdef WIN32
828     Sleep( tm->millis );
829     #else
830     struct timespec ts;
831     ts.tv_sec = tm->millis / 1000;
832     ts.tv_nsec = 1000000 * (int)(tm->millis % 1000);
833     nanosleep( &ts, 0 );
834     #endif
835     } /* timeSleep */
836    
837    
838     int ioStream ( Ios *s, int op )
839     {
840     Buf *b;
841     switch ( op ) {
842     case LIO_SSIZE:
843     return sizeof(Ios);
844     case LIO_SOPEN:
845     s->pos = s->b.fill = s->b.done = 0;
846     case LIO_SCLOSE:
847     s->file &= ~LIO_INOUT;
848     return 0;
849     case LIO_SPURGE:
850     if ( !(LIO_IN & s->file) )
851     return -ERR_BADF;
852     /* try to get 4k chunk */
853     b = /* s->alt ? s->alt : */ &s->b;
854     if ( LIO_BUFSIZ/2 < b->fill && b->done ) { /* move contents downwards */
855     if ( b->done < b->fill )
856     memmove( b->c, b->c + b->done, b->fill - b->done );
857     s->pos += b->done;
858     b->fill -= b->done;
859     b->done = 0;
860     }
861     return LIO_BUFSIZ <= b->fill ? 0
862     : LIO_BUFSIZ/2 < b->fill ? LIO_BUFSIZ - b->fill
863     : LIO_BUFSIZ/2;
864     case LIO_SFILL:
865     case LIO_SFLUSH:
866     s->file &= ~LIO_INOUT;
867     }
868     return -ERR_EOF;
869     } /* ioStream */
870    
871    
872     int ioStdio ( Ios *s, int op )
873     {
874     Buf *b;
875     int ret;
876     switch ( op ) {
877     case LIO_SOPEN:
878     ioStream( s, op );
879     if ( 0 < (ret = lio_open( s->name, s->file )) )
880     s->file = ret;
881     return ret;
882     case LIO_SCLOSE:
883     if ( LIO_OUT & s->file )
884     s->func( s, LIO_SFLUSH );
885     /* don't close borrowed fd */
886     return '&' == *s->name ? 0 : lio_close( &s->file, LIO_INOUT );
887     case LIO_SFILL:
888     if ( !(LIO_IN & s->file) )
889     return -ERR_BADF;
890     if ( 0 < (ret = ioStream( s, LIO_SPURGE ))
891     && 0 <= (ret = lio_read( &s->file, s->b.c + s->b.fill, ret ))
892     )
893     s->b.fill += ret;
894     log_msg( LOG_ALL, "LIO_FILL: got %d now %d", ret, s->b.fill );
895     return ret;
896     case LIO_SFLUSH:
897     if ( !(LIO_OUT & s->file) )
898     return -ERR_BADF;
899     b = /* s->alt ? s->alt : */ &s->b;
900     if ( b->fill <= b->done )
901     return 0;
902     if ( 0 < (ret = lio_write( &s->file, b->c + b->done, b->fill - b->done )) )
903     b->done += ret;
904     if ( b->fill == b->done ) {
905     s->pos += b->done;
906     b->fill = b->done = 0;
907     } else if ( b->done && LIO_BUFSIZ/2 < b->fill )
908     ioStream( s, LIO_SPURGE );
909     return ret;
910     }
911     return ioStream( s, op );
912     } /* ioStdio */
913    
914    
915     int sMsg ( int to, const char *fmt, ... )
916     {
917     SESDECL
918     int code = (LOG_MASK|ERR_MASK) & to, err, level;
919     int fd = LIO_FD & to; /* stream id uses same mask as system fd */
920     Ios *o = ses->io[ fd ? fd : code ? 2 : 1 ];
921     va_list ap;
922     int space;
923     int ret;
924    
925     if ( LSES_FILE_MAX <= fd || ! o )
926     return -1;
927    
928     if ( seterrlev( &err, &level, code ) ) /* logging */
929     return -err;
930    
931     /* core fprintf */
932     if ( LIO_BUFSIZ/2 < o->b.fill )
933     LIO_FLUSH( o );
934     space = LIO_BUFSIZ - o->b.fill;
935     va_start( ap, fmt );
936     ret = vsnprintf( (char*)o->b.c + o->b.fill, space, fmt,
937     (MSG_VA & to) ? va_arg( ap, va_list ) : ap );
938     va_end( ap );
939     if ( ret < 0 || space < ret ) /* outta space */
940     ret = space;
941     o->b.fill += ret;
942     if ( ! code )
943     return ret;
944    
945     /* logging afterburner */
946     if ( LOG_SYSERR == level || LOG_IOERR == level ) {
947     int len;
948     char *syserr =
949     #ifndef WIN32
950     strerror(errno);
951     #else
952     0;
953     char buf[256] = "";
954     if (
955     FormatMessage(
956     FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS,
957     0, GetLastError(), 0, buf, sizeof(buf)-1, 0 )
958     )
959     syserr = buf;
960     buf[ sizeof(buf)-1 ] = 0;
961     #endif
962     if ( syserr ) {
963     len = strlen( syserr );
964     if ( o->b.fill+4+len < LIO_BUFSIZ ) {
965     memcpy( o->b.c + o->b.fill, "\n\t: ", 4 );
966     memcpy( o->b.c + o->b.fill+4, syserr, len );
967     o->b.fill += 4+len;
968     }
969     }
970     }
971     if ( o->b.fill < LIO_BUFSIZ )
972     o->b.c[ o->b.fill++ ] = '\n';
973     if ( log_flush )
974     LIO_FLUSH( o );
975     return -err;
976     } /* sMsg */
977    
978    
979     int sGets ( int fd, char **ptr, char delim )
980     {
981     SESDECL
982     Ios *s = ses->io[ LIO_FD & fd ];
983    
984     if ( s->b.fill > s->b.done || 0 < LIO_FILL( s ) ) for (;;) {
985     char *f = memchr( s->b.c + s->b.done, delim, s->b.fill - s->b.done );
986     int len;
987     log_msg( LOG_ALL, "sGets: done %d fill %d", s->b.done, s->b.fill );
988     f = memchr( s->b.c + s->b.done, delim, s->b.fill - s->b.done );
989     if ( ! f ) {
990     if ( (s->b.fill < LIO_BUFSIZ || s->b.done) /* buffer avail */
991     && (LIO_IN & s->file) /* file open */
992     && 0 < LIO_FILL( s )
993     )
994     continue;
995     else if ( s->b.done >= s->b.fill )
996     break;
997     f = (char*)s->b.c + s->b.fill;
998     }
999     len = f - (*ptr = (char*)s->b.c + s->b.done);
1000     s->b.done += len + 1;
1001     if ( len && '\n' == delim && '\r' == (*ptr)[len-1] )
1002     len--;
1003     return len;
1004     }
1005     *ptr = 0;
1006     return -1;
1007     } /* sGets */
1008    
1009    
1010     void cLog ( int level, const char *filename )
1011     {
1012     if ( 0 > level ) /* no change */
1013     ;
1014     else if ( LOG_LEVELS > level ) /* by basic number */
1015     level <<= LOG_SHIFT;
1016     else if ( 'z' >= level ) { /* by ascii value */
1017     switch ( level ) {
1018     case '-': level = LOG_NOCHANGE; break;
1019     case 'o': level = LOG_OFF; break;
1020     case 'f': level = LOG_FATAL; break;
1021     case 's': level = LOG_IOERR /*LOG_SYSERR*/; break;
1022     default:
1023     if ( '0' <= level && level <= '9' ) {
1024     level = (level - '0')<<LOG_SHIFT;
1025     break;
1026     }
1027     case 'e': level = LOG_ERROR; break;
1028     case 'w': level = LOG_WARN; break;
1029     case 'i': level = LOG_INFO; break;
1030     case 'v': level = LOG_VERBOSE; break;
1031     case 'd': level = LOG_DEBUG; break;
1032     case 't': level = LOG_TRACE; break;
1033     case 'a': level = LOG_ALL; break;
1034     }
1035     }
1036     if ( level >= 0 )
1037     log_lev = (LogLevel)level;
1038     (void)filename;
1039     /* TODO if ( filename )
1040     sOpen( cOpen(0), "2>"filename, 0, ioStdio ) */
1041     } /* cLog */

  ViewVC Help
Powered by ViewVC 1.1.26