aboutsummaryrefslogtreecommitdiffstats
path: root/Meter.c
diff options
context:
space:
mode:
Diffstat (limited to 'Meter.c')
-rw-r--r--Meter.c145
1 files changed, 81 insertions, 64 deletions
diff --git a/Meter.c b/Meter.c
index 164c4d3..86f8885 100644
--- a/Meter.c
+++ b/Meter.c
@@ -13,13 +13,13 @@ in the source distribution for its full text.
#include <math.h>
#include <stdlib.h>
#include <string.h>
-#include <stdio.h>
#include "CRT.h"
#include "Macros.h"
#include "Object.h"
#include "ProvideCurses.h"
#include "RichString.h"
+#include "Row.h"
#include "Settings.h"
#include "XUtils.h"
@@ -32,12 +32,12 @@ const MeterClass Meter_class = {
}
};
-Meter* Meter_new(const struct ProcessList_* pl, unsigned int param, const MeterClass* type) {
+Meter* Meter_new(const Machine* host, unsigned int param, const MeterClass* type) {
Meter* this = xCalloc(1, sizeof(Meter));
Object_setClass(this, type);
this->h = 1;
this->param = param;
- this->pl = pl;
+ this->host = host;
this->curItems = type->maxItems;
this->curAttributes = NULL;
this->values = type->maxItems ? xCalloc(type->maxItems, sizeof(double)) : NULL;
@@ -50,32 +50,40 @@ Meter* Meter_new(const struct ProcessList_* pl, unsigned int param, const MeterC
return this;
}
-int Meter_humanUnit(char* buffer, unsigned long int value, size_t size) {
- const char* prefix = "KMGTPEZY";
- unsigned long int powi = 1;
- unsigned int powj = 1, precision = 2;
+/* Converts 'value' in kibibytes into a human readable string.
+ Example output strings: "0K", "1023K", "98.7M" and "1.23G" */
+int Meter_humanUnit(char* buffer, double value, size_t size) {
+ size_t i = 0;
- for (;;) {
- if (value / 1024 < powi)
- break;
-
- if (prefix[1] == '\0')
+ assert(value >= 0.0);
+ while (value >= ONE_K) {
+ if (i >= ARRAYSIZE(unitPrefixes) - 1) {
+ if (value > 9999.0) {
+ return xSnprintf(buffer, size, "inf");
+ }
break;
+ }
- powi *= 1024;
- ++prefix;
+ value /= ONE_K;
+ ++i;
}
- if (*prefix == 'K')
- precision = 0;
+ int precision = 0;
- for (; precision > 0; precision--) {
- powj *= 10;
- if (value / powi < powj)
- break;
+ if (i > 0) {
+ // Fraction digits for mebibytes and above
+ precision = value <= 99.9 ? (value <= 9.99 ? 2 : 1) : 0;
+
+ // Round up if 'value' is in range (99.9, 100) or (9.99, 10)
+ if (precision < 2) {
+ double limit = precision == 1 ? 10.0 : 100.0;
+ if (value < limit) {
+ value = limit;
+ }
+ }
}
- return snprintf(buffer, size, "%.*f%c", precision, (double) value / powi, *prefix);
+ return xSnprintf(buffer, size, "%.*f%c", precision, value, unitPrefixes[i]);
}
void Meter_delete(Object* cast) {
@@ -86,7 +94,7 @@ void Meter_delete(Object* cast) {
if (Meter_doneFn(this)) {
Meter_done(this);
}
- free(this->drawData);
+ free(this->drawData.values);
free(this->caption);
free(this->values);
free(this);
@@ -121,8 +129,9 @@ void Meter_setMode(Meter* this, int modeIndex) {
}
} else {
assert(modeIndex >= 1);
- free(this->drawData);
- this->drawData = NULL;
+ free(this->drawData.values);
+ this->drawData.values = NULL;
+ this->drawData.nValues = 0;
const MeterMode* mode = Meter_modes[modeIndex];
this->draw = mode->draw;
@@ -224,8 +233,8 @@ static void BarMeterMode_draw(Meter* this, int x, int y, int w) {
int offset = 0;
for (uint8_t i = 0; i < this->curItems; i++) {
double value = this->values[i];
- value = CLAMP(value, 0.0, this->total);
- if (value > 0) {
+ if (isPositive(value) && this->total > 0.0) {
+ value = MINIMUM(value, this->total);
blockSizes[i] = ceil((value / this->total) * w);
} else {
blockSizes[i] = 0;
@@ -236,6 +245,7 @@ static void BarMeterMode_draw(Meter* this, int x, int y, int w) {
for (int j = offset; j < nextOffset; j++)
if (RichString_getCharVal(bar, startPos + j) == ' ') {
if (CRT_colorScheme == COLORSCHEME_MONOCHROME) {
+ assert(i < strlen(BarMeterMode_characters));
RichString_setChar(&bar, startPos + j, BarMeterMode_characters[i]);
} else {
RichString_setChar(&bar, startPos + j, '|');
@@ -287,13 +297,46 @@ static const char* const GraphMeterMode_dotsAscii[] = {
};
static void GraphMeterMode_draw(Meter* this, int x, int y, int w) {
- const ProcessList* pl = this->pl;
+ const char* caption = Meter_getCaption(this);
+ attrset(CRT_colors[METER_TEXT]);
+ const int captionLen = 3;
+ mvaddnstr(y, x, caption, captionLen);
+ x += captionLen;
+ w -= captionLen;
+
+ GraphData* data = &this->drawData;
+ assert(data->nValues / 2 <= INT_MAX);
+ if (w > (int)(data->nValues / 2) && MAX_METER_GRAPHDATA_VALUES > data->nValues) {
+ size_t oldNValues = data->nValues;
+ data->nValues = MAXIMUM(oldNValues + oldNValues / 2, (size_t)w * 2);
+ data->nValues = MINIMUM(data->nValues, MAX_METER_GRAPHDATA_VALUES);
+ data->values = xReallocArray(data->values, data->nValues, sizeof(*data->values));
+ memmove(data->values + (data->nValues - oldNValues), data->values, oldNValues * sizeof(*data->values));
+ memset(data->values, 0, (data->nValues - oldNValues) * sizeof(*data->values));
+ }
+
+ const size_t nValues = data->nValues;
+ if (nValues < 1)
+ return;
+
+ const Machine* host = this->host;
+ if (!timercmp(&host->realtime, &(data->time), <)) {
+ int globalDelay = host->settings->delay;
+ struct timeval delay = { .tv_sec = globalDelay / 10, .tv_usec = (globalDelay % 10) * 100000L };
+ timeradd(&host->realtime, &delay, &(data->time));
- if (!this->drawData) {
- this->drawData = xCalloc(1, sizeof(GraphData));
+ memmove(&data->values[0], &data->values[1], (nValues - 1) * sizeof(*data->values));
+
+ data->values[nValues - 1] = sumPositiveValues(this->values, this->curItems);
+ }
+
+ if (w <= 0)
+ return;
+
+ if ((size_t)w > nValues / 2) {
+ x += w - nValues / 2;
+ w = nValues / 2;
}
- GraphData* data = this->drawData;
- const int nValues = METER_GRAPHDATA_SIZE;
const char* const* GraphMeterMode_dots;
int GraphMeterMode_pixPerRow;
@@ -308,38 +351,12 @@ static void GraphMeterMode_draw(Meter* this, int x, int y, int w) {
GraphMeterMode_pixPerRow = PIXPERROW_ASCII;
}
- const char* caption = Meter_getCaption(this);
- attrset(CRT_colors[METER_TEXT]);
- int captionLen = 3;
- mvaddnstr(y, x, caption, captionLen);
- x += captionLen;
- w -= captionLen;
-
- if (!timercmp(&pl->realtime, &(data->time), <)) {
- int globalDelay = this->pl->settings->delay;
- struct timeval delay = { .tv_sec = globalDelay / 10, .tv_usec = (globalDelay % 10) * 100000L };
- timeradd(&pl->realtime, &delay, &(data->time));
-
- for (int i = 0; i < nValues - 1; i++)
- data->values[i] = data->values[i + 1];
-
- double value = 0.0;
- for (uint8_t i = 0; i < this->curItems; i++)
- value += this->values[i];
- data->values[nValues - 1] = value;
- }
-
- int i = nValues - (w * 2), k = 0;
- if (i < 0) {
- k = -i / 2;
- i = 0;
- }
- for (; i < nValues - 1; i += 2, k++) {
+ size_t i = nValues - (size_t)w * 2;
+ for (int col = 0; i < nValues - 1; i += 2, col++) {
int pix = GraphMeterMode_pixPerRow * GRAPH_HEIGHT;
- if (this->total < 1)
- this->total = 1;
- int v1 = CLAMP((int) lround(data->values[i] / this->total * pix), 1, pix);
- int v2 = CLAMP((int) lround(data->values[i + 1] / this->total * pix), 1, pix);
+ double total = MAXIMUM(this->total, 1);
+ int v1 = CLAMP((int) lround(data->values[i] / total * pix), 1, pix);
+ int v2 = CLAMP((int) lround(data->values[i + 1] / total * pix), 1, pix);
int colorIdx = GRAPH_1;
for (int line = 0; line < GRAPH_HEIGHT; line++) {
@@ -347,7 +364,7 @@ static void GraphMeterMode_draw(Meter* this, int x, int y, int w) {
int line2 = CLAMP(v2 - (GraphMeterMode_pixPerRow * (GRAPH_HEIGHT - 1 - line)), 0, GraphMeterMode_pixPerRow);
attrset(CRT_colors[colorIdx]);
- mvaddstr(y + line, x + k, GraphMeterMode_dots[line1 * (GraphMeterMode_pixPerRow + 1) + line2]);
+ mvaddstr(y + line, x + col, GraphMeterMode_dots[line1 * (GraphMeterMode_pixPerRow + 1) + line2]);
colorIdx = GRAPH_2;
}
}
@@ -367,7 +384,7 @@ static const char* const LEDMeterMode_digitsAscii[] = {
static const char* const LEDMeterMode_digitsUtf8[] = {
"┌──┐", " ┐ ", "╶──┐", "╶──┐", "╷ ╷", "┌──╴", "┌──╴", "╶──┐", "┌──┐", "┌──┐",
"│ │", " │ ", "┌──┘", " ──┤", "└──┤", "└──┐", "├──┐", " │", "├──┤", "└──┤",
- "└──┘", " ╵ ", "└──╴", "╶──┘", " ╵", "╶──┘", "└──┘", " ╵", "└──┘", " ──┘"
+ "└──┘", " ╵ ", "└──╴", "╶──┘", " ╵", "╶──┘", "└──┘", " ╵", "└──┘", "╶──┘"
};
#endif

© 2014-2024 Faster IT GmbH | imprint | privacy policy