Blame MakeTools/patch_version/patch_version.c

Packit 857059
/*!
Packit 857059
 @file    $Source: /cvs/ics/MakeTools/patch_version/patch_version.c,v $
Packit 857059
 $Name:  $
Packit 857059
 $Revision: 1.14 $
Packit 857059
 $Date: 2015/01/22 18:03:59 $
Packit 857059
 @brief   Utility to manage version and branding strings in executable code
Packit 857059
 */
Packit 857059
/* BEGIN_ICS_COPYRIGHT7 ****************************************
Packit 857059
Packit 857059
Copyright (c) 2015-2017, Intel Corporation
Packit 857059
Packit 857059
Redistribution and use in source and binary forms, with or without
Packit 857059
modification, are permitted provided that the following conditions are met:
Packit 857059
Packit 857059
    * Redistributions of source code must retain the above copyright notice,
Packit 857059
      this list of conditions and the following disclaimer.
Packit 857059
    * Redistributions in binary form must reproduce the above copyright
Packit 857059
      notice, this list of conditions and the following disclaimer in the
Packit 857059
      documentation and/or other materials provided with the distribution.
Packit 857059
    * Neither the name of Intel Corporation nor the names of its contributors
Packit 857059
      may be used to endorse or promote products derived from this software
Packit 857059
      without specific prior written permission.
Packit 857059
Packit 857059
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
Packit 857059
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
Packit 857059
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
Packit 857059
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
Packit 857059
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
Packit 857059
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
Packit 857059
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
Packit 857059
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
Packit 857059
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
Packit 857059
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Packit 857059
Packit 857059
 * ** END_ICS_COPYRIGHT7   ****************************************/
