1/*
2 * Copyright (c) 2008 Apple Computer, Inc.  All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License").  You may not use this file except in compliance with the
9 * License.  Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
11 *
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
17 * License for the specific language governing rights and limitations
18 * under the License.
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22
23#include <stdbool.h>
24#include <string.h>
25#include <inttypes.h>
26#include <libutil.h>
27#include "uinteger.h"
28#include "preferences.h"
29
30struct top_uinteger top_init_uinteger(uint64_t value, bool is_negative) {
31    struct top_uinteger r;
32
33    r.is_negative = is_negative;
34    r.value = value;
35
36    return r;
37}
38
39struct top_uinteger top_sub_uinteger(const struct top_uinteger *a, const struct top_uinteger *b) {
40    struct top_uinteger r;
41
42    if(!a->is_negative && !b->is_negative) {
43	if(a->value > b->value) {
44	    /* The value will fit without underflow. */
45	    r.is_negative = false;
46	    r.value = a->value - b->value;
47	} else {
48	    /* B is larger or we have a r.value of 0. */
49	    r.is_negative = true;
50	    r.value = b->value - a->value;
51	}
52    } else if (a->is_negative && !b->is_negative) {
53	/* A is negative and B is positive. */
54	r.is_negative = true;
55	/*
56	 * The A value is negative, so actually add the amount we would subtract.
57	 * Thus if a is -5 and b is 2: -5 - 2 = -7;
58	 */
59	r.value = a->value + b->value;
60    } else if(!a->is_negative && b->is_negative) {
61	/* A is positive and b is negative. */
62	r.is_negative = false;
63	/*
64	 * If say A is 2 and b is -3 we want value to be: 2 - -3 = 5;
65	 */
66	r.value = a->value + b->value;
67    } else {
68	/* They are both negative. */
69	r.is_negative = true;
70	r.value = a->value + b->value;
71    }
72
73    if(0 == r.value)
74	r.is_negative = 0;
75
76    return r;
77}
78
79/* Return true if an error occurred. */
80bool top_humanize_uinteger(char *buf, size_t bufsize,
81			   struct top_uinteger i) {
82
83    if(i.is_negative) {
84	if(-1 == humanize_number(buf + 1, bufsize - 1,
85				 (int64_t)i.value, "",
86				 HN_AUTOSCALE, HN_NOSPACE | HN_B)) {
87	    return true;
88	}
89	buf[0] = '-';
90    } else {
91	if(-1 == humanize_number(buf, bufsize,
92				 (int64_t)i.value, "",
93				 HN_AUTOSCALE, HN_NOSPACE | HN_B)) {
94	    return true;
95	}
96    }
97
98    return false;
99}
100
101bool top_sprint_uinteger(char *buf, size_t bufsize,
102			 struct top_uinteger i) {
103
104    if(i.is_negative) {
105	if(-1 == snprintf(buf, bufsize, "-%" PRIu64, i.value))
106	    return true;
107    } else {
108	if(-1 == snprintf(buf, bufsize, "%" PRIu64, i.value))
109	    return true;
110    }
111
112    return false;
113}
114
115struct top_uinteger top_uinteger_calc_result(uint64_t now, uint64_t prev,
116					     uint64_t beg) {
117    struct top_uinteger result, prevu, begu;
118
119    result = top_init_uinteger(now, false);
120
121    switch(top_prefs_get_mode()) {
122    case STATMODE_ACCUM:
123	begu = top_init_uinteger(beg, false);
124	result = top_sub_uinteger(&result, &begu);
125	break;
126
127    case STATMODE_DELTA:
128    	prevu = top_init_uinteger(prev, false);
129	result = top_sub_uinteger(&result, &prevu);
130	break;
131    }
132
133    return result;
134}
135
136/* Return true if an error occurred. */
137bool top_uinteger_format_result(char *buf, size_t bufsize, uint64_t now,
138				uint64_t prev, uint64_t beg) {
139    struct top_uinteger i;
140    int suffix = '\0';
141
142    i = top_uinteger_calc_result(now, prev, beg);
143
144    if(STATMODE_DELTA == top_prefs_get_mode()) {
145	/* We don't need a suffix in delta mode. */
146	if(top_sprint_uinteger(buf, bufsize, i)) {
147	    return true;
148	}
149    } else {
150	if(now < prev) {
151	    /* The value has decreased since the previous sample. */
152	    suffix = '-';
153	} else if(now > prev) {
154	    suffix = '+';
155	}
156
157	if(-1 == snprintf(buf, bufsize, "%s%" PRIu64 "%c",
158			  (i.is_negative ? "-" : ""),
159			  i.value,
160			  suffix)) {
161	    return true;
162	}
163    }
164
165    return false;
166}
167
168
169/* Return true if an error occurred. */
170bool top_uinteger_format_mem_result(char *buf, size_t bufsize, uint64_t now,
171				    uint64_t prev, uint64_t beg) {
172    struct top_uinteger i;
173    size_t len;
174
175    i = top_uinteger_calc_result(now, prev, beg);
176
177    if(STATMODE_DELTA == top_prefs_get_mode()) {
178	/* We don't need a suffix in delta mode. */
179	if(top_humanize_uinteger(buf, bufsize, i)) {
180	    return true;
181	}
182    } else {
183	if(top_humanize_uinteger(buf, bufsize - 1, i)) {
184	    return true;
185	}
186
187	len = strlen(buf);
188
189	if((len + 2) <= bufsize) {
190	    if(now < prev) {
191		buf[len] = '-';
192		buf[len + 1] = '\0';
193	    } else if(now > prev) {
194		buf[len] = '+';
195		buf[len + 1] = '\0';
196	    }
197	}
198    }
199
200    return false;
201}
202