summaryrefslogtreecommitdiff
path: root/src/common/strlib.h
blob: 006bbd14b415216eee8dd7a88a5871ad757c54b6 (plain) (blame)
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
203
204
205
206
207
208
209
210
211
212
213
214
215
216
/**
 * This file is part of Hercules.
 * http://herc.ws - http://github.com/HerculesWS/Hercules
 *
 * Copyright (C) 2012-2018  Hercules Dev Team
 * Copyright (C)  Athena Dev Teams
 *
 * Hercules is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
#ifndef COMMON_STRLIB_H
#define COMMON_STRLIB_H

#include "common/hercules.h"

#include <stdarg.h>
#include <string.h>

/// Convenience macros

#define remove_control_chars(str)  (strlib->remove_control_chars_(str))
#define trim(str)                  (strlib->trim_(str))
#define normalize_name(str,delims) (strlib->normalize_name_((str),(delims)))
#define stristr(haystack,needle)   (strlib->stristr_((haystack),(needle)))

#if !(defined(WIN32) && defined(_MSC_VER)) && !defined(HAVE_STRNLEN)
	#define strnlen(string,maxlen) (strlib->strnlen_((string),(maxlen)))
#endif

#ifdef WIN32
	#define HAVE_STRTOK_R
	#define strtok_r(s,delim,save_ptr) strlib->strtok_r_((s),(delim),(save_ptr))
#endif

#define e_mail_check(email)          (strlib->e_mail_check_(email))
#define config_switch(str)           (strlib->config_switch_(str))
#define safestrncpy(dst,src,n)       (strlib->safestrncpy_((dst),(src),(n)))
#define safestrnlen(string,maxlen)   (strlib->safestrnlen_((string),(maxlen)))
#define safesnprintf(buf,sz,fmt,...) (strlib->safesnprintf_((buf),(sz),(fmt),##__VA_ARGS__))
#define strline(str,pos)             (strlib->strline_((str),(pos)))
#define bin2hex(output,input,count)  (strlib->bin2hex_((output),(input),(count)))
#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L)
#if defined(__GNUC__) && !defined(__clang__) && GCC_VERSION < 40900
// _Generic is only supported starting with GCC 4.9
#else
#ifdef strchr
#undef strchr
#endif // strchr
#define strchr(src, chr)             _Generic((src), \
		const char * : ((const char *)(strchr)((src), (chr))), \
		char *       : ((strchr)((src), (chr))) \
		)
#define strrchr(src, chr)            _Generic((src), \
		const char * : ((const char *)(strrchr)((src), (chr))), \
		char *       : ((strrchr)((src), (chr))) \
		)
#define strstr(haystack, needle)     _Generic((haystack), \
		const char * : ((const char *)(strstr)((haystack), (needle))), \
		char *       : ((strstr)((haystack), (needle))) \
		)
#endif
#endif

/// Bitfield determining the behavior of sv_parse and sv_split.
typedef enum e_svopt {
	// default: no escapes and no line terminator
	SV_NOESCAPE_NOTERMINATE = 0,
	// Escapes according to the C compiler.
	SV_ESCAPE_C = 1,
	// Line terminators
	SV_TERMINATE_LF = 2,
	SV_TERMINATE_CRLF = 4,
	SV_TERMINATE_CR = 8,
	// If sv_split keeps the end of line terminator, instead of replacing with '\0'
	SV_KEEP_TERMINATOR = 16
} e_svopt;

/// Other escape sequences supported by the C compiler.
#define SV_ESCAPE_C_SUPPORTED "abtnvfr\?\"'\\"

/// Parse state.
/// The field is [start,end[
struct s_svstate {
	const char* str; //< string to parse
	int len; //< string length
	int off; //< current offset in the string
	int start; //< where the field starts
	int end; //< where the field ends
	enum e_svopt opt; //< parse options
	char delim; //< field delimiter
	bool done; //< if all the text has been parsed
};


/// StringBuf - dynamic string
struct StringBuf {
	char *buf_;
	char *ptr_;
	unsigned int max_;
};
typedef struct StringBuf StringBuf;

struct strlib_interface {
	char *(*jstrescape) (char* pt);
	char *(*jstrescapecpy) (char* pt, const char* spt);
	int (*jmemescapecpy) (char* pt, const char* spt, int size);
	int (*remove_control_chars_) (char* str);
	char *(*trim_) (char* str);
	char *(*normalize_name_) (char* str,const char* delims);
	const char *(*stristr_) (const char *haystack, const char *needle);

	/* only used when '!(defined(WIN32) && defined(_MSC_VER)) && !defined(HAVE_STRNLEN)', needs to be defined at all times however  */
	size_t (*strnlen_) (const char* string, size_t maxlen);

	/* only used when 'WIN32' */
	char * (*strtok_r_) (char *s1, const char *s2, char **lasts);

	int (*e_mail_check_) (char* email);
	int (*config_switch_) (const char* str);

	/// strncpy that always null-terminates the string
	char *(*safestrncpy_) (char* dst, const char* src, size_t n);

	/// doesn't crash on null pointer
	size_t (*safestrnlen_) (const char* string, size_t maxlen);

	/// Works like snprintf, but always null-terminates the buffer.
	/// Returns the size of the string (without null-terminator)
	/// or -1 if the buffer is too small.
	int (*safesnprintf_) (char *buf, size_t sz, const char *fmt, ...) __attribute__((format(printf, 3, 4)));

	/// Returns the line of the target position in the string.
	/// Lines start at 1.
	int (*strline_) (const char* str, size_t pos);

	/// Produces the hexadecimal representation of the given input.
	/// The output buffer must be at least count*2+1 in size.
	/// Returns true on success, false on failure.
	bool (*bin2hex_) (char *output, const unsigned char *input, size_t count);
};