Packit 857059
/* [ICS VERSION STRING: unknown] */
Packit 857059
Packit 857059
/*!
Packit 857059
This program can be invoked in 2 ways:
Packit 857059
Packit 857059
When invoked as patch_version, this program has 2 main uses:
Packit 857059
In its simplest form, it can take a tag number of the form: R#_#M#P#I#
Packit 857059
and convert it to #.#.#.# format (it does allow for alpha and beta
Packit 857059
release of the form: R#_#A#I# and R#_#B#I#, they get converted to
Packit 857059
#.#A# or #.#B#).
Packit 857059
Packit 857059
In addition, if given an executable, compiled program with an embedded
Packit 857059
version string, it can alter the embedded version string.  This can be
Packit 857059
useful to change version strings after the build, especially when the
Packit 857059
decisions for the final version # are changing, and/or the product takes
Packit 857059
a long amount of time to compile.  
Packit 857059
Packit 857059
When invoked as patch_brand, this program has a simple purpose:
Packit 857059
Packit 857059
In its simplest form it can take a brand (or an empty string) as its argument
Packit 857059
and it will report on stdout the brand which will be used (and will verify the
Packit 857059
brand's length).  This can be useful to obtain the default brand.
Packit 857059
Packit 857059
In addition, if given an executable, compiled program with an embedded
Packit 857059
brand string, it can alter the embedded brand string.  This can be
Packit 857059
useful to change brand strings after the build, especially when the
Packit 857059
decisions for the final brand are changing (or to brand for multiple customers),
Packit 857059
and/or the product takes a long amount of time to compile.  
Packit 857059
Packit 857059
@heading Usage
Packit 857059
	patch_version release_tag [file ...]
Packit 857059
	patch_brand brand [file ...]
Packit 857059
Packit 857059
@param release_tag - version tag of the form R#_#M#P#I# or R#_#A#I# or R#_#B#I#
Packit 857059
@param brand - a branding string such as "Intel"
Packit 857059
@param file - object/exe file(s) to place the #.#.#.# style version string in
Packit 857059
		If no files are specified, the program merely
Packit 857059
		performs the simpler behaviour of outputing the #.#.#.#
Packit 857059
		style version string.
Packit 857059
Packit 857059
@example
Packit 857059
	The version string and brand in programs to be patched
Packit 857059
	should be coded as follows:
Packit 857059
Packit 857059
	// GetCodeVersion
Packit 857059
	// -----------------
Packit 857059
	// GetCodeVersion - retrieve the code version as set by build process.
Packit 857059
	// The static string contained in this function will be changed
Packit 857059
	// by patch_version after the build is complete and the string
Packit 857059
	// has been compiled into the application.  This string will be
Packit 857059
	// modified as necessary to set the version number to match that of
Packit 857059
	// the build cycle.  This routine extracts the version number from
Packit 857059
	// the string and returns it.
Packit 857059
	// It accepts no arguments and returns NULL if the string cannot
Packit 857059
	// be evaluated.
Packit 857059
	// The version number created can also be extracted by the strings command
Packit 857059
	// or the internal whatversion tool
Packit 857059
	//
Packit 857059
	#define ICS_BUILD_VERSION "THIS_IS_THE_ICS_VERSION_NUMBER:@(#)000.000.000.000B000"
Packit 857059
	const char* GetCodeVersion(void)
Packit 857059
	{
Packit 857059
		static const char* BuildVersion=ICS_BUILD_VERSION;
Packit 857059
		static char* version;
Packit 857059
		static int built=0;
Packit 857059
		if (!built)
Packit 857059
		{
Packit 857059
			// locate start of version string,
Packit 857059
			// its the first digit in BuildVersion
Packit 857059
			version = strpbrk(BuildVersion, "0123456789");
Packit 857059
			built=1;
Packit 857059
		}
Packit 857059
		return(version);
Packit 857059
	}
Packit 857059
Packit 857059
	#define ICS_BUILD_BRAND "THIS_IS_THE_ICS_BRAND:Intel\000                    "
Packit 857059
	const char* GetCodeBrand(void)
Packit 857059
	{
Packit 857059
		static const char* BuildBrand=ICS_BUILD_BRAND;
Packit 857059
		static char* brand;
Packit 857059
		static int built=0;
Packit 857059
		if (!built)
Packit 857059
		{
Packit 857059
			// locate start of brand string,
Packit 857059
			// its the first : in BuildBrand
Packit 857059
			brand = strpbrk(BuildBrand, ":")+1;
Packit 857059
			built=1;
Packit 857059
		}
Packit 857059
		return(brand);
Packit 857059
	}
Packit 857059
Packit 857059
	Then use the brand and version string as follows:
Packit 857059
		printf("%s XYZ version %s\n", GetCodeBrand(), GetCodeVersion());
Packit 857059
Packit 857059
	The version strings can actually be more flexibly specified than
Packit 857059
	outlined above.
Packit 857059
Packit 857059
@see UiUtil::GetCodeVersion();
Packit 857059
@see UiUtil::GetCodeBrand();
Packit 857059
*/
Packit 857059
Packit 857059
#include <stdio.h>
Packit 857059
#include <stdlib.h>
Packit 857059
#include <string.h>
Packit 857059
#include <ctype.h>
Packit 857059
#include <errno.h>
Packit 857059
#include <getopt.h>
Packit 857059
Packit 857059
#define ICS_BUILD_VERSION "THIS_IS_THE_ICS_VERSION_NUMBER:@(#)000.000.000.000B000"
Packit 857059
#define ICS_BUILD_INTERNAL_VERSION "THIS_IS_THE_ICS_INTERNAL_VERSION_NUMBER:@(#)000.000.000.000B000I0000"
Packit 857059
#define ICS_BUILD_BRAND "THIS_IS_THE_ICS_BRAND:Intel\000           "
Packit 857059
#define DEFAULT_BRAND "Intel"
Packit 857059
Packit 857059
typedef enum { B_FALSE=0, B_TRUE } boolean;
Packit 857059
Packit 857059
#define BUFFER_SIZE 8192
Packit 857059
Packit 857059
typedef enum {
Packit 857059
	NO_ERROR=0,		/* Program terminated normally */
Packit 857059
	INTERNAL_ERROR,	/* Error occurred in processing */
Packit 857059
	USAGE_ERROR		/* Improper commandline arguments */
Packit 857059
} ApplicationExitcode;
Packit 857059
Packit 857059
/*!
Packit 857059
display a usage message to the user if the incorrect
Packit 857059
set of arguments is passed to the application.
Packit 857059
*/
Packit 857059
void Usage(const char *program_name)
Packit 857059
{
Packit 857059
	fprintf(stderr,"\nUsage:     %s [-i][-m marker][-n version] release_tag [file ...]\n",program_name);
Packit 857059
	exit(USAGE_ERROR);
Packit 857059
}
Packit 857059
void UsageBrand(const char *program_name)
Packit 857059
{
Packit 857059
	fprintf(stderr,"\nUsage:     %s [-m marker] brand [file ...]\n",program_name);
Packit 857059
	exit(USAGE_ERROR);
Packit 857059
}
Packit 857059
Packit 857059
/*!
Packit 857059
parse the command line argument for the release tag into the external version
Packit 857059
numbers.
Packit 857059
Packit 857059
The following transformations on the release tag are done:
Packit 857059
	- All non-digits up to the 1st digit are dropped
Packit 857059
	- _ is changed to .
Packit 857059
	- M is changed to .
Packit 857059
	- P is changed to .
Packit 857059
	- I and all characters after it are dropped if the -i option is used
Packit 857059
Packit 857059
Note to properly conform to the release numbering scheme
Packit 857059
Tags must include an M level if they include a P level.
Packit 857059
To work properly with this and other programs, the 1st character
Packit 857059
in the resulting version # must be a digit (0-9).  Hence when
Packit 857059
using code names as the temporary version string during
Packit 857059
development they should be started with a digit.  For example:
Packit 857059
	R0capemay
Packit 857059
will result in a version number of 0capemay
Packit 857059
Packit 857059
This would be the typical way to build releases for a product
Packit 857059
with a code name of "capemay".
Packit 857059
Packit 857059
For Example:
Packit 857059
	release_tag	Version String
Packit 857059
	R1_0I5		1.0
Packit 857059
	R1_0M1I2	1.0.1
Packit 857059
	R1_0B1I2	1.0B1
Packit 857059
	R1_0M1A1I3	1.0.1A1
Packit 857059
	R1_0M0P4I5	1.0.0.4
Packit 857059
	R1_0B1P4	1.0B1.4
Packit 857059
	R0capemayI7	0capemay
Packit 857059
	R0capemayP4I1	0capemay.4
Packit 857059
	ICS_R2_0I5	2.0
Packit 857059
Packit 857059
@param string the string to be parsed.
Packit 857059
@param dropI should I level be omitted
Packit 857059
Packit 857059
@return pointer to a static string containing the constructed version string.
Packit 857059
Packit 857059
@heading Special Cases and Error Handling
Packit 857059
	prints an error message and returns NULL on failure.
Packit 857059
*/
Packit 857059
const char* ParseReleaseTag(const char* string, int dropI)
Packit 857059
{
Packit 857059
	static char version[100];
Packit 857059
	const char* p;
Packit 857059
	char* q;
Packit 857059
	int done;
Packit 857059
	int processedM = 0;
Packit 857059
	int processedP = 0;
Packit 857059
Packit 857059
	if (! string || ! *string)
Packit 857059
	{
Packit 857059
		fprintf(stderr,"\nInvalid release tag format, empty string\n");
Packit 857059
		return(NULL);
Packit 857059
	}
Packit 857059
	for (p=string; *p && ! isdigit(*p); p++)
Packit 857059
		;
Packit 857059
	for (done=0, q=version; ! done && *p; p++)
Packit 857059
	{
Packit 857059
		switch (*p)
Packit 857059
		{
Packit 857059
			case 'I':
Packit 857059
				/* I starts the trailer for the release tag, it is not placed
Packit 857059
				 * in the version string
Packit 857059
			 	 */
Packit 857059
				if (dropI)
Packit 857059
					done=1;
Packit 857059
				else
Packit 857059
				{
Packit 857059
					/* replaced with a . */
Packit 857059
Packit 857059
					/* if no M tag was processed, must insert a zero placeholder */
Packit 857059
					if (!processedM)
Packit 857059
					{
Packit 857059
						*q++ = '.';
Packit 857059
						*q++ = '0';
Packit 857059
					}
Packit 857059
					/* if no P tag was processed, must insert a zero placeholder */
Packit 857059
					if (!processedP)
Packit 857059
					{
Packit 857059
						*q++ = '.';
Packit 857059
						*q++ = '0';
Packit 857059
					}
Packit 857059
					*q++ = '.';
Packit 857059
				}
Packit 857059
				break;
Packit 857059
			case '_':
Packit 857059
				/* replaced with a . */
Packit 857059
				*q++ = '.';
Packit 857059
				break;
Packit 857059
			case 'M':
Packit 857059
				/* replaced with a . */
Packit 857059
				*q++ = '.';
Packit 857059
				processedM = 1;
Packit 857059
				break;
Packit 857059
			case 'P':
Packit 857059
				/* replaced with a . */
Packit 857059
				/* if no M tag was processed, must insert a zero placeholder */
Packit 857059
				if (!processedM)
Packit 857059
				{
Packit 857059
					*q++ = '.';
Packit 857059
					*q++ = '0';
Packit 857059
					processedM = 1;
Packit 857059
				}
Packit 857059
				*q++ = '.';
Packit 857059
				processedP = 1;
Packit 857059
				break;
Packit 857059
			default:
Packit 857059
				*q++ = *p;
Packit 857059
				break;
Packit 857059
		}
Packit 857059
	}
Packit 857059
	/* version strings must start with a digit */
Packit 857059
	if (*version < '0' || *version > '9')
Packit 857059
	{
Packit 857059
		fprintf(stderr,"\nInvalid release tag format yields: %s\n", version);
Packit 857059
		return(NULL);
Packit 857059
	}
Packit 857059
	return(version);
Packit 857059
}
Packit 857059
Packit 857059
/*!
Packit 857059
append a marker character to the string
Packit 857059
Packit 857059
@param string - string to add marker to
Packit 857059
@param marker - marker character to add
Packit 857059
Packit 857059
@return new string
Packit 857059
Packit 857059
@heading Special Cases and Error Handling
Packit 857059
*/
Packit 857059
char* append_marker(const char* string, char marker)
Packit 857059
{
Packit 857059
	char *result;
Packit 857059
Packit 857059
	result = malloc(strlen(string)+2);
Packit 857059
	if (result) {
Packit 857059
		strcpy(result, string);
Packit 857059
		if (marker)
Packit 857059
			strncat(result, &marker, 1);
Packit 857059
	}
Packit 857059
	return result;
Packit 857059
}
Packit 857059
Packit 857059
/*!
Packit 857059
build the pattern string to search for and verifies the
Packit 857059
version string will fit within the patch area
Packit 857059
Packit 857059
@param version - version string intended to be placed into file
Packit 857059
Packit 857059
@return pattern to search for
Packit 857059
Packit 857059
@heading Special Cases and Error Handling
Packit 857059
	if version is larger than space alloted in Pattern, outputs error and
Packit 857059
	returns NULL
Packit 857059
*/
Packit 857059
const char* BuildPattern(char* dest, const char* pattern, const char* version)
Packit 857059
{
Packit 857059
	int length;
Packit 857059
Packit 857059
	strcpy(dest, pattern);
Packit 857059
	/* determine length of pattern itself */
Packit 857059
	length = strcspn(dest, "0123456789");
Packit 857059
	/* confirm the version can be used to overwrite the rest of the
Packit 857059
	 * default version string
Packit 857059
	 */
Packit 857059
	if (strlen(dest) - length < strlen(version))
Packit 857059
	{
Packit 857059
		fprintf(stderr,"\nInvalid release tag format, too long, yields: %s\n", version);
Packit 857059
		return(NULL); /* won't fit */
Packit 857059
	}
Packit 857059
Packit 857059
	dest[length] = '\0';
Packit 857059
	return(dest);
Packit 857059
}
Packit 857059
Packit 857059
/*!
Packit 857059
build the pattern string to search for and verifies the
Packit 857059
brand string will fit within the patch area
Packit 857059
Packit 857059
@param brand - brand string intended to be placed into file
Packit 857059
Packit 857059
@return pattern to search for
Packit 857059
Packit 857059
@heading Special Cases and Error Handling
Packit 857059
	if brand is larger than space alloted in Pattern, outputs error and
Packit 857059
	returns NULL
Packit 857059
*/
Packit 857059
const char* BuildBrandPattern(char* dest, const char* pattern, size_t brand_size, const char* brand)
Packit 857059
{
Packit 857059
	int length;
Packit 857059
Packit 857059
	strcpy(dest, pattern);
Packit 857059
	/* determine length of pattern itself */
Packit 857059
	length = strcspn(dest, ":")+1;
Packit 857059
	/* confirm the brand can be used to overwrite the rest of the
Packit 857059
	 * default brand string
Packit 857059
	 * brand_size includes \0 terminator
Packit 857059
	 */
Packit 857059
	if ((brand_size-1) - length < strlen(brand))
Packit 857059
	{
Packit 857059
		fprintf(stderr,"\nInvalid brand, too long: '%s'\n", brand);
Packit 857059
		return(NULL); /* won't fit */
Packit 857059
	}
Packit 857059
Packit 857059
	dest[length] = '\0';
Packit 857059
	return(dest);
Packit 857059
}
Packit 857059
Packit 857059
/*!
Packit 857059
Patch the File
Packit 857059
Packit 857059
This function does an lseek, hence the position in fp is not important
Packit 857059
when called.  However it will leave fp after the bytes written.
Packit 857059
Packit 857059
@param fp - file to patch.
Packit 857059
@param offset - offset in file to place version
Packit 857059
@param version - version string to write
Packit 857059
@param verlen - strlen(version)+1
Packit 857059
Packit 857059
@return B_TRUE on success, or prints an error message and returns B_FALSE
Packit 857059
	on error.
Packit 857059
*/
Packit 857059
boolean PerformPatch(FILE* fp, long offset, const char* version, size_t verlen)
Packit 857059
{
Packit 857059
	if (fp)
Packit 857059
	{
Packit 857059
		long current=ftell(fp);
Packit 857059
		if (!fseek(fp,offset,SEEK_SET))
Packit 857059
		{
Packit 857059
			if (fwrite(version,sizeof(char),verlen,fp)==verlen)
Packit 857059
			{
Packit 857059
				if (!fseek(fp,current,SEEK_SET))
Packit 857059
				{
Packit 857059
					return(B_TRUE);
Packit 857059
				}
Packit 857059
				fprintf(stderr,"\nRead seek on file (stream) failed\n");
Packit 857059
			} else {
Packit 857059
				fprintf(stderr,"\nWrite of patched data failed\n");
Packit 857059
			}
Packit 857059
		} else {
Packit 857059
			fprintf(stderr,"\nWrite seek on file (stream) failed\n");
Packit 857059
		}
Packit 857059
	}
Packit 857059
	return(B_FALSE);
Packit 857059
}
Packit 857059
Packit 857059
/*!
Packit 857059
Patch the version string into the given filename at the position where pattern
Packit 857059
is found.
Packit 857059
Packit 857059
The function opens the filename specified, searches the file for the
Packit 857059
matching ID string, patches the version number and closes the file.
Packit 857059
Packit 857059
@param filename - file to patch
Packit 857059
@param pattern - search pattern
Packit 857059
@param patlen - strlen(pattern)
Packit 857059
@param version - version string
Packit 857059
@param verlen - strlen(version)+1
Packit 857059
Packit 857059
@return B_TRUE on success, otherwise it prints an error message
Packit 857059
	 and returns B_FALSE.
Packit 857059
*/
Packit 857059
boolean PatchFilename(const char* filename, const char* pattern, int patlen,
Packit 857059
					  const char* version, size_t verlen)
