CnC_Remastered_Collection

Command and Conquer: Red Alert
Log | Files | Refs | README | LICENSE

PROFILE.CPP (24851B)


      1 //
      2 // Copyright 2020 Electronic Arts Inc.
      3 //
      4 // TiberianDawn.DLL and RedAlert.dll and corresponding source code is free 
      5 // software: you can redistribute it and/or modify it under the terms of 
      6 // the GNU General Public License as published by the Free Software Foundation, 
      7 // either version 3 of the License, or (at your option) any later version.
      8 
      9 // TiberianDawn.DLL and RedAlert.dll and corresponding source code is distributed 
     10 // in the hope that it will be useful, but with permitted additional restrictions 
     11 // under Section 7 of the GPL. See the GNU General Public License in LICENSE.TXT 
     12 // distributed with this program. You should have received a copy of the 
     13 // GNU General Public License along with permitted additional restrictions 
     14 // with this program. If not, see https://github.com/electronicarts/CnC_Remastered_Collection
     15 
     16 /* $Header:   F:\projects\c&c\vcs\code\profile.cpv   2.18   16 Oct 1995 16:51:14   JOE_BOSTIC  $ */
     17 /***********************************************************************************************
     18  ***             C O N F I D E N T I A L  ---  W E S T W O O D   S T U D I O S               ***
     19  ***********************************************************************************************
     20  *                                                                                             *
     21  *                 Project Name : Command & Conquer                                            *
     22  *                                                                                             *
     23  *                    File Name : PROFILE.CPP                                                  *
     24  *                                                                                             *
     25  *                   Programmer : Joe L. Bostic                                                *
     26  *                                                                                             *
     27  *                   Start Date : September 10, 1993                                           *
     28  *                                                                                             *
     29  *                  Last Update : September 10, 1993   [JLB]                                   *
     30  *                                                                                             *
     31  *---------------------------------------------------------------------------------------------*
     32  * Functions:                                                                                  *
     33  *   WWGetPrivateProfileInt -- Fetches integer value from INI.                                   *
     34  *   WWWritePrivateProfileInt -- Write a profile int to the profile data block.                  *
     35  *   WWGetPrivateProfileString -- Fetch string from INI.                                         *
     36  *   WWWritePrivateProfileString -- Write a string to the profile data block.                    *
     37  * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
     38 
     39 #include	"function.h"
     40 
     41 
     42 /***************************************************************************
     43  * Read_Private_Config_Struct -- Fetches override integer value.           *
     44  *                                                                         *
     45  * INPUT:                                                                  *
     46  * OUTPUT:                                                                 *
     47  * WARNINGS:                                                               *
     48  * HISTORY:                                                                *
     49  *   08/05/1992 JLB : Created.                                             *
     50  *=========================================================================*/
     51 bool Read_Private_Config_Struct (char *profile, NewConfigType *config)
     52 {
     53 	config->DigitCard 	= WWGetPrivateProfileHex ("Sound", "Card", 			 profile);
     54 	config->IRQ 			= WWGetPrivateProfileInt ("Sound", "IRQ", 			 0,profile);
     55 	config->DMA 			= WWGetPrivateProfileInt ("Sound", "DMA", 			 0,profile);
     56 	config->Port 			= WWGetPrivateProfileHex ("Sound", "Port", 			 profile);
     57 	config->BitsPerSample= WWGetPrivateProfileInt ("Sound", "BitsPerSample",0,profile);
     58 	config->Channels 		= WWGetPrivateProfileInt ("Sound", "Channels",		 0,profile);
     59 	config->Reverse      = WWGetPrivateProfileInt ("Sound", "Reverse", 		 0,profile);
     60 	config->Speed        = WWGetPrivateProfileInt ("Sound", "Speed", 		 0,profile);
     61 	WWGetPrivateProfileString ("Language", "Language", NULL, config->Language, 3, profile);
     62 
     63 	return((config->DigitCard == 0) && (config->IRQ == 0) && (config->DMA == 0));
     64 }
     65 
     66 
     67 /***************************************************************************
     68  * Get_Private_Profile_Hex -- Fetches override integer value.              *
     69  *                                                                         *
     70  * INPUT:                                                                  *
     71  * OUTPUT:                                                                 *
     72  * WARNINGS:                                                               *
     73  * HISTORY:                                                                *
     74  *   08/05/1992 JLB : Created.                                             *
     75  *=========================================================================*/
     76 unsigned WWGetPrivateProfileHex (char const *section, char const *entry, char *profile)
     77 {
     78 	// This buffer was overrun at the end due to the forced termination at MAX_ENTRY_SIZE below
     79 	char	buffer[MAX_ENTRY_SIZE + 1];					// Integer staging buffer.
     80 	unsigned card;
     81 
     82 	memset (buffer, '0', MAX_ENTRY_SIZE);		// MAX_ENTRY_SIZE = 15
     83 	buffer[MAX_ENTRY_SIZE] = '\0';
     84 
     85 	WWGetPrivateProfileString(section, entry, "0", buffer, MAX_ENTRY_SIZE, profile);
     86 
     87 	if (strlen (buffer) > 0) {
     88 		sscanf (buffer, "%x", &card);
     89 	} else {
     90 		card = 0;
     91 	}
     92 
     93 	return(card);
     94 }
     95 
     96 
     97 /***********************************************************************************************
     98  * WWGetPrivateProfileInt -- Fetches integer value.                                              *
     99  *                                                                                             *
    100  * INPUT:                                                                                      *
    101  *      section      section to read from                                                      *
    102  *                                                                                             *
    103  *      entry         name of entry to read                                                    *
    104  *                                                                                             *
    105  *      def         default value, if entry isn't found                                        *
    106  *                                                                                             *
    107  *      profile      buffer containing INI data                                                *
    108  *                                                                                             *
    109  * OUTPUT:                                                                                     *
    110  *      integer requested                                                                      *
    111  *                                                                                             *
    112  * WARNINGS:                                                                                   *
    113  *      none.                                                                                  *
    114  *                                                                                             *
    115  * HISTORY:                                                                                    *
    116  *   08/05/1992 JLB : Created.                                                                 *
    117  *=============================================================================================*/
    118 int WWGetPrivateProfileInt(char const *section, char const *entry, int def, char *profile)
    119 {
    120 	char	buffer[16];			// Integer staging buffer.
    121 
    122 	/*
    123 	**	Store the default in the buffer.
    124 	*/
    125 	sprintf(buffer, "%d", def);
    126 
    127 	/*
    128 	**	Get the buffer; use itself as the default.
    129 	*/
    130 	WWGetPrivateProfileString(section, entry, buffer, buffer, 15, profile);
    131 
    132 	/*
    133 	**	Convert to int & return.
    134 	*/
    135 	return(atoi(buffer));
    136 }
    137 
    138 
    139 /***********************************************************************************************
    140  * WWWritePrivateProfileInt -- Write a profile int to the profile data block.                    *
    141  *                                                                                             *
    142  * INPUT:                                                                                      *
    143  *      section      section name to write to                                                  *
    144  *                                                                                             *
    145  *      entry         name of entry to write; if NULL, the entire section is deleted           *
    146  *                                                                                             *
    147  *      value         value to write                                                           *
    148  *                                                                                             *
    149  *      profile      INI buffer                                                                *
    150  *                                                                                             *
    151  * OUTPUT:                                                                                     *
    152  *      true = success, false = failure                                                        *
    153  *                                                                                             *
    154  * WARNINGS:                                                                                   *
    155  *      none.                                                                                  *
    156  *                                                                                             *
    157  * HISTORY:                                                                                    *
    158  *   10/07/1992 JLB : Created.                                                                 *
    159  *=============================================================================================*/
    160 bool WWWritePrivateProfileInt(char const *section, char const *entry, int value, char *profile)
    161 {
    162 	char	buffer[250];			// Working section buffer.
    163 
    164 	/*
    165 	**	Just return if nothing to do.
    166 	*/
    167 	if (!profile || !section) {
    168 		return(true);
    169 	}
    170 
    171 	/*
    172 	**	Generate string to save.
    173 	*/
    174 	sprintf(buffer, "%d", value);
    175 
    176 	/*
    177 	**	Save the string.
    178 	*/
    179 	return(WWWritePrivateProfileString(section, entry, buffer, profile));
    180 }
    181 
    182 
    183 /***********************************************************************************************
    184  * WWGetPrivateProfileString -- Fetch game override string.                                      *
    185  *                                                                                             *
    186  * INPUT:                                                                                      *
    187  *      section      section name to read from                                                 *
    188  *                                                                                             *
    189  *      entry         name of entry to read; if NULL, all entry names are returned             *
    190  *                                                                                             *
    191  *      def         default string to use if not found; can be NULL                            *
    192  *                                                                                             *
    193  *      retbuffer   buffer to store result in                                                  *
    194  *                                                                                             *
    195  *      retlen      max length of return buffer                                                *
    196  *                                                                                             *
    197  *      profile      INI buffer                                                                *
    198  *                                                                                             *
    199  * OUTPUT:                                                                                     *
    200  *      ptr to entry found in INI buf; NULL if not found                                       *
    201  *                                                                                             *
    202  * WARNINGS:                                                                                   *
    203  *      On the PC, the "\n" (10) is translated to "\r\n" (13,10) when it's written             *
    204  *      to disk. This routine must take this into consideration, by searching                  *
    205  *      for \n when scanning backward, and for \r when scanning forward.                       *
    206  *                                                                                             *
    207  * HISTORY:                                                                                    *
    208  *   08/05/1992 JLB : Created.                                                                 *
    209  *=============================================================================================*/
    210 char * WWGetPrivateProfileString(char const *section, char const *entry, char const *def, char *retbuffer, int retlen, char *profile)
    211 {
    212 	char	* workptr,		// Working pointer into profile block.
    213 			* altworkptr;	// Alternate work pointer.
    214 	char	sec[50];			// Working section buffer.
    215 	char	*retval;			// Start of section or entry pointer.
    216 	char	* next;			// Pointer to start of next section (or EOF).
    217 	char	c,c2;				// Working character values.
    218 	int	len;				// Working substring length value.
    219 	int	entrylen;		// Byte length of specified entry.
    220 	char *orig_retbuf;	// original retbuffer ptr
    221 
    222 	/*
    223 	**	Fill in the default value just in case the entry could not be found.
    224 	*/
    225 	if (retbuffer) {
    226 		if (def) {
    227 			strncpy(retbuffer, def, retlen);
    228 		}
    229 		retbuffer[retlen-1] = '\0';
    230 		orig_retbuf = retbuffer;
    231 	}
    232 
    233 	/*
    234 	**	Make sure a profile string was passed in
    235 	*/
    236 	if (!profile || !section) {
    237 		return(retbuffer);
    238 	}
    239 
    240 	/*
    241 	**	Build section string to match file image.
    242 	*/
    243 	sprintf(sec, "[%s]", section);	// sec = section name including []'s
    244 	strupr(sec);
    245 	len = strlen(sec);					// len = section name length, incl []'s
    246 
    247 	/*
    248 	**	Scan for a matching section
    249 	*/
    250 	retval = profile;
    251 	workptr = profile;
    252 	for (;;) {
    253 
    254 		/*
    255 		**	'workptr' = start of next section
    256 		*/
    257 		workptr = strchr(workptr, '[');
    258 
    259 		/*
    260 		**	If the end has been reached without finding the desired section
    261 		**	then abort with a failure flag.
    262 		*/
    263 		if (!workptr) {
    264 			return(NULL);
    265 		}
    266 
    267 		/*
    268 		**	'c' = character just before the '['
    269 		*/
    270 		if (workptr==profile) {
    271 			c = '\n';
    272 		} else {
    273 			c = *(workptr-1);
    274 		}
    275 
    276 		/*
    277 		**	If this is the section name & the character before is a newline,
    278 		**	process this section
    279 		*/
    280 		if (memicmp(workptr, sec, len) == 0 && (c == '\n')) {
    281 
    282 			/*
    283 			**	Skip work pointer to start of first valid entry.
    284 			*/
    285 			workptr += len;
    286 			while (isspace(*workptr)) {
    287 				workptr++;
    288 			}
    289 
    290 			/*
    291 			**	If the section name is empty, we will have stepped onto the start
    292 			**	of the next section name; inserting new entries here will leave
    293 			**	a blank line between this section's name & 1st entry. So, check
    294 			**	for 2 newlines in a row & step backward.
    295 			*/
    296 			if (workptr - profile > 4) {
    297 				if ( *(workptr-1)=='\n' && *(workptr-3)=='\n')
    298 					workptr -= 2;
    299 			}
    300 
    301 			/*
    302 			**	'next = end of section or end of file.
    303 			*/
    304 			next = strchr(workptr, '[');
    305 			for (;;) {
    306 				if (next) {
    307 
    308 					c = *(next-1);
    309 
    310 					/*
    311 					**	If character before '[' is newline, this is the start of the
    312 					**	next section
    313 					*/
    314 					if (c == '\n') {
    315 						if (*(next-1)=='\n' && *(next-3)=='\n') {
    316 							next -= 2;
    317 						}
    318 						break;
    319 					}
    320 
    321 					/*
    322 					**	This bracket was in the section; keep looking
    323 					*/
    324 					next = strchr(next+1, '[');
    325 				} else {
    326 
    327 					/*
    328 					**	No bracket found; set 'next' to the end of the file
    329 					*/
    330 					next = workptr + strlen(workptr)-1;
    331 					break;
    332 				}
    333 			}
    334 
    335 			/*
    336 			**	If a specific entry was specified then return with the associated
    337 			**	string.
    338 			*/
    339 			if (entry) {
    340 				retval = workptr;
    341 				entrylen = strlen(entry);
    342 
    343 				for (;;) {
    344 					/*
    345 					** Search for the 1st character of the entry
    346 					*/
    347 					workptr = strchr(workptr, *entry);
    348 
    349 					/*
    350 					**	If the end of the file has been reached or we have spilled
    351 					**	into the next section, then abort
    352 					*/
    353 					if (!workptr || workptr >= next) {
    354 						return(NULL);
    355 					}
    356 
    357 					/*
    358 					**	'c' = character before possible entry; must be a newline
    359 					**	'c2' = character after possible entry; must be '=' or space
    360 					*/
    361 					c = *(workptr-1);
    362 					c2 = *(workptr+entrylen);
    363 
    364 					/*
    365 					**	Entry found; extract it
    366 					*/
    367 					if (memicmp(workptr, entry, entrylen) == 0 && (c == '\n') &&
    368 						(c2 == '=' || isspace(c2))) {
    369 						retval = workptr;
    370 						workptr += entrylen;							// skip entry name
    371 						workptr = strchr(workptr, '=');			// find '='
    372 
    373 						/*
    374 						** 'altworkptr' = next newline; \r is used here since we're
    375 						** scanning forward!
    376 						*/
    377 						if (workptr) {
    378 							altworkptr = strchr(workptr, '\r');	// find next newline
    379 						}
    380 
    381 						/*
    382 						**	Return if there was no '=', or if the newline is before
    383 						**	the next '='
    384 						*/
    385 						if (workptr == NULL || altworkptr < workptr) {
    386 							return(retval);
    387 						}
    388 
    389 						/*
    390 						**	Skip any white space after the '=' and before the first
    391 						**	valid character of the parameter.
    392 						*/
    393 						workptr++;										// Skip the '='.
    394 						while (isspace(*workptr)) {
    395 
    396 							/*
    397 							**	Just return if there's no entry past the '='.
    398 							*/
    399 							if (workptr >= altworkptr)
    400 								return(retval);
    401 
    402 							workptr++;									// Skip the whitespace
    403 						}
    404 
    405 						/*
    406 						**	Copy the entry into the return buffer.
    407 						*/
    408 						len = (int)(altworkptr - workptr);
    409 						if (len > retlen-1) {
    410 							len = retlen-1;
    411 						}
    412 
    413 						if (retbuffer) {
    414 							memcpy(retbuffer, workptr, len);
    415 							*(retbuffer + len) = '\0';		// Insert trailing null.
    416 							strtrim(retbuffer);
    417 						}
    418 						return(retval);
    419 					}
    420 
    421 					/*
    422 					**	Entry was not found; go to the next one
    423 					*/
    424 					workptr++;
    425 				}
    426 			} else {
    427 
    428 				/*
    429 				**	No entry was specified, so build a list of all entries.
    430 				**	'workptr' is at 1st entry after section name
    431 				**	'next' is next bracket, or end of file
    432 				*/
    433 				retval = workptr;
    434 
    435 				if (retbuffer) {
    436 
    437 					/*
    438 					**	Keep accumulating the identifier strings in the retbuffer.
    439 					*/
    440 					while (workptr && workptr < next) {
    441 						altworkptr = strchr(workptr, '=');		// find '='
    442 
    443 						if (altworkptr && altworkptr < next) {
    444 							int	length;								// Length of ID string.
    445 
    446 							length = (int)(altworkptr - workptr);
    447 
    448 							/*
    449 							**	Make sure we don't write past the end of the retbuffer;
    450 							**	add '3' for the 3 NULL's at the end
    451 							*/
    452 							if (retbuffer - orig_retbuf + length + 3 < retlen) {
    453 								memcpy(retbuffer, workptr, length);	// copy entry name
    454 								*(retbuffer+length) = '\0';			// NULL-terminate it
    455 								strtrim(retbuffer);						// trim spaces
    456 								retbuffer += strlen(retbuffer)+1;	// next pos in dest buf
    457 							} else {
    458 								break;
    459 							}
    460 
    461 							/*
    462 							**	Advance the work pointer to the start of the next line
    463 							**	by skipping the end of line character.
    464 							*/
    465 							workptr = strchr(altworkptr, '\n');
    466 							if (!workptr) {
    467 								break;
    468 							}
    469 							workptr++;
    470 						} else {
    471 
    472 							/*
    473 							**	If no '=', break out of loop
    474 							*/
    475 							break;
    476 						}
    477 					}
    478 
    479 					/*
    480 					**	Final trailing terminator. Make double sure the double
    481 					**	trailing null is added.
    482 					*/
    483 					*retbuffer++ = '\0';
    484 					*retbuffer++ = '\0';
    485 				}
    486 				break;
    487 			}
    488 		} else {
    489 
    490 			/*
    491 			**	Section name not found; go to the next bracket & try again
    492 			**	Advance past '[' and keep scanning.
    493 			*/
    494 			workptr++;
    495 		}
    496 	}
    497 
    498 	return(retval);
    499 }
    500 
    501 
    502 /***********************************************************************************************
    503  * WWWritePrivateProfileString -- Write a string to the profile data block.                      *
    504  *                                                                                             *
    505  * INPUT:                                                                                      *
    506  *      section      section name to write to                                                  *
    507  *      entry         name of entry to write; if NULL, the section is deleted                  *
    508  *      string      string to write; if NULL, the entry is deleted                             *
    509  *      profile      INI buffer                                                                *
    510  *                                                                                             *
    511  * OUTPUT:                                                                                     *
    512  *      true = success, false = failure                                                        *
    513  *                                                                                             *
    514  * WARNINGS:                                                                                   *
    515  *      This function has to translate newlines into \r\n sequences.                           *
    516  *                                                                                             *
    517  * HISTORY:                                                                                    *
    518  *   10/07/1992 JLB : Created.                                                                 *
    519  *=============================================================================================*/
    520 bool WWWritePrivateProfileString(char const *section, char const *entry, char const *string, char *profile)
    521 {
    522 	char	buffer[250];			// Working section buffer
    523 	char	*offset;
    524 	char *next;						// ptr to next section
    525 	char	c;							// Working character value
    526 
    527 	/*
    528 	**	Just return if nothing to do.
    529 	*/
    530 	if (!profile || !section) {
    531 		return(true);
    532 	}
    533 
    534 	/*
    535 	**	Try to find the section. WWGetPrivateProfileString with NULL entry name
    536 	**	will return all entry names in the given buffer, truncated to the given
    537 	**	buffer length. 'offset' will point to 1st entry in the section, NULL if
    538 	**	section not found.
    539 	*/
    540 	offset = WWGetPrivateProfileString(section, NULL, NULL, NULL, 0, profile);
    541 
    542 	/*
    543 	**	If the section could not be found, then add it to the end. Don't add
    544 	**	anything if a removal of an entry is requested (it is obviously already
    545 	**	non-existent). Make sure two newlines precede the section name.
    546 	*/
    547 	if (!offset && entry) {
    548 		sprintf(buffer, "\r\n[%s]\r\n", section);
    549 		strcat(profile, buffer);
    550 	}
    551 
    552 	/*
    553 	**	If the section is there and 'entry' is NULL, remove the entire section
    554 	*/
    555 	if (offset && !entry) {
    556 
    557 		/*
    558 		**	'next = end of section or end of file.
    559 		*/
    560 		next = strchr(offset, '[');
    561 		for (;;) {
    562 			if (next) {
    563 				c = *(next-1);
    564 
    565 				/*
    566 				**	If character before '[' is newline, this is the start of the
    567 				**	next section
    568 				*/
    569 				if (c == '\n') {
    570 					if ( *(next-1)=='\n' && *(next-3)=='\n') {
    571 						next -= 2;
    572 					}
    573 					break;
    574 				}
    575 
    576 				/*
    577 				**	This bracket was in the section; keep looking
    578 				*/
    579 				next = strchr(next+1, '[');
    580 			} else {
    581 
    582 				/*
    583 				**	No bracket found; set 'next' to the end of the file
    584 				*/
    585 				next = offset + strlen(offset);
    586 				break;
    587 			}
    588 		}
    589 
    590 		/*
    591 		**	Remove the section
    592 		*/
    593 		strcpy(offset,next);
    594 
    595 		return(true);
    596 	}
    597 
    598 	/*
    599 	**	Find the matching entry within the desired section. A NULL return buffer
    600 	**	with 0 length will just return the offset of the found entry, NULL if
    601 	**	entry not found.
    602 	*/
    603 	offset = WWGetPrivateProfileString(section, entry, NULL, NULL, 0, profile);
    604 
    605 	/*
    606 	**	Remove any existing entry
    607 	*/
    608 	if (offset) {
    609 		int	eol;			// Working EOL offset.
    610 
    611 		/*
    612 		**	Get # characters up to newline; \n is used since we're after the end
    613 		**	of this line
    614 		*/
    615 		eol = strcspn(offset, "\n");
    616 
    617 		/*
    618 		**	Erase the entry by strcpy'ing the entire INI file over this entry
    619 		*/
    620 		if (eol) {
    621 			strcpy(offset, offset + eol + 1);
    622 		}
    623 	} else {
    624 
    625 		/*
    626 		**	Entry doesn't exist, so point 'offset' to the 1st entry position in
    627 		**	the section.
    628 		*/
    629 		offset = WWGetPrivateProfileString(section, NULL, NULL, NULL, 0, profile);
    630 	}
    631 
    632 	/*
    633 	**	Add the desired entry.
    634 	*/
    635 	if (entry && string) {
    636 
    637 		/*
    638 		**	Generate entry string.
    639 		*/
    640 		sprintf(buffer, "%s=%s\r\n", entry, string);
    641 
    642 		/*
    643 		**	Make room for new entry.
    644 		*/
    645 		memmove(offset+strlen(buffer), offset, strlen(offset)+1);
    646 
    647 		/*
    648 		**	Copy the entry into the INI buffer.
    649 		*/
    650 		memcpy(offset, buffer, strlen(buffer));
    651 	}
    652 
    653 	return(true);
    654 }