struct stringbuf_interface {
	StringBuf* (*Malloc) (void);
	void (*Init) (StringBuf* self);
	int (*Printf) (StringBuf *self, const char *fmt, ...) __attribute__((format(printf, 2, 3)));
	int (*Vprintf) (StringBuf* self, const char* fmt, va_list args);
	int (*Append) (StringBuf* self, const StringBuf *sbuf);
	int (*AppendStr) (StringBuf* self, const char* str);
	int (*Length) (StringBuf* self);
	char* (*Value) (StringBuf* self);
	void (*Clear) (StringBuf* self);
	void (*Destroy) (StringBuf* self);
	void (*Free) (StringBuf* self);
};

struct sv_interface {
	/// Parses a single field in a delim-separated string.
	/// The delimiter after the field is skipped.
	///
	/// @param svstate Parse state
	/// @return 1 if a field was parsed, 0 if done, -1 on error.
	int (*parse_next) (struct s_svstate* svstate);

	/// Parses a delim-separated string.
	/// Starts parsing at startoff and fills the pos array with position pairs.
	/// out_pos[0] and out_pos[1] are the start and end of line.
	/// Other position pairs are the start and end of fields.
	/// Returns the number of fields found or -1 if an error occurs.
	int (*parse) (const char* str, int len, int startoff, char delim, int* out_pos, int npos, enum e_svopt opt);

	/// Splits a delim-separated string.
	/// WARNING: this function modifies the input string
	/// Starts splitting at startoff and fills the out_fields array.
	/// out_fields[0] is the start of the next line.
	/// Other entries are the start of fields (null-terminated).
	/// Returns the number of fields found or -1 if an error occurs.
	int (*split) (char* str, int len, int startoff, char delim, char** out_fields, int nfields, enum e_svopt opt);

	/// Escapes src to out_dest according to the format of the C compiler.
	/// Returns the length of the escaped string.
	/// out_dest should be len*4+1 in size.
	size_t (*escape_c) (char* out_dest, const char* src, size_t len, const char* escapes);

	/// Unescapes src to out_dest according to the format of the C compiler.
	/// Returns the length of the unescaped string.
	/// out_dest should be len+1 in size and can be the same buffer as src.
	size_t (*unescape_c) (char* out_dest, const char* src, size_t len);

	/// Skips a C escape sequence (starting with '\\').
	const char* (*skip_escaped_c) (const char* p);

	/// Opens and parses a file containing delim-separated columns, feeding them to the specified callback function row by row.
	/// Tracks the progress of the operation (current line number, number of successfully processed rows).
	/// Returns 'true' if it was able to process the specified file, or 'false' if it could not be read.
	bool (*readdb) (const char* directory, const char* filename, char delim, int mincols, int maxcols, int maxrows, bool (*parseproc)(char* fields[], int columns, int current));
};

#ifdef HERCULES_CORE
void strlib_defaults(void);
#endif // HERCULES_CORE

HPShared struct strlib_interface *strlib;
HPShared struct stringbuf_interface *StrBuf;
HPShared struct sv_interface *sv;

#endif /* COMMON_STRLIB_H */