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