Packit 857059
{
Packit 857059
	FILE* fp = NULL;
Packit 857059
	char buffer[BUFFER_SIZE];
Packit 857059
	char* bufp;
Packit 857059
	char* bufp2;
Packit 857059
	const char* patp;
Packit 857059
	int i;
Packit 857059
	boolean patched=B_FALSE;
Packit 857059
	boolean finished=B_FALSE;
Packit 857059
	if (filename && *filename)
Packit 857059
	{
Packit 857059
		if ((fp=fopen(filename,"r+"))==NULL)
Packit 857059
		{
Packit 857059
			perror(filename);
Packit 857059
			goto patch_error;
Packit 857059
		}
Packit 857059
		while (!finished)
Packit 857059
		{
Packit 857059
			int nbytes=fread(buffer,sizeof(char),BUFFER_SIZE,fp);
Packit 857059
			bufp=buffer;
Packit 857059
			if (!nbytes) /* End of file */
Packit 857059
			{
Packit 857059
				finished=B_TRUE;
Packit 857059
				continue;
Packit 857059
			}
Packit 857059
			if (nbytes<0) /* Error */
Packit 857059
			{
Packit 857059
				fprintf(stderr,"\nPremature EOF: %s\n",filename);
Packit 857059
				goto patch_error;
Packit 857059
			}
Packit 857059
			while ((bufp-buffer)+patlen<=nbytes)
Packit 857059
			{
Packit 857059
			  i = 0;
Packit 857059
			  patp = pattern;
Packit 857059
			  bufp2 = bufp;
Packit 857059
			  while ((*bufp++ == *patp++) && (i < patlen)) i++; 
Packit 857059
Packit 857059
			  if (i == patlen)
Packit 857059
			  {
Packit 857059
				long match_offset=(ftell(fp)-nbytes)+(bufp2-buffer)+patlen;
Packit 857059
				if (!PerformPatch(fp,match_offset,version, verlen)) 
Packit 857059
				{
Packit 857059
				  goto patch_error;
Packit 857059
				}
Packit 857059
				patched=B_TRUE;
Packit 857059
			  }
Packit 857059
Packit 857059
			  bufp = bufp2 + 1;
Packit 857059
			}
Packit 857059
			if (nbytes <= patlen)
Packit 857059
			{
Packit 857059
				/* must have just processed the last part of the file */
Packit 857059
				finished=B_TRUE;
Packit 857059
				continue;
Packit 857059
			}
Packit 857059
			/* go to next buffer, but include patlen bytes from previous
Packit 857059
			 * in case version string crosses a buffer boundary
Packit 857059
			 */
Packit 857059
			if (fseek(fp, -patlen, SEEK_CUR) == -1)
Packit 857059
			{
Packit 857059
				fprintf(stderr,"\nCan't seek: %s\n",filename);
Packit 857059
				goto patch_error;
Packit 857059
			}
Packit 857059
		}
Packit 857059
		fclose(fp);
Packit 857059
		fp = NULL;
Packit 857059
		if (!patched)
Packit 857059
		{
Packit 857059
			fprintf(stderr,"\nVersion string search pattern not found: %.*s\n", patlen, pattern);
Packit 857059
			goto patch_error;
Packit 857059
		}
Packit 857059
		return(B_TRUE);
Packit 857059
	}
Packit 857059
patch_error:
Packit 857059
	if (fp != NULL)
Packit 857059
	{
Packit 857059
		fclose(fp);
Packit 857059
	}
Packit 857059
	fprintf(stderr,"Patch failed for filename: %s\n\n",(filename)?filename:"NULL");
Packit 857059
	return(B_FALSE);
Packit 857059
}
Packit 857059
Packit 857059
char *basename(char *filename)
Packit 857059
{
Packit 857059
	char *p;
Packit 857059
Packit 857059
	p = strrchr(filename, '/');
Packit 857059
	if (p == NULL)
Packit 857059
		return filename;
Packit 857059
	else
Packit 857059
		return p+1;
Packit 857059
}
Packit 857059
Packit 857059
/*!
Packit 857059
search through binary a.out files looking for the ICS version string
Packit 857059
and updating the internal field so that the executables will have the correct
Packit 857059
version string information usable internally from a post build scenario.
Packit 857059
This application is not used to place a version reference in all a.out files,
Packit 857059
but specifically in a few with a certain internal static buffer.
Packit 857059
The program accepts two or more arguments on the command line.
Packit 857059
Packit 857059
The first argument must specify the source repository tag.
Packit 857059
Packit 857059
The other arguments specify filenames.
Packit 857059
Packit 857059
The tag is split into four numeric fields (major, minor, patch,
Packit 857059
and integration build).  All four fields
Packit 857059
must be valid and the tag argument is required.  At least one filename must
Packit 857059
also be specified and all filename arguments are opened in sequence and the
Packit 857059
patch performed.  The program returns a 0 on success and a positive number
Packit 857059
on error.  (1=Error in processing, 2=Usage).
Packit 857059
*/
Packit 857059
int main(int argc,char* argv[])
Packit 857059
{
Packit 857059
	ApplicationExitcode result=NO_ERROR;
Packit 857059
	const char* version = NULL;
Packit 857059
	const char* internalVersion;
Packit 857059
	int position;
Packit 857059
	int numArgs;
Packit 857059
	int rc;
Packit 857059
	int dropI = 0;
Packit 857059
	char pattern[1024];
Packit 857059
	char marker = '\0';
Packit 857059
	/*char pattern[MAX(sizeof(ICS_BUILD_VERSION)+1,sizeof(ICS_BUILD_BRAND)+1]; */
Packit 857059
	char internalPattern[sizeof(ICS_BUILD_INTERNAL_VERSION)+1];
Packit 857059
	int brand = 0;
Packit 857059
  
Packit 857059
	brand = (strcmp(basename(argv[0]), "patch_brand") == 0);
Packit 857059
Packit 857059
	while ((rc = getopt(argc, argv, "im:n:")) != -1)
Packit 857059
	{
Packit 857059
		switch (rc)
Packit 857059
		{
Packit 857059
			case 'i':
Packit 857059
				dropI = 1;
Packit 857059
				break;
Packit 857059
			case 'm':
Packit 857059
				marker = optarg[0];
Packit 857059
				break;
Packit 857059
			case 'n':
Packit 857059
				/* Override ParseReleaseTag() functionality by supplying an already-formatted version string. */
Packit 857059
				version = optarg;
Packit 857059
				break;
Packit 857059
			default:
Packit 857059
				break;
Packit 857059
		}
Packit 857059
	}
Packit 857059
	numArgs = argc - optind;
Packit 857059
	if (brand)
Packit 857059
	{
Packit 857059
		if (numArgs<1)
Packit 857059
		{
Packit 857059
			UsageBrand(argv[0]);
Packit 857059
		}
Packit 857059
		version = argv[optind];
Packit 857059
		if (strlen(version) == 0)
Packit 857059
		{
Packit 857059
			version = DEFAULT_BRAND;
Packit 857059
		}
Packit 857059
		version = append_marker(version, marker);
Packit 857059
		if (!version)
Packit 857059
		{
Packit 857059
			exit(INTERNAL_ERROR);
Packit 857059
		}
Packit 857059
		internalVersion = NULL;
Packit 857059
		if ((BuildBrandPattern(pattern, ICS_BUILD_BRAND, sizeof(ICS_BUILD_BRAND), version)) == NULL)
Packit 857059
		{
Packit 857059
			exit(USAGE_ERROR);
Packit 857059
		}
Packit 857059
	} else {
Packit 857059
		if (numArgs<1)
Packit 857059
		{
Packit 857059
			Usage(argv[0]);
Packit 857059
		}
Packit 857059
Packit 857059
		if (version == NULL && (version = ParseReleaseTag(argv[optind], dropI)) == NULL)
Packit 857059
		{
Packit 857059
			exit(USAGE_ERROR);
Packit 857059
		}
Packit 857059
		version = append_marker(version, marker);
Packit 857059
		if (!version)
Packit 857059
		{
Packit 857059
			exit(INTERNAL_ERROR);
Packit 857059
		}
Packit 857059
		internalVersion = append_marker(argv[optind], marker);
Packit 857059
		if (!internalVersion)
Packit 857059
		{
Packit 857059
			exit(INTERNAL_ERROR);
Packit 857059
		}
Packit 857059
		if ((BuildPattern(pattern, ICS_BUILD_VERSION, version)) == NULL)
Packit 857059
		{
Packit 857059
			exit(USAGE_ERROR);
Packit 857059
		}
Packit 857059
		if ((BuildPattern(internalPattern, ICS_BUILD_INTERNAL_VERSION, internalVersion)) == NULL)
Packit 857059
		{
Packit 857059
			exit(USAGE_ERROR);
Packit 857059
		}
Packit 857059
	}
Packit 857059
	if (numArgs == 1)
Packit 857059
	{
Packit 857059
		/* no program names, just put version string to stdout */
Packit 857059
		printf("%s\n", version);
Packit 857059
		exit(NO_ERROR);
Packit 857059
	}
Packit 857059
	for (position = optind + 1; position < argc; position++)
Packit 857059
	{
Packit 857059
		/* include the '\0' in the version in the patch so that the version string
Packit 857059
		 * is properly terminated when version is shorter than the space allowed
Packit 857059
		 */
Packit 857059
		if (brand)
Packit 857059
			printf("Patching %s with brand '%s'\n", argv[position], version);
Packit 857059
		else
Packit 857059
			printf("Patching %s with version strings %s and %s\n", argv[position], version, 
Packit 857059
				internalVersion?internalVersion:"");
Packit 857059
		if (!PatchFilename(argv[position], pattern, strlen(pattern), version, strlen(version)+1))
Packit 857059
		{
Packit 857059
			result=INTERNAL_ERROR;
Packit 857059
		}
Packit 857059
		if (internalVersion)
Packit 857059
		{
Packit 857059
			if (!PatchFilename(argv[position], internalPattern, strlen(internalPattern), internalVersion, strlen(internalVersion)+1))
Packit 857059
			{
Packit 857059
				result=INTERNAL_ERROR;
Packit 857059
			}
Packit 857059
		}
Packit 857059
	}
Packit 857059
	exit(result);
Packit 857059
}