/[webpac]/openisis/0.9.9e/core/sys.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 /openisis/0.9.9e/core/sys.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 604 - (show annotations)
Mon Dec 27 21:49:01 2004 UTC (19 years, 2 months ago) by dpavlin
File MIME type: text/plain
File size: 22151 byte(s)
import of new openisis release, 0.9.9e

1 /*
2 The Malete project - the Z39.2/Z39.50 database framework of OpenIsis.
3 Version 0.9.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.
14 See the GNU 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: sys.c,v 1.29 2004/11/12 09:38:02 kripke Exp $
25 I/O support for the openisis library.
26 */
27 #include <stdlib.h>
28 #include <stdarg.h>
29 #include <string.h>
30 #include <errno.h>
31 #include <limits.h> /* PATH_MAX */
32 #include <sys/types.h>
33
34 #ifdef WIN32
35 #define WIN32_LEAN_AND_MEAN
36 #define NONAMELESSUNION
37 # include <windows.h>
38 # include <sys/timeb.h>
39 #else /* have operating system */
40 # define __USE_UNIX98
41 /*
42 # define _POSIX_MAPPED_FILES
43 # define _POSIX_SYNCHRONIZED_IO
44 */
45 # include <fcntl.h> /* or try unixio */
46 # ifndef O_SYNC
47 # if defined( __FreeBSD__ )
48 # define O_SYNC O_FSYNC
49 # else
50 # define O_SYNC 0
51 # endif
52 # endif
53 # include <sys/stat.h>
54 # include <sys/file.h> /* flock */
55 #if defined(__linux__) && !defined(__USE_GNU)
56 # define __USE_GNU /* weird trigger to declare MREMAP_MAYMOVE */
57 #endif
58 # include <sys/mman.h>
59 # include <sys/socket.h>
60 # include <unistd.h>
61 #endif /* WIN32 */
62
63 #include <sys/time.h> /* gettimeofday */
64 #include <time.h> /* localtime */
65
66
67 #include "../core/core.h"
68
69
70
71 /* ************************************************************
72 private data
73 */
74
75
76 /* ************************************************************
77 private functions
78 */
79
80 static void *memordie ( int size )
81 {
82 void *p = malloc( size );
83 if ( p )
84 return p;
85 exit( 71/*EX_OSERR*/ ); /* exit handlers MUST NOT alloc memory */
86 return 0;
87 }
88
89 /* ************************************************************
90 private functions
91 */
92
93
94 /* ************************************************************
95 public data
96 */
97 Env env;
98
99
100
101 /* ************************************************************
102 public functions
103 */
104
105
106 void *mAlloc ( int size )
107 {
108 void *p = memordie( size );
109 memset(p, 0, size);
110 return p;
111 } /* mAlloc */
112
113
114 void mFree ( void *mem )
115 {
116 if ( mem )
117 free( mem );
118 } /* mFree */
119
120
121 void *mDup ( const void *str, int sz )
122 {
123 void *m = memordie( 0<=sz ? sz : (sz = strlen( str ) + 1) );
124 memcpy( m, str, sz );
125 return m;
126 } /* mDup */
127
128
129 char *mDupz ( const char *str, int sz )
130 {
131 char *m = memordie( sz+1 );
132 memcpy( m, str, sz );
133 m[sz] = 0;
134 return m;
135 } /* mDupz */
136
137
138 LBlk *mBlkAlloc ( int size )
139 {
140 LBlk *b = memordie( (((char*)(&((LBlk*)0)->byt))-(char*)0) + size );
141 b->nxt = 0;
142 b->siz = size;
143 memset(b->byt, 0, size);
144 return b;
145 } /* mBlkAlloc */
146
147
148 List *mListAlloc ( const char *name )
149 {
150 return lInit(memordie(sizeof(List)), name);
151 } /* mListAlloc */
152
153
154 int tUpd ( lolo *tm )
155 {
156 lolo o;
157 #ifdef WIN32
158 struct _timeb tb;
159 _ftime( &tb );
160 if ( !tm )
161 return tb.time;
162 o = *tm;
163 *tm = tb.time*LOLO(1000) + tb.millitm;
164 #else
165 struct timeval tv;
166 gettimeofday( &tv, 0 );
167 if ( !tm )
168 return tv.tv_sec;
169 o = *tm;
170 *tm = tv.tv_sec*LOLO(1000) + tv.tv_usec/1000;
171 #endif
172 return (int)(*tm - o);
173 } /* tUpd */
174
175
176 static int tLoc ( struct tm *t, lolo *tm )
177 {
178 lolo x;
179 time_t tt;
180 if ( !tm || !*tm )
181 tUpd( tm ? tm : (tm = &x) );
182 tt = (time_t)(*tm / 1000);
183 #ifdef WIN32 /* did I mention it's not threadsafe ? */
184 *t = *localtime( &tt );
185 #else
186 localtime_r( &tt, t );
187 #endif
188 return (int)(*tm % 1000);
189 } /* tLoc */
190
191
192 /* logically belongs to uti.c; here so tGtf may consider inlining */
193 void u2a0 ( char *p, unsigned u, unsigned n )
194 {
195 for ( ; n--; u/=10 )
196 p[n] = '0' + (u % 10);
197 } /* u2a0 */
198
199
200 int tGtf ( char *buf, lolo *tm )
201 {
202 struct tm t;
203 int millis = tLoc( &t, tm );
204
205 u2a0(buf, 1900+t.tm_year, 1900+t.tm_year);
206 u2a0(buf+4, 1+t.tm_mon, 2);
207 u2a0(buf+6, t.tm_mday, 2);
208 u2a0(buf+8, t.tm_hour, 2);
209 u2a0(buf+10, t.tm_min, 2);
210 u2a0(buf+12, t.tm_sec, 2);
211 buf[14] = 0;
212 return millis;
213 } /* tGtf */
214
215
216 char *tGtfm ( char *buf, lolo *tm )
217 {
218 u2a0(buf+14, tGtf(buf, tm), 3);
219 buf[18] = 0;
220 return buf;
221 } /* tGtfm */
222
223
224 #if 0 /* unused */
225 void tSleep ( lolo tm )
226 {
227 #ifdef WIN32
228 Sleep( tm );
229 #else
230 struct timespec ts;
231 ts.tv_sec = tm / 1000;
232 ts.tv_nsec = 1000000 * (int)(tm % 1000);
233 nanosleep( &ts, 0 );
234 #endif
235 } /* tSleep */
236 #endif
237
238
239 #ifndef WIN32
240 static const char *lmode (int f)
241 {
242 switch ( (FIL_BLOCK|FIL_TLOCK|FIL_WR) & f ) {
243 case FIL_BLOCK|FIL_WR: return "wait ex";
244 case FIL_BLOCK: return "wait sh";
245 case FIL_TLOCK|FIL_WR: return "test ex";
246 case FIL_TLOCK: return "test sh";
247 }
248 return "unlock";
249 }
250 #endif
251
252
253 int fOpen ( file *fil, const char *name, int flags )
254 {
255 int faillvl = FIL_TRY&flags ? LOG_VERBOSE : ERR_NO;
256
257 #ifndef WIN32
258 int fd = -1;
259 int f = !(FIL_WR&flags) ? O_RDONLY : ((FIL_RD&flags) ? O_RDWR : O_WRONLY);
260
261 *fil = FIL_NONE;
262 if (!name) { /* tempfile */
263 const char tpl[] = "/tmp/maleteXXXXXX";
264 char nam[sizeof tpl];
265 memcpy(nam, tpl, sizeof tpl);
266 fd = mkstemp(nam);
267 if (0 > fd)
268 return eRr(ERR_NO, "could not create tmpfile");
269 eRr(LOG_VERBOSE, "tempfile '%s'", nam);
270 unlink(nam);
271 *fil = fd;
272 return 0;
273 }
274 if ( FIL_CREAT & flags && FIL_WR & flags ) f |= O_CREAT;
275 if ( FIL_SYNC & flags ) f |= O_SYNC;
276 if ( FIL_TRUNC & flags ) f |= O_TRUNC;
277 fd = open( name, f, 00664 ); /* let umask finetune */
278 if ( 0 > fd )
279 return eRr( faillvl, "could not open '%s' %x", name, flags );
280 if ( FIL_FLOCK & flags ) {
281 struct flock fl;
282 memset(&fl, 0, sizeof(fl));
283 fl.l_type = FIL_WR&flags ? F_WRLCK : F_RDLCK;
284 fl.l_whence = SEEK_SET;
285 fl.l_start = 0;
286 fl.l_len = 0;
287 eRr(LOG_VERBOSE, "%s perm lock on '%s'", lmode(flags), name);
288 if ( fcntl(fd, FIL_BLOCK&flags ? F_SETLKW : F_SETLK, &fl) ) {
289 close(fd);
290 return eRr(ERR_NO, "err %s perm lock on '%s'", lmode(flags), name);
291 }
292 }
293 *fil = fd;
294 #else
295 HANDLE h;
296 int acc = 0;
297 int shr = FILE_SHARE_READ | (FIL_FLOCK&flags ? 0 : FILE_SHARE_WRITE);
298 int cre = (FIL_CREAT & flags && FIL_WR & flags)
299 ? (FIL_TRUNC & flags) ? CREATE_ALWAYS : OPEN_ALWAYS
300 : (FIL_TRUNC & flags) ? TRUNCATE_EXISTING : OPEN_EXISTING;
301 int f = (FIL_WR&flags) ? FILE_ATTRIBUTE_ARCHIVE : FILE_ATTRIBUTE_NORMAL;
302 char nam[128];
303
304 *fil = FIL_NONE;
305 if (!name) { /* tempfile */
306 GetTempPath(sizeof nam, nam);
307 GetTempFileName(nam, "mtp", 0, nam);
308 name = nam;
309 eRr(LOG_VERBOSE, "tempfile '%s'", nam);
310 acc = GENERIC_READ|GENERIC_WRITE;
311 shr = 0;
312 cre = TRUNCATE_EXISTING;
313 f = FILE_ATTRIBUTE_TEMPORARY|FILE_FLAG_DELETE_ON_CLOSE;
314 } else {
315 if ( FIL_RD & flags ) acc |= GENERIC_READ; /* FILE_READ_DATA; */
316 if ( FIL_WR & flags ) acc |= GENERIC_WRITE;
317 if ( FIL_SYNC & flags ) f |= FILE_FLAG_WRITE_THROUGH;
318 }
319 f |= FILE_FLAG_RANDOM_ACCESS;
320
321 h = CreateFile( name, acc, shr, 0, cre, f, 0 );
322 if ( INVALID_HANDLE_VALUE == h )
323 return eRr( faillvl, "could not open '%s' %x", name, flags );
324 *fil = h;
325 #endif
326 return 0;
327 } /* fOpen */
328
329
330 int fClose ( file *f )
331 {
332 if ( FIL_NONE != *f ) {
333 #ifndef WIN32
334 for ( fsync( *f ); close( *f ); errno = 0 )
335 if ( EINTR != errno ) {
336 eRr( LOG_SYSERR, "could not close file %d", *f );
337 return errno ? -errno : -1;
338 }
339 #else
340 CloseHandle( (HANDLE)*f );
341 #endif
342 *f = FIL_NONE;
343 }
344 return 0;
345 } /* fClose */
346
347
348 int fSize ( file f )
349 {
350 #ifndef WIN32
351 {
352 struct stat s;
353 return fstat( f, &s ) ? 0 : s.st_size;
354 }
355 #else
356 return GetFileSize( (HANDLE)f, 0 );
357 #endif
358 } /* fSize */
359
360
361 unsigned fTime ( file f )
362 {
363 #ifndef WIN32
364 struct stat s;
365 return fstat( f, &s ) ? 0 : (unsigned)s.st_mtime;
366 #else
367 FILETIME foo; /* time since 160101011200 UTC in hundred nanoseconds !!! */
368 lulu bar;
369 if ( ! GetFileTime( (HANDLE)f, 0, 0, &foo ) )
370 return 0;
371 bar = ((lulu)foo.dwHighDateTime<<32 | (lulu)foo.dwLowDateTime) / LULU(10000000);
372 return (unsigned)(bar - LULU(11644473600));
373 #endif
374 } /* fTime */
375
376
377 int fRead ( file *f, void *buf, unsigned count )
378 {
379 #ifndef WIN32
380 int got = read( *f, buf, count );
381 return 0 <= got ? got
382 : eRr( ERR_NO, "could not read %d bytes from %d", count, *f );
383 #else
384 DWORD got = 0;
385 int ok = ReadFile( (HANDLE)*f, buf, count, &got, 0 );
386 return ok ? got : eRr( ERR_NO, "could not read %d bytes", count );
387 #endif
388 } /* fRead */
389
390
391 int fWrite ( file *f, const void *buf, unsigned count )
392 {
393 {
394 #ifndef WIN32
395 int got = write( *f, buf, count );
396 return 0 <= got ? got
397 : eRr( ERR_NO, "could not write %d bytes to %d", count, *f );
398 #else
399 DWORD got = 0;
400 int ok = WriteFile( (HANDLE)*f, buf, count, &got, 0 );
401 return ok ? got
402 : eRr( ERR_NO, "could not write %d bytes", count );
403 #endif
404 }
405 } /* fWrite */
406
407
408
409 int fSeek ( file *f, unsigned offset )
410 {
411 {
412 #ifndef WIN32
413 int got = (int)lseek( *f, offset, SEEK_SET );
414 return (int)offset == got ? 0
415 : eRr( ERR_NO, "could not seek to %d", offset );
416 #else
417 return 0xffffffff /* "INVALID_SET_FILE_POINTER" */
418 == SetFilePointer( (HANDLE)*f, offset, 0, FILE_BEGIN )
419 ? -1 : 0;
420 #endif
421 }
422 } /* fSeek */
423
424
425 int fPread ( file *f, void *buf, unsigned count, unsigned offset )
426 {
427 {
428 #ifndef WIN32
429 int got = pread( *f, buf, count, offset );
430 return 0 <= got ? got
431 : eRr( ERR_NO, "could not read %d bytes from %d at %d",
432 count, *f, offset );
433 #else
434 return 0xffffffff /* "INVALID_SET_FILE_POINTER" */
435 == SetFilePointer( (HANDLE)*f, offset, 0, FILE_BEGIN )
436 ? -1 : fRead( f, buf, count );
437 #endif
438 }
439 } /* fPread */
440
441
442 int fPwrite ( file *f, const void *buf, unsigned count, unsigned offset )
443 {
444 {
445 #ifndef WIN32
446 int got = pwrite( *f, buf, count, offset );
447 return 0 <= got ? got
448 : eRr( ERR_NO, "could not write %d bytes to %d at %d",
449 count, *f, offset );
450 #else
451 return 0xffffffff /* "INVALID_SET_FILE_POINTER" */
452 == SetFilePointer( (HANDLE)*f, offset, 0, FILE_BEGIN )
453 ? -1 : fWrite( f, buf, count );
454 #endif
455 }
456 } /* fPwrite */
457
458
459 int fTrunc ( file *f, unsigned length )
460 {
461 #ifndef WIN32
462 ftruncate( *f, length );
463 if ( length && (int)length != fSize(*f) ) {
464 /* Solaris and FreeBSD guarantee that ftruncate can extend files,
465 but Linux does not.
466 */
467 static char nosh = 0;
468 fPwrite(f, &nosh, 1, length-1);
469 }
470 #else
471 /* SetFileValidData( (HANDLE)*f, length ); XP only */
472 return 0xffffffff /* "INVALID_SET_FILE_POINTER" */
473 == SetFilePointer( (HANDLE)*f, length, 0, FILE_BEGIN )
474 ? -1 : SetEndOfFile( (HANDLE)*f )
475 ? 0 : eRr( ERR_NO, "could not truncate %d", length );
476 #endif
477 return 0;
478 } /* fTrunc */
479
480
481 #ifdef BUILD_SHMODE
482 int fLock ( file f, unsigned n, int flg )
483 {
484 struct flock fl;
485
486 memset( &fl, 0, sizeof(fl) );
487 fl.l_type = FIL_WR&flg ? F_WRLCK : flg ? F_RDLCK : F_UNLCK;
488 fl.l_whence = SEEK_SET;
489 fl.l_start = n;
490 fl.l_len = 1;
491 eRr( LOG_VERBOSE, "%s tmp lock %d", lmode(flg), n );
492 return fcntl(f, FIL_BLOCK&flg ? F_SETLKW : F_SETLK, &fl)
493 ? eRr(ERR_NO, "err %s tmp lock %d", lmode(flg), n) : 0;
494 } /* fLock */
495 #endif
496
497
498 int fMOpen ( FMap *fm, const char *name, int flags )
499 {
500 int ret;
501 fm->map = 0;
502 fm->npg = 0;
503 if ( (ret = fOpen(&fm->fil, name, flags)) )
504 fm->flg = 0;
505 else {
506 #ifdef WIN32 /* save mapping name */
507 static const char pfx[] = "Malete";
508 int l = strlen(name);
509 char *c;
510 fm->nam = mAlloc(sizeof(pfx)+l);
511 memcpy(fm->nam, pfx, sizeof(pfx)-1);
512 memcpy(c = fm->nam+sizeof(pfx)-1, name, l+1);
513 for (; *c; c++) if ( '\\' == *c ) *c = '/'; /* must not contain \ */
514 #endif
515 fm->flg = flags;
516 }
517 return ret;
518 } /* fMOpen */
519
520
521 int fMClose ( FMap *fm )
522 {
523 if ( fm->map )
524 fMap(fm, 0);
525 #ifdef WIN32 /* save mapping name */
526 if ( fm->nam ) {
527 mFree(fm->nam);
528 fm->nam = 0;
529 }
530 #endif
531 return fClose(&fm->fil);
532 } /* fMClose */
533
534
535 int fMap ( FMap *fm, unsigned npg )
536 {
537 if ( npg > fm->lim && fm->npg == (npg = fm->lim) )
538 return npg;
539 #ifndef WIN32
540 if ((FIL_WR & fm->flg) && npg && (((int)npg<<env.psh) > fSize(fm->fil)))
541 fTrunc(&fm->fil, npg<<env.psh);
542 if ( fm->map ) { /* unmap or remap */
543 #ifdef __linux__
544 if ( npg ) {
545 fm->map = mremap(fm->map, fm->npg<<env.psh, npg<<env.psh, MREMAP_MAYMOVE);
546 fm->npg = 0;
547 goto done;
548 }
549 #endif
550 munmap(fm->map, fm->npg<<env.psh);
551 }
552 fm->map = 0;
553 fm->npg = 0;
554 if (!npg)
555 return 0;
556 /* get new map */
557 fm->map = mmap( 0, npg<<env.psh,
558 PROT_READ | ((FIL_WR&fm->flg) ? PROT_WRITE : 0), MAP_SHARED, fm->fil, 0 );
559 #ifdef __linux__
560 done:
561 #endif
562 LOG_DBG(LOG_DEBUG, "mapped %d pages at %8x", npg, fm->map);
563 if ( MAP_FAILED != fm->map )
564 return (int)(fm->npg = npg);
565 fm->map = 0;
566 return eRr(ERR_NO, "mmap failed");
567 #else
568 /* awfully complicated here
569 -- need CreateFileMapping, MapViewOfFile
570 stupid piece of shrott
571 true mapping supported in NT family only, 9x copies to swap
572 */
573 if ( fm->map ) {
574 UnmapViewOfFile(fm->map);
575 CloseHandle(fm->hdl);
576 }
577 fm->map = 0;
578 fm->npg = 0;
579 fm->hdl = 0;
580 if (!npg)
581 return 0;
582 /*
583 note that shared writing of a mapping does not work,
584 because to be consistent, it needs to be the same mapping object,
585 which we can not grow.
586 However, windoze doesn't support shared writing anyway.
587 */
588 {
589 int size = fSize(fm->fil);
590 if (FIL_WR&fm->flg || size > npg<<env.psh)
591 size = npg<<env.psh;
592 else
593 npg = (size + env.psz-1)>>env.psh;
594 if ( (fm->hdl = CreateFileMapping(fm->fil,0,
595 (FIL_WR&fm->flg)?PAGE_READWRITE:PAGE_READONLY,0,size,fm->nam)) ) {
596 if ( (fm->map = MapViewOfFile(fm->hdl,
597 (FIL_WR&fm->flg)?FILE_MAP_WRITE:FILE_MAP_READ,0,0,size))
598 )
599 return fm->npg = npg;
600 CloseHandle(fm->hdl);
601 fm->hdl = 0;
602 return eRr(ERR_NO, "MapViewOfFile %d failed", npg);
603 }
604 }
605 return eRr(ERR_NO, "CreateFileMapping failed");
606 #endif
607 } /* fMap */
608
609
610 int fMSync ( FMap *fm, unsigned page )
611 {
612 char * buf = fm->map + (page<<env.psh);
613 LOG_DBG(LOG_DEBUG, "msync %d", page);
614 #ifndef WIN32
615 return msync( buf, env.psz, (
616 #ifdef BUILD_SHMODE
617 ENV_SHARED == env.wri ? MS_INVALIDATE :
618 #endif
619 0) | (FIL_SYNC&fm->flg ? MS_SYNC : MS_ASYNC) )
620 ? eRr( ERR_NO, "msync" ) : 0;
621 #else
622 return FlushViewOfFile(buf, env.psz) ? 0 : eRr(ERR_NO, "msync");
623 #endif
624 } /* fMSync */
625
626
627 int fSlurp ( char **buf, int sz, const char *name, int opt )
628 {
629 int size;
630 int ret;
631 char *p = *buf;
632 file f;
633
634 if ( (ret = fOpen( &f, name, FIL_RD|(opt ? FIL_TRY : 0) )) )
635 return ret;
636 size = fSize( f );
637 if ( 0 >= size )
638 return size;
639 if ( size > sz ) {
640 eRr(ERR_INVAL, "file '%.*s' too big: %d > %d", 30, name, size, sz);
641 goto done;
642 }
643 if ( ! p && !(p = mAlloc(size)) ) {
644 ret = ERR_NOMEM;
645 goto done;
646 }
647 ret = fRead( &f, p, size );
648 if ( size == ret )
649 *buf = p;
650 else {
651 if ( ret >= 0 )
652 ret = eRr( ERR_IO, "OOPS! got %d of %d bytes from '%.*s'",
653 ret, size, 30, name );
654 if ( ! *buf )
655 free( p );
656 }
657 done:
658 fClose( &f );
659 return ret;
660 } /* fSlurp */
661
662
663 int fGets ( FBuf *b )
664 {
665 char *c;
666 int n;
667 if ( b->l ) {
668 b->p += b->l;
669 b->o += b->l;
670 b->l = 0;
671 }
672 if ( b->m ) {
673 b->p++;
674 b->o++;
675 b->m--;
676 b->n++;
677 }
678 for (;;) { /* now have b->m bytes at b->p+b->l */
679 if ( b->m ) { /* add all or part of this b->l */
680 if ( (c = memchr(b->p+b->l, LF, b->m)) ) {
681 b->m -= c - b->p - b->l;
682 b->l = c - b->p;
683 return !0;
684 }
685 b->l += b->m;
686 b->m = 0;
687 if ( b->l == b->s ) /* buffer exhausted */
688 return !0;
689 if ( b->p != b->b )
690 memmove(b->b, b->p, b->l);
691 }
692 b->p = b->b;
693 if ( 0 >= (n = fRead(&b->f, b->p+b->l, b->s-b->l)) ) /* eof */
694 return b->l; /* but had line */
695 b->m = n;
696 }
697 } /* fGets */
698
699
700 int fGetr ( List *l, FBuf *fb )
701 {
702 if ( !fGets(fb) )
703 return 0;
704 while ( fb->l ) {
705 int tag;
706 int n = a2il(fb->p, fb->l, &tag);
707 if ( !l->fld->tag ) { /* init rec */
708 if ( n ) /* this is a data field, add blank header */
709 LPREF(l, -1, 0);
710 else /* use this one as header */
711 tag = -1;
712 }
713 if ( n < (int)fb->l && TAB == fb->p[n] )
714 n++;
715 LADD(l, tag, fb->p+n, fb->l-n);
716 if ( !fGets(fb) )
717 break;
718 }
719 return !0;
720 } /* fGetr */
721
722
723
724 static void fSinkf (Sink *lo, int eor, int full)
725 {
726 Fld *f = lo->lst.fld, *e = f + RLEN(f);
727 file to = (file)lo->dst;
728
729 if ( FIL_NONE == to ) goto reset;
730 for ( f++; f < e; f++ ) {
731 char buf[8192];
732 int l;
733 if ( full ) {
734 l = i2a(buf, f->tag);
735 buf[l++] = '\t';
736 } else {
737 if ( !f->len )
738 continue;
739 l = 0;
740 }
741 if ( f->len < sizeof(buf)-l ) {
742 memcpy(buf+l, f->val, f->len);
743 buf[l += f->len] = '\n';
744 fWrite(&to, buf, l+1);
745 } else {
746 if ( l )
747 fWrite(&to, buf, l);
748 if ( f->len )
749 fWrite(&to, f->val, f->len);
750 buf[0] = '\n';
751 fWrite(&to, buf, 1);
752 }
753 }
754 if ( eor )
755 fWrite(&to, "\n", 1);
756 reset:
757 lReset(&lo->lst);
758 } /* fSinkf */
759
760 void fSinkl (Sink *lo, int eor)
761 {
762 fSinkf(lo, eor, 0);
763 } /* fSinkl */
764
765 void fSinkr (Sink *lo, int eor)
766 {
767 Fld *f = lo->lst.fld;
768 file to = (file)lo->dst;
769 char buf[8192];
770 int l;
771
772 if ( FIL_NONE == to ) goto reset;
773 if ( f->tag ) { /* not empty */
774 if ( !lo->off && f->len ) { /* skip header if off or empty */
775 if ( 10>b36val[(unsigned)*f->val] ) {/* starts with digit */
776 buf[0] = 'W';
777 buf[1] = TAB;
778 l = 2;
779 } else
780 l = 0;
781 if ( f->len < sizeof(buf)-l ) {
782 memcpy(buf+l, f->val, f->len);
783 buf[l += f->len] = '\n';
784 fWrite(&to, buf, l+1);
785 } else {
786 if ( l )
787 fWrite(&to, buf, l);
788 if ( f->len )
789 fWrite(&to, f->val, f->len);
790 fWrite(&to, "\n", 1);
791 }
792 }
793 }
794 fSinkf(lo, eor, 1);
795 if ( ! eor ) {
796 lo->off += f->tag; /* no of fields passed by */
797 return;
798 }
799 reset:
800 lo->off = 0;
801 lClr(&lo->lst);
802 } /* fSinkr */
803
804
805 int eOut ( int tag, const char *fmt, ... )
806 {
807 if ( env.out ) {
808 va_list ap;
809 va_start( ap, fmt );
810 lOut(&env.out->lst, tag, 0, fmt, ap);
811 va_end( ap );
812 SINK(env.out);
813 }
814 return tag;
815 } /* eOut */
816
817
818 int eRr ( int tag, const char *fmt, ... )
819 {
820 va_list ap;
821
822 if ( ERR_NO == tag )
823 #ifndef WIN32
824 switch ( errno ) {
825 case EINTR: case EAGAIN:
826 tag = ERR_AGAIN; break;
827 case EFAULT: case ENAMETOOLONG: case ELOOP:
828 tag = ERR_FAULT; break; /* structurally bad address */
829 case EBADF: case ENOENT: case ENOTDIR:
830 tag = ERR_BADF; break; /* file "does not exist" */
831 case EIO: case EEXIST: case EISDIR: case EACCES: case ENXIO:
832 case ENODEV: case EROFS: case ETXTBSY: case ENOSPC:
833 case EPIPE: case ESPIPE:
834 tag = ERR_IO; break; /* file "is not accessible" */
835 case ENOMEM: case EMFILE: case ENFILE:
836 tag = ERR_NOMEM; break;
837 case EBUSY:
838 tag = ERR_BUSY; break;
839 default:
840 tag = ERR_INVAL;
841 }
842 #else
843 tag = ERR_INVAL;
844 #endif
845 if ( env.log > tag )
846 return tag;
847
848 if ( !env.err )
849 return tag;
850 va_start( ap, fmt );
851 lOut(&env.err->lst, -tag, 0, fmt, ap);
852 va_end( ap );
853
854 /* logging afterburner */
855 if ( ERR_NOMEM >= tag && tag >= ERR_AGAIN ) {
856 char *syserr =
857 #ifndef WIN32
858 errno ? strerror(errno) : 0;
859 #else
860 0;
861 char buf[256] = "";
862 if (
863 FormatMessage(
864 FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS,
865 0, GetLastError(), 0, buf, sizeof(buf)-1, 0 )
866 )
867 syserr = buf;
868 buf[ sizeof(buf)-1 ] = 0;
869 #endif
870 if ( syserr ) {
871 LAPP(&env.err->lst, ": ", 2);
872 LAPPS(&env.err->lst, syserr);
873 }
874 }
875 SINK(env.err); /* just trigger the sink, buffering should be handled there */
876 return tag;
877 } /* eRr */
878
879
880
881 /*
882 NOTE: no shared lib support
883 */
884 void cFini ()
885 {
886 dCloseAll();
887 /* close env's buffers */
888 if ( env.out ) env.out->snk(env.out, 1);
889 if ( env.err ) env.err->snk(env.err, 1);
890 } /* cFini */
891
892
893 void cInit ( List *opts, Sink *out, Sink *err )
894 {
895 Sink **oe;
896 Fld opt = { 0, 0, 0 };
897 int i;
898
899 if ( env.out )
900 return;
901 memset(&env, 0, sizeof(env));
902 env.opt = opts;
903 #ifndef WIN32
904 env.in = 0;
905 #else
906 if ( INVALID_HANDLE_VALUE == (env.in = GetStdHandle(STD_INPUT_HANDLE)) )
907 env.in = FIL_NONE;
908 #endif
909 env.out = out;
910 env.err = err;
911 oe = (Sink**)&env.out;
912 for ( i=0; i<2; i++ ) {
913 oe = i ? &env.err : &env.out;
914 if ( *oe )
915 continue;
916 *oe = (Sink*)mAlloc(sizeof(Sink));
917 #ifndef WIN32
918 (*oe)->dst = (void*)(i + 1);
919 #else
920 if ( INVALID_HANDLE_VALUE ==
921 ((*oe)->dst = GetStdHandle(i?STD_ERROR_HANDLE:STD_OUTPUT_HANDLE))
922 )
923 fOpen((file*)&(*oe)->dst, i ? "err.txt" : "out.txt", FIL_WR|FIL_CREAT);
924 #endif
925 if ( i ) {
926 lInit(&env.err->lst, "err");
927 env.err->snk = fSinkl;
928 } else {
929 lInit(&env.out->lst, 0);
930 env.out->snk = fSinkr;
931 }
932 }
933
934 /* check pagesize */
935 #ifndef WIN32
936 env.psz = sysconf(_SC_PAGESIZE); /* getpagesize(); */
937 #else
938 {
939 SYSTEM_INFO si;
940 GetSystemInfo(&si);
941 env.psz = si.dwPageSize; /* usually also 4k */
942 }
943 #endif
944 {
945 int t = env.psz;
946 env.psh = 0;
947 while (t >>= 1) env.psh++;
948 if ( env.psz != (unsigned)1<<env.psh || env.psh > CPU_PAGE_SHIFT ) {
949 eRr(ERR_TRASH, "weirdness! pagesize %d shift %d max %d",
950 env.psz, env.psh, CPU_PAGE_SHIFT);
951 exit(1);
952 }
953 if ( env.psh < 12 ) { /* but using multiples is ok */
954 eRr(LOG_WARN, "page_shift is %d !!!", env.psh);
955 env.psz = 1<<(env.psh = 12);
956 }
957 }
958 /* defaults */
959 env.log = LOG_WARN;
960 env.wri = ENV_EXCL;
961 env.qml = env.rml = 1<<(30-env.psh); /* map 1 GB at most */
962
963 if ( opts ) for ( opt.val = 0; vGet(&opt, opts->fld, "vw"); )
964 switch (opt.tag) {
965 case 'v':
966 /*
967 logging:
968 first char selects level, a 'b' as second sets buffering
969 */
970 if ( opt.len ) {
971 switch ( *opt.val ) {
972 case '0': case 'o': env.log = 0; break;
973 case '1': case 'f': env.log = LOG_FATAL; break;
974 case '2': case 's': env.log = LOG_IOERR /*LOG_SYSERR*/; break;
975 case '3': case 'e': env.log = LOG_ERROR; break;
976 case '4': case 'w': env.log = LOG_WARN; break;
977 case '5': case 'i': env.log = LOG_INFO; break;
978 case '6': case 'v': env.log = LOG_VERBOSE; break;
979 case '7': case 'd': env.log = LOG_DEBUG; break;
980 case '8': case 't': env.log = LOG_TRACE; break;
981 case '9': case 'a': env.log = LOG_ALL; break;
982 }
983 if ( 1 < opt.len && 'b' == opt.val[1] )
984 env.flg |= ENV_BUFFER;
985 }
986 break;
987 case 'w': /* write/concurrency mode */
988 if ( opt.len )
989 switch ( *opt.val ) {
990 case '0': env.wri = ENV_RO; break;
991 case 's':
992 #ifdef BUILD_SHMODE
993 env.wri = ENV_SHARED;
994 env.flg |= ENV_MSYNC;
995 #else
996 eRr(ERR_INVAL, "no shared mode build");
997 #endif
998 break;
999 }
1000 } /* if (in) for switch */
1001
1002 atexit( cFini );
1003 } /* cInit */

  ViewVC Help
Powered by ViewVC 1.1.26