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