+ finish_c_values(result);
+ }
+ return result;
+}
+
+static PICS_HEAD *
+parse_xpm(char **data)
+{
+ int state = 0;
+ PICS_HEAD *result;
+ RGB_NAME *by_name;
+ int n;
+ int cells = 0;
+ int cpp = 1; /* chars per pixel */
+ int num[6];
+ int found;
+ int which = 0;
+ int num_colors = 0;
+ char ch;
+ const char *cs;
+ char *s;
+ char buf[BUFSIZ];
+ char arg1[BUFSIZ];
+ char arg2[BUFSIZ];
+ char arg3[BUFSIZ];
+ char **list = 0;
+
+ debugmsg("called parse_xpm");
+
+ result = typeCalloc(PICS_HEAD, 1);
+ how_much.head += sizeof(PICS_HEAD);
+
+ for (n = 0; data[n] != 0; ++n) {
+ if (strlen(s = data[n]) >= sizeof(buf) - 1)
+ continue;
+ switch (state) {
+ case 0:
+ if (match_c(s, " /* XPM */ ")) {
+ state = 1;
+ }
+ break;
+ case 1:
+ if (match_c(s, " static char * %s [] = %c ", arg1, &ch) &&
+ ch == L_CURLY) {
+ result->name = strdup(arg1);
+ state = 2;
+ }
+ break;
+ case 2:
+ if (match_c(s, " \" %d %d %d %d \" , ",
+ num + 0, num + 1, num + 2, num + 3) ||
+ match_c(s, " \" %d %d %d %d %d %d \" , ",
+ num + 0, num + 1, num + 2, num + 3, num + 4, num + 5)) {
+ result->wide = (short) num[0];
+ result->high = (short) num[1];
+ result->colors = num[2];
+
+ begin_c_values(num[2]);
+
+ cells = (result->wide * result->high);
+
+ result->cells = typeCalloc(PICS_CELL, cells);
+ how_much.cell += sizeof(PICS_CELL) * (size_t) cells;
+
+ list = typeCalloc(char *, result->colors + 1);
+ how_much.list += sizeof(char *) * (size_t) (result->colors + 1);
+
+ cpp = num[3];
+ state = 3;
+ }
+ break;
+ case 3:
+ if (!match_colors(s, cpp, arg1, arg2, arg3)) {
+ break;
+ }
+ num_colors++;
+ free(list[reading_last]);
+ list[reading_last] = strdup(arg1);
+ if ((by_name = lookup_rgb(arg3)) != 0) {
+ found = gather_c_values(by_name->value);
+ } else if (*arg3 == '#') {
+ char *rgb = arg3 + 1;
+ unsigned long value = strtoul(rgb, &s, 16);
+ switch ((int) strlen(rgb)) {
+ case 6:
+ break;
+ case 12:
+ value = (((value >> 24) & 0xff0000L)
+ | ((value >> 16) & 0xff00L)
+ | ((value >> 8) & 0xffL));
+ break;
+ default:
+ warning("unexpected rgb value %s", rgb);
+ break;
+ }
+ found = gather_c_values((int) value);
+ } else {
+ found = gather_c_values(0); /* actually an error */
+ }
+ debugmsg(" [%d:%d] %06X", num_colors, result->colors,
+ reading_ncols[(found >= 0) ? found : 0].fgcol);
+ if (num_colors >= result->colors) {
+ finish_c_values(result);
+ state = 4;
+ if (list[0] == 0)
+ list[0] = strdup("\033");
+ }
+ break;
+ case 4:
+ if (*(cs = skip_cs(s)) == '"') {
+ ++cs;
+ while (*cs != '\0' && *cs != '"') {
+ int c;
+
+ /* FIXME - factor out */
+ for (c = 0; c < result->colors; ++c) {
+ if (list[c] == 0) {
+ /* should not happen... */
+ continue;
+ }
+ if (!(strncmp) (cs, list[c], (size_t) cpp)) {
+ result->cells[which].ch = list[c][0];
+ result->cells[which].fg = c;
+ result->fgcol[c].count++;
+ break;
+ }
+ }
+
+ if (result->cells[which].ch == 0) {
+ result->cells[which].ch = '?';
+ result->cells[which].fg = 0;
+ }
+
+ if (++which >= cells) {
+ state = 5;
+ break;
+ }
+ for (c = cpp; c > 0; --c, ++cs) {
+ if (*cs == '\0')
+ break;
+ }
+ }
+ }
+ break;
+ }
+ }
+
+ if (result && list) {
+ for (n = 0; n < result->colors; ++n)
+ free(list[n]);
+ free(list);
+ }
+
+ if (state < 5) {
+ debugmsg("...state was only %d", state);
+ result = free_pics_head(result);
+ }
+
+ if (result) {
+ debugmsg("...allocated %d colors", result->colors);
+ }
+
+ return result;
+}
+
+/*
+ * The obscurely-named "convert" is provided by ImageMagick
+ */
+static PICS_HEAD *
+parse_img(const char *filename)
+{
+ size_t need = strlen(filename) + 256;
+ char *cmd = malloc(need);
+ FILE *pp;
+ char buffer[BUFSIZ];
+ char dummy[BUFSIZ];
+ bool okay = TRUE;
+ PICS_HEAD *result;
+ int pic_x = 0;
+ int pic_y = 0;
+ int width = in_curses ? COLS : 80;
+
+ _nc_SPRINTF(cmd, _nc_SLIMIT(need) "identify \"%s\"", filename);
+ if (quiet)
+ _nc_STRCAT(cmd, " 2>/dev/null", need);
+
+ logmsg("...opening pipe to %s", cmd);
+
+ result = typeCalloc(PICS_HEAD, 1);
+ how_much.head += sizeof(PICS_HEAD);
+
+ if ((pp = popen(cmd, "r")) != 0) {
+ if (fgets(buffer, sizeof(buffer), pp) != 0) {
+ size_t n = strlen(filename);
+ debugmsg2("...read %s", buffer);
+ if (strlen(buffer) > n &&
+ !(strncmp) (buffer, filename, n) &&
+ isspace(UChar(buffer[n])) &&
+ sscanf(skip_word(buffer + n), " %dx%d ", &pic_x, &pic_y) == 2) {
+ /* distort image to make it show normally on terminal */
+ pic_x = (int) ((double) pic_x / aspect_ratio);
+ } else {
+ pic_x = pic_y = 0;
+ }
+ }
+ pclose(pp);
+ }
+ if (pic_x <= 0 || pic_y <= 0)
+ goto finish;
+
+ _nc_SPRINTF(cmd, _nc_SLIMIT(need)
+ "convert " "-resize %dx%d\\! " "-thumbnail %dx \"%s\" "
+ "-define txt:compliance=SVG txt:-",
+ pic_x, pic_y, width, filename);
+ if (quiet)
+ _nc_STRCAT(cmd, " 2>/dev/null", need);
+
+ logmsg("...opening pipe to %s", cmd);
+ if ((pp = popen(cmd, "r")) != 0) {
+ int count = 0;
+ int col = 0;
+ int row = 0;
+ int len = 0;
+ while (fgets(buffer, sizeof(buffer), pp) != 0) {
+ debugmsg2("[%5d] %s", count + 1, buffer);
+ if (strlen(buffer) > 160) { /* 80 columns would be enough */
+ okay = FALSE;
+ break;
+ }
+ if (count++ == 0) {
+ if (match_c(buffer,
+ "# ImageMagick pixel enumeration: %d,%d,%d,%s ",
+ &col, &row, &len, dummy)) {
+ result->name = strdup(filename);
+ result->wide = (short) col;
+ result->high = (short) row;
+
+ begin_c_values(256);
+
+ result->cells = typeCalloc(PICS_CELL, (size_t) (col * row));
+ how_much.cell += (sizeof(PICS_CELL) * (size_t) (col * row));
+ } else {
+ okay = FALSE;
+ break;
+ }
+ } else {
+ /* subsequent lines begin "col,row: (r,g,b,a) #RGB" */
+ int r, g, b, nocolor;
+ unsigned check;
+ char *t;
+ char *s = t = strchr(buffer, '#');
+
+ if (s != 0) {
+ /* after the "#RGB", there are differences - just ignore */
+ while (*s != '\0' && !isspace(UChar(*s)))
+ ++s;
+ *++s = '\0';
+ }
+ if (match_c(buffer,
+ "%d,%d: (%d,%d,%d,%d) #%x ",
+ &col, &row,
+ &r, &g, &b, &nocolor,
+ &check)) {
+ int which, c;
+
+ if ((s - t) > 8) /* 6 hex digits vs 8 */
+ check /= 256;
+ if (r > MaxRGB ||
+ g > MaxRGB ||
+ b > MaxRGB ||
+ check != (unsigned) ((r << 16) | (g << 8) | b)) {
+ okay = FALSE;
+ break;
+ }
+ c = gather_c_values((int) check);
+ which = col + (row * result->wide);
+ result->cells[which].ch = ((in_curses ||
+ check == 0xffffff)
+ ? ' '
+ : '#');
+ if (c >= 0 && c < reading_last) {
+ result->cells[which].fg = c;
+ reading_ncols[c].count++;
+ } else {
+ result->cells[which].fg = -1;
+ }
+ } else {
+ okay = FALSE;
+ break;
+ }
+ }
+ }
+ finish_c_values(result);
+ pclose(pp);
+ if (okay) {
+ /* FIXME - is this trimming needed? */
+ for (len = result->colors; len > 3; len--) {
+ if (result->fgcol[len - 1].fgcol == 0) {
+ result->colors = len - 1;
+ } else {
+ break;
+ }
+ }
+ }