summaryrefslogtreecommitdiff
path: root/src/common/strlib.h
blob: 9b1875d459b079f1de87ac0fe29827e239a2af61 (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
// Copyright (c) Hercules Dev Team, licensed under GNU GPL.
// See the LICENSE file
// Portions Copyright (c) Athena Dev Teams

#ifndef _STRLIB_H_
#define _STRLIB_H_

#include "../common/cbasetypes.h"
#include <stdarg.h>

#ifndef __USE_GNU
	#define __USE_GNU  // required to enable strnlen on some platforms
	#include <string.h>
	#undef __USE_GNU
#else
	#include <string.h>
#endif

#ifdef WIN32
	#define HAVE_STRTOK_R
	#define strtok_r(s,delim,save_ptr) _strtok_r((s),(delim),(save_ptr))
	char *_strtok_r(char* s1, const char* s2, char** lasts);
#endif

/// Bitfield determining the behaviour 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);
		
#if !(defined(WIN32) && defined(_MSC_VER) && _MSC_VER >= 1400) && !defined(HAVE_STRNLEN)
	size_t (*strnlen) (const char* string, size_t maxlen);
#endif
	
#if defined(WIN32) && defined(_MSC_VER) && _MSC_VER <= 1200
	uint64 (*strtoull) (const char* str, char** endptr, int base);
#endif
	
	int (*e_mail_check) (char* email);
	int (*config_switch) (const char* str);
	
	/// strncpy that always nul-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 nul-terminates the buffer.
	/// Returns the size of the string (without nul-terminator)
	/// or -1 if the buffer is too small.
	int (*safesnprintf) (char* buf, size_t sz, const char* fmt, ...);
	
	/// 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, unsigned char* input, size_t count);
} strlib_s;

struct strlib_interface *strlib;

struct stringbuf_interface {
	StringBuf* (*Malloc) (void);
	void (*Init) (StringBuf* self);
	int (*Printf) (StringBuf* self, const char* fmt, ...);
	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);
} stringbuf_s;

struct stringbuf_interface *StrBuf;

struct sv_interface {
	/// Parses a single field in a delim-separated string.
	/// The delimiter after the field is skipped.
	///
	/// @param sv Parse state
	/// @return 1 if a field was parsed, 0 if done, -1 on error.
	int (*parse_next) (struct s_svstate* sv);
	
	/// 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 (nul-teminated).
	/// 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));
} sv_s;

struct sv_interface *sv;

void strlib_defaults(void);

/* the purpose of these macros is simply to not make calling them be an annoyance */
#ifndef STRLIB_C
	#define jstrescape(pt) strlib->jstrescape(pt)
	#define jstrescapecpy(pt,spt) strlib->jstrescapecpy(pt,spt)
	#define jmemescapecpy(pt,spt,size) strlib->jmemescapecpy(pt,spt,size)
	#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) && _MSC_VER >= 1400) && !defined(HAVE_STRNLEN)
		#define strnln(string,maxlen) strlib->strnlen(string,maxlen)
	#endif

	#if defined(WIN32) && defined(_MSC_VER) && _MSC_VER <= 1200
		#define strtoull(str,endptr,base) strlib->strtoull(str,endptr,base)
	#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)
#endif /* STRLIB_C */
#endif /* _STRLIB_H_ */