bool parse_xpm_file(Image *image, const char *file_path) {
line_number = 0;
- switch (sigsetjmp(env, 0)) {
+ switch (sigsetjmp(env, 0))
case 1:
return false;
- }
if ((file = fopen(file_path, "r")) == NULL)
SIMPLE_XPM_ERROR("Unable to open provided file");
char *line_buffer_p = line_buffer;
check_next_token(&line_buffer_p, "static");
if (!isspace(*line_buffer_p))
- SIMPLE_XPM_ERROR("Expected token \"static\"");
+ SIMPLE_XPM_ERROR("The word `static' at line %d lacks trailing whitespace",
+ line_number);
check_next_token(&line_buffer_p, "char");
check_next_token(&line_buffer_p, "*");
if (isdigit(strstrip(&line_buffer_p)[0]))
- SIMPLE_XPM_ERROR("Incorrect C variable name");
+ SIMPLE_XPM_ERROR("Invalid name for array at line %d (must be a valid C "
+ "variable name)", line_number);
for (; strlen(line_buffer_p) != 0 && (isalnum(*line_buffer_p) || *line_buffer_p == '_'); ++line_buffer_p);
check_next_token(&line_buffer_p, "[");
xpm_ext_token = NULL;
if (!get_terminal_token(&line_buffer_p, &y_hotspot_token)) {
if (!get_terminal_token(&line_buffer_p, &xpm_ext_token))
- SIMPLE_XPM_ERROR("Too many arguments for values");
- else if (strncmp(xpm_ext_token, "XPMEXT", strlen("XPMEXT")) != 0)
- SIMPLE_XPM_ERROR("XPMEXT value not set correctly");
+ SIMPLE_XPM_ERROR("The values section contains too many words");
+ else if (strlen(xpm_ext_token) != strlen("XPMEXT")
+ || strncmp(xpm_ext_token, "XPMEXT", strlen("XPMEXT")) != 0)
+ SIMPLE_XPM_ERROR("The \"XPMEXT\" value should be set to `XPMEXT' if XPM "
+ "extensions are desired, else no tag should be "
+ "specified (line %d)", line_number);
}
- } else if (strncmp(xpm_ext_token, "XPMEXT", strlen("XPMEXT")) != 0)
- SIMPLE_XPM_ERROR("Must specify y_hotspot alongside x_hotspot");
+ } else if (strlen(xpm_ext_token) != strlen("XPMEXT")
+ || strncmp(xpm_ext_token, "XPMEXT", strlen("XPMEXT")) != 0)
+ SIMPLE_XPM_ERROR("Can't specify a value for \"x_hotspot\" without a value "
+ "for \"y_hotspot\" (line %d)", line_number);
}
size_t chars_per_pixel = convert_token_to_num(chars_per_pixel_token, 10);
if (width == 0 || height == 0 || num_colors == 0 || chars_per_pixel == 0)
- SIMPLE_XPM_ERROR("Invalid values token");
+ SIMPLE_XPM_ERROR("One of the values on line %d is zero; make sure all values "
+ "are positive integers", line_number);
// TODO: Hotspots are not implemented
ssize_t x_hotspot = x_hotspot_token ? convert_token_to_num(x_hotspot_token, 10) : -1;
check_next_token(&line_buffer_p, "\"");
if (strlen(line_buffer_p) < chars_per_pixel)
- SIMPLE_XPM_ERROR("Unable to parse color line");
+ SIMPLE_XPM_ERROR("Line %d in the color section contains too few characters "
+ "to be properly parsed", line_number);
strncpy(&keys[i * chars_per_pixel], line_buffer_p, chars_per_pixel);
line_buffer_p += chars_per_pixel;
if (*line_buffer_p != '\t' && *line_buffer_p != ' ')
- SIMPLE_XPM_ERROR("Incorrect whitespace in color line");
+ SIMPLE_XPM_ERROR("Words must be separated by tabs and/or spaces; line %d "
+ "contains nonstandard whitespace after the first word",
+ line_number);
*line_buffer_p++ = '\0';
bool is_last_token;
switch(*color_str) {
case '#':; // RGB
size_t hex_value = convert_token_to_num(++color_str, 16);
- if (hex_value> 0xffffff)
- SIMPLE_XPM_ERROR("Hex #%s is not a valid color value", color_str);
+ if (hex_value > 0xffffff) {
+ if (strlen(color_str))
+ SIMPLE_XPM_ERROR("Hex value `#%s' on line %d is not a valid color value",
+ color_str, line_number);
+ else
+ SIMPLE_XPM_ERROR("Empty hex value on line %d is not a valid color value",
+ line_number);
+ }
size_t r = (hex_value & 0x00ff0000) >> (2 * 8),
g = (hex_value & 0x0000ff00),
b = (hex_value & 0x000000ff) << (2 * 8),
break;
case '%':; // HSV
// TODO: Parse %HSV codes
- SIMPLE_XPM_ERROR("HSV values not implemented yet");
+ SIMPLE_XPM_ERROR("Parsing HSV values is not implemented yet (line %d)",
+ line_number);
default:; // "Colornames"
// TODO: Parse colornames
// https://en.wikipedia.org/wiki/X11_color_names#Color_name_chart
- SIMPLE_XPM_ERROR("Colorname values not implemented yet");
+ SIMPLE_XPM_ERROR("Parsing colorname values is not implemented yet "
+ "(line %d)", line_number);
}
color_table[mode * num_colors + i] = color;
} while(!is_last_token);
// TODO: Be able to dynamically change modes
Xpm_Mode current_mode = XPM_MODE_COLOR;
if (!possible_modes[current_mode])
- SIMPLE_XPM_ERROR("Current mode not supported");
+ SIMPLE_XPM_ERROR("Color visual mode is the only mode currently supported "
+ "(line %d)", line_number);
// Parse array of pixel values
SIMPLE_XPM_FREE(pixels); // Need to have the pixels still exist even when this function exits
line_buffer_p = line_buffer;
check_next_token(&line_buffer_p, "\"");
if (strlen(line_buffer_p) < width * chars_per_pixel + strlen("\","))
- SIMPLE_XPM_ERROR("String in pixels section is formatted improperly");
+ SIMPLE_XPM_ERROR("Line %d in pixels sections contains too few characters to "
+ "be properly parsed", line_number);
for (size_t j = 0; j < width; ++j) {
for (size_t k = 0; k < chars_per_pixel; ++k) {
key_buffer[k] = *line_buffer_p++;
}
}
}
- if (*line_buffer_p++ != '"')
- SIMPLE_XPM_ERROR("Pixels section is not formatted correctly");
+ if (*line_buffer_p++ != '"') // Needs to be done manually for whitespace
+ SIMPLE_XPM_ERROR("Expected a `\"' at the end of line %d", line_number);
check_next_token(&line_buffer_p, ",");
}
SIMPLE_XPM_FREE(key_buffer);
// TODO: Extensions are not implemented
if (xpm_ext) {
- printf("Parsing XPM extensions\n");
+ fprintf(stdout, "simplexpm: INFO: Parsing XPM extensions\n");
}
get_next_line_check_eof(&line_buffer, file);
check_next_token(&line_buffer_p, "}");
check_next_token(&line_buffer_p, ";");
if (*strstrip(&line_buffer_p) != '\0')
- SIMPLE_XPM_ERROR("File can't have elements after array declaration");
+ SIMPLE_XPM_ERROR("Trailing elements on line %d after the array aren't "
+ "allowed", line_number);
while (get_next_line(&line_buffer, file)) {
line_buffer_p = line_buffer;
if (*strstrip(&line_buffer_p) != '\0')
- SIMPLE_XPM_ERROR("File can't have elements after array declaration");
+ SIMPLE_XPM_ERROR("Trailing elements on line %d after the array aren't "
+ "allowed", line_number);
}
fclose(file);
SIMPLE_XPM_FREE(line_buffer);
void check_next_token(char **string, const char *token) {
size_t token_len = strlen(token);
if (strncmp(strstrip(string), token, token_len) != 0)
- SIMPLE_XPM_ERROR("Expected \"%s\" at line %d", token, line_number);
+ SIMPLE_XPM_ERROR("Expected the word `%s' at line %d", token, line_number);
*string += token_len;
}
char *get_next_token(char **string) {
char *result;
- do {
+ do
if ((result = strsep(string, "\t ")) == NULL)
- SIMPLE_XPM_ERROR("Couldn't parse expected next token");
- } while (*result == '\0');
- if (*string == NULL)
- SIMPLE_XPM_ERROR("Did not expect next token to be a terminal token");
+ SIMPLE_XPM_ERROR("Unable to parse expected token on line %d", line_number);
+ while (*result == '\0');
+ if (*string == NULL) // This function doesn't expect terminal tokens
+ SIMPLE_XPM_ERROR("Missing words on line %d", line_number);
if (strlen(result) != strlen(strstrip(&result)))
- SIMPLE_XPM_ERROR("Weird whitespace characters between array tokens");
+ SIMPLE_XPM_ERROR("Words must be separated by tabs and/or spaces; line %d "
+ "contains nonstandard whitespace", line_number);
return result;
}
}
*(*string)++ = '\0';
if (*token == *string)
- SIMPLE_XPM_ERROR("Couldn't parse potential last token");
+ SIMPLE_XPM_ERROR("Missing last word on line %d", line_number);
while (**string == '\t' || **string == ' ') ++*string;
if (**string != '"') {
result = false;
defer:
if (strlen(*token) != strlen(strstrip(token)))
- SIMPLE_XPM_ERROR("Weird whitespace characters between array tokens");
+ SIMPLE_XPM_ERROR("Words must be separated by tabs and/or spaces; line %d "
+ "contains nonstandard whitespace", line_number);
return result;
}
size_t convert_token_to_num(const char *token, int base) {
if (token == NULL)
- SIMPLE_XPM_ERROR("Expected non-null token to parse");
+ SIMPLE_XPM_ERROR("Unable to parse empty word from line %d", line_number);
errno = 0;
char *end_p;
long result = strtol(token, &end_p, base);
- if (*end_p != '\0' || errno == ERANGE || result < 0)
- SIMPLE_XPM_ERROR("\"%s\" is not a valid number", token);
+ if (*end_p != '\0' || errno == ERANGE || result < 0) {
+ if (strlen(token) == 0)
+ SIMPLE_XPM_ERROR("Unable to parse an empty word from line %d as a number",
+ line_number);
+ else
+ SIMPLE_XPM_ERROR("Word `%s' from line %d is not a valid number",
+ token, line_number);
+ }
return (size_t)result;
}