Files
fastfetch/src/common/format.c
T

275 lines
9.5 KiB
C
Raw Normal View History

2021-04-09 14:07:05 +02:00
#include "fastfetch.h"
#include "common/format.h"
2022-09-05 17:42:42 +02:00
#include "common/parsing.h"
2022-12-06 17:03:31 +08:00
#include "util/textModifier.h"
2021-04-09 14:07:05 +02:00
2022-10-13 18:12:54 +08:00
#include <inttypes.h>
2021-04-16 17:46:50 +02:00
void ffFormatAppendFormatArg(FFstrbuf* buffer, const FFformatarg* formatarg)
{
if(formatarg->type == FF_FORMAT_ARG_TYPE_INT)
ffStrbufAppendF(buffer, "%i", *(int*)formatarg->value);
else if(formatarg->type == FF_FORMAT_ARG_TYPE_UINT)
2022-10-13 18:12:54 +08:00
ffStrbufAppendF(buffer, "%" PRIu32, *(uint32_t*)formatarg->value);
2021-10-18 22:38:00 +08:00
else if(formatarg->type == FF_FORMAT_ARG_TYPE_UINT16)
2022-10-13 18:12:54 +08:00
ffStrbufAppendF(buffer, "%" PRIu16, *(uint16_t*)formatarg->value);
2021-04-16 17:46:50 +02:00
else if(formatarg->type == FF_FORMAT_ARG_TYPE_UINT8)
2022-10-13 18:12:54 +08:00
ffStrbufAppendF(buffer, "%" PRIu8, *(uint8_t*)formatarg->value);
2021-04-16 17:46:50 +02:00
else if(formatarg->type == FF_FORMAT_ARG_TYPE_STRING)
2021-05-09 12:30:10 +02:00
ffStrbufAppendS(buffer, (const char*)formatarg->value);
2021-04-16 17:46:50 +02:00
else if(formatarg->type == FF_FORMAT_ARG_TYPE_STRBUF)
ffStrbufAppend(buffer, (FFstrbuf*)formatarg->value);
else if(formatarg->type == FF_FORMAT_ARG_TYPE_DOUBLE)
ffStrbufAppendF(buffer, "%g", *(double*)formatarg->value);
2022-10-17 13:19:48 +02:00
else if(formatarg->type == FF_FORMAT_ARG_TYPE_BOOL)
ffStrbufAppendS(buffer, formatarg->value != NULL ? "true" : "false");
2021-05-23 19:40:34 +02:00
else if(formatarg->type == FF_FORMAT_ARG_TYPE_LIST)
{
const FFlist* list = formatarg->value;
for(uint32_t i = 0; i < list->length; i++)
{
ffStrbufAppend(buffer, ffListGet(list, i));
if(i < list->length - 1)
ffStrbufAppendS(buffer, ", ");
}
}
2021-04-16 17:46:50 +02:00
else if(formatarg->type != FF_FORMAT_ARG_TYPE_NULL)
{
fprintf(stderr, "Error: format string \"%s\": argument is not implemented: %i\n", buffer->chars, formatarg->type);
}
}
/**
* @brief parses a string to a uint32_t
*
* If the string can't be parsed, or is < 1, uint32_t max is returned.
*
* @param placeholderValue the string to parse
* @return uint32_t the parsed value
*/
2021-04-24 21:42:48 +02:00
static inline uint32_t getArgumentIndex(const FFstrbuf* placeholderValue)
{
uint32_t result = UINT32_MAX;
if(placeholderValue->chars[0] != '-')
sscanf(placeholderValue->chars, "%u", &result);
return result == 0 ? UINT32_MAX : result;
2021-04-24 21:42:48 +02:00
}
static inline void appendInvalidPlaceholder(FFstrbuf* buffer, const char* start, const FFstrbuf* placeholderValue, uint32_t index, uint32_t formatStringLength)
{
ffStrbufAppendS(buffer, start);
ffStrbufAppend(buffer, placeholderValue);
if(index < formatStringLength)
ffStrbufAppendC(buffer, '}');
}
static inline void appendEmptyPlaceholder(FFstrbuf* buffer, const char* placeholder, uint32_t* argCounter, uint32_t numArgs, const FFformatarg* arguments)
{
if(*argCounter >= numArgs)
2021-04-24 21:42:48 +02:00
ffStrbufAppendS(buffer, placeholder);
else
ffFormatAppendFormatArg(buffer, arguments + *argCounter);
(*argCounter)++;
2021-04-24 21:42:48 +02:00
}
static inline bool formatArgSet(const FFformatarg* arg)
{
return arg->value != NULL && (
2022-09-05 17:42:42 +02:00
(arg->type == FF_FORMAT_ARG_TYPE_DOUBLE && *(double*)arg->value > 0.0) || //Also is false for NaN
2021-04-24 21:42:48 +02:00
(arg->type == FF_FORMAT_ARG_TYPE_INT && *(int*)arg->value > 0) ||
(arg->type == FF_FORMAT_ARG_TYPE_STRBUF && ((FFstrbuf*)arg->value)->length > 0) ||
2022-09-05 17:42:42 +02:00
(arg->type == FF_FORMAT_ARG_TYPE_STRING && ffStrSet(arg->value)) ||
2021-04-24 21:42:48 +02:00
(arg->type == FF_FORMAT_ARG_TYPE_UINT8 && *(uint8_t*)arg->value > 0) ||
2021-10-18 22:38:00 +08:00
(arg->type == FF_FORMAT_ARG_TYPE_UINT16 && *(uint16_t*)arg->value > 0) ||
2022-10-17 13:19:48 +02:00
(arg->type == FF_FORMAT_ARG_TYPE_UINT && *(uint32_t*)arg->value > 0) ||
(arg->type == FF_FORMAT_ARG_TYPE_BOOL && arg->value != NULL)
2021-04-24 21:42:48 +02:00
);
}
2022-06-17 18:15:36 +02:00
void ffParseFormatString(FFstrbuf* buffer, const FFstrbuf* formatstr, uint32_t numArgs, const FFformatarg* arguments)
2021-04-09 14:07:05 +02:00
{
2021-04-24 21:42:48 +02:00
uint32_t argCounter = 0;
uint32_t numOpenIfs = 0;
uint32_t numOpenNotIfs = 0;
2021-04-25 09:13:18 +02:00
uint32_t numOpenColors = 0;
2021-04-09 14:07:05 +02:00
for(uint32_t i = 0; i < formatstr->length; ++i)
{
2021-04-24 21:42:48 +02:00
// if we don't have a placeholder start just copy the chars over to output buffer
2021-04-09 14:07:05 +02:00
if(formatstr->chars[i] != '{')
{
ffStrbufAppendC(buffer, formatstr->chars[i]);
continue;
}
2021-04-24 21:42:48 +02:00
// if we have an { at the end handle it as {}
2021-04-09 14:07:05 +02:00
if(i == formatstr->length - 1)
{
2021-04-24 21:42:48 +02:00
appendEmptyPlaceholder(buffer, "{", &argCounter, numArgs, arguments);
continue;
2021-04-09 14:07:05 +02:00
}
2021-04-24 21:42:48 +02:00
// jump to next char, the start of the placeholder value
2021-04-09 14:07:05 +02:00
++i;
2021-04-24 21:42:48 +02:00
// double {{ elvaluates to a single { and doesn't count as start
2021-04-09 14:07:05 +02:00
if(formatstr->chars[i] == '{')
{
ffStrbufAppendC(buffer, '{');
continue;
}
2021-04-24 21:42:48 +02:00
// placeholder is {}
2021-04-09 14:07:05 +02:00
if(formatstr->chars[i] == '}')
{
2021-04-24 21:42:48 +02:00
appendEmptyPlaceholder(buffer, "{}", &argCounter, numArgs, arguments);
continue;
}
FFstrbuf placeholderValue;
ffStrbufInit(&placeholderValue);
2021-05-13 12:27:44 +02:00
while(i < formatstr->length && formatstr->chars[i] != '}')
2021-04-24 21:42:48 +02:00
ffStrbufAppendC(&placeholderValue, formatstr->chars[i++]);
// test if for stop, if so break the loop
if(placeholderValue.length == 1 && placeholderValue.chars[0] == '-')
{
ffStrbufDestroy(&placeholderValue);
break;
}
// test for end of an if, if so do nothing
if(placeholderValue.length == 1 && placeholderValue.chars[0] == '?')
{
if(numOpenIfs == 0)
appendInvalidPlaceholder(buffer, "{", &placeholderValue, i, formatstr->length);
else
--numOpenIfs;
ffStrbufDestroy(&placeholderValue);
continue;
}
// test for end of a not if, if so do nothing
if(placeholderValue.length == 1 && placeholderValue.chars[0] == '/')
{
if(numOpenNotIfs == 0)
appendInvalidPlaceholder(buffer, "{", &placeholderValue, i, formatstr->length);
else
--numOpenNotIfs;
ffStrbufDestroy(&placeholderValue);
continue;
}
2021-04-25 09:13:18 +02:00
// test for end of a color, if so do nothing
if(placeholderValue.length == 1 && placeholderValue.chars[0] == '#')
{
if(numOpenColors == 0)
appendInvalidPlaceholder(buffer, "{", &placeholderValue, i, formatstr->length);
else
{
2022-04-08 15:50:49 +02:00
ffStrbufAppendS(buffer, FASTFETCH_TEXT_MODIFIER_RESET);
2021-04-25 09:13:18 +02:00
--numOpenColors;
}
ffStrbufDestroy(&placeholderValue);
continue;
}
2021-04-24 21:42:48 +02:00
// test for if, if so evaluate it
if(placeholderValue.chars[0] == '?')
{
ffStrbufSubstrAfter(&placeholderValue, 0);
uint32_t index = getArgumentIndex(&placeholderValue);
// testing for an invalid index
if(index > numArgs)
{
appendInvalidPlaceholder(buffer, "{?", &placeholderValue, i, formatstr->length);
ffStrbufDestroy(&placeholderValue);
continue;
}
// continue normally if an format arg is set and the value is > 0
if(formatArgSet(&arguments[index - 1]))
2021-04-09 14:07:05 +02:00
{
2021-04-24 21:42:48 +02:00
++numOpenIfs;
ffStrbufDestroy(&placeholderValue);
2021-04-09 14:07:05 +02:00
continue;
}
2021-04-24 21:42:48 +02:00
// fastforward to the end of the if without printing the in between
2021-06-26 15:34:01 +02:00
i = ffStrbufNextIndexS(formatstr, i, "{?}") + 2; // 2 is the length of "{?}" - 1 because the loop will increament it again directly after continue
2021-04-24 21:42:48 +02:00
ffStrbufDestroy(&placeholderValue);
continue;
2021-04-09 14:07:05 +02:00
}
2021-04-24 21:42:48 +02:00
// test for not if, if so evaluate it
if(placeholderValue.chars[0] == '/')
2021-04-09 14:07:05 +02:00
{
2021-04-24 21:42:48 +02:00
ffStrbufSubstrAfter(&placeholderValue, 0);
uint32_t index = getArgumentIndex(&placeholderValue);
// testing for an invalid index
if(index > numArgs)
{
appendInvalidPlaceholder(buffer, "{/", &placeholderValue, i, formatstr->length);
ffStrbufDestroy(&placeholderValue);
2021-04-09 14:07:05 +02:00
continue;
}
2021-04-24 21:42:48 +02:00
//continue normally if an format arg is not set or the value is 0
if(!formatArgSet(&arguments[index - 1]))
{
++numOpenNotIfs;
ffStrbufDestroy(&placeholderValue);
continue;
}
// fastforward to the end of the if without printing the in between
2021-06-26 15:34:01 +02:00
i = ffStrbufNextIndexS(formatstr, i, "{/}") + 2; // 2 is the length of "{/}" - 1 because the loop will increament it again directly after continue
2021-04-24 21:42:48 +02:00
ffStrbufDestroy(&placeholderValue);
continue;
}
2021-04-25 09:13:18 +02:00
//test for color, if so evaluate it
if(placeholderValue.chars[0] == '#')
{
++numOpenColors;
ffStrbufSubstrAfter(&placeholderValue, 0);
ffStrbufAppendS(buffer, "\033[");
ffStrbufAppend(buffer, &placeholderValue);
ffStrbufAppendC(buffer, 'm');
ffStrbufDestroy(&placeholderValue);
continue;
}
2021-04-24 21:42:48 +02:00
uint32_t index = getArgumentIndex(&placeholderValue);
// test for invalid index
if(index > numArgs)
{
appendInvalidPlaceholder(buffer, "{", &placeholderValue, i, formatstr->length);
ffStrbufDestroy(&placeholderValue);
continue;
2021-04-09 14:07:05 +02:00
}
2021-04-24 21:42:48 +02:00
ffFormatAppendFormatArg(buffer, &arguments[index - 1]);
ffStrbufDestroy(&placeholderValue);
2021-04-09 14:07:05 +02:00
}
ffStrbufTrimRight(buffer, ' ');
2021-04-25 09:13:18 +02:00
2022-04-08 15:50:49 +02:00
ffStrbufAppendS(buffer, FASTFETCH_TEXT_MODIFIER_RESET);
2021-04-09 14:07:05 +02:00
}