/*
 * Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
 *
 * @APPLE_LICENSE_HEADER_START@
 * 
 * This file contains Original Code and/or Modifications of Original Code
 * as defined in and that are subject to the Apple Public Source License
 * Version 2.0 (the 'License'). You may not use this file except in
 * compliance with the License. Please obtain a copy of the License at
 * http://www.opensource.apple.com/apsl/ and read it before using this
 * file.
 * 
 * The Original Code and all software distributed under the License are
 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
 * Please see the License for the specific language governing rights and
 * limitations under the License.
 * 
 * @APPLE_LICENSE_HEADER_END@
 */
#ifndef RLD
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <mach/mach.h>
#include <sys/types.h>
#include <sys/sysctl.h>
#include "stuff/errors.h"
#include "stuff/allocate.h"
#include "stuff/macosx_deployment_target.h"

/* last value passed to put_macosx_deployment_target() */
static char *command_line_macosx_deployment_target = NULL;

/*
 * put_macosx_deployment_target() is called with the command line argument to
 * -macosx_version_min which the compiler uses to allow the user to asked for
 * a particular macosx deployment target on the command-line to override the
 * environment variable. This simply saves away the value requested.  The
 * string passed is not copied. If NULL is passed, it removes any previous
 * setting.
 */
__private_extern__
void
put_macosx_deployment_target(
char *target)
{
	command_line_macosx_deployment_target = target;
}

/*
 * get_macosx_deployment_target() sets the fields of the
 * macosx_deployment_target struct passed to it based on the last
 * command_line_macosx_deployment_target value set (if any) or the specified
 * MACOSX_DEPLOYMENT_TARGET environment variable or the default which the
 * the value the machine this is running on.  The name field in the struct is
 * always pointing to memory allocated here so it can be free()'ed when no
 * longer needed.
 */
__private_extern__
void
get_macosx_deployment_target(
struct macosx_deployment_target *value)
{
    uint32_t ten, major, minor;
    char *p, *q, *endp;
    char osversion[32];
    size_t osversion_len;
    static int osversion_name[2];

	/*
	 * Pick up the Mac OS X deployment target set by the command line
	 * or the environment variable if any.  If that does not parse out
	 * use the default and generate a warning.  We accept "10.x" or "10.x.y"
	 * where x and y are unsigned numbers. And x is non-zero.
	 */
	if(command_line_macosx_deployment_target != NULL)
	    p = command_line_macosx_deployment_target;
	else
	    p = getenv("MACOSX_DEPLOYMENT_TARGET");
	if(p != NULL){
	    ten = strtoul(p, &endp, 10);
	    if(*endp != '.')
		goto use_default;
	    if(ten != 10)
		goto use_default;
	    q = endp + 1;
	    major = strtoul(q, &endp, 10);
	    if(major == 0)
		goto use_default;
	    if(*endp != '.' && *endp != '\0')
		goto use_default;
	    if(*endp == '.'){
		q = endp + 1;
		minor = strtoul(q, &endp, 10);
		if(*endp != '\0')
		    goto use_default;
	    }
	    else{
		minor = 0;
	    }
	    value->major = major;
	    value->minor = minor;
	    value->name = allocate(strlen(p) + 1);
	    strcpy(value->name, p);
	    return;
	}

use_default:
	/*
	 * The default value is the version of the running OS.
	 */
	osversion_name[0] = CTL_KERN;
	osversion_name[1] = KERN_OSRELEASE;
	osversion_len = sizeof(osversion) - 1;
	if(sysctl(osversion_name, 2, osversion, &osversion_len, NULL, 0) == -1)
	    system_error("sysctl for kern.osversion failed");

	/*
	 * Now parse this out.  It is expected to be of the form "x.y.z" where
	 * x, y and z are unsigned numbers.  Where x-4 is the Mac OS X major
	 * version number, and y is the minor version number.  We don't parse
	 * out the value of z.
	 */
	major = strtoul(osversion, &endp, 10);
	if(*endp != '.')
	    goto bad_system_value;
	if(major <= 4)
	    goto bad_system_value;
	major = major - 4;
	q = endp + 1;
	minor = strtoul(q, &endp, 10);
	if(*endp != '.')
	    goto bad_system_value;

	value->major = major;
	value->minor = minor;
	value->name = allocate(32);
	sprintf(value->name, "10.%u.%u", major, minor);
	goto warn_if_bad_user_values;

bad_system_value:
	/*
	 * As a last resort we set the default to the highest known shipping
	 * system to date.
	 */
	value->major = 6;
	value->minor = 0;
	value->name = allocate(strlen("10.6") + 1);
	strcpy(value->name, "10.6");
	warning("unknown value returned by sysctl() for kern.osrelease: %s "
		"ignored (using %s)", osversion, value->name);
	/* fall through to also warn about a possble bad user value */

warn_if_bad_user_values:
	if(p != NULL){
	    if(command_line_macosx_deployment_target != NULL)
		warning("unknown -macosx_version_min parameter value: "
			"%s ignored (using %s)", p, value->name);
	    else
		warning("unknown MACOSX_DEPLOYMENT_TARGET environment "
			"variable value: %s ignored (using %s)", p,value->name);
	}
}
#endif /* !defined(RLD) */
