1 // Copyright (c) 1999-2018 David Muse
2 // See the file COPYING for more information
3 
4 #include <rudiments/dynamiclib.h>
5 #include <rudiments/file.h>
6 
7 
8 // types...
9 typedef void		CS_VOID;
10 typedef	unsigned char	CS_BYTE;
11 typedef char		CS_CHAR;
12 typedef	short		CS_SMALLINT;
13 typedef	int		CS_INT;
14 typedef	int		CS_BOOL;
15 typedef	int		CS_RETCODE;
16 typedef unsigned int	CS_MSGNUM;
17 
18 
19 // structs...
20 struct CS_CONTEXT;
21 struct CS_CONNECTION;
22 struct CS_COMMAND;
23 struct CS_LOCALE;
24 
25 struct CS_DATAFMT {
26 	CS_CHAR		name[256];
27 	CS_INT		namelen;
28 	CS_INT		datatype;
29 	CS_INT		format;
30 	CS_INT		maxlength;
31 	CS_INT		scale;
32 	CS_INT		precision;
33 	CS_INT		status;
34 	CS_INT		count;
35 	CS_INT		usertype;
36 	CS_LOCALE	*locale;
37 };
38 
39 struct CS_DATEREC {
40 	CS_INT		dateyear;
41 	CS_INT		datemonth;
42 	CS_INT		datedmonth;
43 	CS_INT		datedyear;
44 	CS_INT		datedweek;
45 	CS_INT		datehour;
46 	CS_INT		dateminute;
47 	CS_INT		datesecond;
48 	CS_INT		datemsecond;
49 	CS_INT		datetzone;
50 	CS_INT		datesecfrac;
51 	CS_INT		datesecprec;
52 };
53 
54 struct CS_DATETIME {
55 	CS_INT		dtdays;
56 	CS_INT		dttime;
57 };
58 
59 struct CS_CLIENTMSG {
60 	CS_INT		severity;
61 	CS_MSGNUM	msgnumber;
62 	CS_CHAR		msgstring[1024];
63 	CS_INT		msgstringlen;
64 	CS_INT		osnumber;
65 	CS_CHAR		osstring[1024];
66 	CS_INT		osstringlen;
67 	CS_INT		status;
68 	CS_BYTE		sqlstate[8];
69 	CS_INT		sqlstatelen;
70 };
71 
72 struct CS_SERVERMSG {
73 	CS_MSGNUM	msgnumber;
74 	CS_INT		state;
75 	CS_INT		severity;
76 	CS_CHAR		text[1024];
77 	CS_INT		textlen;
78 	CS_CHAR		svrname[256];
79 	CS_INT		svrnlen;
80 	CS_CHAR		proc[256];
81 	CS_INT		proclen;
82 	CS_INT		line;
83 	CS_INT		status;
84 	CS_BYTE		sqlstate[8];
85 	CS_INT		sqlstatelen;
86 };
87 
88 #define CS_LAYER(L)	(CS_MSGNUM) (((L) >> 24) & 0xff)
89 #define CS_ORIGIN(O)	(CS_MSGNUM) (((O) >> 16) & 0xff)
90 #define CS_SEVERITY(S)	(CS_MSGNUM) (((S) >> 8) & 0xff)
91 #define CS_NUMBER(N)	(CS_MSGNUM) ((N) & 0xff)
92 
93 
94 // create aliases to prevent collisions
95 // eg. cs_ctx_alloc calls cs_config and if my function pointer is named
96 // cs_config, then when cs_ctx_alloc calls cs_config it ends up jumping to the
97 // location of the variable (not the location stored in the variable), rather
98 // than the location of the function.
99 #define ct_init ct_init_ptr
100 #define ct_callback ct_callback_ptr
101 #define ct_con_alloc ct_con_alloc_ptr
102 #define ct_con_props ct_con_props_ptr
103 #define ct_connect ct_connect_ptr
104 #define ct_cancel ct_cancel_ptr
105 #define ct_con_drop ct_con_drop_ptr
106 #define ct_exit ct_exit_ptr
107 #define ct_close ct_close_ptr
108 #define ct_cmd_alloc ct_cmd_alloc_ptr
109 #define ct_cmd_drop ct_cmd_drop_ptr
110 #define ct_cursor ct_cursor_ptr
111 #define ct_command ct_command_ptr
112 #define ct_param ct_param_ptr
113 #define ct_send ct_send_ptr
114 #define ct_results ct_results_ptr
115 #define ct_res_info ct_res_info_ptr
116 #define ct_bind ct_bind_ptr
117 #define ct_describe ct_describe_ptr
118 #define ct_fetch ct_fetch_ptr
119 #define cs_ctx_alloc cs_ctx_alloc_ptr
120 #define cs_config cs_config_ptr
121 #define cs_locale cs_locale_ptr
122 #define cs_loc_alloc cs_loc_alloc_ptr
123 #define cs_loc_drop cs_loc_drop_ptr
124 #define cs_ctx_drop cs_ctx_drop_ptr
125 #define cs_dt_crack cs_dt_crack_ptr
126 
127 
128 // function pointers...
129 CS_RETCODE (*ct_init)(
130 		CS_CONTEXT *,
131 		CS_INT);
132 
133 CS_RETCODE (*ct_callback)(
134 		CS_CONTEXT *,
135 		CS_CONNECTION *,
136 		CS_INT,
137 		CS_INT,
138 		CS_VOID *);
139 
140 CS_RETCODE (*ct_con_alloc)(
141 		CS_CONTEXT *,
142 		CS_CONNECTION **);
143 
144 CS_RETCODE (*ct_con_props)(
145 		CS_CONNECTION *,
146 		CS_INT,
147 		CS_INT,
148 		CS_VOID *,
149 		CS_INT,
150 		CS_INT *);
151 
152 CS_RETCODE (*ct_connect)(
153 		CS_CONNECTION *,
154 		CS_CHAR *,
155 		CS_INT);
156 
157 CS_RETCODE (*ct_cancel)(
158 		CS_CONNECTION *,
159 		CS_COMMAND *,
160 		CS_INT);
161 
162 CS_RETCODE (*ct_con_drop)(
163 		CS_CONNECTION *);
164 
165 CS_RETCODE (*ct_exit)(
166 		CS_CONTEXT *,
167 		CS_INT);
168 
169 CS_RETCODE (*ct_close)(
170 		CS_CONNECTION *,
171 		CS_INT);
172 
173 CS_RETCODE (*ct_cmd_alloc)(
174 		CS_CONNECTION *,
175 		CS_COMMAND **);
176 
177 CS_RETCODE (*ct_cmd_drop)(
178 		CS_COMMAND *);
179 
180 CS_RETCODE (*ct_cursor)(
181 		CS_COMMAND *,
182 		CS_INT,
183 		CS_CHAR *,
184 		CS_INT,
185 		CS_CHAR *,
186 		CS_INT,
187 		CS_INT);
188 
189 CS_RETCODE (*ct_command)(
190 		CS_COMMAND *,
191 		CS_INT,
192 		CS_CHAR *,
193 		CS_INT,
194 		CS_INT);
195 
196 CS_RETCODE (*ct_param)(
197 		CS_COMMAND *,
198 		CS_DATAFMT *,
199 		CS_VOID *,
200 		CS_INT,
201 		CS_SMALLINT);
202 
203 CS_RETCODE (*ct_send)(
204 		CS_COMMAND *);
205 
206 CS_RETCODE (*ct_results)(
207 		CS_COMMAND *,
208 		CS_INT *);
209 
210 CS_RETCODE (*ct_res_info)(
211 		CS_COMMAND *,
212 		CS_INT,
213 		CS_VOID *,
214 		CS_INT,
215 		CS_INT *);
216 
217 CS_RETCODE (*ct_bind)(
218 		CS_COMMAND *,
219 		CS_INT,
220 		CS_DATAFMT *,
221 		CS_VOID *,
222 		CS_INT *,
223 		CS_SMALLINT *);
224 
225 CS_RETCODE (*ct_describe)(
226 		CS_COMMAND *,
227 		CS_INT,
228 		CS_DATAFMT *);
229 
230 CS_RETCODE (*ct_fetch)(
231 		CS_COMMAND *,
232 		CS_INT,
233 		CS_INT,
234 		CS_INT,
235 		CS_INT *);
236 
237 CS_RETCODE (*cs_ctx_alloc)(
238 		CS_INT,
239 		CS_CONTEXT **);
240 
241 CS_RETCODE (*cs_config)(
242 		CS_CONTEXT *,
243 		CS_INT,
244 		CS_INT,
245 		CS_VOID *,
246 		CS_INT,
247 		CS_INT *);
248 
249 CS_RETCODE (*cs_locale)(
250 		CS_CONTEXT *,
251 		CS_INT,
252 		CS_LOCALE *,
253 		CS_INT,
254 		CS_CHAR *,
255 		CS_INT,
256 		CS_INT *);
257 
258 CS_RETCODE (*cs_loc_alloc)(
259 		CS_CONTEXT *,
260 		CS_LOCALE **);
261 
262 CS_RETCODE (*cs_loc_drop)(
263 		CS_CONTEXT *,
264 		CS_LOCALE *);
265 
266 CS_RETCODE (*cs_ctx_drop)(
267 		CS_CONTEXT *);
268 
269 CS_RETCODE (*cs_dt_crack)(
270 		CS_CONTEXT *,
271 		CS_INT,
272 		CS_VOID *,
273 		CS_DATEREC *);
274 
275 
276 // constants...
277 #define CS_VERSION_100		(CS_INT)113
278 
279 #define	CS_SET			(CS_INT)34
280 
281 #define	CS_MESSAGE_CB		(CS_INT)9119
282 
283 #define	CS_UNUSED		(CS_INT)(-99999)
284 
285 #define	CS_SUCCEED		(CS_RETCODE)1
286 #define CS_FAIL			(CS_RETCODE)0
287 
288 #define	CS_SERVERMSG_CB		(CS_INT)2
289 #define	CS_CLIENTMSG_CB		(CS_INT)3
290 
291 #define CS_USERNAME		(CS_INT)9100
292 #define CS_PASSWORD		(CS_INT)9101
293 #define CS_APPNAME		(CS_INT)9102
294 #define CS_HOSTNAME		(CS_INT)9103
295 #define CS_PACKETSIZE		(CS_INT)9107
296 #define CS_LOC_PROP		(CS_INT)9125
297 #define CS_SEC_ENCRYPTION	(CS_INT)9135
298 
299 #define CS_TRUE			(CS_BOOL)1
300 #define CS_FALSE		(CS_BOOL)0
301 
302 #define CS_SYB_LANG		(CS_INT)8
303 #define CS_SYB_CHARSET		(CS_INT)9
304 
305 #define CS_LANG_CMD		(CS_INT)148
306 #define CS_RPC_CMD		(CS_INT)149
307 
308 #define CS_ROW_RESULT		(CS_INT)4040
309 #define CS_CURSOR_RESULT	(CS_INT)4041
310 #define CS_PARAM_RESULT		(CS_INT)4042
311 #define CS_COMPUTE_RESULT	(CS_INT)4045
312 #define CS_CMD_SUCCEED		(CS_INT)4047
313 #define CS_CMD_FAIL		(CS_INT)4048
314 
315 #define CS_ROW_COUNT		(CS_INT)800
316 #define CS_NUMDATA		(CS_INT)803
317 
318 #define CS_CANCEL_CURRENT	(CS_INT)6000
319 #define CS_CANCEL_ALL		(CS_INT)6001
320 
321 #define CS_ILLEGAL_TYPE		(CS_INT)(-1)
322 #define CS_CHAR_TYPE		(CS_INT)0
323 #define CS_BINARY_TYPE		(CS_INT)1
324 #define CS_LONGCHAR_TYPE	(CS_INT)2
325 #define CS_LONGBINARY_TYPE	(CS_INT)3
326 #define CS_TEXT_TYPE		(CS_INT)4
327 #define CS_IMAGE_TYPE		(CS_INT)5
328 #define CS_TINYINT_TYPE		(CS_INT)6
329 #define CS_SMALLINT_TYPE	(CS_INT)7
330 #define CS_INT_TYPE		(CS_INT)8
331 #define CS_REAL_TYPE		(CS_INT)9
332 #define CS_FLOAT_TYPE		(CS_INT)10
333 #define CS_BIT_TYPE		(CS_INT)11
334 #define CS_DATETIME_TYPE	(CS_INT)12
335 #define CS_DATETIME4_TYPE	(CS_INT)13
336 #define CS_MONEY_TYPE		(CS_INT)14
337 #define CS_MONEY4_TYPE		(CS_INT)15
338 #define CS_NUMERIC_TYPE		(CS_INT)16
339 #define CS_DECIMAL_TYPE		(CS_INT)17
340 #define CS_VARCHAR_TYPE		(CS_INT)18
341 #define CS_VARBINARY_TYPE	(CS_INT)19
342 #define CS_LONG_TYPE		(CS_INT)20
343 #define CS_SENSITIVITY_TYPE	(CS_INT)21
344 #define CS_BOUNDARY_TYPE	(CS_INT)22
345 #define CS_VOID_TYPE		(CS_INT)23
346 #define CS_USHORT_TYPE		(CS_INT)24
347 #define CS_BIGINT_TYPE		(CS_INT)30
348 #define CS_UBIGINT_TYPE		(CS_INT)33
349 #define CS_XML_TYPE		(CS_INT)34
350 
351 #define CS_FMT_NULLTERM		(CS_INT)0x1
352 
353 #define CS_CURSOR_DECLARE	(CS_INT)700
354 #define CS_CURSOR_OPEN		(CS_INT)701
355 #define CS_CURSOR_ROWS		(CS_INT)703
356 #define CS_CURSOR_CLOSE		(CS_INT)706
357 
358 #define CS_DEALLOC		(CS_INT)711
359 
360 #define CS_READ_ONLY		(CS_INT)0x0002
361 
362 #define CS_EXTERNAL_ERR		(CS_RETCODE)(-200)
363 #define CS_ROW_FAIL		(CS_RETCODE)(CS_EXTERNAL_ERR - 3)
364 #define CS_END_RESULTS		(CS_RETCODE)(CS_EXTERNAL_ERR - 5)
365 
366 #define CS_FORCE_CLOSE		(CS_INT)301
367 
368 #define CS_FMT_UNUSED		(CS_INT)0x0
369 
370 #define CS_KEY			(CS_INT)0x2
371 #define CS_VERSION_KEY		(CS_INT)0x4
372 #define CS_CANBENULL		(CS_INT)0x20
373 #define CS_INPUTVALUE		(CS_INT)0x100
374 #define CS_IDENTITY		(CS_INT)0x8000
375 
376 #define CS_RETURN		(CS_INT)0x400
377 
378 #define CS_LC_ALL		(CS_INT)7
379 
380 #define CS_SV_RETRY_FAIL	(CS_INT)2
381 
382 
383 // dlopen infrastructure...
384 static bool		alreadyopen=false;
385 static dynamiclib	lib;
386 
loadLibraries(stringbuffer * errormessage)387 static bool loadLibraries(stringbuffer *errormessage) {
388 
389 	// don't open multiple times...
390 	if (alreadyopen) {
391 		return true;
392 	}
393 	alreadyopen=true;
394 
395 	// build path names
396 	const char	**pathnames=new const char *[12];
397 	uint16_t	p=0;
398 	stringbuffer	libdir16;
399 	stringbuffer	libdir15;
400 	stringbuffer	libdir125;
401 	const char	*sybase=environment::getValue("SYBASE");
402 	if (!charstring::isNullOrEmpty(sybase)) {
403 		libdir16.append(sybase)->append("/OCS-16_0/lib");
404 		libdir15.append(sybase)->append("/OCS-15_0/lib");
405 		libdir125.append(sybase)->append("/OCS-12_5/lib");
406 		pathnames[p++]=libdir16.getString();
407 		pathnames[p++]=libdir15.getString();
408 		pathnames[p++]=libdir125.getString();
409 	}
410 	pathnames[p++]="/opt/sap/OCS-16_0/lib";
411 	pathnames[p++]="/opt/sybase/OCS-15_0/lib";
412 	pathnames[p++]="/opt/sybase/OCS-12_5/lib";
413 	pathnames[p++]="/opt/sybase-12.5/OCS-12_5/lib";
414 	pathnames[p++]="/opt/sybase-11.9.2/lib";
415 	pathnames[p++]="/opt/sybase-11.0.3.3/lib";
416 	pathnames[p++]="/opt/sybase/lib";
417 	pathnames[p++]="/usr/local/sybase/lib";
418 	pathnames[p++]=NULL;
419 
420 	// look for the library
421 	const char	*libname="libsybblk64.so";
422 	stringbuffer	libfilename;
423 	const char	**path=pathnames;
424 	while (*path) {
425 		libfilename.clear();
426 		libfilename.append(*path)->append('/')->append(libname);
427 		if (file::readable(libfilename.getString())) {
428 			break;
429 		}
430 		path++;
431 	}
432 	if (!*path) {
433 		errormessage->clear();
434 		errormessage->append("\nFailed to load SAP libraries.\n");
435 		if (charstring::isNullOrEmpty(sybase)) {
436 			errormessage->append("SYBASE not set and ");
437 		}
438 		errormessage->append(libname)->append(" was not found in any "
439 							"of these paths:\n");
440 		path=pathnames;
441 		while (*path) {
442 			errormessage->append('	')->append(*path)->append('\n');
443 			path++;
444 		}
445 		return false;
446 	}
447 
448 	// open the library
449 	if (!lib.open(libfilename.getString(),true,true)) {
450 		goto error;
451 	}
452 
453 	// get the functions we need
454 	ct_init=(CS_RETCODE (*)(
455 				CS_CONTEXT *,
456 				CS_INT))
457 			lib.getSymbol("ct_init");
458 	if (!ct_init) {
459 		goto error;
460 	}
461 
462 	ct_callback=(CS_RETCODE (*)(
463 				CS_CONTEXT *,
464 				CS_CONNECTION *,
465 				CS_INT,
466 				CS_INT,
467 				CS_VOID *))
468 			lib.getSymbol("ct_callback");
469 	if (!ct_callback) {
470 		goto error;
471 	}
472 
473 	ct_con_alloc=(CS_RETCODE (*)(
474 				CS_CONTEXT *,
475 				CS_CONNECTION **))
476 			lib.getSymbol("ct_con_alloc");
477 	if (!ct_con_alloc) {
478 		goto error;
479 	}
480 
481 	ct_con_props=(CS_RETCODE (*)(
482 				CS_CONNECTION *,
483 				CS_INT,
484 				CS_INT,
485 				CS_VOID *,
486 				CS_INT,
487 				CS_INT *))
488 			lib.getSymbol("ct_con_props");
489 	if (!ct_con_props) {
490 		goto error;
491 	}
492 
493 	ct_connect=(CS_RETCODE (*)(
494 				CS_CONNECTION *,
495 				CS_CHAR *,
496 				CS_INT))
497 			lib.getSymbol("ct_connect");
498 	if (!ct_connect) {
499 		goto error;
500 	}
501 
502 	ct_cancel=(CS_RETCODE (*)(
503 				CS_CONNECTION *,
504 				CS_COMMAND *,
505 				CS_INT))
506 			lib.getSymbol("ct_cancel");
507 	if (!ct_cancel) {
508 		goto error;
509 	}
510 
511 	ct_con_drop=(CS_RETCODE (*)(
512 				CS_CONNECTION *))
513 			lib.getSymbol("ct_con_drop");
514 	if (!ct_con_drop) {
515 		goto error;
516 	}
517 
518 	ct_exit=(CS_RETCODE (*)(
519 				CS_CONTEXT *,
520 				CS_INT))
521 			lib.getSymbol("ct_exit");
522 	if (!ct_exit) {
523 		goto error;
524 	}
525 
526 	ct_close=(CS_RETCODE (*)(
527 				CS_CONNECTION *,
528 				CS_INT))
529 			lib.getSymbol("ct_close");
530 	if (!ct_close) {
531 		goto error;
532 	}
533 
534 	ct_cmd_alloc=(CS_RETCODE (*)(
535 				CS_CONNECTION *,
536 				CS_COMMAND **))
537 			lib.getSymbol("ct_cmd_alloc");
538 	if (!ct_cmd_alloc) {
539 		goto error;
540 	}
541 
542 	ct_cmd_drop=(CS_RETCODE (*)(
543 				CS_COMMAND *))
544 			lib.getSymbol("ct_cmd_drop");
545 	if (!ct_cmd_drop) {
546 		goto error;
547 	}
548 
549 	ct_cursor=(CS_RETCODE (*)(
550 				CS_COMMAND *,
551 				CS_INT,
552 				CS_CHAR *,
553 				CS_INT,
554 				CS_CHAR *,
555 				CS_INT,
556 				CS_INT))
557 			lib.getSymbol("ct_cursor");
558 	if (!ct_cursor) {
559 		goto error;
560 	}
561 
562 	ct_command=(CS_RETCODE (*)(
563 				CS_COMMAND *,
564 				CS_INT,
565 				CS_CHAR *,
566 				CS_INT,
567 				CS_INT))
568 			lib.getSymbol("ct_command");
569 	if (!ct_command) {
570 		goto error;
571 	}
572 
573 	ct_param=(CS_RETCODE (*)(
574 				CS_COMMAND *,
575 				CS_DATAFMT *,
576 				CS_VOID *,
577 				CS_INT,
578 				CS_SMALLINT))
579 			lib.getSymbol("ct_param");
580 	if (!ct_param) {
581 		goto error;
582 	}
583 
584 	ct_send=(CS_RETCODE (*)(
585 				CS_COMMAND *))
586 			lib.getSymbol("ct_send");
587 	if (!ct_send) {
588 		goto error;
589 	}
590 
591 	ct_results=(CS_RETCODE (*)(
592 				CS_COMMAND *,
593 				CS_INT *))
594 			lib.getSymbol("ct_results");
595 	if (!ct_results) {
596 		goto error;
597 	}
598 
599 	ct_res_info=(CS_RETCODE (*)(
600 				CS_COMMAND *,
601 				CS_INT,
602 				CS_VOID *,
603 				CS_INT,
604 				CS_INT *))
605 			lib.getSymbol("ct_res_info");
606 	if (!ct_res_info) {
607 		goto error;
608 	}
609 
610 	ct_bind=(CS_RETCODE (*)(
611 				CS_COMMAND *,
612 				CS_INT,
613 				CS_DATAFMT *,
614 				CS_VOID *,
615 				CS_INT *,
616 				CS_SMALLINT *))
617 			lib.getSymbol("ct_bind");
618 	if (!ct_bind) {
619 		goto error;
620 	}
621 
622 	ct_describe=(CS_RETCODE (*)(
623 				CS_COMMAND *,
624 				CS_INT,
625 				CS_DATAFMT *))
626 			lib.getSymbol("ct_describe");
627 	if (!ct_describe) {
628 		goto error;
629 	}
630 
631 	ct_fetch=(CS_RETCODE (*)(
632 				CS_COMMAND *,
633 				CS_INT,
634 				CS_INT,
635 				CS_INT,
636 				CS_INT *))
637 			lib.getSymbol("ct_fetch");
638 	if (!ct_fetch) {
639 		goto error;
640 	}
641 
642 	cs_ctx_alloc=(CS_RETCODE (*)(
643 				CS_INT,
644 				CS_CONTEXT **))
645 			lib.getSymbol("cs_ctx_alloc");
646 	if (!cs_ctx_alloc) {
647 		goto error;
648 	}
649 
650 	cs_config=(CS_RETCODE (*)(
651 				CS_CONTEXT *,
652 				CS_INT,
653 				CS_INT,
654 				CS_VOID *,
655 				CS_INT,
656 				CS_INT *))
657 			lib.getSymbol("cs_config");
658 	if (!cs_config) {
659 		goto error;
660 	}
661 
662 	cs_locale=(CS_RETCODE (*)(
663 				CS_CONTEXT *,
664 				CS_INT,
665 				CS_LOCALE *,
666 				CS_INT,
667 				CS_CHAR *,
668 				CS_INT,
669 				CS_INT *))
670 			lib.getSymbol("cs_locale");
671 	if (!cs_locale) {
672 		goto error;
673 	}
674 
675 	cs_loc_alloc=(CS_RETCODE (*)(
676 				CS_CONTEXT *,
677 				CS_LOCALE **))
678 			lib.getSymbol("cs_loc_alloc");
679 	if (!cs_loc_alloc) {
680 		goto error;
681 	}
682 
683 	cs_loc_drop=(CS_RETCODE (*)(
684 				CS_CONTEXT *,
685 				CS_LOCALE *))
686 			lib.getSymbol("cs_loc_drop");
687 	if (!cs_loc_drop) {
688 		goto error;
689 	}
690 
691 	cs_ctx_drop=(CS_RETCODE (*)(
692 				CS_CONTEXT *))
693 			lib.getSymbol("cs_ctx_drop");
694 	if (!cs_ctx_drop) {
695 		goto error;
696 	}
697 
698 	cs_dt_crack=(CS_RETCODE (*)(
699 				CS_CONTEXT *,
700 				CS_INT,
701 				CS_VOID *,
702 				CS_DATEREC *))
703 			lib.getSymbol("cs_dt_crack");
704 	if (!cs_dt_crack) {
705 		goto error;
706 	}
707 
708 	// success
709 	return true;
710 
711 	// error
712 error:
713 	char	*error=lib.getError();
714 	errormessage->clear();
715 	errormessage->append("\nFailed to load SAP libraries.\n");
716 	errormessage->append(error)->append('\n');
717 	#ifndef _WIN32
718 	if (charstring::contains(error,"No such file or directory")) {
719 		errormessage->append("\n(NOTE: The error message above may "
720 					"be misleading.  Most likely it means "
721 					"that a library that ");
722 		errormessage->append(libname);
723 		errormessage->append(" depends on could not be located.  ");
724 		errormessage->append(libname)->append(" was found in ");
725 		errormessage->append(*path)->append(".  Verify that ");
726 		errormessage->append(*path);
727 		errormessage->append(" and directories containing each of "
728 					"the libraries that ");
729 		errormessage->append(libname);
730 		errormessage->append(" depends on are included in your "
731 					"LD_LIBRARY_PATH, /etc/ld.so.conf, "
732 					"or /etc/ld.so.conf.d.  Try using "
733 					"ldd to show ");
734 		errormessage->append(*path)->append('/')->append(libname);
735 		errormessage->append("'s dependencies.)\n");
736 	}
737 	#endif
738 	delete[] error;
739 	return false;
740 }
741