#ifndef __STRBUF_H #define __STRBUF_H #ifdef __cplusplus extern "C" { #endif #define STRBUF_MAXLINE (2*PATH_MAX) typedef void (*strbuf_error)( const char *fmt, ... ); struct strbuf { size_t alloc; size_t len; strbuf_error fatal; char *buf; }; /************************************************************************ Таблица размещается на стороне клиента, а указатель присваивается переменной strbuf_envtab, который используется функциями чтения файлов для подстановки значений вместо переменных: ${root-title}, ${root-desc}, ${repo}, ${repo-desc}, ... Освобождать выделенную память нет необходимости, так как таблица используется в CGI-скрипте, который срабатывает однократно. При необходимости повторного создания таблицы переменных, надо освободить память с помощью envtab_release( &strbuf_envtab ) которая обнулит указатель strbuf_envtab, являющийся адресом первой записи в таблице. */ typedef void (*envtab_error)( const char *fmt, ... ); struct symbol { char *name; char *value; struct symbol *next; }; extern struct symbol *strbuf_envtab; extern struct symbol *envtab_install( struct symbol **sym, const char *n, const char *v, envtab_error fatal ); extern struct symbol *envtab_lookup( struct symbol **sym, const char *n ); extern void envtab_release( struct symbol **sym ); /* ************************************************************************/ extern char strbuf_slopbuf[]; extern void strbuf_fatal( const char *fmt, ... ); #define STRBUF_INIT { .alloc = 0, .len = 0, .fatal = strbuf_fatal, .buf = strbuf_slopbuf } extern void strbuf_grow( struct strbuf *sb, size_t amount ); extern void strbuf_init( struct strbuf *sb, strbuf_error fatal, size_t alloc ); extern void strbuf_release( struct strbuf *sb ); extern char *strbuf_detach( struct strbuf *sb, size_t *sz ); extern void strbuf_attach( struct strbuf *sb, void *str, size_t len, size_t mem ); static inline size_t strbuf_avail( const struct strbuf *sb ) { return sb->alloc ? sb->alloc - sb->len - 1 : 0; } static inline void strbuf_setlen(struct strbuf *sb, size_t len) { if( len > (sb->alloc ? sb->alloc - 1 : 0) ) sb->fatal( "BUG: strbuf_setlen() beyond buffer" ); sb->len = len; if (sb->buf != strbuf_slopbuf) sb->buf[len] = '\0'; else if( !strbuf_slopbuf[0] ) sb->fatal( "BUG: strbuf_slopbuf[0] = '\0'" ); } #define strbuf_reset(sb) strbuf_setlen(sb, 0) /*************************************************************************** BUILD_ASSERT_OR_ZERO - assert a build-time dependency, as an expression. @cond: the compile-time condition which must be true. Your compile will fail if the condition isn't true, or can't be evaluated by the compiler. This can be used in an expression: its value is "0". Example: #define foo_to_char(foo) \ ((char *)(foo) \ + BUILD_ASSERT_OR_ZERO(offsetof(struct foo, string) == 0)) ***************************************************************************/ #define BUILD_ASSERT_OR_ZERO(cond) \ (sizeof(char [1 - 2*!(cond)]) - 1) #define SWAP(a, b) \ do { \ void *_swap_a_ptr = &(a); \ void *_swap_b_ptr = &(b); \ unsigned char _swap_buffer[sizeof(a)]; \ memcpy(_swap_buffer, _swap_a_ptr, sizeof(a)); \ memcpy(_swap_a_ptr, _swap_b_ptr, sizeof(a) + \ BUILD_ASSERT_OR_ZERO(sizeof(a) == sizeof(b))); \ memcpy(_swap_b_ptr, _swap_buffer, sizeof(a)); \ } while (0) static inline void strbuf_swap( struct strbuf *a, struct strbuf *b ) { SWAP(*a, *b); } extern void strbuf_ltrim( struct strbuf *sb ); extern void strbuf_rtrim( struct strbuf *sb ); extern void strbuf_trim( struct strbuf *sb ); #ifndef is_dir_sep static inline int is_dir_sep( int c ) { return c == '/'; } #endif static inline int is_absolute_path( const char *path ) { return is_dir_sep( path[0] ); } extern void strbuf_trim_trailing_dir_sep( struct strbuf *sb ); extern void strbuf_trim_trailing_newline( struct strbuf *sb ); extern int strbuf_cmp( const struct strbuf *a, const struct strbuf *b ); /* Adding data to the buffer */ extern void strbuf_add( struct strbuf *sb, const void *data, size_t len ); extern void strbuf_addbuf( struct strbuf *sb, const struct strbuf *sb2 ); extern void strbuf_addbuf_percentquote( struct strbuf *dst, const struct strbuf *src ); /* Add a single ASCII character to the buffer. */ static inline void strbuf_addch( struct strbuf *sb, int c ) { if( !strbuf_avail(sb) ) strbuf_grow(sb, 1); sb->buf[sb->len++] = c; sb->buf[sb->len] = '\0'; } /* Add n ASCII characters to the buffer. */ extern void strbuf_addchars( struct strbuf *sb, int c, size_t n ); /* Add a NUL-terminated string to the buffer. */ static inline void strbuf_addstr( struct strbuf *sb, const char *s ) { strbuf_add( sb, (const void *)s, strlen(s) ); } extern void strbuf_vaddf( struct strbuf *sb, const char *fmt, va_list ap ); extern void strbuf_addf( struct strbuf *sb, const char *fmt, ... ); extern size_t strbuf_fread( struct strbuf *sb, FILE *fp ); extern size_t strbuf_env_fread( struct strbuf *sb, FILE *fp ); extern size_t strbuf_fwrite( struct strbuf *sb, FILE *fp ); extern ssize_t strbuf_read( struct strbuf *sb, int fd, size_t hint ); extern ssize_t strbuf_write( struct strbuf *sb, int fd ); /* XML/HTML quoted: */ extern void strbuf_addstr_xml_quoted( struct strbuf *sb, const char *s ); extern void strbuf_addstr_html_quoted( struct strbuf *sb, const char *s ); /* urlencode: */ typedef int (*char_predicate)(char ch); extern int is_rfc3986_unreserved( char ch ); extern int is_rfc3986_reserved_or_unreserved( char ch ); extern void strbuf_addstr_urlencode( struct strbuf *sb, const char *name, char_predicate allow_unencoded_fn ); extern void strbuf_humanise_bytes( struct strbuf *sb, off_t bytes ); extern void strbuf_humanise_rate( struct strbuf *sb, off_t bytes ); extern int is_directory( const char *path ); extern void strbuf_selfdir( struct strbuf *sb ); extern void strbuf_relpath( struct strbuf *sb, const char *path ); extern void strbuf_abspath( struct strbuf *sb, const char *path ); #ifdef __cplusplus } #endif #endif /* __STRBUF_H */