/[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

Annotation of /openisis/0.9.9e/core/sys.c

Parent Directory Parent Directory | Revision Log Revision Log


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

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