1/* 2 * inifile.c 3 * 4 * $Id: inifile.c,v 1.8 2006/12/15 14:04:16 source Exp $ 5 * 6 * Configuration File Management 7 * 8 * The iODBC driver manager. 9 * 10 * Copyright (C) 1996-2006 by 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 95extern BOOL ValidDSN (LPCSTR lpszDSN); 96 97static PCFGENTRY __iodbcdm_cfg_poolalloc (PCONFIG p, u_int count); 98static int __iodbcdm_cfg_parse (PCONFIG pconfig); 99 100/*** READ MODULE ****/ 101 102#ifndef O_BINARY 103#define O_BINARY 0 104#endif 105 106#ifdef _MAC 107static int 108strcasecmp (const char *s1, const char *s2) 109{ 110 int cmp; 111 112 while (*s1) 113 { 114 if ((cmp = toupper (*s1) - toupper (*s2)) != 0) 115 return cmp; 116 s1++; 117 s2++; 118 } 119 return (*s2) ? -1 : 0; 120} 121#endif 122 123/* 124 * Initialize a configuration 125 */ 126int 127_iodbcdm_cfg_init (PCONFIG *ppconf, const char *filename, int doCreate) 128{ 129 PCONFIG pconfig; 130 131 *ppconf = NULL; 132 133 if (!filename) 134 return -1; 135 136 if ((pconfig = (PCONFIG) calloc (1, sizeof (TCONFIG))) == NULL) 137 return -1; 138 139 pconfig->fileName = strdup (filename); 140 if (pconfig->fileName == NULL) 141 { 142 _iodbcdm_cfg_done (pconfig); 143 return -1; 144 } 145 146 /* If the file does not exist, try to create it */ 147 if (doCreate && access (pconfig->fileName, 0) == -1) 148 { 149 int fd; 150 151 fd = creat (filename, 0644); 152 if (fd) 153 close (fd); 154 } 155 156 if (_iodbcdm_cfg_refresh (pconfig) == -1) 157 { 158 _iodbcdm_cfg_done (pconfig); 159 return -1; 160 } 161 *ppconf = pconfig; 162 163 return 0; 164} 165 166 167/* 168 * Free all data associated with a configuration 169 */ 170int 171_iodbcdm_cfg_done (PCONFIG pconfig) 172{ 173 if (pconfig) 174 { 175 _iodbcdm_cfg_freeimage (pconfig); 176 if (pconfig->fileName) 177 free (pconfig->fileName); 178 free (pconfig); 179 } 180 181 return 0; 182} 183 184 185/* 186 * Free the content specific data of a configuration 187 */ 188int 189_iodbcdm_cfg_freeimage (PCONFIG pconfig) 190{ 191 char *saveName; 192 PCFGENTRY e; 193 u_int i; 194 195 if (pconfig->image) 196 free (pconfig->image); 197 if (pconfig->entries) 198 { 199 e = pconfig->entries; 200 for (i = 0; i < pconfig->numEntries; i++, e++) 201 { 202 if (e->flags & CFE_MUST_FREE_SECTION) 203 free (e->section); 204 if (e->flags & CFE_MUST_FREE_ID) 205 free (e->id); 206 if (e->flags & CFE_MUST_FREE_VALUE) 207 free (e->value); 208 if (e->flags & CFE_MUST_FREE_COMMENT) 209 free (e->comment); 210 } 211 free (pconfig->entries); 212 } 213 214 saveName = pconfig->fileName; 215 memset (pconfig, 0, sizeof (TCONFIG)); 216 pconfig->fileName = saveName; 217 218 return 0; 219} 220 221 222/* 223 * This procedure reads an copy of the file into memory 224 * caching the content based on stat 225 */ 226int 227_iodbcdm_cfg_refresh (PCONFIG pconfig) 228{ 229 struct stat sb; 230 char *mem; 231 int fd; 232 233 if (pconfig == NULL || stat (pconfig->fileName, &sb) == -1) 234 return -1; 235 236 /* 237 * If our image is dirty, ignore all local changes 238 * and force a reread of the image, thus ignoring all mods 239 */ 240 if (pconfig->dirty) 241 _iodbcdm_cfg_freeimage (pconfig); 242 243 /* 244 * Check to see if our incore image is still valid 245 */ 246 if (pconfig->image && sb.st_size == pconfig->size 247 && sb.st_mtime == pconfig->mtime) 248 return 0; 249 250 /* 251 * Now read the full image 252 */ 253 if ((fd = open (pconfig->fileName, O_RDONLY | O_BINARY)) == -1) 254 return -1; 255 256 mem = (char *) malloc (sb.st_size + 1); 257 if (mem == NULL || read (fd, mem, sb.st_size) != sb.st_size) 258 { 259 free (mem); 260 close (fd); 261 return -1; 262 } 263 mem[sb.st_size] = 0; 264 265 close (fd); 266 267 /* 268 * Store the new copy 269 */ 270 _iodbcdm_cfg_freeimage (pconfig); 271 pconfig->image = mem; 272 pconfig->size = sb.st_size; 273 pconfig->mtime = sb.st_mtime; 274 275 if (__iodbcdm_cfg_parse (pconfig) == -1) 276 { 277 _iodbcdm_cfg_freeimage (pconfig); 278 return -1; 279 } 280 281 return 1; 282} 283 284 285#define iseolchar(C) (strchr ("\n\r\x1a", C) != NULL) 286#define iswhite(C) (strchr ("\f\t ", C) != NULL) 287 288 289static char * 290__iodbcdm_cfg_skipwhite (char *s) 291{ 292 while (*s && iswhite (*s)) 293 s++; 294 return s; 295} 296 297 298static int 299__iodbcdm_cfg_getline (char **pCp, char **pLinePtr) 300{ 301 char *start; 302 char *cp = *pCp; 303 304 while (*cp && iseolchar (*cp)) 305 cp++; 306 start = cp; 307 if (pLinePtr) 308 *pLinePtr = cp; 309 310 while (*cp && !iseolchar (*cp)) 311 cp++; 312 if (*cp) 313 { 314 *cp++ = 0; 315 *pCp = cp; 316 317 while (--cp >= start && iswhite (*cp)); 318 cp[1] = 0; 319 } 320 else 321 *pCp = cp; 322 323 return *start ? 1 : 0; 324} 325 326 327static char * 328rtrim (char *str) 329{ 330 char *endPtr; 331 332 if (str == NULL || *str == '\0') 333 return NULL; 334 335 for (endPtr = &str[strlen (str) - 1]; endPtr >= str && isspace (*endPtr); 336 endPtr--); 337 endPtr[1] = 0; 338 return endPtr >= str ? endPtr : NULL; 339} 340 341 342/* 343 * Parse the in-memory copy of the configuration data 344 */ 345static int 346__iodbcdm_cfg_parse (PCONFIG pconfig) 347{ 348 int isContinue, inString; 349 char *imgPtr; 350 char *endPtr; 351 char *lp; 352 char *section; 353 char *id; 354 char *value; 355 char *comment; 356 357 if (_iodbcdm_cfg_valid (pconfig)) 358 return 0; 359 360 endPtr = pconfig->image + pconfig->size; 361 for (imgPtr = pconfig->image; imgPtr < endPtr;) 362 { 363 if (!__iodbcdm_cfg_getline (&imgPtr, &lp)) 364 continue; 365 366 section = id = value = comment = NULL; 367 368 /* 369 * Skip leading spaces 370 */ 371 if (iswhite (*lp)) 372 { 373 lp = __iodbcdm_cfg_skipwhite (lp); 374 isContinue = 1; 375 } 376 else 377 isContinue = 0; 378 379 /* 380 * Parse Section 381 */ 382 if (*lp == '[') 383 { 384 section = __iodbcdm_cfg_skipwhite (lp + 1); 385 if ((lp = strchr (section, ']')) == NULL) 386 continue; 387 *lp++ = 0; 388 if (rtrim (section) == NULL) 389 { 390 section = NULL; 391 continue; 392 } 393 lp = __iodbcdm_cfg_skipwhite (lp); 394 } 395 else if (*lp != ';' && *lp != '#') 396 { 397 /* Try to parse 398 * 1. Key = Value 399 * 2. Value (iff isContinue) 400 */ 401 if (!isContinue) 402 { 403 /* Parse `<Key> = ..' */ 404 id = lp; 405 if ((lp = strchr (id, '=')) == NULL) 406 continue; 407 *lp++ = 0; 408 rtrim (id); 409 lp = __iodbcdm_cfg_skipwhite (lp); 410 } 411 412 /* Parse value */ 413 inString = 0; 414 value = lp; 415 while (*lp) 416 { 417 if (inString) 418 { 419 if (*lp == inString) 420 inString = 0; 421 } 422 else if (*lp == '"' || *lp == '\'') 423 inString = *lp; 424 else if ((*lp == ';' || *lp == '#') && iswhite (lp[-1])) 425 { 426 *lp = 0; 427 comment = lp + 1; 428 rtrim (value); 429 break; 430 } 431 lp++; 432 } 433 } 434 435 /* 436 * Parse Comment 437 */ 438 if (*lp == ';' || *lp == '#') 439 comment = lp + 1; 440 441 if (_iodbcdm_cfg_storeentry (pconfig, section, id, value, comment, 442 0) == -1) 443 { 444 pconfig->dirty = 1; 445 return -1; 446 } 447 } 448 449 pconfig->flags |= CFG_VALID; 450 451 return 0; 452} 453 454 455int 456_iodbcdm_cfg_storeentry ( 457 PCONFIG pconfig, 458 char *section, 459 char *id, 460 char *value, 461 char *comment, 462 int dynamic) 463{ 464 PCFGENTRY data; 465 466 if ((data = __iodbcdm_cfg_poolalloc (pconfig, 1)) == NULL) 467 return -1; 468 469 data->flags = 0; 470 if (dynamic) 471 { 472 if (section) 473 section = strdup (section); 474 if (id) 475 id = strdup (id); 476 if (value) 477 value = strdup (value); 478 if (comment) 479 comment = strdup (value); 480 481 if (section) 482 data->flags |= CFE_MUST_FREE_SECTION; 483 if (id) 484 data->flags |= CFE_MUST_FREE_ID; 485 if (value) 486 data->flags |= CFE_MUST_FREE_VALUE; 487 if (comment) 488 data->flags |= CFE_MUST_FREE_COMMENT; 489 } 490 491 data->section = section; 492 data->id = id; 493 data->value = value; 494 data->comment = comment; 495 496 return 0; 497} 498 499 500static PCFGENTRY 501__iodbcdm_cfg_poolalloc (PCONFIG p, u_int count) 502{ 503 PCFGENTRY newBase; 504 u_int newMax; 505 506 if (p->numEntries + count > p->maxEntries) 507 { 508 newMax = 509 p->maxEntries ? count + p->maxEntries + p->maxEntries / 2 : count + 510 4096 / sizeof (TCFGENTRY); 511 newBase = (PCFGENTRY) malloc (newMax * sizeof (TCFGENTRY)); 512 if (newBase == NULL) 513 return NULL; 514 if (p->entries) 515 { 516 memcpy (newBase, p->entries, p->numEntries * sizeof (TCFGENTRY)); 517 free (p->entries); 518 } 519 p->entries = newBase; 520 p->maxEntries = newMax; 521 } 522 523 newBase = &p->entries[p->numEntries]; 524 p->numEntries += count; 525 526 return newBase; 527} 528 529 530/*** COMPATIBILITY LAYER ***/ 531 532 533int 534_iodbcdm_cfg_rewind (PCONFIG pconfig) 535{ 536 if (!_iodbcdm_cfg_valid (pconfig)) 537 return -1; 538 539 pconfig->flags = CFG_VALID; 540 pconfig->cursor = 0; 541 542 return 0; 543} 544 545 546/* 547 * returns: 548 * 0 success 549 * -1 no next entry 550 * 551 * section id value flags meaning 552 * !0 0 !0 SECTION [value] 553 * !0 !0 !0 DEFINE id = value|id="value"|id='value' 554 * !0 0 !0 0 value 555 * 0 0 0 EOF end of file encountered 556 */ 557int 558_iodbcdm_cfg_nextentry (PCONFIG pconfig) 559{ 560 PCFGENTRY e; 561 562 if (!_iodbcdm_cfg_valid (pconfig) || _iodbcdm_cfg_eof (pconfig)) 563 return -1; 564 565 pconfig->flags &= ~(CFG_TYPEMASK); 566 pconfig->id = pconfig->value = NULL; 567 568 while (1) 569 { 570 if (pconfig->cursor >= pconfig->numEntries) 571 { 572 pconfig->flags |= CFG_EOF; 573 return -1; 574 } 575 e = &pconfig->entries[pconfig->cursor++]; 576 577 if (e->section) 578 { 579 pconfig->section = e->section; 580 pconfig->flags |= CFG_SECTION; 581 return 0; 582 } 583 if (e->value) 584 { 585 pconfig->value = e->value; 586 if (e->id) 587 { 588 pconfig->id = e->id; 589 pconfig->flags |= CFG_DEFINE; 590 } 591 else 592 pconfig->flags |= CFG_CONTINUE; 593 return 0; 594 } 595 } 596} 597 598 599int 600_iodbcdm_cfg_find (PCONFIG pconfig, char *section, char *id) 601{ 602 int atsection; 603 604 if (!_iodbcdm_cfg_valid (pconfig) || _iodbcdm_cfg_rewind (pconfig)) 605 return -1; 606 607 atsection = 0; 608 while (_iodbcdm_cfg_nextentry (pconfig) == 0) 609 { 610 if (atsection) 611 { 612 if (_iodbcdm_cfg_section (pconfig)) 613 return -1; 614 else if (_iodbcdm_cfg_define (pconfig)) 615 { 616 char *szId = _iodbcdm_remove_quotes (pconfig->id); 617 int bSame; 618 if (szId) 619 { 620 bSame = !strcasecmp (szId, id); 621 free (szId); 622 if (bSame) 623 return 0; 624 } 625 } 626 } 627 else if (_iodbcdm_cfg_section (pconfig) 628 && !strcasecmp (pconfig->section, section)) 629 { 630 if (id == NULL) 631 return 0; 632 atsection = 1; 633 } 634 } 635 return -1; 636} 637 638 639/*** WRITE MODULE ****/ 640 641 642/* 643 * Change the configuration 644 * 645 * section id value action 646 * -------------------------------------------------------------------------- 647 * value value value update '<entry>=<string>' in section <section> 648 * value value NULL delete '<entry>' from section <section> 649 * value NULL NULL delete section <section> 650 */ 651int 652_iodbcdm_cfg_write ( 653 PCONFIG pconfig, 654 char *section, 655 char *id, 656 char *value) 657{ 658 PCFGENTRY e, e2, eSect; 659 int idx; 660 int i; 661 662 if (!_iodbcdm_cfg_valid (pconfig) || section == NULL) 663 return -1; 664 665 /* find the section */ 666 e = pconfig->entries; 667 i = pconfig->numEntries; 668 eSect = 0; 669 while (i--) 670 { 671 if (e->section && !strcasecmp (e->section, section)) 672 { 673 eSect = e; 674 break; 675 } 676 e++; 677 } 678 679 /* did we find the section? */ 680 if (!eSect) 681 { 682 /* check for delete operation on a nonexisting section */ 683 if (!id || !value) 684 return 0; 685 686 /* add section first */ 687 if (_iodbcdm_cfg_storeentry (pconfig, section, NULL, NULL, NULL, 688 1) == -1 689 || _iodbcdm_cfg_storeentry (pconfig, NULL, id, value, NULL, 690 1) == -1) 691 return -1; 692 693 pconfig->dirty = 1; 694 return 0; 695 } 696 697 /* ok - we have found the section - let's see what we need to do */ 698 699 if (id) 700 { 701 if (value) 702 { 703 /* add / update a key */ 704 while (i--) 705 { 706 e++; 707 /* break on next section */ 708 if (e->section) 709 { 710 /* insert new entry before e */ 711 idx = e - pconfig->entries; 712 if (__iodbcdm_cfg_poolalloc (pconfig, 1) == NULL) 713 return -1; 714 memmove (e + 1, e, 715 (pconfig->numEntries - idx) * sizeof (TCFGENTRY)); 716 e->section = NULL; 717 e->id = strdup (id); 718 e->value = strdup (value); 719 e->comment = NULL; 720 if (e->id == NULL || e->value == NULL) 721 return -1; 722 e->flags |= CFE_MUST_FREE_ID | CFE_MUST_FREE_VALUE; 723 pconfig->dirty = 1; 724 return 0; 725 } 726 727 if (e->id && !strcasecmp (e->id, id)) 728 { 729 /* found key - do update */ 730 if (e->value && (e->flags & CFE_MUST_FREE_VALUE)) 731 { 732 e->flags &= ~CFE_MUST_FREE_VALUE; 733 free (e->value); 734 } 735 pconfig->dirty = 1; 736 if ((e->value = strdup (value)) == NULL) 737 return -1; 738 e->flags |= CFE_MUST_FREE_VALUE; 739 return 0; 740 } 741 } 742 743 /* last section in file - add new entry */ 744 if (_iodbcdm_cfg_storeentry (pconfig, NULL, id, value, NULL, 745 1) == -1) 746 return -1; 747 pconfig->dirty = 1; 748 return 0; 749 } 750 else 751 { 752 /* delete a key */ 753 while (i--) 754 { 755 e++; 756 /* break on next section */ 757 if (e->section) 758 return 0; /* not found */ 759 760 if (e->id && !strcasecmp (e->id, id)) 761 { 762 /* found key - do delete */ 763 eSect = e; 764 e++; 765 goto doDelete; 766 } 767 } 768 /* key not found - that' ok */ 769 return 0; 770 } 771 } 772 else 773 { 774 /* delete entire section */ 775 776 /* find e : next section */ 777 while (i--) 778 { 779 e++; 780 /* break on next section */ 781 if (e->section) 782 break; 783 } 784 if (i < 0) 785 e++; 786 787 /* move up e while comment */ 788 e2 = e - 1; 789 while (e2->comment && !e2->section && !e2->id && !e2->value 790 && (iswhite (e2->comment[0]) || e2->comment[0] == ';')) 791 e2--; 792 e = e2 + 1; 793 794 doDelete: 795 /* move up eSect while comment */ 796 e2 = eSect - 1; 797 while (e2->comment && !e2->section && !e2->id && !e2->value 798 && (iswhite (e2->comment[0]) || e2->comment[0] == ';')) 799 e2--; 800 eSect = e2 + 1; 801 802 /* delete everything between eSect .. e */ 803 for (e2 = eSect; e2 < e; e2++) 804 { 805 if (e2->flags & CFE_MUST_FREE_SECTION) 806 free (e2->section); 807 if (e2->flags & CFE_MUST_FREE_ID) 808 free (e2->id); 809 if (e2->flags & CFE_MUST_FREE_VALUE) 810 free (e2->value); 811 if (e2->flags & CFE_MUST_FREE_COMMENT) 812 free (e2->comment); 813 } 814 idx = e - pconfig->entries; 815 memmove (eSect, e, (pconfig->numEntries - idx) * sizeof (TCFGENTRY)); 816 pconfig->numEntries -= e - eSect; 817 pconfig->dirty = 1; 818 } 819 820 return 0; 821} 822 823 824/* 825 * Write a formatted copy of the configuration to a file 826 * 827 * This assumes that the inifile has already been parsed 828 */ 829static void 830__iodbcdm_cfg_outputformatted (PCONFIG pconfig, FILE *fd) 831{ 832 PCFGENTRY e = pconfig->entries; 833 int i = pconfig->numEntries; 834 int m = 0; 835 int j, l; 836 int skip = 0; 837 838 while (i--) 839 { 840 if (e->section) 841 { 842 /* Add extra line before section, unless comment block found */ 843 if (skip) 844 fprintf (fd, "\n"); 845 fprintf (fd, "[%s]", e->section); 846 if (e->comment) 847 fprintf (fd, "\t;%s", e->comment); 848 849 /* Calculate m, which is the length of the longest key */ 850 m = 0; 851 for (j = 1; j <= i; j++) 852 { 853 if (e[j].section) 854 break; 855 if (e[j].id && (l = strlen (e[j].id)) > m) 856 m = l; 857 } 858 859 /* Add an extra lf next time around */ 860 skip = 1; 861 } 862 /* 863 * Key = value 864 */ 865 else if (e->id && e->value) 866 { 867 if (m) 868 fprintf (fd, "%-*.*s = %s", m, m, e->id, e->value); 869 else 870 fprintf (fd, "%s = %s", e->id, e->value); 871 if (e->comment) 872 fprintf (fd, "\t;%s", e->comment); 873 } 874 /* 875 * Value only (continuation) 876 */ 877 else if (e->value) 878 { 879 fprintf (fd, " %s", e->value); 880 if (e->comment) 881 fprintf (fd, "\t;%s", e->comment); 882 } 883 /* 884 * Comment only - check if we need an extra lf 885 * 886 * 1. Comment before section gets an extra blank line before 887 * the comment starts. 888 * 889 * previousEntry = value 890 * <<< INSERT BLANK LINE HERE >>> 891 * ; Comment Block 892 * ; Sticks to section below 893 * [new section] 894 * 895 * 2. Exception on 1. for commented out definitions: 896 * (Immediate nonwhitespace after ;) 897 * [some section] 898 * v1 = 1 899 * ;v2 = 2 << NO EXTRA LINE >> 900 * v3 = 3 901 * 902 * 3. Exception on 2. for ;; which certainly is a section comment 903 * [some section] 904 * definitions 905 * <<< INSERT BLANK LINE HERE >>> 906 * ;; block comment 907 * [new section] 908 */ 909 else if (e->comment) 910 { 911 if (skip && (iswhite (e->comment[0]) || e->comment[0] == ';')) 912 { 913 for (j = 1; j <= i; j++) 914 { 915 if (e[j].section) 916 { 917 fprintf (fd, "\n"); 918 skip = 0; 919 break; 920 } 921 if (e[j].id || e[j].value) 922 break; 923 } 924 } 925 fprintf (fd, ";%s", e->comment); 926 } 927 fprintf (fd, "\n"); 928 e++; 929 } 930} 931 932 933/* 934 * Write the changed file back 935 */ 936int 937_iodbcdm_cfg_commit (PCONFIG pconfig) 938{ 939 FILE *fp; 940 941 if (!_iodbcdm_cfg_valid (pconfig)) 942 return -1; 943 944 if (pconfig->dirty) 945 { 946 if ((fp = fopen (pconfig->fileName, "w")) == NULL) 947 return -1; 948 949 __iodbcdm_cfg_outputformatted (pconfig, fp); 950 951 fclose (fp); 952 953 pconfig->dirty = 0; 954 } 955 956 return 0; 957} 958 959 960int 961_iodbcdm_cfg_next_section(PCONFIG pconfig) 962{ 963 do 964 if (0 != _iodbcdm_cfg_nextentry (pconfig)) 965 return -1; 966 while (!_iodbcdm_cfg_section (pconfig)); 967 968 return 0; 969} 970 971 972int 973_iodbcdm_cfg_search_init(PCONFIG *ppconf, const char *filename, int doCreate) 974{ 975 char pathbuf[1024]; 976 977 if (strstr (filename, "odbc.ini") || strstr (filename, "ODBC.INI")) 978 return _iodbcdm_cfg_init (ppconf, _iodbcadm_getinifile (pathbuf, 979 sizeof (pathbuf), FALSE, doCreate), doCreate); 980 else if (strstr (filename, "odbcinst.ini") 981 || strstr (filename, "ODBCINST.INI")) 982 return _iodbcdm_cfg_init (ppconf, _iodbcadm_getinifile (pathbuf, 983 sizeof (pathbuf), TRUE, doCreate), doCreate); 984 else if (doCreate || (!doCreate && access(filename, R_OK) == 0)) 985 return _iodbcdm_cfg_init (ppconf, filename, doCreate); 986 else 987 return -1; 988} 989 990 991int 992_iodbcdm_list_sections (PCONFIG pCfg, LPSTR lpszRetBuffer, int cbRetBuffer) 993{ 994 int curr = 0, sect_len = 0; 995 lpszRetBuffer[0] = 0; 996 997 if (0 == _iodbcdm_cfg_rewind (pCfg)) 998 { 999 while (curr < cbRetBuffer && 0 == _iodbcdm_cfg_next_section (pCfg) 1000 && pCfg->section) 1001 { 1002 sect_len = strlen (pCfg->section) + 1; 1003 sect_len = 1004 sect_len > cbRetBuffer - curr ? cbRetBuffer - curr : sect_len; 1005 1006 memmove (lpszRetBuffer + curr, pCfg->section, sect_len); 1007 1008 curr += sect_len; 1009 } 1010 if (curr < cbRetBuffer) 1011 lpszRetBuffer[curr] = 0; 1012 return curr; 1013 } 1014 return 0; 1015} 1016 1017 1018int 1019_iodbcdm_list_entries (PCONFIG pCfg, LPCSTR lpszSection, LPSTR lpszRetBuffer, int cbRetBuffer) 1020{ 1021 int curr = 0, sect_len = 0; 1022 lpszRetBuffer[0] = 0; 1023 1024 if (0 == _iodbcdm_cfg_rewind (pCfg)) 1025 { 1026 while (curr < cbRetBuffer && 0 == _iodbcdm_cfg_nextentry (pCfg)) 1027 { 1028 if (_iodbcdm_cfg_define (pCfg) 1029 && !strcmp (pCfg->section, lpszSection) && pCfg->id) 1030 { 1031 sect_len = strlen (pCfg->id) + 1; 1032 sect_len = 1033 sect_len > 1034 cbRetBuffer - curr ? cbRetBuffer - curr : sect_len; 1035 1036 memmove (lpszRetBuffer + curr, pCfg->id, sect_len); 1037 1038 curr += sect_len; 1039 } 1040 } 1041 if (curr < cbRetBuffer) 1042 lpszRetBuffer[curr] = 0; 1043 return curr; 1044 } 1045 return 0; 1046} 1047 1048 1049BOOL 1050do_create_dsns (PCONFIG pCfg, PCONFIG pInfCfg, LPSTR szDriver, LPSTR szDSNS, LPSTR szDiz) 1051{ 1052 char *szValue = strdup (szDSNS), *szCurr = szValue, *szComma; 1053 int hasMore = FALSE; 1054 BOOL retcode = FALSE; 1055 1056 do 1057 { 1058 szComma = strchr (szCurr, ','); 1059 if (szComma) 1060 { 1061 *szComma = 0; 1062 hasMore = TRUE; 1063 } 1064 else 1065 hasMore = FALSE; 1066 1067#ifdef WIN32 1068 if (_iodbcdm_cfg_write (pCfg, "ODBC 32 bit Data Sources", szCurr, 1069 szDiz)) 1070#else 1071 if (_iodbcdm_cfg_write (pCfg, "ODBC Data Sources", szCurr, szDiz)) 1072#endif 1073 goto error; 1074 1075 if (!ValidDSN (szCurr) || _iodbcdm_cfg_write (pCfg, szCurr, NULL, NULL)) 1076 goto error; 1077 1078 if (_iodbcdm_cfg_find (pInfCfg, szCurr, NULL) 1079 && !_iodbcdm_cfg_write (pCfg, szCurr, NULL, NULL)) 1080 { 1081 if (_iodbcdm_cfg_write (pCfg, szCurr, "Driver", szDriver)) 1082 goto error; 1083 while (!_iodbcdm_cfg_nextentry (pInfCfg) 1084 && _iodbcdm_cfg_define (pInfCfg)) 1085 { 1086 if (_iodbcdm_cfg_write (pCfg, szCurr, pInfCfg->id, 1087 pInfCfg->value)) 1088 goto error; 1089 } 1090 } 1091 1092 szCurr = szComma + 1; 1093 } 1094 while (hasMore); 1095 1096 retcode = TRUE; 1097 1098error: 1099 free (szValue); 1100 return retcode; 1101} 1102 1103 1104BOOL 1105install_from_ini (PCONFIG pCfg, PCONFIG pOdbcCfg, LPSTR szInfFile, LPSTR szDriver, BOOL drivers) 1106{ 1107 PCONFIG pInfCfg; 1108 char *szKeysSection = NULL, *szDriverFile = NULL, *szSetupFile = NULL, 1109 *szValue = NULL, *szId = NULL, *szComma, *szComma1; 1110 BOOL ret = FALSE; 1111 1112 if (_iodbcdm_cfg_write (pCfg, szDriver, NULL, NULL)) 1113 return ret; 1114 1115 if (_iodbcdm_cfg_init (&pInfCfg, szInfFile, FALSE)) 1116 return ret; 1117 1118 if (_iodbcdm_cfg_find (pInfCfg, 1119 drivers ? "ODBC Drivers" : "ODBC Translators", szDriver)) 1120 goto error; 1121 1122#ifdef WIN32 1123 if (_iodbcdm_cfg_write (pCfg, 1124 drivers ? "ODBC 32 bit Drivers" : "ODBC 32 bit Translators", 1125 szDriver, "Installed")) 1126#else 1127 if (_iodbcdm_cfg_write (pCfg, drivers ? "ODBC Drivers" : "ODBC Translators", 1128 szDriver, "Installed")) 1129#endif 1130 goto error; 1131 1132 if (_iodbcdm_cfg_find (pInfCfg, szDriver, 1133 drivers ? "Driver" : "Translator")) 1134 goto error; 1135 1136 szComma = strchr (pInfCfg->value, ','); 1137 szComma1 = strchr (szComma + 1, ','); 1138 if (!szComma || !szComma1 || szComma + 1 == szComma1) 1139 goto error; 1140 1141 *szComma1 = 0; 1142 szDriverFile = strdup (szComma + 1); 1143 if (_iodbcdm_cfg_write (pCfg, szDriver, drivers ? "Driver" : "Translator", 1144 szDriverFile)) 1145 goto error; 1146 1147 if (!_iodbcdm_cfg_find (pInfCfg, szDriver, "Setup")) 1148 { 1149 szComma = strchr (pInfCfg->value, ','); 1150 szComma1 = strchr (szComma + 1, ','); 1151 if (!szComma || !szComma1 || szComma + 1 == szComma1) 1152 goto error; 1153 1154 *szComma1 = 0; 1155 szSetupFile = strdup (szComma + 1); 1156 1157 if (_iodbcdm_cfg_write (pCfg, szDriver, "Setup", szSetupFile)) 1158 goto error; 1159 } 1160 1161 if (!_iodbcdm_cfg_find (pInfCfg, szDriver, NULL)) 1162 { 1163 while (!_iodbcdm_cfg_nextentry (pInfCfg) 1164 && _iodbcdm_cfg_define (pInfCfg)) 1165 if (strcmp (pInfCfg->id, drivers ? "\"Driver\"" : "\"Translator\"") 1166 && strcmp (pInfCfg->id, "\"Setup\"")) 1167 { 1168 szComma = strchr (pInfCfg->value, ','); 1169 szComma1 = strchr (szComma + 1, ','); 1170 if (!szComma || !szComma1 || szComma + 1 == szComma1) 1171 szValue = strdup (""); 1172 else 1173 { 1174 *szComma1 = 0; 1175 szValue = strdup (szComma + 1); 1176 } 1177 1178 szComma = strchr (pInfCfg->id, '"'); 1179 szComma1 = strchr (szComma + 1, '"'); 1180 if (!szComma || !szComma1 || szComma + 1 == szComma1) 1181 goto loop_cont; 1182 else 1183 { 1184 *szComma1 = 0; 1185 szId = strdup (szComma + 1); 1186 } 1187 1188 if (_iodbcdm_cfg_write (pCfg, szDriver, szId, szValue)) 1189 goto error; 1190 1191 loop_cont: 1192 if (szValue) 1193 { 1194 free (szValue); 1195 szValue = NULL; 1196 } 1197 if (szId) 1198 { 1199 free (szId); 1200 szId = NULL; 1201 } 1202 } 1203 } 1204 1205 if (!drivers) 1206 goto quit; 1207 1208 szKeysSection = (char *) calloc (strlen (szDriver) + 6, sizeof (char)); 1209 strcpy (szKeysSection, szDriver); 1210 strcat (szKeysSection, "-Keys"); 1211 1212 if (!_iodbcdm_cfg_find (pInfCfg, szKeysSection, NULL)) 1213 { 1214 while (!_iodbcdm_cfg_nextentry (pInfCfg) 1215 && _iodbcdm_cfg_define (pInfCfg)) 1216 { 1217 if (strcmp (pInfCfg->id, "CreateDSN")) 1218 { 1219 if (_iodbcdm_cfg_write (pCfg, szDriver, pInfCfg->id, 1220 pInfCfg->value)) 1221 goto error; 1222 } 1223 else if (!do_create_dsns (pOdbcCfg, pCfg, szDriverFile, 1224 pInfCfg->value, szDriver)) 1225 goto error; 1226 } 1227 } 1228 1229quit: 1230 ret = TRUE; 1231 1232error: 1233 if (szKeysSection) 1234 free (szKeysSection); 1235 if (szDriverFile) 1236 free (szDriverFile); 1237 if (szSetupFile) 1238 free (szSetupFile); 1239 if (szValue) 1240 free (szValue); 1241 if (szId) 1242 free (szId); 1243 _iodbcdm_cfg_done (pInfCfg); 1244 return ret; 1245} 1246 1247 1248int 1249install_from_string (PCONFIG pCfg, PCONFIG pOdbcCfg, LPSTR lpszDriver, BOOL drivers) 1250{ 1251 char *szCurr = (char *) lpszDriver, *szDiz = lpszDriver; 1252 char *szAsignment, *szEqual, *szValue, *szDriver = NULL; 1253 1254 if (_iodbcdm_cfg_write (pCfg, lpszDriver, NULL, NULL)) 1255 return FALSE; 1256 1257#ifdef WIN32 1258 if (_iodbcdm_cfg_write (pCfg, 1259 drivers ? "ODBC 32 bit Drivers" : "ODBC 32 bit Translators", 1260 lpszDriver, "Installed")) 1261#else 1262 if (_iodbcdm_cfg_write (pCfg, drivers ? "ODBC Drivers" : "ODBC Translators", 1263 lpszDriver, "Installed")) 1264#endif 1265 return FALSE; 1266 1267 for (szCurr = lpszDriver + strlen (lpszDriver) + 1; *szCurr; 1268 szCurr += strlen (szCurr) + 1) 1269 { 1270 szAsignment = strdup (szCurr); 1271 szEqual = strchr (szAsignment, '='); 1272 szValue = szEqual + 1; 1273 1274 if (szEqual) 1275 *szEqual = 0; 1276 else 1277 goto loop_error; 1278 1279 if ((drivers && !strcmp (szAsignment, "Driver")) || (!drivers 1280 && !strcmp (szAsignment, "Translator"))) 1281 { 1282 if (szDriver) 1283 free (szDriver); 1284 szDriver = strdup (szValue); 1285 } 1286 1287 if (drivers) 1288 { 1289 if (strcmp (szAsignment, "CreateDSN")) 1290 { 1291 if (_iodbcdm_cfg_write (pCfg, lpszDriver, szAsignment, szValue)) 1292 goto loop_error; 1293 } 1294 else if (!do_create_dsns (pOdbcCfg, pCfg, szDriver, szValue, szDiz)) 1295 goto loop_error; 1296 } 1297 else if (_iodbcdm_cfg_write (pCfg, lpszDriver, szAsignment, szValue)) 1298 goto loop_error; 1299 1300 free (szAsignment); 1301 continue; 1302 1303 loop_error: 1304 if (szDriver) 1305 free (szDriver); 1306 free (szAsignment); 1307 return FALSE; 1308 } 1309 1310 if (szDriver) 1311 free (szDriver); 1312 else 1313 return FALSE; 1314 1315 return TRUE; 1316} 1317