/* sax_buf.h * Copyright (c) 2011, Peter Ohler * All rights reserved. */ #ifndef OX_SAX_BUF_H #define OX_SAX_BUF_H #include typedef struct _buf { char base[0x00001000]; char *head; char *end; char *tail; char *read_end; /* one past last character read */ char *pro; /* protection start, buffer can not slide past this point */ char *str; /* start of current string being read */ off_t pos; off_t line; off_t col; off_t pro_pos; off_t pro_line; off_t pro_col; int (*read_func)(struct _buf *buf); union { int fd; VALUE io; const char *str; } in; struct _saxDrive *dr; } *Buf; typedef struct _checkPt { off_t pro_dif; off_t pos; off_t line; off_t col; char c; } *CheckPt; #define CHECK_PT_INIT { -1, 0, 0, 0, '\0' } extern void ox_sax_buf_init(Buf buf, VALUE io); extern int ox_sax_buf_read(Buf buf); static inline char buf_get(Buf buf) { //printf("*** drive get from '%s' from start: %ld buf: %p from read_end: %ld\n", buf->tail, buf->tail - buf->head, buf->head, buf->read_end - buf->tail); if (buf->read_end <= buf->tail) { if (0 != ox_sax_buf_read(buf)) { return '\0'; } } if ('\n' == *buf->tail) { buf->line++; buf->col = 0; } else { buf->col++; } buf->pos++; return *buf->tail++; } static inline void buf_backup(Buf buf) { buf->tail--; buf->col--; buf->pos--; if (0 >= buf->col) { buf->line--; // allow col to be negative since we never backup twice in a row } } static inline void buf_protect(Buf buf) { buf->pro = buf->tail; buf->str = buf->tail; // can't have str before pro buf->pro_pos = buf->pos; buf->pro_line = buf->line; buf->pro_col = buf->col; } static inline void buf_reset(Buf buf) { buf->tail = buf->pro; buf->pos = buf->pro_pos; buf->line = buf->pro_line; buf->col = buf->pro_col; } /* Starts by reading a character so it is safe to use with an empty or * compacted buffer. */ static inline char buf_next_non_white(Buf buf) { char c; while ('\0' != (c = buf_get(buf))) { switch(c) { case ' ': case '\t': case '\f': case '\n': case '\r': break; default: return c; } } return '\0'; } /* Starts by reading a character so it is safe to use with an empty or * compacted buffer. */ static inline char buf_next_white(Buf buf) { char c; while ('\0' != (c = buf_get(buf))) { switch(c) { case ' ': case '\t': case '\f': case '\n': case '\r': case '\0': return c; default: break; } } return '\0'; } static inline void buf_cleanup(Buf buf) { if (buf->base != buf->head && 0 != buf->head) { xfree(buf->head); buf->head = 0; } } static inline int is_white(char c) { switch(c) { case ' ': case '\t': case '\f': case '\n': case '\r': return 1; default: break; } return 0; } static inline void buf_checkpoint(Buf buf, CheckPt cp) { cp->pro_dif = (int)(buf->tail - buf->pro); cp->pos = buf->pos; cp->line = buf->line; cp->col = buf->col; cp->c = *(buf->tail - 1); } static inline int buf_checkset(CheckPt cp) { return (0 <= cp->pro_dif); } static inline char buf_checkback(Buf buf, CheckPt cp) { buf->tail = buf->pro + cp->pro_dif; buf->pos = cp->pos; buf->line = cp->line; buf->col = cp->col; return cp->c; } static inline void buf_collapse_return(char *str) { char *s = str; char *back = str; for (; '\0' != *s; s++) { if (back != str && '\n' == *s && '\r' == *(back - 1)) { *(back - 1) = '\n'; } else { *back++ = *s; } } *back = '\0'; } static inline void buf_collapse_white(char *str) { char *s = str; char *back = str; for (; '\0' != *s; s++) { switch(*s) { case ' ': case '\t': case '\f': case '\n': case '\r': if (back == str || ' ' != *(back - 1)) { *back++ = ' '; } break; default: *back++ = *s; break; } } *back = '\0'; } #endif /* OX_SAX_BUF_H */