/[webpac]/trunk/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

Contents of /trunk/openisis/lio.c

Parent Directory Parent Directory | Revision Log Revision Log


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

1 /*
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