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