+#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__) || defined(__OpenBSD__)
+ /* These OSes report battery time in minutes. */
+ hide_seconds = true;
+#endif
+
+ if (number < 0) {
+ if (!slurp_all_batteries(&batt_info, json_gen, buffer, path, format_down))
+ return;
+ } else {
+ if (!slurp_battery_info(&batt_info, json_gen, buffer, number, path, format_down))
+ return;
+ }
+
+ int full = (last_full_capacity ? batt_info.full_last : batt_info.full_design);
+ if (full < 0 && batt_info.percentage_remaining < 0) {
+ /* We have no physical measurements and no estimates. Nothing
+ * much we can report, then. */
+ OUTPUT_FULL_TEXT(format_down);
+ return;
+ }
+
+ if (batt_info.percentage_remaining < 0) {
+ batt_info.percentage_remaining = (((float)batt_info.remaining / (float)full) * 100);
+ /* Some batteries report POWER_SUPPLY_CHARGE_NOW=<full_design> when fully
+ * charged, even though that’s plainly wrong. For people who chose to see
+ * the percentage calculated based on the last full capacity, we clamp the
+ * value to 100%, as that makes more sense.
+ * See http://bugs.debian.org/785398 */
+ if (last_full_capacity && batt_info.percentage_remaining > 100) {
+ batt_info.percentage_remaining = 100;
+ }
+ }
+
+ if (batt_info.seconds_remaining < 0 && batt_info.present_rate > 0 && batt_info.status != CS_FULL) {
+ if (batt_info.status == CS_CHARGING)
+ batt_info.seconds_remaining = 3600.0 * (full - batt_info.remaining) / batt_info.present_rate;
+ else if (batt_info.status == CS_DISCHARGING)
+ batt_info.seconds_remaining = 3600.0 * batt_info.remaining / batt_info.present_rate;
+ else
+ batt_info.seconds_remaining = 0;
+ }
+
+ if (batt_info.status == CS_DISCHARGING && low_threshold > 0) {
+ if (batt_info.percentage_remaining >= 0 && strcasecmp(threshold_type, "percentage") == 0 && batt_info.percentage_remaining < low_threshold) {
+ START_COLOR("color_bad");
+ colorful_output = true;
+ } else if (batt_info.seconds_remaining >= 0 && strcasecmp(threshold_type, "time") == 0 && batt_info.seconds_remaining < 60 * low_threshold) {
+ START_COLOR("color_bad");
+ colorful_output = true;
+ }
+ }
+
+#define EAT_SPACE_FROM_OUTPUT_IF_NO_OUTPUT() \
+ do { \
+ if (outwalk == prevoutwalk) { \
+ if (outwalk > buffer && isspace((int)outwalk[-1])) \
+ outwalk--; \
+ else if (isspace((int)*(walk + 1))) \
+ walk++; \
+ } \
+ } while (0)
+
+ for (walk = format; *walk != '\0'; walk++) {
+ char *prevoutwalk = outwalk;
+
+ if (*walk != '%') {
+ *(outwalk++) = *walk;
+ continue;
+ }
+
+ if (BEGINS_WITH(walk + 1, "status")) {
+ const char *statusstr;
+ switch (batt_info.status) {
+ case CS_CHARGING:
+ statusstr = status_chr;
+ break;
+ case CS_DISCHARGING:
+ statusstr = status_bat;
+ break;
+ case CS_FULL:
+ statusstr = status_full;
+ break;
+ default:
+ statusstr = status_unk;
+ }
+
+ outwalk += sprintf(outwalk, "%s", statusstr);
+ walk += strlen("status");
+ } else if (BEGINS_WITH(walk + 1, "percentage")) {
+ if (integer_battery_capacity) {
+ outwalk += sprintf(outwalk, "%.00f%s", batt_info.percentage_remaining, pct_mark);
+ } else {
+ outwalk += sprintf(outwalk, "%.02f%s", batt_info.percentage_remaining, pct_mark);
+ }
+ walk += strlen("percentage");
+ } else if (BEGINS_WITH(walk + 1, "remaining")) {
+ if (batt_info.seconds_remaining >= 0) {
+ int seconds, hours, minutes;
+
+ hours = batt_info.seconds_remaining / 3600;
+ seconds = batt_info.seconds_remaining - (hours * 3600);
+ minutes = seconds / 60;
+ seconds -= (minutes * 60);
+
+ if (hide_seconds)
+ outwalk += sprintf(outwalk, "%02d:%02d",
+ max(hours, 0), max(minutes, 0));
+ else
+ outwalk += sprintf(outwalk, "%02d:%02d:%02d",
+ max(hours, 0), max(minutes, 0), max(seconds, 0));
+ }
+ walk += strlen("remaining");
+ EAT_SPACE_FROM_OUTPUT_IF_NO_OUTPUT();
+ } else if (BEGINS_WITH(walk + 1, "emptytime")) {
+ if (batt_info.seconds_remaining >= 0) {
+ time_t empty_time = time(NULL) + batt_info.seconds_remaining;
+ struct tm *empty_tm = localtime(&empty_time);
+
+ if (hide_seconds)
+ outwalk += sprintf(outwalk, "%02d:%02d",
+ max(empty_tm->tm_hour, 0), max(empty_tm->tm_min, 0));
+ else
+ outwalk += sprintf(outwalk, "%02d:%02d:%02d",
+ max(empty_tm->tm_hour, 0), max(empty_tm->tm_min, 0), max(empty_tm->tm_sec, 0));
+ }
+ walk += strlen("emptytime");
+ EAT_SPACE_FROM_OUTPUT_IF_NO_OUTPUT();
+ } else if (BEGINS_WITH(walk + 1, "consumption")) {
+ if (batt_info.present_rate >= 0)
+ outwalk += sprintf(outwalk, "%1.2fW", batt_info.present_rate / 1e6);
+
+ walk += strlen("consumption");
+ EAT_SPACE_FROM_OUTPUT_IF_NO_OUTPUT();
+ }
+ }
+
+ if (colorful_output)
+ END_COLOR;
+
+ OUTPUT_FULL_TEXT(buffer);