1 /*
2 * inifile.c
3 *
4 * $Id$
5 *
6 * Configuration File Management
7 *
8 * The iODBC driver manager.
9 *
10 * Copyright (C) 1996-2021 OpenLink Software <iodbc@openlinksw.com>
11 * All Rights Reserved.
12 *
13 * This software is released under the terms of either of the following
14 * licenses:
15 *
16 * - GNU Library General Public License (see LICENSE.LGPL)
17 * - The BSD License (see LICENSE.BSD).
18 *
19 * Note that the only valid version of the LGPL license as far as this
20 * project is concerned is the original GNU Library General Public License
21 * Version 2, dated June 1991.
22 *
23 * While not mandated by the BSD license, any patches you make to the
24 * iODBC source code may be contributed back into the iODBC project
25 * at your discretion. Contributions will benefit the Open Source and
26 * Data Access community as a whole. Submissions may be made at:
27 *
28 * http://www.iodbc.org
29 *
30 *
31 * GNU Library Generic Public License Version 2
32 * ============================================
33 * This library is free software; you can redistribute it and/or
34 * modify it under the terms of the GNU Library General Public
35 * License as published by the Free Software Foundation; only
36 * Version 2 of the License dated June 1991.
37 *
38 * This library is distributed in the hope that it will be useful,
39 * but WITHOUT ANY WARRANTY; without even the implied warranty of
40 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
41 * Library General Public License for more details.
42 *
43 * You should have received a copy of the GNU Library General Public
44 * License along with this library; if not, write to the Free
45 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
46 *
47 *
48 * The BSD License
49 * ===============
50 * Redistribution and use in source and binary forms, with or without
51 * modification, are permitted provided that the following conditions
52 * are met:
53 *
54 * 1. Redistributions of source code must retain the above copyright
55 * notice, this list of conditions and the following disclaimer.
56 * 2. Redistributions in binary form must reproduce the above copyright
57 * notice, this list of conditions and the following disclaimer in
58 * the documentation and/or other materials provided with the
59 * distribution.
60 * 3. Neither the name of OpenLink Software Inc. nor the names of its
61 * contributors may be used to endorse or promote products derived
62 * from this software without specific prior written permission.
63 *
64 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
65 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
66 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
67 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL OPENLINK OR
68 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
69 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
70 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
71 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
72 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
73 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
74 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
75 */
76
77
78 #include <iodbc.h>
79 #include <odbcinst.h>
80
81 #include <stdarg.h>
82 #include <stdio.h>
83 #include <string.h>
84 #ifndef _MAC
85 #include <sys/types.h>
86 #include <sys/stat.h>
87 #endif
88 #include <unistd.h>
89 #include <ctype.h>
90
91 #include "inifile.h"
92 #include "misc.h"
93
94 #if !defined(WINDOWS) && !defined(WIN32) && !defined(OS2) && !defined(macintosh)
95 # include <pwd.h>
96 # define UNIX_PWD
97 #endif
98
99
100 extern BOOL ValidDSN (LPCSTR lpszDSN);
101
102 static PCFGENTRY __iodbcdm_cfg_poolalloc (PCONFIG p, unsigned int count);
103 static int __iodbcdm_cfg_parse (PCONFIG pconfig);
104
105 /*** READ MODULE ****/
106
107 #ifndef O_BINARY
108 #define O_BINARY 0
109 #endif
110
111 #ifdef _MAC
112 static int
strcasecmp(const char * s1,const char * s2)113 strcasecmp (const char *s1, const char *s2)
114 {
115 int cmp;
116
117 while (*s1)
118 {
119 if ((cmp = toupper (*s1) - toupper (*s2)) != 0)
120 return cmp;
121 s1++;
122 s2++;
123 }
124 return (*s2) ? -1 : 0;
125 }
126 #endif
127
128 /*
129 * Initialize a configuration
130 */
131 int
_iodbcdm_cfg_init(PCONFIG * ppconf,const char * filename,int doCreate)132 _iodbcdm_cfg_init (PCONFIG *ppconf, const char *filename, int doCreate)
133 {
134 PCONFIG pconfig;
135
136 *ppconf = NULL;
137
138 if (!filename)
139 return -1;
140
141 if ((pconfig = (PCONFIG) calloc (1, sizeof (TCONFIG))) == NULL)
142 return -1;
143
144 pconfig->fileName = strdup (filename);
145 if (pconfig->fileName == NULL)
146 {
147 _iodbcdm_cfg_done (pconfig);
148 return -1;
149 }
150
151 /* If the file does not exist, try to create it */
152 if (doCreate && access (pconfig->fileName, 0) == -1)
153 {
154 int fd;
155
156 fd = creat (filename, 0644);
157 if (fd)
158 close (fd);
159 }
160
161 if (_iodbcdm_cfg_refresh (pconfig) == -1)
162 {
163 _iodbcdm_cfg_done (pconfig);
164 return -1;
165 }
166 *ppconf = pconfig;
167
168 return 0;
169 }
170
171
172 /*
173 * Free all data associated with a configuration
174 */
175 int
_iodbcdm_cfg_done(PCONFIG pconfig)176 _iodbcdm_cfg_done (PCONFIG pconfig)
177 {
178 if (pconfig)
179 {
180 _iodbcdm_cfg_freeimage (pconfig);
181 if (pconfig->fileName)
182 free (pconfig->fileName);
183 free (pconfig);
184 }
185
186 return 0;
187 }
188
189
190 /*
191 * Free the content specific data of a configuration
192 */
193 int
_iodbcdm_cfg_freeimage(PCONFIG pconfig)194 _iodbcdm_cfg_freeimage (PCONFIG pconfig)
195 {
196 char *saveName;
197 PCFGENTRY e;
198 unsigned int i;
199
200 if (pconfig->image)
201 free (pconfig->image);
202 if (pconfig->entries)
203 {
204 e = pconfig->entries;
205 for (i = 0; i < pconfig->numEntries; i++, e++)
206 {
207 if (e->flags & CFE_MUST_FREE_SECTION)
208 free (e->section);
209 if (e->flags & CFE_MUST_FREE_ID)
210 free (e->id);
211 if (e->flags & CFE_MUST_FREE_VALUE)
212 free (e->value);
213 if (e->flags & CFE_MUST_FREE_COMMENT)
214 free (e->comment);
215 }
216 free (pconfig->entries);
217 }
218
219 saveName = pconfig->fileName;
220 memset (pconfig, 0, sizeof (TCONFIG));
221 pconfig->fileName = saveName;
222
223 return 0;
224 }
225
226
227 /*
228 * This procedure reads an copy of the file into memory
229 * caching the content based on stat
230 */
231 int
_iodbcdm_cfg_refresh(PCONFIG pconfig)232 _iodbcdm_cfg_refresh (PCONFIG pconfig)
233 {
234 struct stat sb;
235 char *mem;
236 int fd;
237
238 if (pconfig == NULL || stat (pconfig->fileName, &sb) == -1)
239 return -1;
240
241 /*
242 * If our image is dirty, ignore all local changes
243 * and force a reread of the image, thus ignoring all mods
244 */
245 if (pconfig->dirty)
246 _iodbcdm_cfg_freeimage (pconfig);
247
248 /*
249 * Check to see if our incore image is still valid
250 */
251 if (pconfig->image && sb.st_size == pconfig->size
252 && sb.st_mtime == pconfig->mtime)
253 return 0;
254
255 /*
256 * Now read the full image
257 */
258 if ((fd = open (pconfig->fileName, O_RDONLY | O_BINARY)) == -1)
259 return -1;
260
261 mem = (char *) malloc (sb.st_size + 1);
262 if (mem == NULL || read (fd, mem, sb.st_size) != sb.st_size)
263 {
264 free (mem);
265 close (fd);
266 return -1;
267 }
268 mem[sb.st_size] = 0;
269
270 close (fd);
271
272 /*
273 * Store the new copy
274 */
275 _iodbcdm_cfg_freeimage (pconfig);
276 pconfig->image = mem;
277 pconfig->size = sb.st_size;
278 pconfig->mtime = sb.st_mtime;
279
280 if (__iodbcdm_cfg_parse (pconfig) == -1)
281 {
282 _iodbcdm_cfg_freeimage (pconfig);
283 return -1;
284 }
285
286 return 1;
287 }
288
289
290 #define iseolchar(C) (strchr ("\n\r\x1a", C) != NULL)
291 #define iswhite(C) (strchr ("\f\t ", C) != NULL)
292
293
294 static char *
__iodbcdm_cfg_skipwhite(char * s)295 __iodbcdm_cfg_skipwhite (char *s)
296 {
297 while (*s && iswhite (*s))
298 s++;
299 return s;
300 }
301
302
303 static int
__iodbcdm_cfg_getline(char ** pCp,char ** pLinePtr)304 __iodbcdm_cfg_getline (char **pCp, char **pLinePtr)
305 {
306 char *start;
307 char *cp = *pCp;
308
309 while (*cp && iseolchar (*cp))
310 cp++;
311 start = cp;
312 if (pLinePtr)
313 *pLinePtr = cp;
314
315 while (*cp && !iseolchar (*cp))
316 cp++;
317 if (*cp)
318 {
319 *cp++ = 0;
320 *pCp = cp;
321
322 while (--cp >= start && iswhite (*cp));
323 cp[1] = 0;
324 }
325 else
326 *pCp = cp;
327
328 return *start ? 1 : 0;
329 }
330
331
332 static char *
rtrim(char * str)333 rtrim (char *str)
334 {
335 char *endPtr;
336
337 if (str == NULL || *str == '\0')
338 return NULL;
339
340 for (endPtr = &str[strlen (str) - 1]; endPtr >= str && isspace (*endPtr);
341 endPtr--);
342 endPtr[1] = 0;
343 return endPtr >= str ? endPtr : NULL;
344 }
345
346
347 /*
348 * Parse the in-memory copy of the configuration data
349 */
350 static int
__iodbcdm_cfg_parse(PCONFIG pconfig)351 __iodbcdm_cfg_parse (PCONFIG pconfig)
352 {
353 int isContinue, inString;
354 char *imgPtr;
355 char *endPtr;
356 char *lp;
357 char *section;
358 char *id;
359 char *value;
360 char *comment;
361
362 if (_iodbcdm_cfg_valid (pconfig))
363 return 0;
364
365 endPtr = pconfig->image + pconfig->size;
366 for (imgPtr = pconfig->image; imgPtr < endPtr;)
367 {
368 if (!__iodbcdm_cfg_getline (&imgPtr, &lp))
369 continue;
370
371 section = id = value = comment = NULL;
372
373 /*
374 * Skip leading spaces
375 */
376 if (iswhite (*lp))
377 {
378 lp = __iodbcdm_cfg_skipwhite (lp);
379 isContinue = 1;
380 }
381 else
382 isContinue = 0;
383
384 /*
385 * Parse Section
386 */
387 if (*lp == '[')
388 {
389 section = __iodbcdm_cfg_skipwhite (lp + 1);
390 if ((lp = strchr (section, ']')) == NULL)
391 continue;
392 *lp++ = 0;
393 if (rtrim (section) == NULL)
394 {
395 section = NULL;
396 continue;
397 }
398 lp = __iodbcdm_cfg_skipwhite (lp);
399 }
400 else if (*lp != ';' && *lp != '#')
401 {
402 /* Try to parse
403 * 1. Key = Value
404 * 2. Value (iff isContinue)
405 */
406 if (!isContinue)
407 {
408 /* Parse `<Key> = ..' */
409 id = lp;
410 if ((lp = strchr (id, '=')) == NULL)
411 continue;
412 *lp++ = 0;
413 rtrim (id);
414 lp = __iodbcdm_cfg_skipwhite (lp);
415 }
416
417 /* Parse value */
418 inString = 0;
419 value = lp;
420 while (*lp)
421 {
422 if (inString)
423 {
424 if (*lp == inString)
425 inString = 0;
426 }
427 else if (*lp == '"' || *lp == '\'')
428 inString = *lp;
429 else if ((*lp == ';' || *lp == '#') && iswhite (lp[-1]))
430 {
431 *lp = 0;
432 comment = lp + 1;
433 rtrim (value);
434 break;
435 }
436 lp++;
437 }
438 }
439
440 /*
441 * Parse Comment
442 */
443 if (*lp == ';' || *lp == '#')
444 comment = lp + 1;
445
446 if (_iodbcdm_cfg_storeentry (pconfig, section, id, value, comment,
447 0) == -1)
448 {
449 pconfig->dirty = 1;
450 return -1;
451 }
452 }
453
454 pconfig->flags |= CFG_VALID;
455
456 return 0;
457 }
458
459
460 int
_iodbcdm_cfg_storeentry(PCONFIG pconfig,char * section,char * id,char * value,char * comment,int dynamic)461 _iodbcdm_cfg_storeentry (
462 PCONFIG pconfig,
463 char *section,
464 char *id,
465 char *value,
466 char *comment,
467 int dynamic)
468 {
469 PCFGENTRY data;
470
471 if ((data = __iodbcdm_cfg_poolalloc (pconfig, 1)) == NULL)
472 return -1;
473
474 data->flags = 0;
475 if (dynamic)
476 {
477 if (section)
478 section = strdup (section);
479 if (id)
480 id = strdup (id);
481 if (value)
482 value = strdup (value);
483 if (comment)
484 comment = strdup (value);
485
486 if (section)
487 data->flags |= CFE_MUST_FREE_SECTION;
488 if (id)
489 data->flags |= CFE_MUST_FREE_ID;
490 if (value)
491 data->flags |= CFE_MUST_FREE_VALUE;
492 if (comment)
493 data->flags |= CFE_MUST_FREE_COMMENT;
494 }
495
496 data->section = section;
497 data->id = id;
498 data->value = value;
499 data->comment = comment;
500
501 return 0;
502 }
503
504
505 static PCFGENTRY
__iodbcdm_cfg_poolalloc(PCONFIG p,unsigned int count)506 __iodbcdm_cfg_poolalloc (PCONFIG p, unsigned int count)
507 {
508 PCFGENTRY newBase;
509 unsigned int newMax;
510
511 if (p->numEntries + count > p->maxEntries)
512 {
513 newMax =
514 p->maxEntries ? count + p->maxEntries + p->maxEntries / 2 : count +
515 4096 / sizeof (TCFGENTRY);
516 newBase = (PCFGENTRY) calloc (newMax, sizeof (TCFGENTRY));
517 if (newBase == NULL)
518 return NULL;
519 if (p->entries)
520 {
521 memcpy (newBase, p->entries, p->numEntries * sizeof (TCFGENTRY));
522 free (p->entries);
523 }
524 p->entries = newBase;
525 p->maxEntries = newMax;
526 }
527
528 newBase = &p->entries[p->numEntries];
529 p->numEntries += count;
530
531 return newBase;
532 }
533
534
535 /*** COMPATIBILITY LAYER ***/
536
537
538 int
_iodbcdm_cfg_rewind(PCONFIG pconfig)539 _iodbcdm_cfg_rewind (PCONFIG pconfig)
540 {
541 if (!_iodbcdm_cfg_valid (pconfig))
542 return -1;
543
544 pconfig->flags = CFG_VALID;
545 pconfig->cursor = 0;
546
547 return 0;
548 }
549
550
551 /*
552 * returns:
553 * 0 success
554 * -1 no next entry
555 *
556 * section id value flags meaning
557 * !0 0 !0 SECTION [value]
558 * !0 !0 !0 DEFINE id = value|id="value"|id='value'
559 * !0 0 !0 0 value
560 * 0 0 0 EOF end of file encountered
561 */
562 int
_iodbcdm_cfg_nextentry(PCONFIG pconfig)563 _iodbcdm_cfg_nextentry (PCONFIG pconfig)
564 {
565 PCFGENTRY e;
566
567 if (!_iodbcdm_cfg_valid (pconfig) || _iodbcdm_cfg_eof (pconfig))
568 return -1;
569
570 pconfig->flags &= ~(CFG_TYPEMASK);
571 pconfig->id = pconfig->value = NULL;
572
573 while (1)
574 {
575 if (pconfig->cursor >= pconfig->numEntries)
576 {
577 pconfig->flags |= CFG_EOF;
578 return -1;
579 }
580 e = &pconfig->entries[pconfig->cursor++];
581
582 if (e->section)
583 {
584 pconfig->section = e->section;
585 pconfig->flags |= CFG_SECTION;
586 return 0;
587 }
588 if (e->value)
589 {
590 pconfig->value = e->value;
591 if (e->id)
592 {
593 pconfig->id = e->id;
594 pconfig->flags |= CFG_DEFINE;
595 }
596 else
597 pconfig->flags |= CFG_CONTINUE;
598 return 0;
599 }
600 }
601 }
602
603
604 int
_iodbcdm_cfg_find(PCONFIG pconfig,char * section,char * id)605 _iodbcdm_cfg_find (PCONFIG pconfig, char *section, char *id)
606 {
607 int atsection;
608
609 if (!_iodbcdm_cfg_valid (pconfig) || _iodbcdm_cfg_rewind (pconfig))
610 return -1;
611
612 atsection = 0;
613 while (_iodbcdm_cfg_nextentry (pconfig) == 0)
614 {
615 if (atsection)
616 {
617 if (_iodbcdm_cfg_section (pconfig))
618 return -1;
619 else if (_iodbcdm_cfg_define (pconfig))
620 {
621 char *szId = _iodbcdm_remove_quotes (pconfig->id);
622 int bSame;
623 if (szId)
624 {
625 bSame = !strcasecmp (szId, id);
626 free (szId);
627 if (bSame)
628 return 0;
629 }
630 }
631 }
632 else if (_iodbcdm_cfg_section (pconfig)
633 && !strcasecmp (pconfig->section, section))
634 {
635 if (id == NULL)
636 return 0;
637 atsection = 1;
638 }
639 }
640 return -1;
641 }
642
643
644 /*** WRITE MODULE ****/
645
646
647 /*
648 * Change the configuration
649 *
650 * section id value action
651 * --------------------------------------------------------------------------
652 * value value value update '<entry>=<string>' in section <section>
653 * value value NULL delete '<entry>' from section <section>
654 * value NULL NULL delete section <section>
655 */
656 int
_iodbcdm_cfg_write(PCONFIG pconfig,char * section,char * id,char * value)657 _iodbcdm_cfg_write (
658 PCONFIG pconfig,
659 char *section,
660 char *id,
661 char *value)
662 {
663 PCFGENTRY e, e2, eSect;
664 int idx;
665 int i;
666
667 if (!_iodbcdm_cfg_valid (pconfig) || section == NULL)
668 return -1;
669
670 /* find the section */
671 e = pconfig->entries;
672 i = pconfig->numEntries;
673 eSect = 0;
674 while (i--)
675 {
676 if (e->section && !strcasecmp (e->section, section))
677 {
678 eSect = e;
679 break;
680 }
681 e++;
682 }
683
684 /* did we find the section? */
685 if (!eSect)
686 {
687 /* check for delete operation on a nonexisting section */
688 if (!id || !value)
689 return 0;
690
691 /* add section first */
692 if (_iodbcdm_cfg_storeentry (pconfig, section, NULL, NULL, NULL,
693 1) == -1
694 || _iodbcdm_cfg_storeentry (pconfig, NULL, id, value, NULL,
695 1) == -1)
696 return -1;
697
698 pconfig->dirty = 1;
699 return 0;
700 }
701
702 /* ok - we have found the section - let's see what we need to do */
703
704 if (id)
705 {
706 if (value)
707 {
708 /* add / update a key */
709 while (i--)
710 {
711 e++;
712 /* break on next section */
713 if (e->section)
714 {
715 /* insert new entry before e */
716 idx = e - pconfig->entries;
717 if (__iodbcdm_cfg_poolalloc (pconfig, 1) == NULL)
718 return -1;
719 memmove (e + 1, e,
720 (pconfig->numEntries - idx) * sizeof (TCFGENTRY));
721 e->section = NULL;
722 e->id = strdup (id);
723 e->value = strdup (value);
724 e->comment = NULL;
725 if (e->id == NULL || e->value == NULL)
726 return -1;
727 e->flags |= CFE_MUST_FREE_ID | CFE_MUST_FREE_VALUE;
728 pconfig->dirty = 1;
729 return 0;
730 }
731
732 if (e->id && !strcasecmp (e->id, id))
733 {
734 /* found key - do update */
735 if (e->value && (e->flags & CFE_MUST_FREE_VALUE))
736 {
737 e->flags &= ~CFE_MUST_FREE_VALUE;
738 free (e->value);
739 }
740 pconfig->dirty = 1;
741 if ((e->value = strdup (value)) == NULL)
742 return -1;
743 e->flags |= CFE_MUST_FREE_VALUE;
744 return 0;
745 }
746 }
747
748 /* last section in file - add new entry */
749 if (_iodbcdm_cfg_storeentry (pconfig, NULL, id, value, NULL,
750 1) == -1)
751 return -1;
752 pconfig->dirty = 1;
753 return 0;
754 }
755 else
756 {
757 /* delete a key */
758 while (i--)
759 {
760 e++;
761 /* break on next section */
762 if (e->section)
763 return 0; /* not found */
764
765 if (e->id && !strcasecmp (e->id, id))
766 {
767 /* found key - do delete */
768 eSect = e;
769 e++;
770 goto doDelete;
771 }
772 }
773 /* key not found - that' ok */
774 return 0;
775 }
776 }
777 else
778 {
779 /* delete entire section */
780
781 /* find e : next section */
782 while (i--)
783 {
784 e++;
785 /* break on next section */
786 if (e->section)
787 break;
788 }
789 if (i < 0)
790 e++;
791
792 /* move up e while comment */
793 e2 = e - 1;
794 while (e2->comment && !e2->section && !e2->id && !e2->value
795 && (iswhite (e2->comment[0]) || e2->comment[0] == ';'))
796 e2--;
797 e = e2 + 1;
798
799 doDelete:
800 /* move up eSect while comment */
801 e2 = eSect - 1;
802 while (e2->comment && !e2->section && !e2->id && !e2->value
803 && (iswhite (e2->comment[0]) || e2->comment[0] == ';'))
804 e2--;
805 eSect = e2 + 1;
806
807 /* delete everything between eSect .. e */
808 for (e2 = eSect; e2 < e; e2++)
809 {
810 if (e2->flags & CFE_MUST_FREE_SECTION)
811 free (e2->section);
812 if (e2->flags & CFE_MUST_FREE_ID)
813 free (e2->id);
814 if (e2->flags & CFE_MUST_FREE_VALUE)
815 free (e2->value);
816 if (e2->flags & CFE_MUST_FREE_COMMENT)
817 free (e2->comment);
818 }
819 idx = e - pconfig->entries;
820 memmove (eSect, e, (pconfig->numEntries - idx) * sizeof (TCFGENTRY));
821 pconfig->numEntries -= e - eSect;
822 pconfig->dirty = 1;
823 }
824
825 return 0;
826 }
827
828
829 /*
830 * Write a formatted copy of the configuration to a file
831 *
832 * This assumes that the inifile has already been parsed
833 */
834 static void
__iodbcdm_cfg_outputformatted(PCONFIG pconfig,FILE * fd)835 __iodbcdm_cfg_outputformatted (PCONFIG pconfig, FILE *fd)
836 {
837 PCFGENTRY e = pconfig->entries;
838 int i = pconfig->numEntries;
839 int m = 0;
840 int j, l;
841 int skip = 0;
842
843 while (i--)
844 {
845 if (e->section)
846 {
847 /* Add extra line before section, unless comment block found */
848 if (skip)
849 fprintf (fd, "\n");
850 fprintf (fd, "[%s]", e->section);
851 if (e->comment)
852 fprintf (fd, "\t;%s", e->comment);
853
854 /* Calculate m, which is the length of the longest key */
855 m = 0;
856 for (j = 1; j <= i; j++)
857 {
858 if (e[j].section)
859 break;
860 if (e[j].id && (l = strlen (e[j].id)) > m)
861 m = l;
862 }
863
864 /* Add an extra lf next time around */
865 skip = 1;
866 }
867 /*
868 * Key = value
869 */
870 else if (e->id && e->value)
871 {
872 if (m)
873 fprintf (fd, "%-*.*s = %s", m, m, e->id, e->value);
874 else
875 fprintf (fd, "%s = %s", e->id, e->value);
876 if (e->comment)
877 fprintf (fd, "\t;%s", e->comment);
878 }
879 /*
880 * Value only (continuation)
881 */
882 else if (e->value)
883 {
884 fprintf (fd, " %s", e->value);
885 if (e->comment)
886 fprintf (fd, "\t;%s", e->comment);
887 }
888 /*
889 * Comment only - check if we need an extra lf
890 *
891 * 1. Comment before section gets an extra blank line before
892 * the comment starts.
893 *
894 * previousEntry = value
895 * <<< INSERT BLANK LINE HERE >>>
896 * ; Comment Block
897 * ; Sticks to section below
898 * [new section]
899 *
900 * 2. Exception on 1. for commented out definitions:
901 * (Immediate nonwhitespace after ;)
902 * [some section]
903 * v1 = 1
904 * ;v2 = 2 << NO EXTRA LINE >>
905 * v3 = 3
906 *
907 * 3. Exception on 2. for ;; which certainly is a section comment
908 * [some section]
909 * definitions
910 * <<< INSERT BLANK LINE HERE >>>
911 * ;; block comment
912 * [new section]
913 */
914 else if (e->comment)
915 {
916 if (skip && (iswhite (e->comment[0]) || e->comment[0] == ';'))
917 {
918 for (j = 1; j <= i; j++)
919 {
920 if (e[j].section)
921 {
922 fprintf (fd, "\n");
923 skip = 0;
924 break;
925 }
926 if (e[j].id || e[j].value)
927 break;
928 }
929 }
930 fprintf (fd, ";%s", e->comment);
931 }
932 fprintf (fd, "\n");
933 e++;
934 }
935 }
936
937
938 /*
939 * Write the changed file back
940 */
941 int
_iodbcdm_cfg_commit(PCONFIG pconfig)942 _iodbcdm_cfg_commit (PCONFIG pconfig)
943 {
944 FILE *fp;
945
946 if (!_iodbcdm_cfg_valid (pconfig))
947 return -1;
948
949 if (pconfig->dirty)
950 {
951 if ((fp = fopen (pconfig->fileName, "w")) == NULL)
952 return -1;
953
954 __iodbcdm_cfg_outputformatted (pconfig, fp);
955
956 fclose (fp);
957
958 pconfig->dirty = 0;
959 }
960
961 return 0;
962 }
963
964
965 int
_iodbcdm_cfg_next_section(PCONFIG pconfig)966 _iodbcdm_cfg_next_section(PCONFIG pconfig)
967 {
968 do
969 if (0 != _iodbcdm_cfg_nextentry (pconfig))
970 return -1;
971 while (!_iodbcdm_cfg_section (pconfig));
972
973 return 0;
974 }
975
976
977 #if defined(__APPLE__)
978
979 #define DSN_LST "ODBC Data Sources"
980 #define DRV_LST "ODBC Drivers"
981
982 typedef struct stat stat_t;
983
984 /**
985 * return name ini file
986 * for $HOME/.odbc.ini or ~/.odbcinst.ini file
987 * OR
988 * for $HOME/Library/ODBC/odbc.ini or $HOME/Library/ODBC/odbcinst.ini
989 *
990 **/
991 static char *
_getinifilename(char * buf,int size,int bIsInst,int bHome)992 _getinifilename (char *buf, int size, int bIsInst, int bHome)
993 {
994 int j;
995 char *ptr;
996
997 j = STRLEN (bIsInst ? "/odbcinst.ini" : "/odbc.ini") + 1;
998
999 if (size < j)
1000 return NULL;
1001
1002 if (wSystemDSN == USERDSN_ONLY)
1003 {
1004 /*
1005 * 2b. Check either $HOME/.odbc.ini or ~/.odbc.ini
1006 */
1007 if ((ptr = getenv ("HOME")) == NULL)
1008 {
1009 ptr = (char *) getpwuid (getuid ());
1010
1011 if (ptr != NULL)
1012 ptr = ((struct passwd *) ptr)->pw_dir;
1013 }
1014
1015 if (ptr != NULL)
1016 {
1017 if (bHome)
1018 snprintf (buf, size, bIsInst ? "%s/.odbcinst.ini" : "%s/.odbc.ini",
1019 ptr);
1020 else
1021 snprintf (buf, size,
1022 bIsInst ? "%s" ODBCINST_INI_APP : "%s" ODBC_INI_APP, ptr);
1023
1024 return buf;
1025 }
1026 }
1027 return NULL;
1028 }
1029
1030
1031
1032 static int
_fix_home_odbc(PCONFIG pconf,char * lib_odbcini,int bIsInst)1033 _fix_home_odbc(PCONFIG pconf, char *lib_odbcini, int bIsInst)
1034 {
1035 char pathbuf[1024];
1036 char *home_odbcini = _getinifilename (pathbuf, sizeof (pathbuf), bIsInst, TRUE);
1037
1038 if (home_odbcini && lib_odbcini)
1039 {
1040 PCONFIG pCfg = NULL;
1041 stat_t home_stat;
1042 stat_t lib_stat;
1043
1044 if (access(home_odbcini, R_OK)!=0)
1045 {
1046 symlink(lib_odbcini, home_odbcini);
1047 return 0;
1048 }
1049 else
1050 {
1051 char buf[4096];
1052 int rc;
1053
1054 if (stat(home_odbcini, &home_stat))
1055 return -1;
1056
1057 /*
1058 * if $HOME/.odbc[inst].ini is link
1059 * to $HOME/Library/ODBC/odbc[inst].ini
1060 */
1061 if ((home_stat.st_mode & S_IFLNK)
1062 && (rc = readlink(home_odbcini, buf, sizeof(buf)))>0)
1063 {
1064 buf[rc]=0;
1065 if (strcmp(buf,lib_odbcini)==0)
1066 return 0; /* OK $HOME/.odbc.ini is linked to odbc.ini */
1067 }
1068
1069 if (stat(lib_odbcini, &lib_stat))
1070 return -1;
1071
1072 /* if $HOME/Library/ODBC/odbc[inst].ini is link
1073 * to $HOME/.odbc[inst].ini
1074 */
1075 if ((lib_stat.st_mode & S_IFLNK)
1076 && (rc = readlink(lib_odbcini, buf, sizeof(buf)))>0)
1077 {
1078 buf[rc]=0;
1079 if (strcmp(buf,home_odbcini)==0)
1080 return 0; /* OK $HOME/.odbc.ini is linked to odbc.ini */
1081 }
1082 }
1083
1084 /*
1085 * import $HOME/.odbc[inst].ini and replace it with link
1086 * to $HOME/Library/ODBC/odbc[inst].ini
1087 */
1088 if (!_iodbcdm_cfg_init (&pCfg, home_odbcini, FALSE))
1089 {
1090 int len = 0;
1091 char root_buf[4096] = {0};
1092 char *proot;
1093 char *root_val = NULL;
1094 int was_error = FALSE;
1095 char *root_lst = bIsInst?DRV_LST:DSN_LST;
1096
1097 /* Move DSN/Driver list*/
1098 len = _iodbcdm_list_entries (pCfg, root_lst, root_buf, sizeof(root_buf));
1099 if (len >0)
1100 {
1101 /* move [ODBC Data Sources] section */
1102 for(proot = root_buf; *proot; proot += STRLEN(proot) + 1)
1103 {
1104 if (!_iodbcdm_cfg_find (pCfg, root_lst, proot))
1105 root_val = pCfg->value;
1106 else
1107 root_val = NULL;
1108
1109 if (!proot || !root_val)
1110 continue;
1111
1112 if (_iodbcdm_cfg_write (pconf, root_lst, proot, root_val)
1113 || _iodbcdm_cfg_commit (pconf))
1114 {
1115 was_error = TRUE;
1116 break;
1117 }
1118 }
1119
1120 /* move DSN defines */
1121 for(proot = root_buf; *proot; proot += STRLEN(proot) + 1)
1122 {
1123 char buffer[4096];
1124 char *pattr;
1125 char *pattr_val;
1126
1127 len = _iodbcdm_list_entries (pCfg, proot, buffer, sizeof(buffer));
1128 if (len>0)
1129 {
1130 /* move [DSN] description */
1131 for(pattr = buffer; *pattr; pattr += STRLEN(pattr) + 1)
1132 {
1133 if (!_iodbcdm_cfg_find (pCfg, proot, pattr))
1134 pattr_val = pCfg->value;
1135 else
1136 pattr_val = NULL;
1137
1138
1139 if (!pattr || !pattr_val)
1140 continue;
1141
1142 if (_iodbcdm_cfg_write (pconf, proot, pattr, pattr_val)
1143 || _iodbcdm_cfg_commit (pconf))
1144 {
1145 was_error = TRUE;
1146 break;
1147 }
1148 }
1149 }
1150 }
1151 }
1152 if (was_error)
1153 return -1;
1154 }
1155 /* make link */
1156 if (access(home_odbcini, R_OK)==0)
1157 {
1158 if (unlink(home_odbcini))
1159 return -1;
1160 }
1161
1162 if (symlink(lib_odbcini, home_odbcini))
1163 return -1;
1164 }
1165 return 0;
1166 }
1167
1168
1169 static void
_fix_office_access(char * fodbcini,int bIsInst)1170 _fix_office_access(char *fodbcini, int bIsInst)
1171 {
1172 char *ptr;
1173 char *office_pwd = {"/Library/Containers/com.microsoft.Excel/Data"};
1174
1175 if ((ptr = getenv ("HOME")) == NULL)
1176 {
1177 ptr = (char *) getpwuid (getuid ());
1178
1179 if (ptr != NULL)
1180 ptr = ((struct passwd *) ptr)->pw_dir;
1181 }
1182
1183 if (ptr != NULL && strcasestr(ptr, office_pwd)==NULL)
1184 {
1185 stat_t src_stat;
1186 stat_t dst_stat;
1187 char src[1024];
1188 char dst[1024];
1189 int j;
1190
1191 snprintf (dst, sizeof(dst),
1192 bIsInst ? "%s%s" ODBCINST_INI_APP
1193 : "%s%s" ODBC_INI_APP, ptr, office_pwd);
1194
1195 j = STRLEN (bIsInst ? "/odbcinst.ini" : "/odbc.ini");
1196 dst[STRLEN(dst)-j] = 0;
1197
1198 mkdir(dst, 0755);
1199
1200 /* source ini file */
1201 snprintf (src, sizeof(src),
1202 bIsInst ? "%s" ODBCINST_INI_APP : "%s" ODBC_INI_APP, ptr);
1203
1204 /* destination ini file */
1205 snprintf (dst, sizeof(dst),
1206 bIsInst ? "%s%s" ODBCINST_INI_APP
1207 : "%s%s" ODBC_INI_APP, ptr, office_pwd);
1208
1209 if (access(src, R_OK)==0 && stat(src, &src_stat)==0)
1210 {
1211 if (access(dst, R_OK)==0 && stat(dst, &dst_stat)==0)
1212 {
1213 if (src_stat.st_ino == dst_stat.st_ino)
1214 return; /* link existed & OK */
1215 else
1216 unlink(dst);
1217 }
1218 link(src, dst); /* create hardlink for use with MSOffice */
1219 }
1220 }
1221 }
1222 #endif
1223
1224
1225 int
_iodbcdm_cfg_search_init(PCONFIG * ppconf,const char * filename,int doCreate)1226 _iodbcdm_cfg_search_init(PCONFIG *ppconf, const char *filename, int doCreate)
1227 {
1228 char pathbuf[1024];
1229 int rc;
1230
1231 if (strstr (filename, "odbc.ini") || strstr (filename, "ODBC.INI"))
1232 {
1233 char *fname_odbcini = _iodbcadm_getinifile (pathbuf,
1234 sizeof (pathbuf), FALSE, doCreate);
1235 #if defined(__APPLE__)
1236 if (fname_odbcini && wSystemDSN == USERDSN_ONLY)
1237 _fix_office_access(fname_odbcini, FALSE);
1238 #endif
1239 rc = _iodbcdm_cfg_init (ppconf, fname_odbcini, doCreate);
1240 #if defined(__APPLE__)
1241 if (!rc && fname_odbcini && wSystemDSN == USERDSN_ONLY)
1242 {
1243 char buf[1024];
1244 char *lib_odbcini = _getinifilename (buf, sizeof (buf), FALSE, FALSE);
1245
1246 /* if we try open ~/Library/ODBC/odbc.ini */
1247 if (lib_odbcini && strcmp(fname_odbcini, lib_odbcini)==0)
1248 _fix_home_odbc(*ppconf, fname_odbcini, FALSE);
1249 }
1250 #endif
1251 return rc;
1252 }
1253 else if (strstr (filename, "odbcinst.ini")
1254 || strstr (filename, "ODBCINST.INI"))
1255 {
1256 char *fname_odbcinst = _iodbcadm_getinifile (pathbuf,
1257 sizeof (pathbuf), TRUE, doCreate);
1258 #if defined(__APPLE__)
1259 if (fname_odbcinst && wSystemDSN == USERDSN_ONLY)
1260 _fix_office_access(fname_odbcinst, TRUE);
1261 #endif
1262 rc = _iodbcdm_cfg_init (ppconf, fname_odbcinst, doCreate);
1263 #if defined(__APPLE__)
1264 if (!rc && fname_odbcinst && wSystemDSN == USERDSN_ONLY)
1265 {
1266 char buf[1024];
1267 char *lib_odbcinst = _getinifilename (buf, sizeof (buf), TRUE, FALSE);
1268
1269 /* if we try open ~/Library/ODBC/odbcinst.ini */
1270 if (lib_odbcinst && strcmp(fname_odbcinst, lib_odbcinst)==0)
1271 _fix_home_odbc(*ppconf, fname_odbcinst, TRUE);
1272 }
1273 #endif
1274 return rc;
1275 }
1276 else if (doCreate || (!doCreate && access(filename, R_OK) == 0))
1277 return _iodbcdm_cfg_init (ppconf, filename, doCreate);
1278 else
1279 return -1;
1280 }
1281
1282
1283 int
_iodbcdm_list_sections(PCONFIG pCfg,LPSTR lpszRetBuffer,int cbRetBuffer)1284 _iodbcdm_list_sections (PCONFIG pCfg, LPSTR lpszRetBuffer, int cbRetBuffer)
1285 {
1286 int curr = 0, sect_len = 0;
1287 lpszRetBuffer[0] = 0;
1288
1289 if (0 == _iodbcdm_cfg_rewind (pCfg))
1290 {
1291 while (curr < cbRetBuffer && 0 == _iodbcdm_cfg_next_section (pCfg)
1292 && pCfg->section)
1293 {
1294 sect_len = strlen (pCfg->section) + 1;
1295 sect_len =
1296 sect_len > cbRetBuffer - curr ? cbRetBuffer - curr : sect_len;
1297
1298 memmove (lpszRetBuffer + curr, pCfg->section, sect_len);
1299
1300 curr += sect_len;
1301 }
1302 if (curr < cbRetBuffer)
1303 lpszRetBuffer[curr] = 0;
1304 return curr;
1305 }
1306 return 0;
1307 }
1308
1309
1310 int
_iodbcdm_list_entries(PCONFIG pCfg,LPCSTR lpszSection,LPSTR lpszRetBuffer,int cbRetBuffer)1311 _iodbcdm_list_entries (PCONFIG pCfg, LPCSTR lpszSection, LPSTR lpszRetBuffer, int cbRetBuffer)
1312 {
1313 int curr = 0, sect_len = 0;
1314 lpszRetBuffer[0] = 0;
1315
1316 if (!_iodbcdm_cfg_find (pCfg, (char*)lpszSection, NULL))
1317 {
1318 while (curr < cbRetBuffer && 0 == _iodbcdm_cfg_nextentry (pCfg)
1319 && pCfg->section)
1320 {
1321 if (_iodbcdm_cfg_section (pCfg))
1322 break;
1323 if (_iodbcdm_cfg_define (pCfg) && pCfg->id)
1324 {
1325 sect_len = strlen (pCfg->id) + 1;
1326 sect_len =
1327 sect_len >
1328 cbRetBuffer - curr ? cbRetBuffer - curr : sect_len;
1329
1330 memmove (lpszRetBuffer + curr, pCfg->id, sect_len);
1331
1332 curr += sect_len;
1333 }
1334 }
1335 if (curr < cbRetBuffer)
1336 lpszRetBuffer[curr] = 0;
1337 return curr;
1338 }
1339 return 0;
1340 }
1341
1342
1343 BOOL
do_create_dsns(PCONFIG pCfg,PCONFIG pInfCfg,LPSTR szDriver,LPSTR szDSNS,LPSTR szDiz)1344 do_create_dsns (PCONFIG pCfg, PCONFIG pInfCfg, LPSTR szDriver, LPSTR szDSNS, LPSTR szDiz)
1345 {
1346 char *szValue = strdup (szDSNS), *szCurr = szValue, *szComma;
1347 int hasMore = FALSE;
1348 BOOL retcode = FALSE;
1349
1350 do
1351 {
1352 szComma = strchr (szCurr, ',');
1353 if (szComma)
1354 {
1355 *szComma = 0;
1356 hasMore = TRUE;
1357 }
1358 else
1359 hasMore = FALSE;
1360
1361 #ifdef WIN32
1362 if (_iodbcdm_cfg_write (pCfg, "ODBC 32 bit Data Sources", szCurr,
1363 szDiz))
1364 #else
1365 if (_iodbcdm_cfg_write (pCfg, "ODBC Data Sources", szCurr, szDiz))
1366 #endif
1367 goto error;
1368
1369 if (!ValidDSN (szCurr) || _iodbcdm_cfg_write (pCfg, szCurr, NULL, NULL))
1370 goto error;
1371
1372 if (_iodbcdm_cfg_find (pInfCfg, szCurr, NULL)
1373 && !_iodbcdm_cfg_write (pCfg, szCurr, NULL, NULL))
1374 {
1375 if (_iodbcdm_cfg_write (pCfg, szCurr, "Driver", szDriver))
1376 goto error;
1377 while (!_iodbcdm_cfg_nextentry (pInfCfg)
1378 && _iodbcdm_cfg_define (pInfCfg))
1379 {
1380 if (_iodbcdm_cfg_write (pCfg, szCurr, pInfCfg->id,
1381 pInfCfg->value))
1382 goto error;
1383 }
1384 }
1385
1386 szCurr = szComma + 1;
1387 }
1388 while (hasMore);
1389
1390 retcode = TRUE;
1391
1392 error:
1393 free (szValue);
1394 return retcode;
1395 }
1396
1397
1398 BOOL
install_from_ini(PCONFIG pCfg,PCONFIG pOdbcCfg,LPSTR szInfFile,LPSTR szDriver,BOOL drivers)1399 install_from_ini (PCONFIG pCfg, PCONFIG pOdbcCfg, LPSTR szInfFile, LPSTR szDriver, BOOL drivers)
1400 {
1401 PCONFIG pInfCfg;
1402 char *szKeysSection = NULL, *szDriverFile = NULL, *szSetupFile = NULL,
1403 *szValue = NULL, *szId = NULL, *szComma, *szComma1;
1404 BOOL ret = FALSE;
1405
1406 if (_iodbcdm_cfg_write (pCfg, szDriver, NULL, NULL))
1407 return ret;
1408
1409 if (_iodbcdm_cfg_init (&pInfCfg, szInfFile, FALSE))
1410 return ret;
1411
1412 if (_iodbcdm_cfg_find (pInfCfg,
1413 drivers ? "ODBC Drivers" : "ODBC Translators", szDriver))
1414 goto error;
1415
1416 #ifdef WIN32
1417 if (_iodbcdm_cfg_write (pCfg,
1418 drivers ? "ODBC 32 bit Drivers" : "ODBC 32 bit Translators",
1419 szDriver, "Installed"))
1420 #else
1421 if (_iodbcdm_cfg_write (pCfg, drivers ? "ODBC Drivers" : "ODBC Translators",
1422 szDriver, "Installed"))
1423 #endif
1424 goto error;
1425
1426 if (_iodbcdm_cfg_find (pInfCfg, szDriver,
1427 drivers ? "Driver" : "Translator"))
1428 goto error;
1429
1430 szComma = strchr (pInfCfg->value, ',');
1431 szComma1 = strchr (szComma + 1, ',');
1432 if (!szComma || !szComma1 || szComma + 1 == szComma1)
1433 goto error;
1434
1435 *szComma1 = 0;
1436 szDriverFile = strdup (szComma + 1);
1437 if (_iodbcdm_cfg_write (pCfg, szDriver, drivers ? "Driver" : "Translator",
1438 szDriverFile))
1439 goto error;
1440
1441 if (!_iodbcdm_cfg_find (pInfCfg, szDriver, "Setup"))
1442 {
1443 szComma = strchr (pInfCfg->value, ',');
1444 szComma1 = strchr (szComma + 1, ',');
1445 if (!szComma || !szComma1 || szComma + 1 == szComma1)
1446 goto error;
1447
1448 *szComma1 = 0;
1449 szSetupFile = strdup (szComma + 1);
1450
1451 if (_iodbcdm_cfg_write (pCfg, szDriver, "Setup", szSetupFile))
1452 goto error;
1453 }
1454
1455 if (!_iodbcdm_cfg_find (pInfCfg, szDriver, NULL))
1456 {
1457 while (!_iodbcdm_cfg_nextentry (pInfCfg)
1458 && _iodbcdm_cfg_define (pInfCfg))
1459 if (strcmp (pInfCfg->id, drivers ? "\"Driver\"" : "\"Translator\"")
1460 && strcmp (pInfCfg->id, "\"Setup\""))
1461 {
1462 szComma = strchr (pInfCfg->value, ',');
1463 szComma1 = strchr (szComma + 1, ',');
1464 if (!szComma || !szComma1 || szComma + 1 == szComma1)
1465 szValue = strdup ("");
1466 else
1467 {
1468 *szComma1 = 0;
1469 szValue = strdup (szComma + 1);
1470 }
1471
1472 szComma = strchr (pInfCfg->id, '"');
1473 szComma1 = strchr (szComma + 1, '"');
1474 if (!szComma || !szComma1 || szComma + 1 == szComma1)
1475 goto loop_cont;
1476 else
1477 {
1478 *szComma1 = 0;
1479 szId = strdup (szComma + 1);
1480 }
1481
1482 if (_iodbcdm_cfg_write (pCfg, szDriver, szId, szValue))
1483 goto error;
1484
1485 loop_cont:
1486 if (szValue)
1487 {
1488 free (szValue);
1489 szValue = NULL;
1490 }
1491 if (szId)
1492 {
1493 free (szId);
1494 szId = NULL;
1495 }
1496 }
1497 }
1498
1499 if (!drivers)
1500 goto quit;
1501
1502 szKeysSection = (char *) calloc (strlen (szDriver) + 6, sizeof (char));
1503 strcpy (szKeysSection, szDriver);
1504 strcat (szKeysSection, "-Keys");
1505
1506 if (!_iodbcdm_cfg_find (pInfCfg, szKeysSection, NULL))
1507 {
1508 while (!_iodbcdm_cfg_nextentry (pInfCfg)
1509 && _iodbcdm_cfg_define (pInfCfg))
1510 {
1511 if (strcmp (pInfCfg->id, "CreateDSN"))
1512 {
1513 if (_iodbcdm_cfg_write (pCfg, szDriver, pInfCfg->id,
1514 pInfCfg->value))
1515 goto error;
1516 }
1517 else if (!do_create_dsns (pOdbcCfg, pCfg, szDriverFile,
1518 pInfCfg->value, szDriver))
1519 goto error;
1520 }
1521 }
1522
1523 quit:
1524 ret = TRUE;
1525
1526 error:
1527 if (szKeysSection)
1528 free (szKeysSection);
1529 if (szDriverFile)
1530 free (szDriverFile);
1531 if (szSetupFile)
1532 free (szSetupFile);
1533 if (szValue)
1534 free (szValue);
1535 if (szId)
1536 free (szId);
1537 _iodbcdm_cfg_done (pInfCfg);
1538 return ret;
1539 }
1540
1541
1542 int
install_from_string(PCONFIG pCfg,PCONFIG pOdbcCfg,LPSTR lpszDriver,BOOL drivers)1543 install_from_string (PCONFIG pCfg, PCONFIG pOdbcCfg, LPSTR lpszDriver, BOOL drivers)
1544 {
1545 char *szCurr = (char *) lpszDriver, *szDiz = lpszDriver;
1546 char *szAssignment, *szEqual, *szValue, *szDriver = NULL;
1547
1548 if (_iodbcdm_cfg_write (pCfg, lpszDriver, NULL, NULL))
1549 return FALSE;
1550
1551 #ifdef WIN32
1552 if (_iodbcdm_cfg_write (pCfg,
1553 drivers ? "ODBC 32 bit Drivers" : "ODBC 32 bit Translators",
1554 lpszDriver, "Installed"))
1555 #else
1556 if (_iodbcdm_cfg_write (pCfg, drivers ? "ODBC Drivers" : "ODBC Translators",
1557 lpszDriver, "Installed"))
1558 #endif
1559 return FALSE;
1560
1561 for (szCurr = lpszDriver + strlen (lpszDriver) + 1; *szCurr;
1562 szCurr += strlen (szCurr) + 1)
1563 {
1564 szAssignment = strdup (szCurr);
1565 szEqual = strchr (szAssignment, '=');
1566 szValue = szEqual + 1;
1567
1568 if (szEqual)
1569 *szEqual = 0;
1570 else
1571 goto loop_error;
1572
1573 if ((drivers && !strcmp (szAssignment, "Driver")) || (!drivers
1574 && !strcmp (szAssignment, "Translator")))
1575 {
1576 if (szDriver)
1577 free (szDriver);
1578 szDriver = strdup (szValue);
1579 }
1580
1581 if (drivers)
1582 {
1583 if (strcmp (szAssignment, "CreateDSN"))
1584 {
1585 if (_iodbcdm_cfg_write (pCfg, lpszDriver, szAssignment, szValue))
1586 goto loop_error;
1587 }
1588 else if (!do_create_dsns (pOdbcCfg, pCfg, szDriver, szValue, szDiz))
1589 goto loop_error;
1590 }
1591 else if (_iodbcdm_cfg_write (pCfg, lpszDriver, szAssignment, szValue))
1592 goto loop_error;
1593
1594 free (szAssignment);
1595 continue;
1596
1597 loop_error:
1598 if (szDriver)
1599 free (szDriver);
1600 free (szAssignment);
1601 return FALSE;
1602 }
1603
1604 if (szDriver)
1605 free (szDriver);
1606 else
1607 return FALSE;
1608
1609 return TRUE;
1610 }
1611