|
@@ -23,49 +23,73 @@ typedef struct {
|
|
|
} UnitDef;
|
|
} UnitDef;
|
|
|
|
|
|
|
|
static const UnitDef UNITS[] = {
|
|
static const UnitDef UNITS[] = {
|
|
|
- {"metre", {"m", "metres", "meter", "meters"}, UNIT_LENGTH, 1.0},
|
|
|
|
|
- {"kilometre", {"km", "kilometres", "kilometer", "kilometers"}, UNIT_LENGTH, 1000.0},
|
|
|
|
|
- {"centimetre", {"cm", "centimetres", "centimeter", "centimeters"}, UNIT_LENGTH, 0.01},
|
|
|
|
|
- {"millimetre", {"mm", "millimetres", "millimeter", "millimeters"}, UNIT_LENGTH, 0.001},
|
|
|
|
|
- {"mile", {"mi", "miles"}, UNIT_LENGTH, 1609.344},
|
|
|
|
|
- {"yard", {"yd", "yards"}, UNIT_LENGTH, 0.9144},
|
|
|
|
|
- {"foot", {"ft", "feet", "'"}, UNIT_LENGTH, 0.3048},
|
|
|
|
|
- {"inch", {"in", "inches", "\""}, UNIT_LENGTH, 0.0254},
|
|
|
|
|
-
|
|
|
|
|
- {"kilogram", {"kg", "kilograms", "kilo", "kilos"}, UNIT_WEIGHT, 1.0},
|
|
|
|
|
- {"gram", {"g", "grams"}, UNIT_WEIGHT, 0.001},
|
|
|
|
|
- {"milligram", {"mg", "milligrams"}, UNIT_WEIGHT, 0.000001},
|
|
|
|
|
- {"pound", {"lb", "lbs", "pounds"}, UNIT_WEIGHT, 0.453592},
|
|
|
|
|
- {"ounce", {"oz", "ounces"}, UNIT_WEIGHT, 0.0283495},
|
|
|
|
|
- {"tonne", {"tonnes", "tons", "ton"}, UNIT_WEIGHT, 1000.0},
|
|
|
|
|
- {"stone", {"st", "stones"}, UNIT_WEIGHT, 6.35029},
|
|
|
|
|
-
|
|
|
|
|
- {"celsius", {"c", "°c", "degrees celsius", "degrees c"}, UNIT_TEMP, 1.0},
|
|
|
|
|
- {"fahrenheit", {"f", "°f", "degrees fahrenheit", "degrees f"}, UNIT_TEMP, 1.0},
|
|
|
|
|
- {"kelvin", {"k", "degrees kelvin", "degrees k"}, UNIT_TEMP, 1.0},
|
|
|
|
|
-
|
|
|
|
|
- {"litre", {"l", "litres", "liter", "liters"}, UNIT_VOLUME, 1.0},
|
|
|
|
|
- {"millilitre", {"ml", "millilitres", "milliliter", "milliliters"}, UNIT_VOLUME, 0.001},
|
|
|
|
|
- {"gallon", {"gal", "gallons"}, UNIT_VOLUME, 3.78541},
|
|
|
|
|
- {"quart", {"qt", "quarts"}, UNIT_VOLUME, 0.946353},
|
|
|
|
|
- {"pint", {"pt", "pints"}, UNIT_VOLUME, 0.473176},
|
|
|
|
|
- {"cup", {"cups"}, UNIT_VOLUME, 0.236588},
|
|
|
|
|
- {"fluid ounce", {"fl oz", "fluid ounces"}, UNIT_VOLUME, 0.0295735},
|
|
|
|
|
-
|
|
|
|
|
- {"square metre", {"sqm", "sq m", "m2", "square metres"}, UNIT_AREA, 1.0},
|
|
|
|
|
- {"square foot", {"sqft", "sq ft", "ft2", "square feet"}, UNIT_AREA, 0.092903},
|
|
|
|
|
- {"square kilometre", {"sqkm", "sq km", "km2", "square kilometres"}, UNIT_AREA, 1000000.0},
|
|
|
|
|
- {"square mile", {"sqmi", "sq mi", "mi2", "square miles"}, UNIT_AREA, 2589988.0},
|
|
|
|
|
- {"acre", {"acres"}, UNIT_AREA, 4046.86},
|
|
|
|
|
- {"hectare", {"ha", "hectares"}, UNIT_AREA, 10000.0},
|
|
|
|
|
-
|
|
|
|
|
- {"second", {"sec", "seconds", "s"}, UNIT_TIME, 1.0},
|
|
|
|
|
- {"minute", {"min", "minutes"}, UNIT_TIME, 60.0},
|
|
|
|
|
- {"hour", {"hr", "hours", "h"}, UNIT_TIME, 3600.0},
|
|
|
|
|
- {"day", {"days", "d"}, UNIT_TIME, 86400.0},
|
|
|
|
|
- {"week", {"weeks", "wk"}, UNIT_TIME, 604800.0},
|
|
|
|
|
- {"month", {"months", "mo"}, UNIT_TIME, 2629746.0},
|
|
|
|
|
- {"year", {"years", "yr"}, UNIT_TIME, 31556952.0},
|
|
|
|
|
|
|
+ {"metre", {"m", "metres", "meter", "meters"}, UNIT_LENGTH, 1.0},
|
|
|
|
|
+ {"kilometre",
|
|
|
|
|
+ {"km", "kilometres", "kilometer", "kilometers"},
|
|
|
|
|
+ UNIT_LENGTH,
|
|
|
|
|
+ 1000.0},
|
|
|
|
|
+ {"centimetre",
|
|
|
|
|
+ {"cm", "centimetres", "centimeter", "centimeters"},
|
|
|
|
|
+ UNIT_LENGTH,
|
|
|
|
|
+ 0.01},
|
|
|
|
|
+ {"millimetre",
|
|
|
|
|
+ {"mm", "millimetres", "millimeter", "millimeters"},
|
|
|
|
|
+ UNIT_LENGTH,
|
|
|
|
|
+ 0.001},
|
|
|
|
|
+ {"mile", {"mi", "miles"}, UNIT_LENGTH, 1609.344},
|
|
|
|
|
+ {"yard", {"yd", "yards"}, UNIT_LENGTH, 0.9144},
|
|
|
|
|
+ {"foot", {"ft", "feet", "'"}, UNIT_LENGTH, 0.3048},
|
|
|
|
|
+ {"inch", {"in", "inches", "\""}, UNIT_LENGTH, 0.0254},
|
|
|
|
|
+
|
|
|
|
|
+ {"kilogram", {"kg", "kilograms", "kilo", "kilos"}, UNIT_WEIGHT, 1.0},
|
|
|
|
|
+ {"gram", {"g", "grams"}, UNIT_WEIGHT, 0.001},
|
|
|
|
|
+ {"milligram", {"mg", "milligrams"}, UNIT_WEIGHT, 0.000001},
|
|
|
|
|
+ {"pound", {"lb", "lbs", "pounds"}, UNIT_WEIGHT, 0.453592},
|
|
|
|
|
+ {"ounce", {"oz", "ounces"}, UNIT_WEIGHT, 0.0283495},
|
|
|
|
|
+ {"tonne", {"tonnes", "tons", "ton"}, UNIT_WEIGHT, 1000.0},
|
|
|
|
|
+ {"stone", {"st", "stones"}, UNIT_WEIGHT, 6.35029},
|
|
|
|
|
+
|
|
|
|
|
+ {"celsius", {"c", "°c", "degrees celsius", "degrees c"}, UNIT_TEMP, 1.0},
|
|
|
|
|
+ {"fahrenheit",
|
|
|
|
|
+ {"f", "°f", "degrees fahrenheit", "degrees f"},
|
|
|
|
|
+ UNIT_TEMP,
|
|
|
|
|
+ 1.0},
|
|
|
|
|
+ {"kelvin", {"k", "degrees kelvin", "degrees k"}, UNIT_TEMP, 1.0},
|
|
|
|
|
+
|
|
|
|
|
+ {"litre", {"l", "litres", "liter", "liters"}, UNIT_VOLUME, 1.0},
|
|
|
|
|
+ {"millilitre",
|
|
|
|
|
+ {"ml", "millilitres", "milliliter", "milliliters"},
|
|
|
|
|
+ UNIT_VOLUME,
|
|
|
|
|
+ 0.001},
|
|
|
|
|
+ {"gallon", {"gal", "gallons"}, UNIT_VOLUME, 3.78541},
|
|
|
|
|
+ {"quart", {"qt", "quarts"}, UNIT_VOLUME, 0.946353},
|
|
|
|
|
+ {"pint", {"pt", "pints"}, UNIT_VOLUME, 0.473176},
|
|
|
|
|
+ {"cup", {"cups"}, UNIT_VOLUME, 0.236588},
|
|
|
|
|
+ {"fluid ounce", {"fl oz", "fluid ounces"}, UNIT_VOLUME, 0.0295735},
|
|
|
|
|
+
|
|
|
|
|
+ {"square metre", {"sqm", "sq m", "m2", "square metres"}, UNIT_AREA, 1.0},
|
|
|
|
|
+ {"square foot",
|
|
|
|
|
+ {"sqft", "sq ft", "ft2", "square feet"},
|
|
|
|
|
+ UNIT_AREA,
|
|
|
|
|
+ 0.092903},
|
|
|
|
|
+ {"square kilometre",
|
|
|
|
|
+ {"sqkm", "sq km", "km2", "square kilometres"},
|
|
|
|
|
+ UNIT_AREA,
|
|
|
|
|
+ 1000000.0},
|
|
|
|
|
+ {"square mile",
|
|
|
|
|
+ {"sqmi", "sq mi", "mi2", "square miles"},
|
|
|
|
|
+ UNIT_AREA,
|
|
|
|
|
+ 2589988.0},
|
|
|
|
|
+ {"acre", {"acres"}, UNIT_AREA, 4046.86},
|
|
|
|
|
+ {"hectare", {"ha", "hectares"}, UNIT_AREA, 10000.0},
|
|
|
|
|
+
|
|
|
|
|
+ {"second", {"sec", "seconds", "s"}, UNIT_TIME, 1.0},
|
|
|
|
|
+ {"minute", {"min", "minutes"}, UNIT_TIME, 60.0},
|
|
|
|
|
+ {"hour", {"hr", "hours", "h"}, UNIT_TIME, 3600.0},
|
|
|
|
|
+ {"day", {"days", "d"}, UNIT_TIME, 86400.0},
|
|
|
|
|
+ {"week", {"weeks", "wk"}, UNIT_TIME, 604800.0},
|
|
|
|
|
+ {"month", {"months", "mo"}, UNIT_TIME, 2629746.0},
|
|
|
|
|
+ {"year", {"years", "yr"}, UNIT_TIME, 31556952.0},
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
static const int UNIT_COUNT = sizeof(UNITS) / sizeof(UNITS[0]);
|
|
static const int UNIT_COUNT = sizeof(UNITS) / sizeof(UNITS[0]);
|
|
@@ -75,136 +99,142 @@ static int is_whitespace(char c) {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
static const UnitDef *find_unit(const char *str) {
|
|
static const UnitDef *find_unit(const char *str) {
|
|
|
- if (!str || !*str) return NULL;
|
|
|
|
|
|
|
+ if (!str || !*str)
|
|
|
|
|
+ return NULL;
|
|
|
|
|
|
|
|
size_t len = strlen(str);
|
|
size_t len = strlen(str);
|
|
|
char normalized[64] = {0};
|
|
char normalized[64] = {0};
|
|
|
size_t j = 0;
|
|
size_t j = 0;
|
|
|
|
|
|
|
|
for (size_t i = 0; i < len && j < 63; i++) {
|
|
for (size_t i = 0; i < len && j < 63; i++) {
|
|
|
- if ((unsigned char)str[i] == 0xC2 && (unsigned char)str[i+1] == 0xB0) {
|
|
|
|
|
- i++;
|
|
|
|
|
- continue;
|
|
|
|
|
- }
|
|
|
|
|
- if (str[i] == '^' && i + 1 < len && str[i + 1] == '2') {
|
|
|
|
|
- normalized[j++] = '2';
|
|
|
|
|
- i++;
|
|
|
|
|
- continue;
|
|
|
|
|
- }
|
|
|
|
|
- normalized[j++] = tolower((unsigned char)str[i]);
|
|
|
|
|
|
|
+ if ((unsigned char)str[i] == 0xC2 && (unsigned char)str[i + 1] == 0xB0) {
|
|
|
|
|
+ i++;
|
|
|
|
|
+ continue;
|
|
|
|
|
+ }
|
|
|
|
|
+ if (str[i] == '^' && i + 1 < len && str[i + 1] == '2') {
|
|
|
|
|
+ normalized[j++] = '2';
|
|
|
|
|
+ i++;
|
|
|
|
|
+ continue;
|
|
|
|
|
+ }
|
|
|
|
|
+ normalized[j++] = tolower((unsigned char)str[i]);
|
|
|
}
|
|
}
|
|
|
normalized[j] = '\0';
|
|
normalized[j] = '\0';
|
|
|
|
|
|
|
|
for (int i = 0; i < UNIT_COUNT; i++) {
|
|
for (int i = 0; i < UNIT_COUNT; i++) {
|
|
|
- if (strcmp(normalized, UNITS[i].name) == 0) return &UNITS[i];
|
|
|
|
|
- for (int k = 0; k < 4 && UNITS[i].alias[k]; k++) {
|
|
|
|
|
- if (strcmp(normalized, UNITS[i].alias[k]) == 0) return &UNITS[i];
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ if (strcmp(normalized, UNITS[i].name) == 0)
|
|
|
|
|
+ return &UNITS[i];
|
|
|
|
|
+ for (int k = 0; k < 4 && UNITS[i].alias[k]; k++) {
|
|
|
|
|
+ if (strcmp(normalized, UNITS[i].alias[k]) == 0)
|
|
|
|
|
+ return &UNITS[i];
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
return NULL;
|
|
return NULL;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
int is_unit_conv_query(const char *query) {
|
|
int is_unit_conv_query(const char *query) {
|
|
|
- if (!query) return 0;
|
|
|
|
|
|
|
+ if (!query)
|
|
|
|
|
+ return 0;
|
|
|
|
|
|
|
|
- const char *patterns[] = {
|
|
|
|
|
- " to ", " in ", " into ",
|
|
|
|
|
- " = ", " equals ", " equal ",
|
|
|
|
|
- " convert ", " conversion ",
|
|
|
|
|
- " -> ", " → ",
|
|
|
|
|
- NULL
|
|
|
|
|
- };
|
|
|
|
|
|
|
+ const char *patterns[] = {" to ", " in ", " into ", " = ",
|
|
|
|
|
+ " equals ", " equal ", " convert ", " conversion ",
|
|
|
|
|
+ " -> ", " → ", NULL};
|
|
|
|
|
|
|
|
int has_pattern = 0;
|
|
int has_pattern = 0;
|
|
|
for (int i = 0; patterns[i]; i++) {
|
|
for (int i = 0; patterns[i]; i++) {
|
|
|
- if (strstr(query, patterns[i])) {
|
|
|
|
|
- has_pattern = 1;
|
|
|
|
|
- break;
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ if (strstr(query, patterns[i])) {
|
|
|
|
|
+ has_pattern = 1;
|
|
|
|
|
+ break;
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
if (!has_pattern) {
|
|
if (!has_pattern) {
|
|
|
- const char *last_space = strrchr(query, ' ');
|
|
|
|
|
- if (last_space) {
|
|
|
|
|
- const UnitDef *u = find_unit(last_space + 1);
|
|
|
|
|
- if (u) {
|
|
|
|
|
- const char *before = query;
|
|
|
|
|
- while (*before && is_whitespace(*before)) before++;
|
|
|
|
|
- const char *num_end = before;
|
|
|
|
|
- while (*num_end &&
|
|
|
|
|
- (isdigit(*num_end) || *num_end == '.' || *num_end == '-' ||
|
|
|
|
|
- *num_end == '+' || *num_end == '/' || *num_end == '\'' || *num_end == '"')) {
|
|
|
|
|
- num_end++;
|
|
|
|
|
- }
|
|
|
|
|
- if (num_end > before) has_pattern = 1;
|
|
|
|
|
|
|
+ const char *last_space = strrchr(query, ' ');
|
|
|
|
|
+ if (last_space) {
|
|
|
|
|
+ const UnitDef *u = find_unit(last_space + 1);
|
|
|
|
|
+ if (u) {
|
|
|
|
|
+ const char *before = query;
|
|
|
|
|
+ while (*before && is_whitespace(*before))
|
|
|
|
|
+ before++;
|
|
|
|
|
+ const char *num_end = before;
|
|
|
|
|
+ while (*num_end &&
|
|
|
|
|
+ (isdigit(*num_end) || *num_end == '.' || *num_end == '-' ||
|
|
|
|
|
+ *num_end == '+' || *num_end == '/' || *num_end == '\'' ||
|
|
|
|
|
+ *num_end == '"')) {
|
|
|
|
|
+ num_end++;
|
|
|
|
|
+ }
|
|
|
|
|
+ if (num_end > before)
|
|
|
|
|
+ has_pattern = 1;
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
- }
|
|
|
|
|
|
|
|
|
|
return has_pattern;
|
|
return has_pattern;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
static double parse_value(const char **ptr) {
|
|
static double parse_value(const char **ptr) {
|
|
|
const char *p = *ptr;
|
|
const char *p = *ptr;
|
|
|
- while (*p && is_whitespace(*p)) p++;
|
|
|
|
|
|
|
+ while (*p && is_whitespace(*p))
|
|
|
|
|
+ p++;
|
|
|
|
|
|
|
|
double value = 0.0;
|
|
double value = 0.0;
|
|
|
int has_num = 0;
|
|
int has_num = 0;
|
|
|
|
|
|
|
|
- if (*p == '-' || *p == '+') p++;
|
|
|
|
|
- while (*p >= '0' && *p <= '9') {
|
|
|
|
|
- value = value * 10 + (*p - '0');
|
|
|
|
|
- has_num = 1;
|
|
|
|
|
- p++;
|
|
|
|
|
- }
|
|
|
|
|
- if (*p == '.') {
|
|
|
|
|
- p++;
|
|
|
|
|
- double frac = 0.1;
|
|
|
|
|
|
|
+ if (*p == '-' || *p == '+')
|
|
|
|
|
+ p++;
|
|
|
while (*p >= '0' && *p <= '9') {
|
|
while (*p >= '0' && *p <= '9') {
|
|
|
- value += (*p - '0') * frac;
|
|
|
|
|
- frac *= 0.1;
|
|
|
|
|
|
|
+ value = value * 10 + (*p - '0');
|
|
|
has_num = 1;
|
|
has_num = 1;
|
|
|
p++;
|
|
p++;
|
|
|
}
|
|
}
|
|
|
|
|
+ if (*p == '.') {
|
|
|
|
|
+ p++;
|
|
|
|
|
+ double frac = 0.1;
|
|
|
|
|
+ while (*p >= '0' && *p <= '9') {
|
|
|
|
|
+ value += (*p - '0') * frac;
|
|
|
|
|
+ frac *= 0.1;
|
|
|
|
|
+ has_num = 1;
|
|
|
|
|
+ p++;
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
if (*p == '/' && has_num) {
|
|
if (*p == '/' && has_num) {
|
|
|
- p++;
|
|
|
|
|
- double denom = 0.0;
|
|
|
|
|
- int has_denom = 0;
|
|
|
|
|
- while (*p >= '0' && *p <= '9') {
|
|
|
|
|
- denom = denom * 10 + (*p - '0');
|
|
|
|
|
- has_denom = 1;
|
|
|
|
|
p++;
|
|
p++;
|
|
|
- }
|
|
|
|
|
- if (has_denom && denom > 0) {
|
|
|
|
|
- value = value / denom;
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ double denom = 0.0;
|
|
|
|
|
+ int has_denom = 0;
|
|
|
|
|
+ while (*p >= '0' && *p <= '9') {
|
|
|
|
|
+ denom = denom * 10 + (*p - '0');
|
|
|
|
|
+ has_denom = 1;
|
|
|
|
|
+ p++;
|
|
|
|
|
+ }
|
|
|
|
|
+ if (has_denom && denom > 0) {
|
|
|
|
|
+ value = value / denom;
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
while (*p == '\'' || *p == '"') {
|
|
while (*p == '\'' || *p == '"') {
|
|
|
- double extra = 0.0;
|
|
|
|
|
- p++;
|
|
|
|
|
- while (*p >= '0' && *p <= '9') {
|
|
|
|
|
- extra = extra * 10 + (*p - '0');
|
|
|
|
|
|
|
+ double extra = 0.0;
|
|
|
p++;
|
|
p++;
|
|
|
- }
|
|
|
|
|
- if (*p == '.') {
|
|
|
|
|
- p++;
|
|
|
|
|
- double frac = 0.1;
|
|
|
|
|
while (*p >= '0' && *p <= '9') {
|
|
while (*p >= '0' && *p <= '9') {
|
|
|
- extra += (*p - '0') * frac;
|
|
|
|
|
- frac *= 0.1;
|
|
|
|
|
- p++;
|
|
|
|
|
|
|
+ extra = extra * 10 + (*p - '0');
|
|
|
|
|
+ p++;
|
|
|
}
|
|
}
|
|
|
- }
|
|
|
|
|
- if (*p == '\'' || *p == '"') p++;
|
|
|
|
|
- value += extra * (p[-1] == '\'' ? 0.3048 : 0.0254);
|
|
|
|
|
|
|
+ if (*p == '.') {
|
|
|
|
|
+ p++;
|
|
|
|
|
+ double frac = 0.1;
|
|
|
|
|
+ while (*p >= '0' && *p <= '9') {
|
|
|
|
|
+ extra += (*p - '0') * frac;
|
|
|
|
|
+ frac *= 0.1;
|
|
|
|
|
+ p++;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ if (*p == '\'' || *p == '"')
|
|
|
|
|
+ p++;
|
|
|
|
|
+ value += extra * (p[-1] == '\'' ? 0.3048 : 0.0254);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
if (!has_num) {
|
|
if (!has_num) {
|
|
|
- *ptr = p;
|
|
|
|
|
- return 0.0;
|
|
|
|
|
|
|
+ *ptr = p;
|
|
|
|
|
+ return 0.0;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
*ptr = p;
|
|
*ptr = p;
|
|
@@ -212,10 +242,13 @@ static double parse_value(const char **ptr) {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
static int is_separator(char c) {
|
|
static int is_separator(char c) {
|
|
|
- return is_whitespace(c) || c == ',' || c == '.' || c == '(' || c == ')' || c == '\0';
|
|
|
|
|
|
|
+ return is_whitespace(c) || c == ',' || c == '.' || c == '(' || c == ')' ||
|
|
|
|
|
+ c == '\0';
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-static int parse_conversion_query(const char *query, double *value, const UnitDef **from_unit, const UnitDef **to_unit) {
|
|
|
|
|
|
|
+static int parse_conversion_query(const char *query, double *value,
|
|
|
|
|
+ const UnitDef **from_unit,
|
|
|
|
|
+ const UnitDef **to_unit) {
|
|
|
*value = 0;
|
|
*value = 0;
|
|
|
*from_unit = NULL;
|
|
*from_unit = NULL;
|
|
|
*to_unit = NULL;
|
|
*to_unit = NULL;
|
|
@@ -223,127 +256,151 @@ static int parse_conversion_query(const char *query, double *value, const UnitDe
|
|
|
const char *value_end = query;
|
|
const char *value_end = query;
|
|
|
*value = parse_value(&value_end);
|
|
*value = parse_value(&value_end);
|
|
|
|
|
|
|
|
- if (value_end == query) return 0;
|
|
|
|
|
|
|
+ if (value_end == query)
|
|
|
|
|
+ return 0;
|
|
|
|
|
|
|
|
const char *p = value_end;
|
|
const char *p = value_end;
|
|
|
- while (*p && is_whitespace(*p)) p++;
|
|
|
|
|
|
|
+ while (*p && is_whitespace(*p))
|
|
|
|
|
+ p++;
|
|
|
|
|
|
|
|
size_t remaining = strlen(p);
|
|
size_t remaining = strlen(p);
|
|
|
- if (remaining < 2) return 0;
|
|
|
|
|
|
|
+ if (remaining < 2)
|
|
|
|
|
+ return 0;
|
|
|
|
|
|
|
|
- const char *to_keywords[] = {" to ", " in ", " into ", " -> ", " → ", " = ", NULL};
|
|
|
|
|
|
|
+ const char *to_keywords[] = {" to ", " in ", " into ", " -> ",
|
|
|
|
|
+ " → ", " = ", NULL};
|
|
|
const char *to_pos = NULL;
|
|
const char *to_pos = NULL;
|
|
|
size_t keyword_len = 0;
|
|
size_t keyword_len = 0;
|
|
|
for (int i = 0; to_keywords[i]; i++) {
|
|
for (int i = 0; to_keywords[i]; i++) {
|
|
|
- const char *found = strstr(p, to_keywords[i]);
|
|
|
|
|
- if (found) {
|
|
|
|
|
- to_pos = found + strlen(to_keywords[i]);
|
|
|
|
|
- keyword_len = strlen(to_keywords[i]);
|
|
|
|
|
- break;
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ const char *found = strstr(p, to_keywords[i]);
|
|
|
|
|
+ if (found) {
|
|
|
|
|
+ to_pos = found + strlen(to_keywords[i]);
|
|
|
|
|
+ keyword_len = strlen(to_keywords[i]);
|
|
|
|
|
+ break;
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
if (!to_pos) {
|
|
if (!to_pos) {
|
|
|
- const char *last_space = strrchr(p, ' ');
|
|
|
|
|
- if (last_space && last_space > p) {
|
|
|
|
|
- char from_part[64] = {0};
|
|
|
|
|
- size_t len = last_space - p;
|
|
|
|
|
- if (len < 63) {
|
|
|
|
|
- strncpy(from_part, p, len);
|
|
|
|
|
- *from_unit = find_unit(from_part);
|
|
|
|
|
- if (*from_unit) {
|
|
|
|
|
- *to_unit = find_unit(last_space + 1);
|
|
|
|
|
- return *to_unit ? 1 : 0;
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ const char *last_space = strrchr(p, ' ');
|
|
|
|
|
+ if (last_space && last_space > p) {
|
|
|
|
|
+ char from_part[64] = {0};
|
|
|
|
|
+ size_t len = last_space - p;
|
|
|
|
|
+ if (len < 63) {
|
|
|
|
|
+ strncpy(from_part, p, len);
|
|
|
|
|
+ *from_unit = find_unit(from_part);
|
|
|
|
|
+ if (*from_unit) {
|
|
|
|
|
+ *to_unit = find_unit(last_space + 1);
|
|
|
|
|
+ return *to_unit ? 1 : 0;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
- }
|
|
|
|
|
- return 0;
|
|
|
|
|
|
|
+ return 0;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
char from_part[64] = {0};
|
|
char from_part[64] = {0};
|
|
|
size_t from_len = to_pos - p - keyword_len;
|
|
size_t from_len = to_pos - p - keyword_len;
|
|
|
- if (from_len > 63) from_len = 63;
|
|
|
|
|
|
|
+ if (from_len > 63)
|
|
|
|
|
+ from_len = 63;
|
|
|
strncpy(from_part, p, from_len);
|
|
strncpy(from_part, p, from_len);
|
|
|
|
|
|
|
|
char *end_from = from_part + from_len;
|
|
char *end_from = from_part + from_len;
|
|
|
- while (end_from > from_part && is_whitespace(end_from[-1])) end_from--;
|
|
|
|
|
|
|
+ while (end_from > from_part && is_whitespace(end_from[-1]))
|
|
|
|
|
+ end_from--;
|
|
|
*end_from = '\0';
|
|
*end_from = '\0';
|
|
|
|
|
|
|
|
*from_unit = find_unit(from_part);
|
|
*from_unit = find_unit(from_part);
|
|
|
if (!*from_unit) {
|
|
if (!*from_unit) {
|
|
|
- char *end = from_part + strlen(from_part);
|
|
|
|
|
- while (end > from_part) {
|
|
|
|
|
- while (end > from_part && is_whitespace(end[-1])) end--;
|
|
|
|
|
- if (end <= from_part) break;
|
|
|
|
|
- char *start = end;
|
|
|
|
|
- while (start > from_part && !is_whitespace(start[-1])) start--;
|
|
|
|
|
- size_t word_len = end - start;
|
|
|
|
|
- memmove(from_part + word_len + 1, from_part, start - from_part);
|
|
|
|
|
- from_part[word_len] = ' ';
|
|
|
|
|
- from_part[word_len + 1] = '\0';
|
|
|
|
|
- *from_unit = find_unit(from_part);
|
|
|
|
|
- if (*from_unit) break;
|
|
|
|
|
- end = start;
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ char *end = from_part + strlen(from_part);
|
|
|
|
|
+ while (end > from_part) {
|
|
|
|
|
+ while (end > from_part && is_whitespace(end[-1]))
|
|
|
|
|
+ end--;
|
|
|
|
|
+ if (end <= from_part)
|
|
|
|
|
+ break;
|
|
|
|
|
+ char *start = end;
|
|
|
|
|
+ while (start > from_part && !is_whitespace(start[-1]))
|
|
|
|
|
+ start--;
|
|
|
|
|
+ size_t word_len = end - start;
|
|
|
|
|
+ memmove(from_part + word_len + 1, from_part, start - from_part);
|
|
|
|
|
+ from_part[word_len] = ' ';
|
|
|
|
|
+ from_part[word_len + 1] = '\0';
|
|
|
|
|
+ *from_unit = find_unit(from_part);
|
|
|
|
|
+ if (*from_unit)
|
|
|
|
|
+ break;
|
|
|
|
|
+ end = start;
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- if (!*from_unit) return 0;
|
|
|
|
|
|
|
+ if (!*from_unit)
|
|
|
|
|
+ return 0;
|
|
|
|
|
|
|
|
- while (*to_pos && is_whitespace(*to_pos)) to_pos++;
|
|
|
|
|
|
|
+ while (*to_pos && is_whitespace(*to_pos))
|
|
|
|
|
+ to_pos++;
|
|
|
|
|
|
|
|
- if (!*to_pos) return 0;
|
|
|
|
|
|
|
+ if (!*to_pos)
|
|
|
|
|
+ return 0;
|
|
|
|
|
|
|
|
char to_part[64] = {0};
|
|
char to_part[64] = {0};
|
|
|
size_t to_len = 0;
|
|
size_t to_len = 0;
|
|
|
const char *tp = to_pos;
|
|
const char *tp = to_pos;
|
|
|
while (*tp && !is_separator(*tp) && to_len < 63) {
|
|
while (*tp && !is_separator(*tp) && to_len < 63) {
|
|
|
- to_part[to_len++] = *tp++;
|
|
|
|
|
|
|
+ to_part[to_len++] = *tp++;
|
|
|
}
|
|
}
|
|
|
to_part[to_len] = '\0';
|
|
to_part[to_len] = '\0';
|
|
|
|
|
|
|
|
*to_unit = find_unit(to_part);
|
|
*to_unit = find_unit(to_part);
|
|
|
if (!*to_unit) {
|
|
if (!*to_unit) {
|
|
|
- const char *try_ptr = to_pos;
|
|
|
|
|
- while (*try_ptr && is_whitespace(*try_ptr)) try_ptr++;
|
|
|
|
|
- char try_buf[64] = {0};
|
|
|
|
|
- size_t try_len = 0;
|
|
|
|
|
- while (*try_ptr && try_len < 63) {
|
|
|
|
|
- try_buf[try_len++] = *try_ptr++;
|
|
|
|
|
- }
|
|
|
|
|
- while (try_len > 0) {
|
|
|
|
|
- *to_unit = find_unit(try_buf);
|
|
|
|
|
- if (*to_unit) {
|
|
|
|
|
- strcpy(to_part, try_buf);
|
|
|
|
|
- break;
|
|
|
|
|
|
|
+ const char *try_ptr = to_pos;
|
|
|
|
|
+ while (*try_ptr && is_whitespace(*try_ptr))
|
|
|
|
|
+ try_ptr++;
|
|
|
|
|
+ char try_buf[64] = {0};
|
|
|
|
|
+ size_t try_len = 0;
|
|
|
|
|
+ while (*try_ptr && try_len < 63) {
|
|
|
|
|
+ try_buf[try_len++] = *try_ptr++;
|
|
|
|
|
+ }
|
|
|
|
|
+ while (try_len > 0) {
|
|
|
|
|
+ *to_unit = find_unit(try_buf);
|
|
|
|
|
+ if (*to_unit) {
|
|
|
|
|
+ strcpy(to_part, try_buf);
|
|
|
|
|
+ break;
|
|
|
|
|
+ }
|
|
|
|
|
+ char *last_space = strrchr(try_buf, ' ');
|
|
|
|
|
+ if (!last_space)
|
|
|
|
|
+ break;
|
|
|
|
|
+ *last_space = '\0';
|
|
|
|
|
+ try_len = strlen(try_buf);
|
|
|
}
|
|
}
|
|
|
- char *last_space = strrchr(try_buf, ' ');
|
|
|
|
|
- if (!last_space) break;
|
|
|
|
|
- *last_space = '\0';
|
|
|
|
|
- try_len = strlen(try_buf);
|
|
|
|
|
- }
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
return *to_unit ? 1 : 0;
|
|
return *to_unit ? 1 : 0;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-static double convert_temp(double value, const UnitDef *from, const UnitDef *to) {
|
|
|
|
|
|
|
+static double convert_temp(double value, const UnitDef *from,
|
|
|
|
|
+ const UnitDef *to) {
|
|
|
double celsius = 0;
|
|
double celsius = 0;
|
|
|
|
|
|
|
|
- if (strcmp(from->name, "celsius") == 0) celsius = value;
|
|
|
|
|
- else if (strcmp(from->name, "fahrenheit") == 0) celsius = (value - 32) * 5.0 / 9.0;
|
|
|
|
|
- else if (strcmp(from->name, "kelvin") == 0) celsius = value - 273.15;
|
|
|
|
|
-
|
|
|
|
|
- if (strcmp(to->name, "celsius") == 0) return celsius;
|
|
|
|
|
- else if (strcmp(to->name, "fahrenheit") == 0) return celsius * 9.0 / 5.0 + 32;
|
|
|
|
|
- else if (strcmp(to->name, "kelvin") == 0) return celsius + 273.15;
|
|
|
|
|
|
|
+ if (strcmp(from->name, "celsius") == 0)
|
|
|
|
|
+ celsius = value;
|
|
|
|
|
+ else if (strcmp(from->name, "fahrenheit") == 0)
|
|
|
|
|
+ celsius = (value - 32) * 5.0 / 9.0;
|
|
|
|
|
+ else if (strcmp(from->name, "kelvin") == 0)
|
|
|
|
|
+ celsius = value - 273.15;
|
|
|
|
|
+
|
|
|
|
|
+ if (strcmp(to->name, "celsius") == 0)
|
|
|
|
|
+ return celsius;
|
|
|
|
|
+ else if (strcmp(to->name, "fahrenheit") == 0)
|
|
|
|
|
+ return celsius * 9.0 / 5.0 + 32;
|
|
|
|
|
+ else if (strcmp(to->name, "kelvin") == 0)
|
|
|
|
|
+ return celsius + 273.15;
|
|
|
return 0;
|
|
return 0;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-static double convert_value(double value, const UnitDef *from, const UnitDef *to) {
|
|
|
|
|
- if (from->type != to->type) return 0;
|
|
|
|
|
|
|
+static double convert_value(double value, const UnitDef *from,
|
|
|
|
|
+ const UnitDef *to) {
|
|
|
|
|
+ if (from->type != to->type)
|
|
|
|
|
+ return 0;
|
|
|
|
|
|
|
|
if (from->type == UNIT_TEMP) {
|
|
if (from->type == UNIT_TEMP) {
|
|
|
- return convert_temp(value, from, to);
|
|
|
|
|
|
|
+ return convert_temp(value, from, to);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
double base_value = value * from->to_base;
|
|
double base_value = value * from->to_base;
|
|
@@ -351,112 +408,124 @@ static double convert_value(double value, const UnitDef *from, const UnitDef *to
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
static void format_number(double val, char *buf, size_t bufsize) {
|
|
static void format_number(double val, char *buf, size_t bufsize) {
|
|
|
- if (bufsize == 0) return;
|
|
|
|
|
|
|
+ if (bufsize == 0)
|
|
|
|
|
+ return;
|
|
|
if (val == 0) {
|
|
if (val == 0) {
|
|
|
- snprintf(buf, bufsize, "0");
|
|
|
|
|
- return;
|
|
|
|
|
|
|
+ snprintf(buf, bufsize, "0");
|
|
|
|
|
+ return;
|
|
|
}
|
|
}
|
|
|
if (fabs(val) < 0.01 && fabs(val) > 0) {
|
|
if (fabs(val) < 0.01 && fabs(val) > 0) {
|
|
|
- snprintf(buf, bufsize, "%.2g", val);
|
|
|
|
|
|
|
+ snprintf(buf, bufsize, "%.2g", val);
|
|
|
} else if (fabs(val) < 1) {
|
|
} else if (fabs(val) < 1) {
|
|
|
- snprintf(buf, bufsize, "%.2f", val);
|
|
|
|
|
- char *p = buf + strlen(buf) - 1;
|
|
|
|
|
- while (p > buf && *p == '0') *p-- = '\0';
|
|
|
|
|
- if (*p == '.') *p = '\0';
|
|
|
|
|
|
|
+ snprintf(buf, bufsize, "%.2f", val);
|
|
|
|
|
+ char *p = buf + strlen(buf) - 1;
|
|
|
|
|
+ while (p > buf && *p == '0')
|
|
|
|
|
+ *p-- = '\0';
|
|
|
|
|
+ if (*p == '.')
|
|
|
|
|
+ *p = '\0';
|
|
|
} else if (fmod(val + 0.0001, 1.0) < 0.0002) {
|
|
} else if (fmod(val + 0.0001, 1.0) < 0.0002) {
|
|
|
- snprintf(buf, bufsize, "%.0f", val);
|
|
|
|
|
|
|
+ snprintf(buf, bufsize, "%.0f", val);
|
|
|
} else {
|
|
} else {
|
|
|
- snprintf(buf, bufsize, "%.2f", val);
|
|
|
|
|
- char *p = buf + strlen(buf) - 1;
|
|
|
|
|
- while (p > buf && *p == '0') *p-- = '\0';
|
|
|
|
|
- if (*p == '.') *p = '\0';
|
|
|
|
|
|
|
+ snprintf(buf, bufsize, "%.2f", val);
|
|
|
|
|
+ char *p = buf + strlen(buf) - 1;
|
|
|
|
|
+ while (p > buf && *p == '0')
|
|
|
|
|
+ *p-- = '\0';
|
|
|
|
|
+ if (*p == '.')
|
|
|
|
|
+ *p = '\0';
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-static const char *pluralize(const char *unit, double value, char *buf, size_t bufsize) {
|
|
|
|
|
|
|
+static const char *pluralize(const char *unit, double value, char *buf,
|
|
|
|
|
+ size_t bufsize) {
|
|
|
int is_one = (fabs(value - 1.0) < 0.0001 || fabs(value + 1.0) < 0.0001);
|
|
int is_one = (fabs(value - 1.0) < 0.0001 || fabs(value + 1.0) < 0.0001);
|
|
|
|
|
|
|
|
size_t len = strlen(unit);
|
|
size_t len = strlen(unit);
|
|
|
- if (len == 0 || bufsize == 0) return unit;
|
|
|
|
|
|
|
+ if (len == 0 || bufsize == 0)
|
|
|
|
|
+ return unit;
|
|
|
|
|
|
|
|
strncpy(buf, unit, bufsize - 1);
|
|
strncpy(buf, unit, bufsize - 1);
|
|
|
buf[bufsize - 1] = '\0';
|
|
buf[bufsize - 1] = '\0';
|
|
|
|
|
|
|
|
if (strcmp(unit, "foot") == 0 || strcmp(unit, "square foot") == 0) {
|
|
if (strcmp(unit, "foot") == 0 || strcmp(unit, "square foot") == 0) {
|
|
|
- if (is_one) strcpy(buf, unit);
|
|
|
|
|
- else strcpy(buf, strcmp(unit, "square foot") == 0 ? "square feet" : "feet");
|
|
|
|
|
- return buf;
|
|
|
|
|
|
|
+ if (is_one)
|
|
|
|
|
+ strcpy(buf, unit);
|
|
|
|
|
+ else
|
|
|
|
|
+ strcpy(buf, strcmp(unit, "square foot") == 0 ? "square feet" : "feet");
|
|
|
|
|
+ return buf;
|
|
|
}
|
|
}
|
|
|
if (strcmp(unit, "inch") == 0 || strcmp(unit, "square inch") == 0) {
|
|
if (strcmp(unit, "inch") == 0 || strcmp(unit, "square inch") == 0) {
|
|
|
- if (is_one) strcpy(buf, unit);
|
|
|
|
|
- else strcpy(buf, strcmp(unit, "square inch") == 0 ? "square inches" : "inches");
|
|
|
|
|
- return buf;
|
|
|
|
|
|
|
+ if (is_one)
|
|
|
|
|
+ strcpy(buf, unit);
|
|
|
|
|
+ else
|
|
|
|
|
+ strcpy(buf,
|
|
|
|
|
+ strcmp(unit, "square inch") == 0 ? "square inches" : "inches");
|
|
|
|
|
+ return buf;
|
|
|
}
|
|
}
|
|
|
if (strcmp(unit, "stone") == 0) {
|
|
if (strcmp(unit, "stone") == 0) {
|
|
|
- if (is_one) strcpy(buf, "stone");
|
|
|
|
|
- else strcpy(buf, "stones");
|
|
|
|
|
- return buf;
|
|
|
|
|
- }
|
|
|
|
|
- if (strcmp(unit, "celsius") == 0 ||
|
|
|
|
|
- strcmp(unit, "fahrenheit") == 0 ||
|
|
|
|
|
- strcmp(unit, "kelvin") == 0) {
|
|
|
|
|
- strcpy(buf, unit);
|
|
|
|
|
- return buf;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- if (unit[len-1] == 's' ||
|
|
|
|
|
- unit[len-1] == 'x' ||
|
|
|
|
|
- unit[len-1] == 'z' ||
|
|
|
|
|
- (len >= 2 && unit[len-2] == 'c' && unit[len-1] == 'h') ||
|
|
|
|
|
- (len >= 2 && unit[len-2] == 's' && unit[len-1] == 'h')) {
|
|
|
|
|
- if (!is_one) {
|
|
|
|
|
- buf[len] = 'e';
|
|
|
|
|
- buf[len+1] = '\0';
|
|
|
|
|
- }
|
|
|
|
|
- } else if (unit[len-1] == 'y' && len >= 2 &&
|
|
|
|
|
- !(unit[len-2] == 'a' || unit[len-2] == 'e' ||
|
|
|
|
|
- unit[len-2] == 'i' || unit[len-2] == 'o' ||
|
|
|
|
|
- unit[len-2] == 'u')) {
|
|
|
|
|
- if (is_one) {
|
|
|
|
|
- buf[len-1] = '\0';
|
|
|
|
|
- } else {
|
|
|
|
|
- buf[len] = 's';
|
|
|
|
|
- buf[len+1] = '\0';
|
|
|
|
|
- }
|
|
|
|
|
- } else if (len >= 2 && unit[len-2] == 'f' && unit[len-1] == 'e') {
|
|
|
|
|
- if (is_one) {
|
|
|
|
|
- buf[len-2] = '\0';
|
|
|
|
|
- } else {
|
|
|
|
|
- buf[len-1] = 's';
|
|
|
|
|
- buf[len] = '\0';
|
|
|
|
|
- }
|
|
|
|
|
- } else if (unit[len-1] == 'f' && len >= 1) {
|
|
|
|
|
- if (is_one) {
|
|
|
|
|
- buf[len-1] = '\0';
|
|
|
|
|
- } else {
|
|
|
|
|
- buf[len-1] = 'v';
|
|
|
|
|
- buf[len] = 'e';
|
|
|
|
|
- buf[len+1] = 's';
|
|
|
|
|
- buf[len+2] = '\0';
|
|
|
|
|
- }
|
|
|
|
|
- } else if (unit[len-1] == 'e' && len >= 2 && unit[len-2] == 'f') {
|
|
|
|
|
- if (is_one) {
|
|
|
|
|
- buf[len-2] = '\0';
|
|
|
|
|
- } else {
|
|
|
|
|
- buf[len-1] = 's';
|
|
|
|
|
- buf[len] = '\0';
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ if (is_one)
|
|
|
|
|
+ strcpy(buf, "stone");
|
|
|
|
|
+ else
|
|
|
|
|
+ strcpy(buf, "stones");
|
|
|
|
|
+ return buf;
|
|
|
|
|
+ }
|
|
|
|
|
+ if (strcmp(unit, "celsius") == 0 || strcmp(unit, "fahrenheit") == 0 ||
|
|
|
|
|
+ strcmp(unit, "kelvin") == 0) {
|
|
|
|
|
+ strcpy(buf, unit);
|
|
|
|
|
+ return buf;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (unit[len - 1] == 's' || unit[len - 1] == 'x' || unit[len - 1] == 'z' ||
|
|
|
|
|
+ (len >= 2 && unit[len - 2] == 'c' && unit[len - 1] == 'h') ||
|
|
|
|
|
+ (len >= 2 && unit[len - 2] == 's' && unit[len - 1] == 'h')) {
|
|
|
|
|
+ if (!is_one) {
|
|
|
|
|
+ buf[len] = 'e';
|
|
|
|
|
+ buf[len + 1] = '\0';
|
|
|
|
|
+ }
|
|
|
|
|
+ } else if (unit[len - 1] == 'y' && len >= 2 &&
|
|
|
|
|
+ !(unit[len - 2] == 'a' || unit[len - 2] == 'e' ||
|
|
|
|
|
+ unit[len - 2] == 'i' || unit[len - 2] == 'o' ||
|
|
|
|
|
+ unit[len - 2] == 'u')) {
|
|
|
|
|
+ if (is_one) {
|
|
|
|
|
+ buf[len - 1] = '\0';
|
|
|
|
|
+ } else {
|
|
|
|
|
+ buf[len] = 's';
|
|
|
|
|
+ buf[len + 1] = '\0';
|
|
|
|
|
+ }
|
|
|
|
|
+ } else if (len >= 2 && unit[len - 2] == 'f' && unit[len - 1] == 'e') {
|
|
|
|
|
+ if (is_one) {
|
|
|
|
|
+ buf[len - 2] = '\0';
|
|
|
|
|
+ } else {
|
|
|
|
|
+ buf[len - 1] = 's';
|
|
|
|
|
+ buf[len] = '\0';
|
|
|
|
|
+ }
|
|
|
|
|
+ } else if (unit[len - 1] == 'f' && len >= 1) {
|
|
|
|
|
+ if (is_one) {
|
|
|
|
|
+ buf[len - 1] = '\0';
|
|
|
|
|
+ } else {
|
|
|
|
|
+ buf[len - 1] = 'v';
|
|
|
|
|
+ buf[len] = 'e';
|
|
|
|
|
+ buf[len + 1] = 's';
|
|
|
|
|
+ buf[len + 2] = '\0';
|
|
|
|
|
+ }
|
|
|
|
|
+ } else if (unit[len - 1] == 'e' && len >= 2 && unit[len - 2] == 'f') {
|
|
|
|
|
+ if (is_one) {
|
|
|
|
|
+ buf[len - 2] = '\0';
|
|
|
|
|
+ } else {
|
|
|
|
|
+ buf[len - 1] = 's';
|
|
|
|
|
+ buf[len] = '\0';
|
|
|
|
|
+ }
|
|
|
} else {
|
|
} else {
|
|
|
- if (!is_one) {
|
|
|
|
|
- buf[len] = 's';
|
|
|
|
|
- buf[len+1] = '\0';
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ if (!is_one) {
|
|
|
|
|
+ buf[len] = 's';
|
|
|
|
|
+ buf[len + 1] = '\0';
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
return buf;
|
|
return buf;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-static char *build_html(double value, const UnitDef *from, double result, const UnitDef *to) {
|
|
|
|
|
|
|
+static char *build_html(double value, const UnitDef *from, double result,
|
|
|
|
|
+ const UnitDef *to) {
|
|
|
static char html[4096];
|
|
static char html[4096];
|
|
|
char val_buf[64], res_buf[64], from_name_buf[64], to_name_buf[64];
|
|
char val_buf[64], res_buf[64], from_name_buf[64], to_name_buf[64];
|
|
|
format_number(value, val_buf, sizeof(val_buf));
|
|
format_number(value, val_buf, sizeof(val_buf));
|
|
@@ -466,30 +535,34 @@ static char *build_html(double value, const UnitDef *from, double result, const
|
|
|
pluralize(to->name, result, to_name_buf, sizeof(to_name_buf));
|
|
pluralize(to->name, result, to_name_buf, sizeof(to_name_buf));
|
|
|
|
|
|
|
|
int n = snprintf(html, sizeof(html),
|
|
int n = snprintf(html, sizeof(html),
|
|
|
- "<div class='unit-conv-container' style='line-height: 1.6;'>"
|
|
|
|
|
- "<div style='font-size: 1.3em; margin-bottom: 8px;'>"
|
|
|
|
|
- "<b>%s %s</b> = <b>%s %s</b>"
|
|
|
|
|
- "</div>",
|
|
|
|
|
- val_buf, from_name_buf,
|
|
|
|
|
- res_buf, to_name_buf);
|
|
|
|
|
|
|
+ "<div class='unit-conv-container' style='line-height: 1.6;'>"
|
|
|
|
|
+ "<div style='font-size: 1.3em; margin-bottom: 8px;'>"
|
|
|
|
|
+ "<b>%s %s</b> = <b>%s %s</b>"
|
|
|
|
|
+ "</div>",
|
|
|
|
|
+ val_buf, from_name_buf, res_buf, to_name_buf);
|
|
|
snprintf(html + n, sizeof(html) - n, "</div>");
|
|
snprintf(html + n, sizeof(html) - n, "</div>");
|
|
|
return html;
|
|
return html;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
InfoBox fetch_unit_conv_data(const char *query) {
|
|
InfoBox fetch_unit_conv_data(const char *query) {
|
|
|
InfoBox info = {NULL, NULL, NULL, NULL};
|
|
InfoBox info = {NULL, NULL, NULL, NULL};
|
|
|
- if (!query) return info;
|
|
|
|
|
|
|
+ if (!query)
|
|
|
|
|
+ return info;
|
|
|
|
|
|
|
|
double value = 0;
|
|
double value = 0;
|
|
|
const UnitDef *from = NULL;
|
|
const UnitDef *from = NULL;
|
|
|
const UnitDef *to = NULL;
|
|
const UnitDef *to = NULL;
|
|
|
|
|
|
|
|
- if (!parse_conversion_query(query, &value, &from, &to)) return info;
|
|
|
|
|
- if (!from || !to) return info;
|
|
|
|
|
- if (from->type != to->type) return info;
|
|
|
|
|
|
|
+ if (!parse_conversion_query(query, &value, &from, &to))
|
|
|
|
|
+ return info;
|
|
|
|
|
+ if (!from || !to)
|
|
|
|
|
+ return info;
|
|
|
|
|
+ if (from->type != to->type)
|
|
|
|
|
+ return info;
|
|
|
|
|
|
|
|
double result = convert_value(value, from, to);
|
|
double result = convert_value(value, from, to);
|
|
|
- if (result == 0 && value != 0 && from->type != UNIT_TEMP) return info;
|
|
|
|
|
|
|
+ if (result == 0 && value != 0 && from->type != UNIT_TEMP)
|
|
|
|
|
+ return info;
|
|
|
|
|
|
|
|
info.title = strdup("Unit Conversion");
|
|
info.title = strdup("Unit Conversion");
|
|
|
info.extract = strdup(build_html(value, from, result, to));
|
|
info.extract = strdup(build_html(value, from, result, to));
|