uinteger.c   [plain text]


/*
 * Copyright (c) 2008 Apple Computer, Inc.  All rights reserved.
 *
 * @APPLE_LICENSE_HEADER_START@
 * 
 * The contents of this file constitute Original Code as defined in and
 * are subject to the Apple Public Source License Version 1.1 (the
 * "License").  You may not use this file except in compliance with the
 * License.  Please obtain a copy of the License at
 * http://www.apple.com/publicsource and read it before using this file.
 * 
 * This 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 OR NON-INFRINGEMENT.  Please see the
 * License for the specific language governing rights and limitations
 * under the License.
 * 
 * @APPLE_LICENSE_HEADER_END@
 */

#include <stdbool.h>
#include <string.h>
#include <inttypes.h>
#include <libutil.h>
#include "uinteger.h"
#include "preferences.h"

bool first_sample = true;

struct top_uinteger top_init_uinteger(uint64_t value, bool is_negative) {
	struct top_uinteger r;

	r.is_negative = is_negative;
	r.value = value;

	return r;
}

struct top_uinteger top_sub_uinteger(const struct top_uinteger *a, const struct top_uinteger *b) {
	struct top_uinteger r;

	if(!a->is_negative && !b->is_negative) {
		if(a->value > b->value) {
			/* The value will fit without underflow. */
			r.is_negative = false;
			r.value = a->value - b->value;
		} else {
			/* B is larger or we have a r.value of 0. */
			r.is_negative = true;
			r.value = b->value - a->value;
		}
	} else if (a->is_negative && !b->is_negative) {
		/* A is negative and B is positive. */
		r.is_negative = true;
		/*
		* The A value is negative, so actually add the amount we would subtract.
		* Thus if a is -5 and b is 2: -5 - 2 = -7;
		*/
		r.value = a->value + b->value;
	} else if(!a->is_negative && b->is_negative) {
		/* A is positive and b is negative. */
		r.is_negative = false;
		/*
		* If say A is 2 and b is -3 we want value to be: 2 - -3 = 5;
		*/
		r.value = a->value + b->value;
	} else {
		/* They are both negative. */
		r.is_negative = true;
		r.value = a->value + b->value;
	}

	if(0 == r.value)
		r.is_negative = 0;

	return r;
}

/* Return true if an error occurred. */
bool top_humanize_uinteger(char *buf, size_t bufsize, 
		struct top_uinteger i) {

	if(i.is_negative) {
		if(-1 == humanize_number(buf + 1, bufsize - 1,
				(int64_t)i.value, "",
				HN_AUTOSCALE, HN_NOSPACE | HN_B)) {
			return true;
		}
		buf[0] = '-';
	} else {
		if(-1 == humanize_number(buf, bufsize,
				(int64_t)i.value, "",
				HN_AUTOSCALE, HN_NOSPACE | HN_B)) {
			return true;
		}
	}

	return false;
}

bool top_sprint_uinteger(char *buf, size_t bufsize,
		struct top_uinteger i) {

	if(i.is_negative) {
		if(-1 == snprintf(buf, bufsize, "-%" PRIu64, i.value))
			return true;
	} else {
		if(-1 == snprintf(buf, bufsize, "%" PRIu64, i.value))
			return true;
	}

	return false;
}

struct top_uinteger top_uinteger_calc_result(uint64_t now, uint64_t prev, 
		uint64_t beg) {
	struct top_uinteger result, prevu, begu;

	result = top_init_uinteger(now, false);

	switch(top_prefs_get_mode()) {
		case STATMODE_ACCUM:
			begu = top_init_uinteger(beg, false);
			result = top_sub_uinteger(&result, &begu);
			break;

		case STATMODE_DELTA:
			prevu = top_init_uinteger(prev, false);
			result = top_sub_uinteger(&result, &prevu);
			break;
	}

	return result;
}

/* Return true if an error occurred. */
bool top_uinteger_format_result(char *buf, size_t bufsize, uint64_t now,
		uint64_t prev, uint64_t beg) {
	struct top_uinteger i;
	int suffix = '\0';

	i = top_uinteger_calc_result(now, prev, beg);

	if(STATMODE_DELTA == top_prefs_get_mode()) {
		/* We don't need a suffix in delta mode. */
		if(top_sprint_uinteger(buf, bufsize, i)) {
			return true;
		}
	} else {
		if (!first_sample) {
			if(now < prev) {
				/* The value has decreased since the previous sample. */
				suffix = '-';
			} else if(now > prev) {
				suffix = '+';
			}
		}
	
		if(-1 == snprintf(buf, bufsize, "%s%" PRIu64 "%c",
				(i.is_negative ? "-" : ""),
				i.value, suffix)) {
			return true;
		}
	}
 
	return false;
}


/* Return true if an error occurred. */
bool top_uinteger_format_mem_result(char *buf, size_t bufsize, uint64_t now,
		uint64_t prev, uint64_t beg) {
	struct top_uinteger i;
	size_t len;

	i = top_uinteger_calc_result(now, prev, beg);

	if(STATMODE_DELTA == top_prefs_get_mode()) {
		/* We don't need a suffix in delta mode. */
		if(top_humanize_uinteger(buf, bufsize, i)) {
			return true;
		}
	} else {
		if(top_humanize_uinteger(buf, bufsize - 1, i)) {
			return true;
		}

		len = strlen(buf);

		if((len + 2) <= bufsize && !first_sample) {
			if(now < prev) {
				buf[len] = '-';
				buf[len + 1] = '\0';
			} else if(now > prev) {
				buf[len] = '+';
				buf[len + 1] = '\0';
			}
		}
	}

	return false;
}