1 /*
2 Copyright (C) 2015-2021, Dirk Krause
3 SPDX-License-Identifier: BSD-3-Clause
4 */
5 
6 /*
7 	WARNING: This file was generated by the dkct program (see
8 	http://dktools.sourceforge.net/ for details).
9 	Changes you make here will be lost if dkct is run again!
10 	You should modify the original source and run dkct on it.
11 	Original source: dk4stt.ctr
12 */
13 
14 /**	@file dk4stt.c The dk4stt module.
15 */
16 
17 
18 #include "dk4conf.h"
19 #include <libdk4base/dk4error.h>
20 #include <libdk4base/dk4mem.h>
21 #include <libdk4base/dk4strd.h>
22 #include <libdk4c/dk4strm.h>
23 #include <libdk4c/dk4stt.h>
24 #include <libdk4c/dk4tspdk.h>
25 #include <libdk4c/dk4enc.h>
26 #include <libdk4base/dk4unused.h>
27 
28 #if DK4_HAVE_ASSERT_H
29 #ifndef	ASSERT_H_INCLUDED
30 #include <assert.h>
31 #define	ASSERT_H_INCLUDED 1
32 #endif
33 #endif
34 
35 
36 
37 
38 
39 
40 void
dk4stt_close(dk4_string_table_t * ptr)41 dk4stt_close(dk4_string_table_t *ptr)
42 {
43   dkChar		**stptr;
44   size_t		  nstrings;
45 
46 #if	DK4_USE_ASSERT
47 	assert(NULL != ptr);
48 #endif
49   if (NULL != ptr) {
50     if (NULL != ptr->strings) {
51       stptr = ptr->strings;
52       nstrings = ptr->nstrings;
53       while (0 < nstrings--) {
54         dk4mem_release(*stptr);
55         stptr++;
56       }
57       dk4mem_release(ptr->strings);
58     }
59     dk4mem_release(ptr->shrtfn);
60     ptr->nstrings = 0;
61     dk4mem_free(ptr);
62   }
63 }
64 
65 
66 
67 dk4_string_table_t *
dk4stt_open(const dkChar * fn,size_t sz,dk4_er_t * erp)68 dk4stt_open(const dkChar *fn, size_t sz, dk4_er_t *erp)
69 {
70   dk4_string_table_t	 *back	= NULL;
71   dkChar		**stptr	= NULL;
72   int			  ok	= 0;
73 
74 #if	DK4_USE_ASSERT
75 	assert(NULL != fn);
76 	assert(0 < sz);
77 #endif
78   if ((NULL != fn) && (0 < sz)) {
79     back = dk4mem_new(dk4_string_table_t,1,erp);
80     if (NULL != back) {
81       back->strings = NULL;
82       back->nstrings = 0;
83       back->shrtfn = dk4str_dup(fn, erp);
84       if (NULL != back->shrtfn) {
85         back->nstrings = sz;
86         back->strings = dk4mem_new(DK4_PDKCHAR,sz,erp);
87 	if (NULL != back->strings) {
88 	  stptr = back->strings;
89 	  while (0 < sz--) { *(stptr++) = NULL; }
90 	  ok = 1;
91 	}
92       }
93       if (1 > ok) {
94         dk4stt_close(back);
95 	back = NULL;
96       }
97     }
98   } else {
99     dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS);
100   }
101   return back;
102 }
103 
104 
105 
106 int
dk4stt_compare(const void * l,const void * r,int cr)107 dk4stt_compare(const void *l, const void *r, int cr)
108 {
109   int				 back	=	0;
110   const dk4_string_table_t	*pl;
111   const dk4_string_table_t	*pr;
112 
113   if (NULL != l) {
114     if (NULL != r) {
115       pl = (const dk4_string_table_t *)l;
116       switch (cr) {
117         case 1: {
118 	  if (NULL != pl->shrtfn) {
119 	    back = dk4str_cmp(pl->shrtfn, (const dkChar *)r);
120 	  } else {
121 	    back = -1;
122 	  }
123 	} break;
124 	default: {
125 	  pr = (const dk4_string_table_t *)r;
126 	  if (NULL != pl->shrtfn) {
127 	    if (NULL != pr->shrtfn) {
128 	      back = dk4str_cmp(pl->shrtfn, pr->shrtfn);
129 	    } else {
130 	      back = 1;
131 	    }
132 	  } else {
133 	    if (NULL != pr->shrtfn) {
134 	      back = -1;
135 	    }
136 	  }
137 	} break;
138       }
139     } else {
140       back = 1;
141     }
142   } else {
143     if (NULL != r) {
144       back = -1;
145     }
146   }
147   return back;
148 }
149 
150 
151 
152 /**	Structure to read a string table from stream.
153 */
154 typedef struct {
155   dk4_string_table_t	*dptr;		/**< String table to configure. */
156   size_t		 curpos;	/**< Current line number. */
157 } dk4_string_table_reader_t;
158 
159 
160 
161 /**	Handler function for text lines.
162 	@param	obj	Object to modify while processing the character.
163 	@param	line	Text line to process.
164 	@param	lineno	Current line number.
165 	@param	erp	Error report, may be NULL.
166 	@return	DK4_TSP_RES_OK		if the character was processed
167 					successfully,
168 		DK4_TSP_RES_ERROR	if there was an error but we can
169 					continue,
170 		DK4_TSP_RES_FATAL	if there was a fatal error so we
171 					should abort processing.
172 */
173 static
174 int
dk4stt_line_handler(void * obj,dkChar * line,dk4_um_t DK4_ARG_UNUSED (lineno),dk4_er_t * DK4_ARG_UNUSED (erp))175 dk4stt_line_handler(
176   void		*obj,
177   dkChar	*line,
178   dk4_um_t	 DK4_ARG_UNUSED(lineno),
179   dk4_er_t	* DK4_ARG_UNUSED(erp)
180 )
181 {
182   dk4_string_table_reader_t	*reader;		/* Reader structure */
183 #if TRACE_DEBUG
184   dkChar			*olcp;			/* Original pointer */
185 #endif
186   dkChar			*linecp;		/* Copy of line */
187   int		 		 back = DK4_TSP_RES_ERROR;
188 
189   DK4_UNUSED_ARG(lineno)
190   DK4_UNUSED_ARG(erp)
191   reader = (dk4_string_table_reader_t *)obj;
192   if (dkT('#') != line[0]) {
193     if (reader->curpos < reader->dptr->nstrings) {
194       linecp = dk4str_dup(line, NULL);
195       if (NULL != linecp) {
196 #if TRACE_DEBUG
197 	olcp = linecp;
198 #endif
199         /* Save copy of line to string table */
200         (reader->dptr->strings)[reader->curpos] = linecp;
201 	reader->curpos += 1;
202 	back = DK4_TSP_RES_OK;
203 	/* Handle backslash escape sequences, remove trailing newline */
204 	while (dkT('\0') != *linecp) {
205 	  if (dkT('\\') == *linecp) {
206 	    if (dkT('r') == linecp[1]) {
207 	      *linecp = dkT('\r');
208 	      dk4str_cpy_to_left(&(linecp[1]), &(linecp[2]));
209 	    } else {
210 	      if (dkT('n') == linecp[1]) {
211 	        *linecp = dkT('\n');
212 		dk4str_cpy_to_left(&(linecp[1]), &(linecp[2]));
213 	      } else {
214 	        if (dkT('t') == linecp[1]) {
215 		  *linecp = dkT('\t');
216 		  dk4str_cpy_to_left(&(linecp[1]), &(linecp[2]));
217 		} else {
218 	          dk4str_cpy_to_left(linecp, &(linecp[1]));
219 		  if (dkT('\0') == *linecp) { linecp--; }
220 		}
221 	      }
222 	    }
223 	  } else {
224 	    if (dkT('\n') == *linecp) {
225 	      *linecp = dkT('\0');
226 	      linecp--;
227 	    } else {
228 	      if ((dkT('\r') == *linecp) && (dkT('\n') == linecp[1])) {
229 	        *linecp = dkT('\0');
230 		linecp--;
231 	      }
232 	    }
233 	  }
234 	  linecp++;
235 	}
236       } else {
237         /* Not enough memory. */
238         back = DK4_TSP_RES_FATAL;
239       }
240     } else {
241       /* More lines than expected, ignore additional lines. */
242       back = DK4_TSP_RES_OK;
243     }
244   } else {
245     /* Comment line, no processing required. */
246     back = DK4_TSP_RES_OK;
247   }
248   return back;
249 }
250 
251 
252 
253 int
dk4stt_apply_stream(dk4_string_table_t * tptr,dk4_stream_t * strm,int pre,dk4_er_t * erp2)254 dk4stt_apply_stream(
255   dk4_string_table_t	*tptr,
256   dk4_stream_t		*strm,
257   int			 pre,
258   dk4_er_t		*erp2
259 )
260 {
261   dkChar			line[1024];	/* Input line buffer */
262   char				buf[4096];	/* Buffer for stream input */
263   dk4_string_table_reader_t	reader;		/* Reader structure */
264   dk4_tspdk_t			tspdk;		/* Text stream processor */
265   dk4_er_t			e1;		/* Error report f decoding */
266   dk4_er_t			e2;		/* Error report f processing */
267   size_t			rdb;		/* Bytes read */
268   int				cc;		/* Flag: Can continue */
269   int		 		back	= 0;
270 
271 #if	DK4_USE_ASSERT
272 	assert(NULL != tptr);
273 	assert(NULL != strm);
274 #endif
275   if ((NULL != tptr) && (NULL != strm)) {
276     dk4error_init(&e1);
277     dk4error_init(&e2);
278     reader.dptr		= tptr;
279     reader.curpos	= 0;
280     back = dk4tspdk_setup_line(
281       &tspdk, (void *)(&reader), dk4stt_line_handler,
282       line, DK4_SIZEOF(line,dkChar),
283       pre, DK4_FILE_ENCODING_UTF8, &e2
284     );
285     if (0 < back) {
286 #if VERSION_BEFORE_20150821
287       cc = 1;
288 #endif
289       do {
290         cc = 0;
291 	rdb = sizeof(buf);
292 	if (0 < dk4stream_read(buf, &rdb, strm, NULL)) {
293 	  if (0 < rdb) {
294 	    switch (dk4tspdk_add_bytes(&tspdk, (unsigned char *)buf, rdb)) {
295 	      case DK4_TSP_RES_OK: {
296 	        cc = 1;
297 	      } break;
298 	      case DK4_TSP_RES_ERROR: {
299 	        cc = 1;
300 	      } break;
301 	      default: {
302 	        back = 0;
303 	      } break;
304 	    }
305 	  } else {
306 	  }
307 	} else {
308 	}
309       } while (cc);
310       if (0 < back) {
311 	if (DK4_TSP_RES_FATAL == dk4tspdk_finish(&tspdk)) {
312 	  back = 0;
313 	}
314 	if (0 < back) {
315 	  if (reader.curpos < (reader.dptr)->nstrings) {
316 	    back = 0;
317 
318 
319 	  }
320 	}
321       }
322     } else {
323     }
324   } else {
325     dk4error_set_simple_error_code(erp2, DK4_E_INVALID_ARGUMENTS);
326   }
327   return back;
328 }
329 
330 
331