summaryrefslogtreecommitdiff
path: root/apps/misc.c
diff options
context:
space:
mode:
Diffstat (limited to 'apps/misc.c')
-rw-r--r--apps/misc.c237
1 files changed, 231 insertions, 6 deletions
diff --git a/apps/misc.c b/apps/misc.c
index b43d347d91..9b8fa3e81c 100644
--- a/apps/misc.c
+++ b/apps/misc.c
@@ -28,6 +28,8 @@
28#include "misc.h" 28#include "misc.h"
29#include "system.h" 29#include "system.h"
30#include "lcd.h" 30#include "lcd.h"
31#include "language.h" /* is_lang_rtl() */
32
31#ifdef HAVE_DIRCACHE 33#ifdef HAVE_DIRCACHE
32#include "dircache.h" 34#include "dircache.h"
33#endif 35#endif
@@ -117,6 +119,20 @@ const unsigned char * const byte_units[] =
117 119
118const unsigned char * const * const kibyte_units = &byte_units[1]; 120const unsigned char * const * const kibyte_units = &byte_units[1];
119 121
122/* units used with format_time_auto, option_select.c->option_get_valuestring() */
123const unsigned char * const unit_strings_core[] =
124{
125 [UNIT_INT] = "", [UNIT_MS] = "ms",
126 [UNIT_SEC] = "s", [UNIT_MIN] = "min",
127 [UNIT_HOUR]= "hr", [UNIT_KHZ] = "kHz",
128 [UNIT_DB] = "dB", [UNIT_PERCENT] = "%",
129 [UNIT_MAH] = "mAh", [UNIT_PIXEL] = "px",
130 [UNIT_PER_SEC] = "per sec",
131 [UNIT_HERTZ] = "Hz",
132 [UNIT_MB] = "MB", [UNIT_KBIT] = "kb/s",
133 [UNIT_PM_TICK] = "units/10ms",
134};
135
120/* Format a large-range value for output, using the appropriate unit so that 136/* Format a large-range value for output, using the appropriate unit so that
121 * the displayed value is in the range 1 <= display < 1000 (1024 for "binary" 137 * the displayed value is in the range 1 <= display < 1000 (1024 for "binary"
122 * units) if possible, and 3 significant digits are shown. If a buffer is 138 * units) if possible, and 3 significant digits are shown. If a buffer is
@@ -1096,6 +1112,216 @@ char* skip_whitespace(char* const str)
1096 return s; 1112 return s;
1097} 1113}
1098 1114
1115/* time_split_units()
1116 split time values depending on base unit
1117 unit_idx: UNIT_HOUR, UNIT_MIN, UNIT_SEC, UNIT_MS
1118 abs_value: absolute time value
1119 units_in: array of unsigned ints with UNIT_IDX_TIME_COUNT fields
1120*/
1121unsigned int time_split_units(int unit_idx, unsigned long abs_val,
1122 unsigned long (*units_in)[UNIT_IDX_TIME_COUNT])
1123{
1124 unsigned int base_idx = UNIT_IDX_HR;
1125 unsigned long hours;
1126 unsigned long minutes = 0;
1127 unsigned long seconds = 0;
1128 unsigned long millisec = 0;
1129
1130 switch (unit_idx & UNIT_IDX_MASK) /*Mask off upper bits*/
1131 {
1132 case UNIT_MS:
1133 base_idx = UNIT_IDX_MS;
1134 millisec = abs_val;
1135 abs_val = abs_val / 1000U;
1136 millisec = millisec - (1000U * abs_val);
1137 /* fallthrough and calculate the rest of the units */
1138 case UNIT_SEC:
1139 if (base_idx == UNIT_IDX_HR)
1140 base_idx = UNIT_IDX_SEC;
1141 seconds = abs_val;
1142 abs_val = abs_val / 60U;
1143 seconds = seconds - (60U * abs_val);
1144 /* fallthrough and calculate the rest of the units */
1145 case UNIT_MIN:
1146 if (base_idx == UNIT_IDX_HR)
1147 base_idx = UNIT_IDX_MIN;
1148 minutes = abs_val;
1149 abs_val = abs_val / 60U;
1150 minutes = minutes -(60U * abs_val);
1151 /* fallthrough and calculate the rest of the units */
1152 case UNIT_HOUR:
1153 default:
1154 hours = abs_val;
1155 break;
1156 }
1157
1158 (*units_in)[UNIT_IDX_HR] = hours;
1159 (*units_in)[UNIT_IDX_MIN] = minutes;
1160 (*units_in)[UNIT_IDX_SEC] = seconds;
1161 (*units_in)[UNIT_IDX_MS] = millisec;
1162
1163 return base_idx;
1164}
1165
1166/* format_time_auto - return an auto ranged time string;
1167 buffer: needs to be at least 25 characters for full range
1168
1169 unit_idx: specifies lowest or base index of the value
1170 add | UNIT_LOCK_ to keep place holder of units that would normally be
1171 discarded.. For instance, UNIT_LOCK_HR would keep the hours place, ex: string
1172 00:10:10 (0 HRS 10 MINS 10 SECONDS) normally it would return as 10:10
1173 add | UNIT_TRIM_ZERO to supress leading zero on the largest unit
1174
1175 value: should be passed in the same form as unit_idx
1176
1177 supress_unit: may be set to true and in this case the
1178 hr, min, sec, ms identifiers will be left off the resulting string but
1179 since right to left languages are handled it is advisable to leave units
1180 as an indication of the text direction
1181*/
1182
1183const char *format_time_auto(char *buffer, int buf_len, long value,
1184 int unit_idx, bool supress_unit)
1185{
1186 const char * const sign = &"-"[value < 0 ? 0 : 1];
1187 bool is_rtl = lang_is_rtl();
1188 char timebuf[25]; /* -2147483648:00:00.00\0 */
1189 int len, left_offset;
1190 unsigned char base_idx, max_idx;
1191
1192 unsigned long units_in[UNIT_IDX_TIME_COUNT];
1193 unsigned char fwidth[UNIT_IDX_TIME_COUNT] =
1194 {
1195 [UNIT_IDX_HR] = 0, /* hr is variable length */
1196 [UNIT_IDX_MIN] = 2,
1197 [UNIT_IDX_SEC] = 2,
1198 [UNIT_IDX_MS] = 3,
1199 }; /* {0,2,2,3}; Field Widths */
1200 unsigned char offsets[UNIT_IDX_TIME_COUNT] =
1201 {
1202 [UNIT_IDX_HR] = 10,/* ?:59:59.999 Std offsets */
1203 [UNIT_IDX_MIN] = 7, /*0?:+1:+4.+7 need calculated */
1204 [UNIT_IDX_SEC] = 4,/* 999.59:59:0 RTL offsets */
1205 [UNIT_IDX_MS] = 0,/* 0 .4 :7 :10 won't change */
1206 }; /* {10,7,4,0}; Offsets */
1207 const uint16_t unitlock[UNIT_IDX_TIME_COUNT] =
1208 {
1209 [UNIT_IDX_HR] = UNIT_LOCK_HR,
1210 [UNIT_IDX_MIN] = UNIT_LOCK_MIN,
1211 [UNIT_IDX_SEC] = UNIT_LOCK_SEC,
1212 [UNIT_IDX_MS] = 0,
1213 }; /* unitlock */
1214 const uint16_t units[UNIT_IDX_TIME_COUNT] =
1215 {
1216 [UNIT_IDX_HR] = UNIT_HOUR,
1217 [UNIT_IDX_MIN] = UNIT_MIN,
1218 [UNIT_IDX_SEC] = UNIT_SEC,
1219 [UNIT_IDX_MS] = UNIT_MS,
1220 }; /* units */
1221
1222#if 0 /* unused */
1223 if (idx_pos != NULL)
1224 {
1225 (*idx_pos)[0] = MIN((*idx_pos)[0], UNIT_IDX_TIME_COUNT - 1);
1226 unit_idx |= unitlock[(*idx_pos)[0]];
1227 }
1228#endif
1229
1230 base_idx = time_split_units(unit_idx, labs(value), &units_in);
1231
1232 if (units_in[UNIT_IDX_HR] || (unit_idx & unitlock[UNIT_IDX_HR]))
1233 max_idx = UNIT_IDX_HR;
1234 else if (units_in[UNIT_IDX_MIN] || (unit_idx & unitlock[UNIT_IDX_MIN]))
1235 max_idx = UNIT_IDX_MIN;
1236 else if (units_in[UNIT_IDX_SEC] || (unit_idx & unitlock[UNIT_IDX_SEC]))
1237 max_idx = UNIT_IDX_SEC;
1238 else if (units_in[UNIT_IDX_MS])
1239 max_idx = UNIT_IDX_MS;
1240 else /* value is 0 */
1241 max_idx = base_idx;
1242
1243 if (!is_rtl)
1244 {
1245 len = snprintf(timebuf, sizeof(timebuf),
1246 "%02lu:%02lu:%02lu.%03lu",
1247 units_in[UNIT_IDX_HR],
1248 units_in[UNIT_IDX_MIN],
1249 units_in[UNIT_IDX_SEC],
1250 units_in[UNIT_IDX_MS]);
1251
1252 fwidth[UNIT_IDX_HR] = len - offsets[UNIT_IDX_HR];
1253
1254 /* calculate offsets of the other fields based on length of previous */
1255 offsets[UNIT_IDX_MS] = fwidth[UNIT_IDX_HR] + offsets[UNIT_IDX_MIN];
1256 offsets[UNIT_IDX_SEC] = fwidth[UNIT_IDX_HR] + offsets[UNIT_IDX_SEC];
1257 offsets[UNIT_IDX_MIN] = fwidth[UNIT_IDX_HR] + 1;
1258 offsets[UNIT_IDX_HR] = 0;
1259
1260 timebuf[offsets[base_idx] + fwidth[base_idx]] = '\0';
1261
1262 left_offset = -(offsets[max_idx]);
1263 left_offset += strlcpy(buffer, sign, buf_len);
1264
1265 /* trim leading zero on the max_idx */
1266 if ((unit_idx & UNIT_TRIM_ZERO) == UNIT_TRIM_ZERO &&
1267 timebuf[offsets[max_idx]] == '0' && fwidth[max_idx] > 1)
1268 {
1269 offsets[max_idx]++;
1270 }
1271
1272 strlcat(buffer, &timebuf[offsets[max_idx]], buf_len);
1273
1274 if (!supress_unit)
1275 {
1276 strlcat(buffer, " ", buf_len);
1277 strlcat(buffer, unit_strings_core[units[max_idx]], buf_len);
1278 }
1279 }
1280 else /*RTL Languages*/
1281 {
1282 len = snprintf(timebuf, sizeof(timebuf),
1283 "%03lu.%02lu:%02lu:%02lu",
1284 units_in[UNIT_IDX_MS],
1285 units_in[UNIT_IDX_SEC],
1286 units_in[UNIT_IDX_MIN],
1287 units_in[UNIT_IDX_HR]);
1288
1289 fwidth[UNIT_IDX_HR] = len - offsets[UNIT_IDX_HR];
1290
1291 left_offset = -(offsets[base_idx]);
1292
1293 /* trim leading zero on the max_idx */
1294 if ((unit_idx & UNIT_TRIM_ZERO) == UNIT_TRIM_ZERO &&
1295 timebuf[offsets[max_idx]] == '0' && fwidth[max_idx] > 1)
1296 {
1297 timebuf[offsets[max_idx]] = timebuf[offsets[max_idx]+1];
1298 fwidth[max_idx]--;
1299 }
1300
1301 timebuf[offsets[max_idx] + fwidth[max_idx]] = '\0';
1302
1303 if (!supress_unit)
1304 {
1305 strlcpy(buffer, unit_strings_core[units[max_idx]], buf_len);
1306 left_offset += strlcat(buffer, " ", buf_len);
1307 strlcat(buffer, &timebuf[offsets[base_idx]], buf_len);
1308 }
1309 else
1310 strlcpy(buffer, &timebuf[offsets[base_idx]], buf_len);
1311
1312 strlcat(buffer, sign, buf_len);
1313 }
1314#if 0 /* unused */
1315 if (idx_pos != NULL)
1316 {
1317 (*idx_pos)[1]= fwidth[*(idx_pos)[0]];
1318 (*idx_pos)[0]= left_offset + offsets[(*idx_pos)[0]];
1319 }
1320#endif
1321
1322 return buffer;
1323}
1324
1099/* Format time into buf. 1325/* Format time into buf.
1100 * 1326 *
1101 * buf - buffer to format to. 1327 * buf - buffer to format to.
@@ -1104,13 +1330,12 @@ char* skip_whitespace(char* const str)
1104 */ 1330 */
1105void format_time(char* buf, int buf_size, long t) 1331void format_time(char* buf, int buf_size, long t)
1106{ 1332{
1107 unsigned long time = labs(t / 1000); 1333 unsigned long units_in[UNIT_IDX_TIME_COUNT] = {0};
1108 unsigned long hours = time / 3600; 1334 time_split_units(UNIT_MS, labs(t), &units_in);
1109 unsigned long minutes = time / 60 - hours * 60; 1335 int hashours = units_in[UNIT_IDX_HR] > 0;
1110 unsigned long seconds = time % 60;
1111 int hashours = hours > 0;
1112 snprintf(buf, buf_size, "%.*s%.0lu%.*s%.*lu:%.2lu", 1336 snprintf(buf, buf_size, "%.*s%.0lu%.*s%.*lu:%.2lu",
1113 t < 0, "-", hours, hashours, ":", hashours+1, minutes, seconds); 1337 t < 0, "-", units_in[UNIT_IDX_HR], hashours, ":",
1338 hashours+1, units_in[UNIT_IDX_MIN], units_in[UNIT_IDX_SEC]);
1114} 1339}
1115 1340
1116/** 1341/**