1/*
2 * Profile functions
3 *
4 * Copyright 1993 Miguel de Icaza
5 * Copyright 1996 Alexandre Julliard
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
20 */
21#include "my_global.h"
22
23#include <ctype.h>
24//#include <errno.h>
25#include <fcntl.h>
26//#include <io.h> commented this line out to compile for solaris
27#include <stdlib.h>
28#include <string.h>
29#include <stdio.h>
30#include <sys/stat.h>
31//#include <sys/types.h>
32//#include <memory.h>
33#include "osutil.h"
34#include "global.h"
35#include "inihandl.h"
36
37// The types and variables used locally
38//typedef int bool;
39typedef unsigned int uint;
40//#define SVP(S) ((S) ? S : "<null>")
41#define _strlwr(P) strlwr(P) //OB: changed this line
42#define MAX_PATHNAME_LEN 256
43#define N_CACHED_PROFILES 10
44#ifndef WIN32
45#define stricmp strcasecmp
46#define _strnicmp strncasecmp
47#endif // !WIN32
48#define EnterCriticalSection(x)
49#define LeaveCriticalSection(x)
50
51#if defined(TEST_MODULE)
52// Stand alone test program
53#include <stdarg.h>
54 int trace = 0;
55void htrc(char const *fmt, ...)
56{
57 va_list ap;
58 va_start (ap, fmt);
59 vfprintf(stderr, fmt, ap);
60 va_end (ap);
61} /* end of htrc */
62#else // !TEST_MODULE
63// Normal included functions
64//extern int trace;
65//void htrc(char const *fmt, ...);
66#endif // !TEST MODULE
67
68
69typedef struct tagPROFILEKEY {
70 char *value;
71 struct tagPROFILEKEY *next;
72 char name[1];
73 } PROFILEKEY;
74
75typedef struct tagPROFILESECTION {
76 struct tagPROFILEKEY *key;
77 struct tagPROFILESECTION *next;
78 char name[1];
79 } PROFILESECTION;
80
81typedef struct {
82 BOOL changed;
83 PROFILESECTION *section;
84//char *dos_name;
85//char *unix_name;
86 char *filename;
87 time_t mtime;
88 } PROFILE;
89
90#define memfree(P) if (P) free(P)
91
92/* Cached profile files */
93static PROFILE *MRUProfile[N_CACHED_PROFILES] = {NULL};
94
95#define CurProfile (MRUProfile[0])
96
97/* wine.ini config file registry root */
98//static HKEY wine_profile_key;
99
100#define PROFILE_MAX_LINE_LEN 1024
101
102/* Wine profile name in $HOME directory; must begin with slash */
103//static const char PROFILE_WineIniName[] = "/.winerc";
104
105/* Wine profile: the profile file being used */
106//static char PROFILE_WineIniUsed[MAX_PATHNAME_LEN] = "";
107
108/* Check for comments in profile */
109#define IS_ENTRY_COMMENT(str) ((str)[0] == ';')
110
111//static const WCHAR wininiW[] = { 'w','i','n','.','i','n','i',0 };
112
113//static CRITICAL_SECTION PROFILE_CritSect = CRITICAL_SECTION_INIT("PROFILE_CritSect");
114
115static const char hex[17] = "0123456789ABCDEF";
116
117BOOL WritePrivateProfileString(LPCSTR section, LPCSTR entry,
118 LPCSTR string, LPCSTR filename);
119
120/***********************************************************************
121 * PROFILE_CopyEntry
122 *
123 * Copy the content of an entry into a buffer, removing quotes,
124 * and possibly translating environment variables.
125 ***********************************************************************/
126static void PROFILE_CopyEntry( char *buffer, const char *value, uint len,
127 int handle_env )
128{
129 const char *p;
130 char quote = '\0';
131
132 if (!buffer)
133 return;
134
135 if ((*value == '\'') || (*value == '\"'))
136 if (value[1] && (value[strlen(value)-1] == *value))
137 quote = *value++;
138
139 if (!handle_env) {
140 strncpy(buffer, value, len);
141
142 if (quote && (len >= strlen(value)))
143 buffer[strlen(buffer)-1] = '\0';
144
145 return;
146 } // endif handle
147
148 for (p = value; (*p && (len > 1)); *buffer++ = *p++, len--) {
149 if ((*p == '$') && (p[1] == '{')) {
150 char env_val[1024];
151 const char *env_p;
152 const char *p2 = strchr(p, '}');
153
154 if (!p2)
155 continue; /* ignore it */
156
157 strncpy(env_val, p + 2, MY_MIN((int) sizeof(env_val), (int)(p2-p)-1));
158
159 if ((env_p = getenv(env_val)) != NULL) {
160 int buffer_len;
161
162 strncpy( buffer, env_p, len );
163 buffer_len = strlen( buffer );
164 buffer += buffer_len;
165 len -= buffer_len;
166 } // endif env_p
167
168 p = p2 + 1;
169 } // endif p
170
171 } // endfor p
172
173 if (quote && (len > 1))
174 buffer--;
175
176 *buffer = '\0';
177} // end of PROFILE_CopyEntry
178
179
180/***********************************************************************
181 * PROFILE_Save
182 *
183 * Save a profile tree to a file.
184 ***********************************************************************/
185static void PROFILE_Save( FILE *file, PROFILESECTION *section )
186{
187 PROFILEKEY *key;
188 int secno;
189
190 for (secno= 0; section; section= section->next) {
191 if (section->name[0]) {
192 fprintf(file, "%s[%s]\n", secno ? "\n" : "", SVP(section->name));
193 secno++;
194 }
195
196 for (key = section->key; key; key = key->next)
197 if (key->name && key->name[0]) {
198 fprintf(file, "%s", SVP(key->name));
199
200 if (key->value)
201 fprintf(file, "=%s", SVP(key->value));
202
203 fprintf(file, "\n");
204 } // endif key->name
205
206 } // endfor section
207
208} // end of PROFILE_Save
209
210
211/***********************************************************************
212 * PROFILE_Free
213 *
214 * Free a profile tree.
215 ***********************************************************************/
216static void PROFILE_Free( PROFILESECTION *section )
217{
218 PROFILESECTION *next_section;
219 PROFILEKEY *key, *next_key;
220
221 for (; section; section = next_section) {
222 for (key = section->key; key; key = next_key) {
223 next_key = key->next;
224 memfree(key->value);
225 free(key);
226 } // endfor key
227
228 next_section = section->next;
229 free(section);
230 } // endfor section
231
232} // end of PROFILE_Free
233
234static int PROFILE_isspace(char c)
235{
236 /* CR and ^Z (DOS EOF) are spaces too (found on CD-ROMs) */
237 if (isspace(c) || c=='\r' || c==0x1a)
238 return 1;
239
240 return 0;
241} // end of PROFILE_isspace
242
243
244/***********************************************************************
245 * PROFILE_Load
246 *
247 * Load a profile tree from a file.
248 ***********************************************************************/
249static PROFILESECTION *PROFILE_Load( FILE *file )
250{
251 char buffer[PROFILE_MAX_LINE_LEN];
252 char *p, *p2;
253 int line = 0;
254 PROFILESECTION *section, *first_section;
255 PROFILESECTION* *next_section;
256 PROFILEKEY *key, *prev_key, **next_key;
257
258 first_section = (PROFILESECTION*)malloc(sizeof(*section));
259
260 if (first_section == NULL)
261 return NULL;
262
263 first_section->name[0] = 0;
264 first_section->key = NULL;
265 first_section->next = NULL;
266 next_section = &first_section->next;
267 next_key = &first_section->key;
268 prev_key = NULL;
269
270 while (fgets(buffer, PROFILE_MAX_LINE_LEN, file)) {
271 line++;
272 p = buffer;
273
274 while (*p && PROFILE_isspace(*p))
275 p++;
276
277 if (*p == '[') { /* section start */
278 if (!(p2 = strrchr( p, ']'))) {
279 fprintf(stderr, "Invalid section header at line %d: '%s'\n",
280 line, p);
281 } else {
282 *p2 = '\0';
283 p++;
284
285 if (!(section = (PROFILESECTION*)malloc(sizeof(*section) + strlen(p))))
286 break;
287
288 strcpy(section->name, p);
289 section->key = NULL;
290 section->next = NULL;
291 *next_section = section;
292 next_section = &section->next;
293 next_key = &section->key;
294 prev_key = NULL;
295
296 if (trace(2))
297 htrc("New section: '%s'\n",section->name);
298
299 continue;
300 } // endif p2
301
302 } // endif p
303
304 p2 = p + strlen(p) - 1;
305
306 while ((p2 > p) && ((*p2 == '\n') || PROFILE_isspace(*p2)))
307 *p2-- = '\0';
308
309 if ((p2 = strchr(p, '=')) != NULL) {
310 char *p3 = p2 - 1;
311
312 while ((p3 > p) && PROFILE_isspace(*p3))
313 *p3-- = '\0';
314
315 *p2++ = '\0';
316
317 while (*p2 && PROFILE_isspace(*p2))
318 p2++;
319
320 } // endif p2
321
322 if (*p || !prev_key || *prev_key->name) {
323 if (!(key = (PROFILEKEY*)malloc(sizeof(*key) + strlen(p))))
324 break;
325
326 strcpy(key->name, p);
327
328 if (p2) {
329 key->value = (char*)malloc(strlen(p2)+1);
330 strcpy(key->value, p2);
331 } else
332 key->value = NULL;
333
334 key->next = NULL;
335 *next_key = key;
336 next_key = &key->next;
337 prev_key = key;
338
339 if (trace(2))
340 htrc("New key: name='%s', value='%s'\n",
341 key->name,key->value?key->value:"(none)");
342
343 } // endif p || prev_key
344
345 } // endif *p
346
347 return first_section;
348} // end of PROFILE_Load
349
350/***********************************************************************
351 * PROFILE_FlushFile
352 *
353 * Flush the current profile to disk if changed.
354 ***********************************************************************/
355static BOOL PROFILE_FlushFile(void)
356{
357//char *p, buffer[MAX_PATHNAME_LEN];
358//const char *unix_name;
359 FILE *file = NULL;
360 struct stat buf;
361
362 if (trace(2))
363 htrc("PROFILE_FlushFile: CurProfile=%p\n", CurProfile);
364
365 if (!CurProfile) {
366 fprintf(stderr, "No current profile!\n");
367 return FALSE;
368 } // endif !CurProfile
369
370 if (!CurProfile->changed || !CurProfile->filename)
371 return TRUE;
372
373#if 0
374 if (!(file = fopen(unix_name, "w"))) {
375 /* Try to create it in $HOME/.wine */
376 /* FIXME: this will need a more general solution */
377 //strcpy( buffer, get_config_dir() );
378 //p = buffer + strlen(buffer);
379 //*p++ = '/';
380 char *p1 = strrchr(CurProfile->filename, '\\');
381
382 p = buffer; // OB: To be elaborate
383
384 if (p1)
385 p1++;
386 else
387 p1 = CurProfile->dos_name;
388
389 strcpy(p, p1);
390 _strlwr(p);
391 file = fopen(buffer, "w");
392 unix_name = buffer;
393 } // endif !unix_name
394#endif // 0
395
396 if (!(file = fopen(CurProfile->filename, "w"))) {
397 fprintf(stderr, "could not save profile file %s\n", CurProfile->filename);
398 return FALSE;
399 } // endif !file
400
401 if (trace(2))
402 htrc("Saving '%s'\n", CurProfile->filename);
403
404 PROFILE_Save(file, CurProfile->section);
405 fclose(file);
406 CurProfile->changed = FALSE;
407
408 if (!stat(CurProfile->filename, &buf))
409 CurProfile->mtime = buf.st_mtime;
410
411 return TRUE;
412} // end of PROFILE_FlushFile
413
414
415/***********************************************************************
416 * PROFILE_ReleaseFile
417 *
418 * Flush the current profile to disk and remove it from the cache.
419 ***********************************************************************/
420static void PROFILE_ReleaseFile(void)
421{
422 PROFILE_FlushFile();
423 PROFILE_Free(CurProfile->section);
424//memfree(CurProfile->dos_name);
425//memfree(CurProfile->unix_name);
426 memfree(CurProfile->filename);
427 CurProfile->changed = FALSE;
428 CurProfile->section = NULL;
429//CurProfile->dos_name = NULL;
430//CurProfile->unix_name = NULL;
431 CurProfile->filename = NULL;
432 CurProfile->mtime = 0;
433} // end of PROFILE_ReleaseFile
434
435
436/***********************************************************************
437 * PROFILE_Open
438 *
439 * Open a profile file, checking the cached file first.
440 ***********************************************************************/
441static BOOL PROFILE_Open(LPCSTR filename)
442{
443//char buffer[MAX_PATHNAME_LEN];
444//char *p;
445 FILE *file = NULL;
446 int i, j;
447 struct stat buf;
448 PROFILE *tempProfile;
449
450 if (trace(2))
451 htrc("PROFILE_Open: CurProfile=%p N=%d\n", CurProfile, N_CACHED_PROFILES);
452
453 /* First time around */
454 if (!CurProfile)
455 for (i = 0; i < N_CACHED_PROFILES; i++) {
456 MRUProfile[i] = (PROFILE*)malloc(sizeof(PROFILE));
457
458 if (MRUProfile[i] == NULL)
459 break;
460
461 MRUProfile[i]->changed=FALSE;
462 MRUProfile[i]->section=NULL;
463// MRUProfile[i]->dos_name=NULL;
464// MRUProfile[i]->unix_name=NULL;
465 MRUProfile[i]->filename=NULL;
466 MRUProfile[i]->mtime=0;
467 } // endfor i
468
469 /* Check for a match */
470 for (i = 0; i < N_CACHED_PROFILES; i++) {
471 if (trace(2))
472 htrc("MRU=%s i=%d\n", SVP(MRUProfile[i]->filename), i);
473
474 if (MRUProfile[i]->filename && !strcmp(filename, MRUProfile[i]->filename)) {
475 if (i) {
476 PROFILE_FlushFile();
477 tempProfile = MRUProfile[i];
478
479 for (j = i; j > 0; j--)
480 MRUProfile[j] = MRUProfile[j-1];
481
482 CurProfile=tempProfile;
483 } // endif i
484
485 if (!stat(CurProfile->filename, &buf) && CurProfile->mtime == buf.st_mtime) {
486 if (trace(2))
487 htrc("(%s): already opened (mru=%d)\n", filename, i);
488
489 } else {
490 if (trace(2))
491 htrc("(%s): already opened, needs refreshing (mru=%d)\n", filename, i);
492
493 } // endif stat
494
495 return TRUE;
496 } // endif filename
497
498 } // endfor i
499
500 /* Flush the old current profile */
501 PROFILE_FlushFile();
502
503 /* Make the oldest profile the current one only in order to get rid of it */
504 if (i == N_CACHED_PROFILES) {
505 tempProfile = MRUProfile[N_CACHED_PROFILES-1];
506
507 for(i = N_CACHED_PROFILES-1; i > 0; i--)
508 MRUProfile[i] = MRUProfile[i-1];
509
510 CurProfile = tempProfile;
511 } // endif i
512
513 if (CurProfile->filename)
514 PROFILE_ReleaseFile();
515
516 /* OK, now that CurProfile is definitely free we assign it our new file */
517// newdos_name = HeapAlloc( GetProcessHeap(), 0, strlen(full_name.short_name)+1 );
518// strcpy( newdos_name, full_name.short_name );
519
520// newdos_name = malloc(strlen(filename)+1);
521// strcpy(newdos_name, filename);
522
523// CurProfile->dos_name = newdos_name;
524 CurProfile->filename = (char*)malloc(strlen(filename) + 1);
525 strcpy(CurProfile->filename, filename);
526
527 /* Try to open the profile file, first in $HOME/.wine */
528
529 /* FIXME: this will need a more general solution */
530// strcpy( buffer, get_config_dir() );
531// p = buffer + strlen(buffer);
532// *p++ = '/';
533// strcpy( p, strrchr( newdos_name, '\\' ) + 1 );
534// p = buffer;
535// strcpy(p, filename);
536// _strlwr(p);
537
538 if (trace(2))
539 htrc("Opening %s\n", filename);
540
541 if ((file = fopen(filename, "r"))) {
542 if (trace(2))
543 htrc("(%s): found it\n", filename);
544
545// CurProfile->unix_name = malloc(strlen(buffer)+1);
546// strcpy(CurProfile->unix_name, buffer);
547 } /* endif file */
548
549 if (file) {
550 CurProfile->section = PROFILE_Load(file);
551 fclose(file);
552
553 if (!stat(CurProfile->filename, &buf))
554 CurProfile->mtime = buf.st_mtime;
555
556 } else {
557 /* Does not exist yet, we will create it in PROFILE_FlushFile */
558 fprintf(stderr, "profile file %s not found\n", filename);
559 } /* endif file */
560
561 return TRUE;
562}
563
564
565/***********************************************************************
566 * PROFILE_Close
567 *
568 * Flush the named profile to disk and remove it from the cache.
569 ***********************************************************************/
570void PROFILE_Close(LPCSTR filename)
571{
572 int i;
573 BOOL close = FALSE;
574 struct stat buf;
575 PROFILE *tempProfile;
576
577 if (trace(2))
578 htrc("PROFILE_Close: CurProfile=%p N=%d\n", CurProfile, N_CACHED_PROFILES);
579
580 /* Check for a match */
581 for (i = 0; i < N_CACHED_PROFILES; i++) {
582 if (trace(2))
583 htrc("MRU=%s i=%d\n", SVP(MRUProfile[i]->filename), i);
584
585 if (MRUProfile[i]->filename && !strcmp(filename, MRUProfile[i]->filename)) {
586 if (i) {
587 /* Make the profile to close current */
588 tempProfile = MRUProfile[i];
589 MRUProfile[i] = MRUProfile[0];
590 MRUProfile[0] = tempProfile;
591 CurProfile=tempProfile;
592 } // endif i
593
594 if (trace(2)) {
595 if (!stat(CurProfile->filename, &buf) && CurProfile->mtime == buf.st_mtime)
596 htrc("(%s): already opened (mru=%d)\n", filename, i);
597 else
598 htrc("(%s): already opened, needs refreshing (mru=%d)\n", filename, i);
599
600 } // endif trace
601
602 close = TRUE;
603 break;
604 } // endif filename
605
606 } // endfor i
607
608 if (close)
609 PROFILE_ReleaseFile();
610
611} // end of PROFILE_Close
612
613
614/***********************************************************************
615 * PROFILE_End
616 *
617 * Terminate and release the cache.
618 ***********************************************************************/
619void PROFILE_End(void)
620{
621 int i;
622
623 if (trace(3))
624 htrc("PROFILE_End: CurProfile=%p N=%d\n", CurProfile, N_CACHED_PROFILES);
625
626 if (!CurProfile) // Sergey Vojtovich
627 return;
628
629 /* Close all opened files and free the cache structure */
630 for (i = 0; i < N_CACHED_PROFILES; i++) {
631 if (trace(3))
632 htrc("MRU=%s i=%d\n", SVP(MRUProfile[i]->filename), i);
633
634// CurProfile = MRUProfile[i]; Sergey Vojtovich
635// PROFILE_ReleaseFile(); see MDEV-9997
636 free(MRUProfile[i]);
637 } // endfor i
638
639} // end of PROFILE_End
640
641
642/***********************************************************************
643 * PROFILE_DeleteSection
644 *
645 * Delete a section from a profile tree.
646 ***********************************************************************/
647static BOOL PROFILE_DeleteSection(PROFILESECTION* *section, LPCSTR name)
648{
649 while (*section) {
650 if ((*section)->name[0] && !stricmp((*section)->name, name)) {
651 PROFILESECTION *to_del = *section;
652
653 *section = to_del->next;
654 to_del->next = NULL;
655 PROFILE_Free(to_del);
656 return TRUE;
657 } // endif section
658
659 section = &(*section)->next;
660 } // endwhile section
661
662 return FALSE;
663} // end of PROFILE_DeleteSection
664
665
666/***********************************************************************
667 * PROFILE_DeleteKey
668 *
669 * Delete a key from a profile tree.
670 ***********************************************************************/
671static BOOL PROFILE_DeleteKey(PROFILESECTION* *section,
672 LPCSTR section_name, LPCSTR key_name)
673{
674 while (*section) {
675 if ((*section)->name[0] && !stricmp((*section)->name, section_name)) {
676 PROFILEKEY* *key = &(*section)->key;
677
678 while (*key) {
679 if (!stricmp((*key)->name, key_name)) {
680 PROFILEKEY *to_del = *key;
681
682 *key = to_del->next;
683 memfree(to_del->value);
684 free(to_del);
685 return TRUE;
686 } // endif name
687
688 key = &(*key)->next;
689 } // endwhile *key
690
691 } // endif section->name
692
693 section = &(*section)->next;
694 } // endwhile *section
695
696 return FALSE;
697} // end of PROFILE_DeleteKey
698
699
700/***********************************************************************
701 * PROFILE_DeleteAllKeys
702 *
703 * Delete all keys from a profile tree.
704 ***********************************************************************/
705static void PROFILE_DeleteAllKeys(LPCSTR section_name)
706{
707 PROFILESECTION* *section= &CurProfile->section;
708
709 while (*section) {
710 if ((*section)->name[0] && !stricmp((*section)->name, section_name)) {
711 PROFILEKEY* *key = &(*section)->key;
712
713 while (*key) {
714 PROFILEKEY *to_del = *key;
715
716 *key = to_del->next;
717 memfree(to_del->value);
718 free(to_del);
719 CurProfile->changed = TRUE;
720 } // endwhile *key
721
722 } // endif section->name
723
724 section = &(*section)->next;
725 } // endwhile *section
726
727} // end of PROFILE_DeleteAllKeys
728
729
730/***********************************************************************
731 * PROFILE_Find
732 *
733 * Find a key in a profile tree, optionally creating it.
734 ***********************************************************************/
735static PROFILEKEY *PROFILE_Find(PROFILESECTION* *section,
736 const char *section_name,
737 const char *key_name,
738 BOOL create, BOOL create_always)
739{
740 const char *p;
741 int seclen, keylen;
742
743 while (PROFILE_isspace(*section_name))
744 section_name++;
745
746 p = section_name + strlen(section_name) - 1;
747
748 while ((p > section_name) && PROFILE_isspace(*p))
749 p--;
750
751 seclen = p - section_name + 1;
752
753 while (PROFILE_isspace(*key_name))
754 key_name++;
755
756 p = key_name + strlen(key_name) - 1;
757
758 while ((p > key_name) && PROFILE_isspace(*p))
759 p--;
760
761 keylen = p - key_name + 1;
762
763 while (*section) {
764 if (((*section)->name[0])
765 && (!(_strnicmp((*section)->name, section_name, seclen )))
766 && (((*section)->name)[seclen] == '\0')) {
767 PROFILEKEY* *key = &(*section)->key;
768
769 while (*key) {
770 /* If create_always is FALSE then we check if the keyname already exists.
771 * Otherwise we add it regardless of its existence, to allow
772 * keys to be added more then once in some cases.
773 */
774 if (!create_always) {
775 if ((!(_strnicmp( (*key)->name, key_name, keylen )))
776 && (((*key)->name)[keylen] == '\0'))
777 return *key;
778
779 } // endif !create_always
780
781 key = &(*key)->next;
782 } // endwhile *key
783
784 if (!create)
785 return NULL;
786
787 if (!(*key = (PROFILEKEY*)malloc(sizeof(PROFILEKEY) + strlen(key_name))))
788 return NULL;
789
790 strcpy((*key)->name, key_name);
791 (*key)->value = NULL;
792 (*key)->next = NULL;
793 return *key;
794 } // endifsection->name
795
796 section = &(*section)->next;
797 } // endwhile *section
798
799 if (!create)
800 return NULL;
801
802 *section = (PROFILESECTION*)malloc(sizeof(PROFILESECTION) + strlen(section_name));
803
804 if (*section == NULL)
805 return NULL;
806
807 strcpy((*section)->name, section_name);
808 (*section)->next = NULL;
809
810 if (!((*section)->key = (tagPROFILEKEY*)malloc(sizeof(PROFILEKEY) + strlen(key_name)))) {
811 free(*section);
812 return NULL;
813 } // endif malloc
814
815 strcpy((*section)->key->name, key_name);
816 (*section)->key->value = NULL;
817 (*section)->key->next = NULL;
818 return (*section)->key;
819} // end of PROFILE_Find
820
821
822/***********************************************************************
823 * PROFILE_GetSection
824 *
825 * Returns all keys of a section.
826 * If return_values is TRUE, also include the corresponding values.
827 ***********************************************************************/
828static int PROFILE_GetSection(PROFILESECTION *section, LPCSTR section_name,
829 LPSTR buffer, uint len,
830 BOOL handle_env, BOOL return_values)
831{
832 PROFILEKEY *key;
833
834 if(!buffer)
835 return 0;
836
837 while (section) {
838 if (section->name[0] && !stricmp(section->name, section_name)) {
839 uint oldlen = len;
840
841 for (key = section->key; key; key = key->next) {
842 if (len <= 2)
843 break;
844
845 if (!*key->name)
846 continue; /* Skip empty lines */
847
848 if (IS_ENTRY_COMMENT(key->name))
849 continue; /* Skip comments */
850
851 PROFILE_CopyEntry(buffer, key->name, len - 1, handle_env);
852 len -= strlen(buffer) + 1;
853 buffer += strlen(buffer) + 1;
854
855 if (len < 2)
856 break;
857
858 if (return_values && key->value) {
859 buffer[-1] = '=';
860 PROFILE_CopyEntry(buffer, key->value, len - 1, handle_env);
861 len -= strlen(buffer) + 1;
862 buffer += strlen(buffer) + 1;
863 } // endif return_values
864
865 } // endfor key
866
867 *buffer = '\0';
868
869 if (len <= 1) {
870 /*If either lpszSection or lpszKey is NULL and the supplied
871 destination buffer is too small to hold all the strings,
872 the last string is truncated and followed by two null characters.
873 In this case, the return value is equal to cchReturnBuffer
874 minus two. */
875 buffer[-1] = '\0';
876 return oldlen - 2;
877 } // endif len
878
879 return oldlen - len;
880 } // endif section->name
881
882 section = section->next;
883 } // endwhile section
884
885 buffer[0] = buffer[1] = '\0';
886 return 0;
887} // end of PROFILE_GetSection
888
889
890/* See GetPrivateProfileSectionNamesA for documentation */
891static int PROFILE_GetSectionNames(LPSTR buffer, uint len)
892{
893 LPSTR buf;
894 uint f,l;
895 PROFILESECTION *section;
896
897 if (trace(2))
898 htrc("GetSectionNames: buffer=%p len=%u\n", buffer, len);
899
900 if (!buffer || !len)
901 return 0;
902
903 if (len == 1) {
904 *buffer='\0';
905 return 0;
906 } // endif len
907
908 f = len - 1;
909 buf = buffer;
910 section = CurProfile->section;
911
912 if (trace(2))
913 htrc("GetSectionNames: section=%p\n", section);
914
915 while (section != NULL) {
916 if (trace(2))
917 htrc("section=%s\n", section->name);
918
919 if (section->name[0]) {
920 l = strlen(section->name) + 1;
921
922 if (trace(2))
923 htrc("l=%u f=%u\n", l, f);
924
925 if (l > f) {
926 if (f > 0) {
927 strncpy(buf, section->name, f-1);
928 buf += f-1;
929 *buf++='\0';
930 } // endif f
931
932 *buf = '\0';
933 return len - 2;
934 } // endif l
935
936 strcpy(buf, section->name);
937 buf += l;
938 f -= l;
939 } // endif section->name
940
941 section = section->next;
942 } // endwhile section
943
944 *buf='\0';
945 return buf-buffer;
946} // end of PROFILE_GetSectionNames
947
948
949/***********************************************************************
950 * PROFILE_GetString
951 *
952 * Get a profile string.
953 *
954 * Tests with GetPrivateProfileString16, W95a,
955 * with filled buffer ("****...") and section "set1" and key_name "1" valid:
956 * section key_name def_val res buffer
957 * "set1" "1" "x" 43 [data]
958 * "set1" "1 " "x" 43 [data] (!)
959 * "set1" " 1 "' "x" 43 [data] (!)
960 * "set1" "" "x" 1 "x"
961 * "set1" "" "x " 1 "x" (!)
962 * "set1" "" " x " 3 " x" (!)
963 * "set1" NULL "x" 6 "1\02\03\0\0"
964 * "set1" "" "x" 1 "x"
965 * NULL "1" "x" 0 "" (!)
966 * "" "1" "x" 1 "x"
967 * NULL NULL "" 0 ""
968 *
969 *************************************************************************/
970static int PROFILE_GetString(LPCSTR section, LPCSTR key_name,
971 LPCSTR def_val, LPSTR buffer, uint len)
972{
973 PROFILEKEY *key = NULL;
974
975 if(!buffer)
976 return 0;
977
978 if (!def_val)
979 def_val = "";
980
981 if (key_name && key_name[0]) {
982 key = PROFILE_Find(&CurProfile->section, section, key_name, FALSE, FALSE);
983 PROFILE_CopyEntry(buffer, (key && key->value) ? key->value : def_val, len, FALSE);
984
985 if (trace(2))
986 htrc("('%s','%s','%s'): returning '%s'\n",
987 section, key_name, def_val, buffer );
988
989 return strlen(buffer);
990 } // endif key_name
991
992 if (key_name && !(key_name[0]))
993 /* Win95 returns 0 on keyname "". Tested with Likse32 bon 000227 */
994 return 0;
995
996 if (section && section[0])
997 return PROFILE_GetSection(CurProfile->section, section, buffer, len,
998 FALSE, FALSE);
999 buffer[0] = '\0';
1000 return 0;
1001} // end of PROFILE_GetString
1002
1003
1004/***********************************************************************
1005 * PROFILE_SetString
1006 *
1007 * Set a profile string.
1008 ***********************************************************************/
1009static BOOL PROFILE_SetString(LPCSTR section_name, LPCSTR key_name,
1010 LPCSTR value, BOOL create_always)
1011{
1012 if (!key_name) { /* Delete a whole section */
1013 if (trace(2))
1014 htrc("Deleting('%s')\n", section_name);
1015
1016 CurProfile->changed |= PROFILE_DeleteSection(&CurProfile->section,
1017 section_name);
1018 return TRUE; /* Even if PROFILE_DeleteSection() has failed,
1019 this is not an error on application's level.*/
1020 } else if (!value) { /* Delete a key */
1021 if (trace(2))
1022 htrc("Deleting('%s','%s')\n", section_name, key_name);
1023
1024 CurProfile->changed |= PROFILE_DeleteKey(&CurProfile->section,
1025 section_name, key_name);
1026 return TRUE; /* same error handling as above */
1027 } else { /* Set the key value */
1028 PROFILEKEY *key = PROFILE_Find(&CurProfile->section, section_name,
1029 key_name, TRUE, create_always);
1030 if (trace(2))
1031 htrc("Setting('%s','%s','%s')\n", section_name, key_name, value);
1032
1033 if (!key)
1034 return FALSE;
1035
1036 if (key->value) {
1037 /* strip the leading spaces. We can safely strip \n\r and
1038 * friends too, they should not happen here anyway. */
1039 while (PROFILE_isspace(*value))
1040 value++;
1041
1042 if (!strcmp(key->value, value)) {
1043 if (trace(2))
1044 htrc(" no change needed\n" );
1045
1046 return TRUE; /* No change needed */
1047 } // endif value
1048
1049 if (trace(2))
1050 htrc(" replacing '%s'\n", key->value);
1051
1052 free(key->value);
1053 } else if (trace(2))
1054 htrc(" creating key\n" );
1055
1056 key->value = (char*)malloc(strlen(value) + 1);
1057 strcpy(key->value, value);
1058 CurProfile->changed = TRUE;
1059 } // endelse
1060
1061 return TRUE;
1062} // end of PROFILE_SetString
1063
1064
1065/***********************************************************************
1066 * PROFILE_GetStringItem
1067 *
1068 * Convenience function that turns a string 'xxx, yyy, zzz' into
1069 * the 'xxx\0 yyy, zzz' and returns a pointer to the 'yyy, zzz'.
1070 ***********************************************************************/
1071#if 0
1072char *PROFILE_GetStringItem(char* start)
1073{
1074 char *lpchX, *lpch;
1075
1076 for (lpchX = start, lpch = NULL; *lpchX != '\0'; lpchX++) {
1077 if (*lpchX == ',') {
1078 if (lpch)
1079 *lpch = '\0';
1080 else
1081 *lpchX = '\0';
1082
1083 while(*(++lpchX))
1084 if (!PROFILE_isspace(*lpchX))
1085 return lpchX;
1086
1087 } else if (PROFILE_isspace(*lpchX) && !lpch) {
1088 lpch = lpchX;
1089 } else
1090 lpch = NULL;
1091
1092 } // endfor lpchX
1093
1094 if (lpch)
1095 *lpch = '\0';
1096
1097 return NULL;
1098} // end of PROFILE_GetStringItem
1099#endif
1100
1101/**********************************************************************
1102 * if allow_section_name_copy is TRUE, allow the copying :
1103 * - of Section names if 'section' is NULL
1104 * - of Keys in a Section if 'entry' is NULL
1105 * (see MSDN doc for GetPrivateProfileString)
1106 **********************************************************************/
1107static int PROFILE_GetPrivateProfileString(LPCSTR section, LPCSTR entry,
1108 LPCSTR def_val, LPSTR buffer,
1109 uint len, LPCSTR filename,
1110 BOOL allow_section_name_copy)
1111{
1112 int ret;
1113 LPSTR pDefVal = NULL;
1114
1115 if (!filename)
1116 filename = "win.ini";
1117
1118 /* strip any trailing ' ' of def_val. */
1119 if (def_val) {
1120 LPSTR p = (LPSTR)&def_val[strlen(def_val)]; // even "" works !
1121
1122 while (p > def_val)
1123 if ((*(--p)) != ' ')
1124 break;
1125
1126 if (*p == ' ') { /* ouch, contained trailing ' ' */
1127 int len = p - (LPSTR)def_val;
1128
1129 pDefVal = (LPSTR)malloc(len + 1);
1130 strncpy(pDefVal, def_val, len);
1131 pDefVal[len] = '\0';
1132 } // endif *p
1133
1134 } // endif def_val
1135
1136 if (!pDefVal)
1137 pDefVal = (LPSTR)def_val;
1138
1139 EnterCriticalSection(&PROFILE_CritSect);
1140
1141 if (PROFILE_Open(filename)) {
1142 if ((allow_section_name_copy) && (section == NULL))
1143 ret = PROFILE_GetSectionNames(buffer, len);
1144 else
1145 /* PROFILE_GetString already handles the 'entry == NULL' case */
1146 ret = PROFILE_GetString(section, entry, pDefVal, buffer, len);
1147
1148 } else {
1149 strncpy(buffer, pDefVal, len);
1150 ret = strlen(buffer);
1151 } // endif Open
1152
1153 LeaveCriticalSection(&PROFILE_CritSect);
1154
1155 if (pDefVal != def_val) /* allocated */
1156 memfree(pDefVal);
1157
1158 return ret;
1159} // end of PROFILE_GetPrivateProfileString
1160
1161/********************** API functions **********************************/
1162
1163/***********************************************************************
1164 * GetPrivateProfileStringA (KERNEL32.@)
1165 ***********************************************************************/
1166int GetPrivateProfileString(LPCSTR section, LPCSTR entry, LPCSTR def_val,
1167 LPSTR buffer, DWORD len, LPCSTR filename)
1168{
1169 return PROFILE_GetPrivateProfileString(section, entry, def_val,
1170 buffer, len, filename, TRUE);
1171} // end of GetPrivateProfileString
1172
1173
1174/***********************************************************************
1175 * GetPrivateProfileIntA (KERNEL32.@)
1176 ***********************************************************************/
1177uint GetPrivateProfileInt(LPCSTR section, LPCSTR entry,
1178 int def_val, LPCSTR filename)
1179{
1180 char buffer[20];
1181 int result;
1182
1183 if (!PROFILE_GetPrivateProfileString(section, entry, "", buffer,
1184 sizeof(buffer), filename, FALSE))
1185 return def_val;
1186
1187 /* FIXME: if entry can be found but it's empty, then Win16 is
1188 * supposed to return 0 instead of def_val ! Difficult/problematic
1189 * to implement (every other failure also returns zero buffer),
1190 * thus wait until testing framework avail for making sure nothing
1191 * else gets broken that way. */
1192 if (!buffer[0])
1193 return (uint)def_val;
1194
1195 /* Don't use strtol() here !
1196 * (returns LONG_MAX/MIN on overflow instead of "proper" overflow)
1197 YES, scan for unsigned format ! (otherwise compatibility error) */
1198 if (!sscanf(buffer, "%u", &result))
1199 return 0;
1200
1201 return (uint)result;
1202} // end of GetPrivateProfileInt
1203
1204
1205/***********************************************************************
1206 * GetPrivateProfileSectionA (KERNEL32.@)
1207 ***********************************************************************/
1208int GetPrivateProfileSection(LPCSTR section, LPSTR buffer,
1209 DWORD len, LPCSTR filename)
1210{
1211 int ret = 0;
1212
1213 EnterCriticalSection( &PROFILE_CritSect );
1214
1215 if (PROFILE_Open(filename))
1216 ret = PROFILE_GetSection(CurProfile->section, section, buffer, len,
1217 FALSE, TRUE);
1218
1219 LeaveCriticalSection( &PROFILE_CritSect );
1220 return ret;
1221} // end of GetPrivateProfileSection
1222
1223
1224/***********************************************************************
1225 * WritePrivateProfileStringA (KERNEL32.@)
1226 ***********************************************************************/
1227BOOL WritePrivateProfileString(LPCSTR section, LPCSTR entry,
1228 LPCSTR string, LPCSTR filename)
1229{
1230 BOOL ret = FALSE;
1231
1232 EnterCriticalSection( &PROFILE_CritSect );
1233
1234 if (PROFILE_Open(filename)) {
1235 if (!section && !entry && !string) /* documented "file flush" case */
1236 PROFILE_ReleaseFile(); /* always return FALSE in this case */
1237 else {
1238 if (!section) {
1239 //FIXME("(NULL?,%s,%s,%s)? \n",entry,string,filename);
1240 } else {
1241 ret = PROFILE_SetString(section, entry, string, FALSE);
1242
1243 if (ret)
1244 ret = PROFILE_FlushFile();
1245
1246 } // endif section
1247
1248 } // endif section || entry|| string
1249
1250 } // endif Open
1251
1252 LeaveCriticalSection( &PROFILE_CritSect );
1253 return ret;
1254} // end of WritePrivateProfileString
1255
1256
1257/***********************************************************************
1258 * WritePrivateProfileSectionA (KERNEL32.@)
1259 ***********************************************************************/
1260BOOL WritePrivateProfileSection(LPCSTR section,
1261 LPCSTR string, LPCSTR filename )
1262{
1263 BOOL ret = FALSE;
1264 LPSTR p ;
1265
1266 EnterCriticalSection(&PROFILE_CritSect);
1267
1268 if (PROFILE_Open(filename)) {
1269 if (!section && !string)
1270 PROFILE_ReleaseFile(); /* always return FALSE in this case */
1271 else if (!string) { /* delete the named section*/
1272 ret = PROFILE_SetString(section, NULL, NULL, FALSE);
1273
1274 if (ret)
1275 ret = PROFILE_FlushFile();
1276 } else {
1277 PROFILE_DeleteAllKeys(section);
1278 ret = TRUE;
1279
1280 while (*string) {
1281 LPSTR buf = (LPSTR)malloc(strlen(string) + 1);
1282 strcpy(buf, string);
1283
1284 if ((p = strchr(buf, '='))) {
1285 *p='\0';
1286 ret = PROFILE_SetString(section, buf, p+1, TRUE);
1287 } // endif p
1288
1289 free(buf);
1290 string += strlen(string) + 1;
1291
1292 if (ret)
1293 ret = PROFILE_FlushFile();
1294
1295 } // endwhile *string
1296
1297 } // endelse
1298
1299 } // endif Open
1300
1301 LeaveCriticalSection(&PROFILE_CritSect);
1302 return ret;
1303} // end of WritePrivateProfileSection
1304
1305
1306/***********************************************************************
1307 * GetPrivateProfileSectionNamesA (KERNEL32.@)
1308 *
1309 * Returns the section names contained in the specified file.
1310 * FIXME: Where do we find this file when the path is relative?
1311 * The section names are returned as a list of strings with an extra
1312 * '\0' to mark the end of the list. Except for that the behavior
1313 * depends on the Windows version.
1314 *
1315 * Win95:
1316 * - if the buffer is 0 or 1 character long then it is as if it was of
1317 * infinite length.
1318 * - otherwise, if the buffer is to small only the section names that fit
1319 * are returned.
1320 * - note that this means if the buffer was to small to return even just
1321 * the first section name then a single '\0' will be returned.
1322 * - the return value is the number of characters written in the buffer,
1323 * except if the buffer was too smal in which case len-2 is returned
1324 *
1325 * Win2000:
1326 * - if the buffer is 0, 1 or 2 characters long then it is filled with
1327 * '\0' and the return value is 0
1328 * - otherwise if the buffer is too small then the first section name that
1329 * does not fit is truncated so that the string list can be terminated
1330 * correctly (double '\0')
1331 * - the return value is the number of characters written in the buffer
1332 * except for the trailing '\0'. If the buffer is too small, then the
1333 * return value is len-2
1334 * - Win2000 has a bug that triggers when the section names and the
1335 * trailing '\0' fit exactly in the buffer. In that case the trailing
1336 * '\0' is missing.
1337 *
1338 * Wine implements the observed Win2000 behavior (except for the bug).
1339 *
1340 * Note that when the buffer is big enough then the return value may be any
1341 * value between 1 and len-1 (or len in Win95), including len-2.
1342 */
1343static DWORD
1344GetPrivateProfileSectionNames(LPSTR buffer, DWORD size, LPCSTR filename)
1345{
1346 DWORD ret = 0;
1347
1348 if (trace(2))
1349 htrc("GPPSN: filename=%s\n", filename);
1350
1351 EnterCriticalSection(&PROFILE_CritSect);
1352
1353 if (PROFILE_Open(filename))
1354 ret = PROFILE_GetSectionNames(buffer, size);
1355
1356 LeaveCriticalSection(&PROFILE_CritSect);
1357 return ret;
1358} // end of GetPrivateProfileSectionNames
1359
1360
1361/************************************************************************
1362 * Program to test the above
1363 ************************************************************************/
1364#ifdef TEST_MODULE
1365int main(int argc, char**argv) {
1366 char buff[128];
1367 char *p, *inifile = "D:\\Plug\\Data\\contact.ini";
1368 DWORD n;
1369
1370 n = GetPrivateProfileSectionNames(buff, 128, inifile);
1371 printf("Sections: n=%d\n", n);
1372
1373 for (p = buff; *p; p += (strlen(p) + 1))
1374 printf("section=[%s]\n", p);
1375
1376 GetPrivateProfileString("BER", "name", "?", buff, 128, inifile);
1377 printf("[BER](name) = %s\n", buff);
1378
1379 WritePrivateProfileString("FOO", "city", NULL, inifile);
1380 GetPrivateProfileString("FOO", "city", "?", buff, 128, inifile);
1381 printf("[FOO](city) = %s\n", buff);
1382
1383 printf("FOO city: ");
1384 fgets(buff, sizeof(buff), stdin);
1385 if (buff[strlen(buff) - 1] == '\n')
1386 buff[strlen(buff) - 1] = '\0';
1387 WritePrivateProfileString("FOO", "city", buff, inifile);
1388 GetPrivateProfileString("FOO", "city", "???", buff, 128, inifile);
1389 printf("After write, [FOO](City) = %s\n", buff);
1390
1391 printf("New city: ");
1392 fgets(buff, sizeof(buff), stdin);
1393 if (buff[strlen(buff) - 1] == '\n')
1394 buff[strlen(buff) - 1] = '\0';
1395 WritePrivateProfileString("FOO", "city", buff, inifile);
1396 GetPrivateProfileString("FOO", "city", "???", buff, 128, inifile);
1397 printf("After update, [FOO](City) = %s\n", buff);
1398
1399 printf("FOO name: ");
1400 fgets(buff, sizeof(buff), stdin);
1401 if (buff[strlen(buff) - 1] == '\n')
1402 buff[strlen(buff) - 1] = '\0';
1403 WritePrivateProfileString("FOO", "name", buff, inifile);
1404 GetPrivateProfileString("FOO", "name", "X", buff, 128, inifile);
1405 printf("[FOO](name) = %s\n", buff);
1406} // end of main
1407#endif // TEST_MODULE
1408