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 // FIXME: for now, assume version 8i+
9 #undef HAVE_ORACLE_8i
10 #define HAVE_ORACLE_8i 1
11
12
13 // types...
14 #define CONST const
15 #define dvoid void
16 typedef signed int sword;
17 typedef unsigned char ub1;
18 typedef unsigned short ub2;
19 typedef short sb2;
20 typedef unsigned int ub4;
21 typedef int sb4;
22 typedef int boolean;
23 typedef unsigned char text;
24 typedef unsigned char OraText;
25 typedef unsigned short OCIDuration;
26
27
28 // structs...
29 struct OCIParam;
30 struct OCIEnv;
31 struct OCIServer;
32 struct OCIError;
33 struct OCISvcCtx;
34 struct OCISession;
35 struct OCITrans;
36 struct OCISession;
37 struct OCIStmt;
38 struct OCIDefine;
39 struct OCILobLocator;
40 struct OCIBind;
41 struct OCISnapshot;
42
43
44 // date/time structs need to be defined...
45 struct OCITime {
46 ub1 OCITimeHH;
47 ub1 OCITimeMI;
48 ub1 OCITimeSS;
49 };
50
51 struct OCIDate {
52 sb2 OCIDateYYYY;
53 ub1 OCIDateMM;
54 ub1 OCIDateDD;
55 OCITime OCIDateTime;
56 };
57
58
59 // function pointers...
60 sword (*OCIEnvCreate)(OCIEnv **,
61 ub4,
62 void *,
63 void *(*)(void *,size_t),
64 void *(*)(void *,void *,size_t),
65 void (*)(void *,void *),
66 size_t,
67 void **);
68 sword (*OCIInitialize)(ub4,
69 void *,
70 void *(*)(void *,size_t),
71 void *(*)(void *,void *,size_t),
72 void (*)(void *,void *));
73 sword (*OCIHandleAlloc)(const void *,
74 void **,
75 const ub4,
76 const size_t,
77 void **);
78 sword (*OCIServerAttach)(OCIServer *,
79 OCIError *,
80 const OraText *,
81 sb4,
82 ub4);
83 sword (*OCIServerDetach)(OCIServer *,
84 OCIError *,
85 ub4);
86 sword (*OCISessionBegin)(OCISvcCtx *,
87 OCIError *,
88 OCISession *,
89 ub4,
90 ub4);
91 sword (*OCISessionEnd)(OCISvcCtx *,
92 OCIError *,
93 OCISession *,
94 ub4);
95 sword (*OCIServerVersion)(void *,
96 OCIError *,
97 OraText *,
98 ub4,
99 ub1);
100 sword (*OCIStmtPrepare2)(OCISvcCtx *,
101 OCIStmt **,
102 OCIError *,
103 const OraText *,
104 ub4,
105 const OraText *,
106 ub4,
107 ub4,
108 ub4);
109 sword (*OCIStmtExecute)(OCISvcCtx *,
110 OCIStmt *,
111 OCIError *,
112 ub4,
113 ub4,
114 const OCISnapshot *,
115 OCISnapshot *,
116 ub4);
117 sword (*OCIStmtRelease)(OCIStmt *,
118 OCIError *,
119 const OraText *,
120 ub4,
121 ub4);
122 sword (*OCIErrorGet)(void *,
123 ub4,
124 OraText *,
125 sb4 *,
126 OraText *,
127 ub4,
128 ub4);
129 sword (*OCIStmtPrepare)(OCIStmt *,
130 OCIError *,
131 const OraText *,
132 ub4,
133 ub4,
134 ub4);
135 sword (*OCIBindByPos)(OCIStmt *,
136 OCIBind **,
137 OCIError *,
138 ub4,
139 void *,
140 sb4,
141 ub2,
142 void *,
143 ub2 *,
144 ub2 *,
145 ub4,
146 ub4 *,
147 ub4);
148 sword (*OCIBindByName)(OCIStmt *,
149 OCIBind **,
150 OCIError *,
151 const OraText *,
152 sb4,
153 void *,
154 sb4,
155 ub2,
156 void *,
157 ub2 *,
158 ub2 *,
159 ub4,
160 ub4 *,
161 ub4);
162 sword (*OCIDescriptorAlloc)(const void *,
163 void **,
164 const ub4,
165 const size_t,
166 void **);
167 sword (*OCILobCreateTemporary)(OCISvcCtx *,
168 OCIError *,
169 OCILobLocator *,
170 ub2,
171 ub1,
172 ub1,
173 boolean,
174 OCIDuration);
175 sword (*OCILobOpen)(OCISvcCtx *,
176 OCIError *,
177 OCILobLocator *,
178 ub1);
179 sword (*OCILobFreeTemporary)(OCISvcCtx *,
180 OCIError *,
181 OCILobLocator *);
182 sword (*OCILobWrite)(OCISvcCtx *,
183 OCIError *,
184 OCILobLocator *,
185 ub4 *,
186 ub4,
187 void *,
188 ub4,
189 ub1,
190 void *,
191 sb4 (*)(dvoid*,dvoid*,ub4*,ub1 *),
192 ub2,
193 ub1);
194 sword (*OCILobClose)(OCISvcCtx *,
195 OCIError *,
196 OCILobLocator *);
197 sword (*OCILobGetLength)(OCISvcCtx *,
198 OCIError *,
199 OCILobLocator *,
200 ub4 *);
201 sword (*OCILobRead)(OCISvcCtx *,
202 OCIError *,
203 OCILobLocator *,
204 ub4 *,
205 ub4,
206 void *,
207 ub4,
208 void *,
209 sb4 (*)(dvoid *,CONST dvoid *,ub4,ub1),
210 ub2,
211 ub1);
212 sword (*OCIAttrSet)(void *,
213 ub4,
214 void *,
215 ub4,
216 ub4,
217 OCIError *);
218 sword (*OCIAttrGet)(const void *,
219 ub4,
220 void *,
221 ub4 *,
222 ub4,
223 OCIError *);
224 sword (*OCIDefineByPos)(OCIStmt *,
225 OCIDefine **,
226 OCIError *,
227 ub4,
228 void *,
229 sb4,
230 ub2,
231 void *,
232 ub2 *,
233 ub2 *,
234 ub4);
235 sword (*OCIStmtGetBindInfo)(OCIStmt *,
236 OCIError *,
237 ub4,
238 ub4,
239 sb4 *,
240 OraText *[],
241 ub1[],
242 OraText *[],
243 ub1[],
244 ub1[],
245 OCIBind **);
246 sword (*OCIStmtFetch)(OCIStmt *,
247 OCIError *,
248 ub4,
249 ub2,
250 ub4);
251 sword (*OCILobIsTemporary)(OCIEnv *,
252 OCIError *,
253 OCILobLocator *locp,
254 boolean *);
255 sword (*OCIDescriptorFree)(void *descp,
256 const ub4);
257 sword (*OCIHandleFree)(void *,
258 const ub4);
259 sword (*OCIParamGet)(const void *,
260 ub4,
261 OCIError *,
262 void **,
263 ub4);
264 sword (*OCITransCommit)(OCISvcCtx *,
265 OCIError *,
266 ub4);
267 sword (*OCITransRollback)(OCISvcCtx *,
268 OCIError *,
269 ub4);
270
271
272 // date/time macros...
273 #define OCIDateSetDate(date,year,month,day) { \
274 (date)->OCIDateYYYY=year; \
275 (date)->OCIDateMM=month; \
276 (date)->OCIDateDD=day; \
277 }
278 #define OCIDateSetTime(date,hour,min,sec) { \
279 (date)->OCIDateTime.OCITimeHH=hour; \
280 (date)->OCIDateTime.OCITimeMI=min; \
281 (date)->OCIDateTime.OCITimeSS=sec; \
282 }
283 #define OCIDateGetDate(date,year,month,day) { \
284 *year=(date)->OCIDateYYYY; \
285 *month=(date)->OCIDateMM; \
286 *day=(date)->OCIDateDD; \
287 }
288 #define OCIDateGetTime(date,hour,min,sec) { \
289 *hour=(date)->OCIDateTime.OCITimeHH; \
290 *min=(date)->OCIDateTime.OCITimeMI; \
291 *sec=(date)->OCIDateTime.OCITimeSS; \
292 }
293
294
295 // constants...
296 #define OCI_DEFAULT 0x00000000
297 #define OCI_SUCCESS 0
298 #define OCI_SUCCESS_WITH_INFO 1
299 #define OCI_ERROR -1
300 #define OCI_INVALID_HANDLE -2
301
302 #define OCI_OBJECT 0x00000002
303
304 #define OCI_HTYPE_ENV 1
305 #define OCI_HTYPE_ERROR 2
306 #define OCI_HTYPE_SVCCTX 3
307 #define OCI_HTYPE_STMT 4
308 #define OCI_HTYPE_SERVER 8
309 #define OCI_HTYPE_SESSION 9
310 #define OCI_HTYPE_TRANS 10
311
312 #define OCI_ATTR_DATA_SIZE 1
313 #define OCI_ATTR_DATA_TYPE 2
314 #define OCI_ATTR_NAME 4
315 #define OCI_ATTR_PRECISION 5
316 #define OCI_ATTR_SCALE 6
317 #define OCI_ATTR_IS_NULL 7
318 #define OCI_ATTR_TRANS 8
319 #define OCI_ATTR_ROW_COUNT 9
320 #define OCI_ATTR_PREFETCH_ROWS 11
321 #define OCI_ATTR_PARAM_COUNT 18
322 #define OCI_ATTR_USERNAME 22
323 #define OCI_ATTR_PASSWORD 23
324 #define OCI_ATTR_NOCACHE 87
325 #define OCI_ATTR_STMTCACHESIZE 176
326
327 #define OCI_ATTR_SERVER 6
328 #define OCI_ATTR_SESSION 7
329 #define OCI_ATTR_STMT_TYPE 24
330
331 #define OCI_CRED_RDBMS 1
332 #define OCI_CRED_EXT 2
333 #define OCI_CRED_PROXY 3
334
335 // FIXME: for now, assume this is supported...
336 #define OCI_ATTR_PROXY_CREDENTIALS 99
337
338 #define OCI_NTV_SYNTAX 1
339
340 #define OCI_COMMIT_ON_SUCCESS 0x00000020
341
342 #define OCI_STRLS_CACHE_DELETE 0x0010
343
344 // FIXME: for now, assume this is supported...
345 #define OCI_STMT_CACHE 0x00000040
346
347 #define OCI_STMT_SELECT 1
348 #define OCI_STMT_CREATE 5
349 #define OCI_STMT_DROP 6
350 #define OCI_STMT_ALTER 7
351
352 #define OCI_PREP2_CACHE_SEARCHONLY 0x0010
353
354 #define OCI_TEMP_BLOB 1
355 #define OCI_TEMP_CLOB 2
356
357 #define OCI_DTYPE_LOB 50
358 #define OCI_DTYPE_PARAM 53
359
360 #define OCI_DURATION_SESSION 10
361
362 #define OCI_LOB_READWRITE 2
363
364 #define OCI_ONE_PIECE 0
365
366 #define OCI_NO_DATA 100
367
368 #define OCI_STRLS_CACHE_DELETE 0x0010
369
370 #define OCI_FETCH_NEXT 0x00000002
371
372 #define SQLT_FLT 4
373 #define SQLT_STR 5
374 #define SQLT_CLOB 112
375 #define SQLT_BLOB 113
376 #define SQLT_RSET 116
377 #define SQLT_ODT 156
378
379 #define SQLCS_IMPLICIT 1
380
381
382 // dlopen infrastructure...
383 static bool alreadyopen=false;
384 static dynamiclib lib;
385
loadLibraries(stringbuffer * errormessage)386 static bool loadLibraries(stringbuffer *errormessage) {
387
388 // don't open multiple times...
389 if (alreadyopen) {
390 return true;
391 }
392 alreadyopen=true;
393
394 // build lib names
395 const char **libnames=new const char *[11];
396 uint16_t p=0;
397 stringbuffer libdir;
398 const char *oraclehome=environment::getValue("ORACLE_HOME");
399 if (!charstring::isNullOrEmpty(oraclehome)) {
400 libdir.append(oraclehome)->append("/lib/libclntsh.so");
401 libnames[p++]=libdir.getString();
402 }
403
404 if (sizeof(long)==8) {
405 libnames[p++]="/usr/lib/oracle/12.1/client64/lib/libclntsh.so";
406 } else {
407 libnames[p++]="/usr/lib/oracle/12.1/client/lib/libclntsh.so";
408 }
409 libnames[p++]="/opt/instantclient_12_1/libclntsh.so.12.1";
410 libnames[p++]="/usr/local/instantclient_12_1/libclntsh.so.12.1";
411
412 if (sizeof(long)==8) {
413 libnames[p++]="/usr/lib/oracle/11.2/client64/lib/libclntsh.so";
414 } else {
415 libnames[p++]="/usr/lib/oracle/11.2/client/lib/libclntsh.so";
416 }
417 libnames[p++]="/opt/instantclient_11_2/libclntsh.so.11.2";
418 libnames[p++]="/usr/local/instantclient_11_2/libclntsh.so.11.2";
419
420 if (sizeof(long)==8) {
421 libnames[p++]="/usr/lib/oracle/10.2/client64/lib/libclntsh.so";
422 } else {
423 libnames[p++]="/usr/lib/oracle/10.2/client/lib/libclntsh.so";
424 }
425 libnames[p++]="/opt/instantclient_10_2/libclntsh.so.10.2";
426 libnames[p++]="/usr/local/instantclient_10_2/libclntsh.so.10.2";
427
428 libnames[p++]=NULL;
429
430 // look for the library
431 const char **libname=libnames;
432 while (*libname) {
433 if (file::readable(*libname)) {
434 break;
435 }
436 libname++;
437 }
438 if (!*libname) {
439 errormessage->clear();
440 errormessage->append("\nFailed to load Oracle libraries.\n");
441 if (charstring::isNullOrEmpty(oraclehome)) {
442 errormessage->append("ORACLE_HOME not set and none");
443 } else {
444 errormessage->append("None");
445 }
446 errormessage->append(" of these libraries were found:\n");
447 libname=libnames;
448 while (*libname) {
449 errormessage->append(' ');
450 errormessage->append(*libname)->append('\n');
451 libname++;
452 }
453 return false;
454 }
455
456 // open the library
457 if (!lib.open(*libname,true,true)) {
458 goto error;
459 }
460
461 // get the functions we need
462 OCIEnvCreate=(sword (*)(OCIEnv **,
463 ub4,
464 void *,
465 void *(*)(void *,size_t),
466 void *(*)(void *,void *,size_t),
467 void (*)(void *,void *),
468 size_t,
469 void **))
470 lib.getSymbol("OCIEnvCreate");
471 if (!OCIEnvCreate) {
472 goto error;
473 }
474
475 OCIInitialize=(sword (*)(ub4,
476 void *,
477 void *(*)(void *,size_t),
478 void *(*ralocfp)(void *,void *,size_t),
479 void (*)(void *,void *)))
480 lib.getSymbol("OCIInitialize");
481 if (!OCIInitialize) {
482 goto error;
483 }
484
485 OCIHandleAlloc=(sword (*)(const void *,
486 void **,
487 const ub4,
488 const size_t,
489 void **))
490 lib.getSymbol("OCIHandleAlloc");
491 if (!OCIHandleAlloc) {
492 goto error;
493 }
494
495 OCIServerAttach=(sword (*)(OCIServer *,
496 OCIError *,
497 const OraText *,
498 sb4,
499 ub4))
500 lib.getSymbol("OCIServerAttach");
501 if (!OCIServerAttach) {
502 goto error;
503 }
504
505 OCIServerDetach=(sword (*)(OCIServer *,
506 OCIError *,
507 ub4))
508 lib.getSymbol("OCIServerDetach");
509 if (!OCIServerDetach) {
510 goto error;
511 }
512
513 OCISessionBegin=(sword (*)(OCISvcCtx *,
514 OCIError *,
515 OCISession *,
516 ub4,
517 ub4))
518 lib.getSymbol("OCISessionBegin");
519 if (!OCISessionBegin) {
520 goto error;
521 }
522
523 OCISessionEnd=(sword (*)(OCISvcCtx *,
524 OCIError *,
525 OCISession *,
526 ub4))
527 lib.getSymbol("OCISessionEnd");
528 if (!OCISessionEnd) {
529 goto error;
530 }
531
532 OCIServerVersion=(sword (*)(void *,
533 OCIError *,
534 OraText *,
535 ub4,
536 ub1))
537 lib.getSymbol("OCIServerVersion");
538 if (!OCIServerVersion) {
539 goto error;
540 }
541
542 OCIStmtPrepare2=(sword (*)(OCISvcCtx *,
543 OCIStmt **,
544 OCIError *,
545 const OraText *,
546 ub4,
547 const OraText *,
548 ub4,
549 ub4,
550 ub4))
551 lib.getSymbol("OCIStmtPrepare2");
552 if (!OCIStmtPrepare2) {
553 goto error;
554 }
555
556 OCIStmtExecute=(sword (*)(OCISvcCtx *,
557 OCIStmt *,
558 OCIError *,
559 ub4,
560 ub4,
561 const OCISnapshot *,
562 OCISnapshot *,
563 ub4))
564 lib.getSymbol("OCIStmtExecute");
565 if (!OCIStmtExecute) {
566 goto error;
567 }
568
569 OCIStmtRelease=(sword (*)(OCIStmt *,
570 OCIError *,
571 const OraText *,
572 ub4,
573 ub4))
574 lib.getSymbol("OCIStmtRelease");
575 if (!OCIStmtRelease) {
576 goto error;
577 }
578
579 OCIErrorGet=(sword (*)(void *,
580 ub4,
581 OraText *,
582 sb4 *,
583 OraText *,
584 ub4,
585 ub4))
586 lib.getSymbol("OCIErrorGet");
587 if (!OCIErrorGet) {
588 goto error;
589 }
590
591 OCIStmtPrepare=(sword (*)(OCIStmt *,
592 OCIError *,
593 const OraText *,
594 ub4,
595 ub4,
596 ub4))
597 lib.getSymbol("OCIStmtPrepare");
598 if (!OCIStmtPrepare) {
599 goto error;
600 }
601
602 OCIBindByPos=(sword (*)(OCIStmt *,
603 OCIBind **,
604 OCIError *,
605 ub4,
606 void *,
607 sb4,
608 ub2,
609 void *,
610 ub2 *,
611 ub2 *,
612 ub4,
613 ub4 *,
614 ub4))
615 lib.getSymbol("OCIBindByPos");
616 if (!OCIBindByPos) {
617 goto error;
618 }
619
620 OCIBindByName=(sword (*)(OCIStmt *,
621 OCIBind **,
622 OCIError *,
623 const OraText *,
624 sb4,
625 void *,
626 sb4,
627 ub2,
628 void *p,
629 ub2 *,
630 ub2 *,
631 ub4,
632 ub4 *,
633 ub4))
634 lib.getSymbol("OCIBindByName");
635 if (!OCIBindByName) {
636 goto error;
637 }
638
639 OCIDescriptorAlloc=(sword (*)(const void *,
640 void **,
641 const ub4,
642 const size_t,
643 void **))
644 lib.getSymbol("OCIDescriptorAlloc");
645 if (!OCIDescriptorAlloc) {
646 goto error;
647 }
648
649 OCILobCreateTemporary=(sword (*)(OCISvcCtx *,
650 OCIError *,
651 OCILobLocator *,
652 ub2,
653 ub1,
654 ub1,
655 boolean,
656 OCIDuration))
657 lib.getSymbol("OCILobCreateTemporary");
658 if (!OCILobCreateTemporary) {
659 goto error;
660 }
661
662 OCILobOpen=(sword (*)(OCISvcCtx *,
663 OCIError *,
664 OCILobLocator *,
665 ub1))
666 lib.getSymbol("OCILobOpen");
667 if (!OCILobOpen) {
668 goto error;
669 }
670
671 OCILobFreeTemporary=(sword (*)(OCISvcCtx *,
672 OCIError *,
673 OCILobLocator *))
674 lib.getSymbol("OCILobFreeTemporary");
675 if (!OCILobFreeTemporary) {
676 goto error;
677 }
678
679 OCILobWrite=(sword (*)(OCISvcCtx *,
680 OCIError *,
681 OCILobLocator *,
682 ub4 *,
683 ub4,
684 void *,
685 ub4,
686 ub1,
687 void *,
688 sb4 (*)(dvoid*,dvoid*,ub4*,ub1 *),
689 ub2,
690 ub1))
691 lib.getSymbol("OCILobWrite");
692 if (!OCILobWrite) {
693 goto error;
694 }
695
696 OCILobClose=(sword (*)(OCISvcCtx *,
697 OCIError *,
698 OCILobLocator *))
699 lib.getSymbol("OCILobClose");
700 if (!OCILobClose) {
701 goto error;
702 }
703
704 OCILobGetLength=(sword (*)(OCISvcCtx *,
705 OCIError *,
706 OCILobLocator *,
707 ub4 *))
708 lib.getSymbol("OCILobGetLength");
709 if (!OCILobGetLength) {
710 goto error;
711 }
712
713 OCILobRead=(sword (*)(OCISvcCtx *,
714 OCIError *,
715 OCILobLocator *,
716 ub4 *,
717 ub4,
718 void *,
719 ub4,
720 void *,
721 sb4 (*)(dvoid *,CONST dvoid *,ub4,ub1),
722 ub2,
723 ub1))
724 lib.getSymbol("OCILobRead");
725 if (!OCILobRead) {
726 goto error;
727 }
728
729 OCIAttrSet=(sword (*)(void *,
730 ub4,
731 void *,
732 ub4,
733 ub4,
734 OCIError *))
735 lib.getSymbol("OCIAttrSet");
736 if (!OCIAttrSet) {
737 goto error;
738 }
739
740 OCIAttrGet=(sword (*)(const void *,
741 ub4,
742 void *,
743 ub4 *,
744 ub4,
745 OCIError *))
746 lib.getSymbol("OCIAttrGet");
747 if (!OCIAttrGet) {
748 goto error;
749 }
750
751 OCIDefineByPos=(sword (*)(OCIStmt *,
752 OCIDefine **,
753 OCIError *,
754 ub4,
755 void *,
756 sb4,
757 ub2,
758 void *,
759 ub2 *,
760 ub2 *,
761 ub4))
762 lib.getSymbol("OCIDefineByPos");
763 if (!OCIDefineByPos) {
764 goto error;
765 }
766
767 OCIStmtGetBindInfo=(sword (*)(OCIStmt *,
768 OCIError *,
769 ub4,
770 ub4,
771 sb4 *,
772 OraText *[],
773 ub1[],
774 OraText *[],
775 ub1[],
776 ub1[],
777 OCIBind **))
778 lib.getSymbol("OCIStmtGetBindInfo");
779 if (!OCIStmtGetBindInfo) {
780 goto error;
781 }
782
783 OCIStmtFetch=(sword (*)(OCIStmt *,
784 OCIError *,
785 ub4,
786 ub2,
787 ub4))
788 lib.getSymbol("OCIStmtFetch");
789 if (!OCIStmtFetch) {
790 goto error;
791 }
792
793 OCILobIsTemporary=(sword (*)(OCIEnv *,
794 OCIError *,
795 OCILobLocator *,
796 boolean *))
797 lib.getSymbol("OCILobIsTemporary");
798 if (!OCILobIsTemporary) {
799 goto error;
800 }
801
802 OCIDescriptorFree=(sword (*)(void *,
803 const ub4))
804 lib.getSymbol("OCIDescriptorFree");
805 if (!OCIDescriptorFree) {
806 goto error;
807 }
808
809 OCIHandleFree=(sword (*)(void *,
810 const ub4))
811 lib.getSymbol("OCIHandleFree");
812 if (!OCIHandleFree) {
813 goto error;
814 }
815
816 OCIParamGet=(sword (*)(const void *,
817 ub4,
818 OCIError *,
819 void **,
820 ub4))
821 lib.getSymbol("OCIParamGet");
822 if (!OCIParamGet) {
823 goto error;
824 }
825
826 OCITransCommit=(sword (*)(OCISvcCtx *,
827 OCIError *,
828 ub4))
829 lib.getSymbol("OCITransCommit");
830 if (!OCITransCommit) {
831 goto error;
832 }
833
834 OCITransRollback=(sword (*)(OCISvcCtx *,
835 OCIError *,
836 ub4))
837 lib.getSymbol("OCITransRollback");
838 if (!OCITransRollback) {
839 goto error;
840 }
841
842 // success
843 return true;
844
845 // error
846 error:
847 char *error=lib.getError();
848 errormessage->clear();
849 errormessage->append("\nFailed to load Oracle libraries.\n");
850 errormessage->append(error)->append('\n');
851 #ifndef _WIN32
852 if (charstring::contains(error,"No such file or directory")) {
853 char *path=file::dirname(*libname);
854 const char *lib=(*libname)+charstring::length(path)+1;
855 errormessage->append("\n(NOTE: The error message above may "
856 "be misleading. Most likely it means "
857 "that a library that ");
858 errormessage->append(lib);
859 errormessage->append(" depends on could not be located. ");
860 errormessage->append(lib)->append(" was found in ");
861 errormessage->append(path)->append(". Verify that ");
862 errormessage->append(path);
863 errormessage->append(" and directories containing each of "
864 "the libraries that ");
865 errormessage->append(lib);
866 errormessage->append(" depends on are included in your "
867 "LD_LIBRARY_PATH, /etc/ld.so.conf, "
868 "or /etc/ld.so.conf.d. Try using "
869 "ldd to show ");
870 errormessage->append(path)->append('/')->append(lib);
871 errormessage->append("'s dependencies.)\n");
872 delete[] path;
873 }
874 #endif
875 delete[] error;
876 return false;
877 }
878