summaryrefslogtreecommitdiff
path: root/csvncgi/strbuf.h
blob: 2d170a0d8ec6ec9a9949795425d3d15591710471 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
#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 */