Annotation of parser3/src/main/pa_common.C, revision 1.90
1.15 paf 1: /** @file
1.16 paf 2: Parser: commonly functions.
3:
1.8 paf 4: Copyright(c) 2001 ArtLebedev Group(http://www.artlebedev.com)
1.85 paf 5: Author: Alexander Petrosyan <paf@design.ru>(http://paf.design.ru)
1.16 paf 6:
1.90 ! paf 7: $Id: pa_common.C,v 1.89 2001/11/14 11:27:39 paf Exp $
1.1 paf 8: */
9:
10: #include "pa_common.h"
1.2 paf 11: #include "pa_types.h"
1.4 paf 12: #include "pa_exception.h"
1.14 paf 13: #include "pa_pool.h"
14: #include "pa_globals.h"
15: #include "pa_value.h"
16: #include "pa_hash.h"
17: #include "pa_string.h"
1.1 paf 18:
1.82 paf 19: #ifndef _O_TEXT
20: # define _O_TEXT 0
21: #endif
22: #ifndef _O_BINARY
23: # define _O_BINARY 0
1.47 paf 24: #endif
1.80 paf 25: #ifndef O_TRUNC
26: # define O_TRUNC 0
27: #endif
28:
1.88 paf 29: int __vsnprintf(char *b, size_t s, const char *f, va_list l) {
30: if(!s)
31: return 0;
32:
33: int r;
34: // note: on win32& maybe somewhere else
35: // vsnprintf do not writes terminating 0 in 'buffer full' case, reducing
36: --s;
1.22 paf 37: #if _MSC_VER
1.88 paf 38: /*
39: win32:
40: mk:@MSITStore:C:\Program%20Files\Microsoft%20Visual%20Studio\MSDN\2001APR\1033\vccore.chm::/html/_crt__vsnprintf.2c_._vsnwprintf.htm
41:
42: if the number of bytes to write exceeds buffer, then count bytes are written and –1 is returned
43: */
44: r=_vsnprintf(b, s, f, l);
45: if(r<0)
46: r=s;
47: #else
1.90 ! paf 48: r=_vsnprintf(b, s, f, l);
1.88 paf 49: /*
50: solaris:
51: man vsnprintf
52:
53: The snprintf() function returns the number of characters
54: formatted, that is, the number of characters that would have
55: been written to the buffer if it were large enough. If the
56: value of n is 0 on a call to snprintf(), an unspecified
57: value less than 1 is returned.
58: */
1.1 paf 59:
1.88 paf 60: if(r<0)
61: r=0;
62: else if(r>s)
63: r=s;
64: #endif
65: b[r]=0;
1.1 paf 66: return r;
67: }
1.88 paf 68:
1.1 paf 69: int __snprintf(char *b, size_t s, const char *f, ...) {
70: va_list l;
71: va_start(l, f);
72: int r=__vsnprintf(b, s, f, l);
73: va_end(l);
74: return r;
75: }
1.2 paf 76:
1.86 paf 77: static char *strnchr(char *buf, size_t size, char c) {
78: for(; size-->0; buf++) {
79: if(*buf==c)
80: return buf;
81: }
82:
83: return 0;
84: }
85:
86: void fix_line_breaks(char *buf, size_t& size) {
1.87 paf 87: //_asm int 3;
1.86 paf 88: const char * const eob=buf+size;
1.87 paf 89: char *dest=buf;
1.72 parser 90: // fix DOS: \r\n -> \n
91: // fix Macintosh: \r -> \n
1.87 paf 92: char *bol=buf;
1.86 paf 93: while(char *eol=strnchr(bol, eob -bol, '\r')) {
1.72 parser 94: size_t len=eol-bol;
95: if(dest!=bol)
96: memcpy(dest, bol, len);
97: dest+=len;
98: *dest++='\n';
99:
1.87 paf 100: if(&eol[1]<eob && eol[1]=='\n') { // \r,\n = DOS
1.72 parser 101: bol=eol+2;
102: size--;
103: } else // \r,not \n = Macintosh
104: bol=eol+1;
105: }
106: // last piece without \r, including terminating 0
107: if(dest!=bol)
1.87 paf 108: memcpy(dest, bol, eob-bol);
1.72 parser 109: }
1.18 paf 110:
1.28 paf 111: char *file_read_text(Pool& pool, const String& file_spec, bool fail_on_read_problem) {
1.72 parser 112: void *result; size_t size;
113: return file_read(pool, file_spec, result, size, true, fail_on_read_problem)?(char *)result:0;
1.34 paf 114: }
115: bool file_read(Pool& pool, const String& file_spec,
1.87 paf 116: void*& data, size_t& data_size, bool as_text,
1.44 paf 117: bool fail_on_read_problem,
118: size_t offset, size_t limit) {
1.64 parser 119: const char *fname=file_spec.cstr(String::UL_FILE_SPEC);
1.62 parser 120: //printf("file_read(%s)\n", fname);
1.33 paf 121: int f;
1.2 paf 122: struct stat finfo;
1.33 paf 123:
124: // first open, next stat:
1.45 paf 125: // directory update of NTFS hard links performed on open.
1.33 paf 126: // ex:
127: // a.html:^test[] and b.html hardlink to a.html
128: // user inserts ! before ^test in a.html
129: // directory entry of b.html in NTFS not updated at once,
1.35 paf 130: // they delay update till open, so we would receive "!^test[" string
131: // if would do stat, next open.
1.34 paf 132: if(
1.72 parser 133: (f=open(fname, O_RDONLY|(as_text?_O_BINARY/*_O_TEXT*/:_O_BINARY)))>=0 &&
1.34 paf 134: stat(fname, &finfo)==0) {
1.2 paf 135: /*if(exclusive)
136: flock(f, LOCK_EX);*/
1.44 paf 137: size_t max_size=limit?min(offset+limit, finfo.st_size)-offset:finfo.st_size;
1.87 paf 138: int read_size;
1.47 paf 139: if(!max_size) { // eof
1.83 paf 140: if(as_text) {
141: data=pool.malloc(1);
142: *(char*)data=0;
143: } else
144: data=0;
1.47 paf 145: read_size=0;
1.59 parser 146: } else {
1.78 paf 147: data=pool.malloc(max_size+(as_text?1:0), 3);
1.59 parser 148: if(offset)
149: lseek(f, offset, SEEK_SET);
150: read_size=read(f, data, max_size);
1.47 paf 151: }
1.2 paf 152: /*if(exclusive)
153: flock(f, LOCK_UN);*/
154: close(f);
1.59 parser 155: if(!max_size) // eof
156: return true;
1.32 paf 157:
1.87 paf 158: if(read_size<0 || read_size>max_size)
1.73 parser 159: throw Exception(0, 0,
1.33 paf 160: &file_spec,
1.44 paf 161: "read failed: actually read %d bytes count not in [0..%lu] valid range",
162: read_size, (unsigned long)max_size); //never
1.87 paf 163:
164: data_size=read_size;
165: if(as_text) {
166: fix_line_breaks((char *)data, data_size);
167: // note: after fixing
168: ((char*&)data)[data_size]=0;
169: }
1.72 parser 170: return true;
1.2 paf 171: }
1.4 paf 172: if(fail_on_read_problem)
1.73 parser 173: throw Exception(0, 0,
1.33 paf 174: &file_spec,
1.54 parser 175: "read failed: %s (%d), actual filename '%s'",
176: strerror(errno), errno, fname);
1.34 paf 177: return false;
1.8 paf 178: }
179:
1.63 parser 180: static void create_dir_for_file(const String& file_spec) {
181: size_t pos_after=1;
182: int pos_before;
183: while((pos_before=file_spec.pos("/", 1, pos_after))>=0) {
1.64 parser 184: mkdir(file_spec.mid(0, pos_before).cstr(String::UL_FILE_SPEC), 0775);
1.63 parser 185: pos_after=pos_before+1;
186: }
187: }
188:
1.18 paf 189: void file_write(Pool& pool,
1.28 paf 190: const String& file_spec,
1.34 paf 191: const void *data, size_t size,
1.80 paf 192: bool as_text,
193: bool do_append/*,
1.20 paf 194: bool exclusive*/) {
1.64 parser 195: const char *fname=file_spec.cstr(String::UL_FILE_SPEC);
1.28 paf 196: int f;
1.80 paf 197: if(access(fname, W_OK)!=0) // no
1.63 parser 198: create_dir_for_file(file_spec);
1.50 paf 199:
1.80 paf 200: if((f=open(fname,
201: O_CREAT|O_RDWR
202: |(as_text?_O_TEXT:_O_BINARY)
203: |(do_append?O_APPEND:O_TRUNC), 0666))>=0) {
204: /*if(exclusive)
205: flock(f, LOCK_EX);*/
206:
207: if(size) write(f, data, size);
208: #if O_TRUNC==0
209: ftruncate(f, size);
1.18 paf 210: #endif
1.80 paf 211: /*if(exclusive)
212: flock(f, LOCK_UN);*/
213: close(f);
214: } else
215: throw Exception(0, 0,
216: &file_spec,
217: "write failed: %s (%d), actual filename '%s'",
218: strerror(errno), errno, fname);
1.30 paf 219: }
220:
1.63 parser 221: // throws nothing! [this is required in file_move & file_delete]
1.50 paf 222: static void rmdir(const String& file_spec, size_t pos_after) {
223: int pos_before;
224: if((pos_before=file_spec.pos("/", 1, pos_after))>=0)
225: rmdir(file_spec, pos_before+1);
226:
1.64 parser 227: rmdir(file_spec.mid(0, pos_after-1/* / */).cstr(String::UL_FILE_SPEC));
1.50 paf 228: }
1.30 paf 229: void file_delete(Pool& pool, const String& file_spec) {
1.64 parser 230: const char *fname=file_spec.cstr(String::UL_FILE_SPEC);
1.54 parser 231: if(unlink(fname)!=0)
1.73 parser 232: throw Exception(0, 0,
1.33 paf 233: &file_spec,
1.54 parser 234: "unlink failed: %s (%d), actual filename '%s'",
235: strerror(errno), errno, fname);
1.50 paf 236:
237: rmdir(file_spec, 1);
1.60 parser 238: }
239: void file_move(Pool& pool, const String& old_spec, const String& new_spec) {
1.64 parser 240: const char *old_spec_cstr=old_spec.cstr(String::UL_FILE_SPEC);
241: const char *new_spec_cstr=new_spec.cstr(String::UL_FILE_SPEC);
1.63 parser 242:
243: create_dir_for_file(new_spec);
244:
1.60 parser 245: if(rename(old_spec_cstr, new_spec_cstr)!=0)
1.73 parser 246: throw Exception(0, 0,
1.60 parser 247: &old_spec,
248: "rename failed: %s (%d), actual filename '%s' to '%s'",
249: strerror(errno), errno, old_spec_cstr, new_spec_cstr);
1.63 parser 250:
251: rmdir(old_spec, 1);
1.31 paf 252: }
253:
1.51 paf 254:
255: static bool entry_readable(const String& file_spec, bool need_dir) {
1.64 parser 256: const char *fname=file_spec.cstr(String::UL_FILE_SPEC);
1.51 paf 257: struct stat finfo;
258: if(access(fname, R_OK)==0 && stat(fname, &finfo)==0) {
1.73 parser 259: bool is_dir=finfo.st_mode&S_IFDIR != 0;
1.51 paf 260: return is_dir==need_dir;
261: }
262: return false;
263: }
1.31 paf 264: bool file_readable(const String& file_spec) {
1.51 paf 265: return entry_readable(file_spec, false);
266: }
267: bool dir_readable(const String& file_spec) {
268: return entry_readable(file_spec, true);
1.65 parser 269: }
270: String *file_readable(const String& path, const String& name) {
271: String *result=new(path.pool()) String(path);
272: *result << "/";
273: *result << name;
274: return file_readable(*result)?result:0;
1.43 paf 275: }
276: bool file_executable(const String& file_spec) {
1.64 parser 277: return access(file_spec.cstr(String::UL_FILE_SPEC), X_OK)==0;
1.44 paf 278: }
279:
1.64 parser 280: bool file_stat(const String& file_spec,
1.58 parser 281: size_t& rsize,
282: time_t& ratime,
283: time_t& rmtime,
1.64 parser 284: time_t& rctime,
285: bool fail_on_read_problem) {
1.44 paf 286: Pool& pool=file_spec.pool();
1.64 parser 287: const char *fname=file_spec.cstr(String::UL_FILE_SPEC);
1.44 paf 288: struct stat finfo;
289: if(stat(fname, &finfo)!=0)
1.64 parser 290: if(fail_on_read_problem)
1.73 parser 291: throw Exception(0, 0,
1.67 parser 292: &file_spec,
293: "getting file size failed: %s (%d), real filename '%s'",
294: strerror(errno), errno, fname);
1.64 parser 295: else
296: return false;
1.58 parser 297: rsize=finfo.st_size;
298: ratime=finfo.st_atime;
299: rmtime=finfo.st_mtime;
300: rctime=finfo.st_ctime;
1.64 parser 301: return true;
1.18 paf 302: }
303:
1.8 paf 304: char *getrow(char **row_ref, char delim) {
305: char *result=*row_ref;
306: if(result) {
307: *row_ref=strchr(result, delim);
308: if(*row_ref)
309: *((*row_ref)++)=0;
310: else if(!*result)
311: return 0;
312: }
313: return result;
314: }
315:
1.23 paf 316: char *lsplit(char *string, char delim) {
317: if(string) {
318: char *v=strchr(string, delim);
1.8 paf 319: if(v) {
320: *v=0;
321: return v+1;
322: }
323: }
324: return 0;
325: }
326:
327: char *lsplit(char **string_ref, char delim) {
328: char *result=*string_ref;
329: char *next=lsplit(*string_ref, delim);
330: *string_ref=next;
331: return result;
1.9 paf 332: }
333:
334: char *rsplit(char *string, char delim) {
1.18 paf 335: if(string) {
1.9 paf 336: char *v=strrchr(string, delim);
1.18 paf 337: if(v) {
1.9 paf 338: *v=0;
339: return v+1;
340: }
341: }
342: return NULL;
1.10 paf 343: }
344:
1.37 paf 345: /// @todo less stupid type detection
1.10 paf 346: char *format(Pool& pool, double value, char *fmt) {
1.78 paf 347: char *result=(char *)pool.malloc(MAX_NUMBER, 4);
1.10 paf 348: if(fmt)
349: if(strpbrk(fmt, "diouxX"))
350: if(strpbrk(fmt, "ouxX"))
1.33 paf 351: snprintf(result, MAX_NUMBER, fmt, (uint)value );
1.10 paf 352: else
1.33 paf 353: snprintf(result, MAX_NUMBER, fmt, (int)value );
1.10 paf 354: else
355: snprintf(result, MAX_NUMBER, fmt, value);
356: else
1.33 paf 357: snprintf(result, MAX_NUMBER, "%d", (int)value);
1.10 paf 358:
359: return result;
1.12 paf 360: }
361:
1.36 paf 362: size_t stdout_write(const void *buf, size_t size) {
1.12 paf 363: #ifdef WIN32
364: do{
365: int chunk_written=fwrite(buf, 1, min(8*0x400, size), stdout);
366: if(chunk_written<=0)
367: break;
368: size-=chunk_written;
1.36 paf 369: buf=((const char*)buf)+chunk_written;
1.12 paf 370: } while(size>0);
371:
372: return size;
373: #else
1.13 paf 374: return fwrite(buf, 1, size, stdout);
1.12 paf 375: #endif
1.2 paf 376: }
1.14 paf 377:
1.77 parser 378: char *unescape_chars(Pool& pool, const char *cp, int len) {
1.78 paf 379: char *s=(char *)pool.malloc(len + 1, 5);
1.14 paf 380: enum EscapeState {
1.33 paf 381: EscapeRest,
382: EscapeFirst,
1.14 paf 383: EscapeSecond
384: } escapeState=EscapeRest;
385: int escapedValue=0;
386: int srcPos=0;
387: int dstPos=0;
388: while(srcPos < len) {
389: int ch=cp[srcPos];
390: switch(escapeState) {
391: case EscapeRest:
392: if(ch=='%') {
393: escapeState=EscapeFirst;
394: } else if(ch=='+') {
395: s[dstPos++]=' ';
396: } else {
397: s[dstPos++]=ch;
398: }
399: break;
400: case EscapeFirst:
401: escapedValue=hex_value[ch] << 4;
402: escapeState=EscapeSecond;
403: break;
404: case EscapeSecond:
405: escapedValue +=hex_value[ch];
406: s[dstPos++]=escapedValue;
407: escapeState=EscapeRest;
408: break;
409: }
410: srcPos++;
411: }
412: s[dstPos]=0;
413: return s;
414: }
415:
1.52 paf 416: /// used by attributed_meaning_to_string / append_attribute_subattribute
1.40 paf 417: struct Attributed_meaning_info {
1.52 paf 418: String *header; // header line being constructed
419: String::Untaint_lang lang; // language in which to append to that line
1.40 paf 420: };
1.17 paf 421: static void append_attribute_subattribute(const Hash::Key& akey, Hash::Val *avalue,
1.14 paf 422: void *info) {
423: if(akey==VALUE_NAME)
424: return;
425:
1.40 paf 426: Attributed_meaning_info& ami=*static_cast<Attributed_meaning_info *>(info);
427:
1.14 paf 428: // ...; charset=windows1251
1.48 paf 429: *ami.header << "; ";
1.70 parser 430: ami.header->append(akey, ami.lang);
1.48 paf 431: *ami.header << "=";
1.70 parser 432: ami.header->append(static_cast<Value *>(avalue)->as_string(), ami.lang);
1.14 paf 433: }
1.49 paf 434: const String& attributed_meaning_to_string(Value& meaning,
435: String::Untaint_lang lang) {
1.20 paf 436: String &result=*new(meaning.pool()) String(meaning.pool());
1.75 parser 437: if(Hash *hash=meaning.get_hash(0)) {
1.14 paf 438: // $value(value) $subattribute(subattribute value)
439: if(Value *value=static_cast<Value *>(hash->get(*value_name)))
1.40 paf 440: result.append(value->as_string(), lang, true);
1.14 paf 441:
1.40 paf 442: Attributed_meaning_info attributed_meaning_info={
1.52 paf 443: &result,
444: lang
1.40 paf 445: };
446: hash->for_each(append_attribute_subattribute, &attributed_meaning_info);
1.14 paf 447: } else // result value
1.40 paf 448: result.append(meaning.as_string(), lang, true);
1.14 paf 449:
450: return result;
1.24 paf 451: }
452:
453: #ifdef WIN32
454: void back_slashes_to_slashes(char *s) {
455: if(s)
456: for(; *s; s++)
457: if(*s=='\\')
458: *s='/';
459: }
1.42 paf 460: /*
461: void slashes_to_back_slashes(char *s) {
462: if(s)
463: for(; *s; s++)
464: if(*s=='/')
465: *s='\\';
466: }
467: */
1.24 paf 468: #endif
1.41 paf 469:
470: bool StrEqNc(const char *s1, const char *s2, bool strict) {
471: while(true) {
472: if(!(*s1)) {
473: if(!(*s2))
474: return true;
475: else
476: return !strict;
477: } else if(!(*s2))
478: return !strict;
479: if(isalpha(*s1)) {
480: if(tolower(*s1) !=tolower(*s2))
481: return false;
482: } else if((*s1) !=(*s2))
483: return false;
484: s1++;
485: s2++;
486: }
1.57 parser 487: }
488:
1.84 paf 489: static bool isLeap(int year) {
1.57 parser 490: return !(
491: (year % 4) || ((year % 400) && !(year % 100))
492: );
493: }
494:
495: int getMonthDays(int year, int month) {
496: int monthDays[]={
497: 31,
498: isLeap(year) ? 29 : 28,
499: 31,
500: 30,
501: 31,
502: 30,
503: 31,
504: 31,
505: 30,
506: 31,
507: 30,
508: 31
509: };
510: return monthDays[month];
1.41 paf 511: }
1.69 parser 512:
513: void remove_crlf(char *start, char *end) {
514: for(char *p=start; p<end; p++)
515: switch(*p) {
516: case '\n': *p='|'; break;
517: case '\r': *p=' '; break;
518: }
1.74 parser 519: }
E-mail: