home *** CD-ROM | disk | FTP | other *** search
- /*
- * $Id: extbind.c,v 0.91 1994/02/20 00:53:17 zhao Pre-Release $
- *
- *. This file is part of BIT shareware package. After the two weeks of
- * free evaluation period, you are encouraged (required) to register
- * your copy for a small registration fee, which is $35 for personal use
- * and $50 for commercial, government and institutional use.
- *
- * Copyright(c) 1993, 1994 by T.C. Zhao.
- * All rights reserved.
- *
- * Permission to use, copy, and distribute this software in its entirety
- * for non-commercial purposes is hereby granted, provided that the
- * above shareware and copyright notices and this permission notice
- * appear in all copies and their documentation.
- *
- * This software may be modified for your own use, but modified versions
- * may not be distributed without prior consent of the author.
- *
- * This software is provided "as is" without expressed or implied
- * warranty of any kind.
- *
- *.
- *
- * Purpose:
- * Handles external bindings. See Doc for formats specifications
- *
- * Code is slightly complicated by the fact that we can not simply
- * create a double-ended pipe to do IO because we MUST guarantee
- * fseek-ablity.
- */
- #if !defined(lint) && defined (F_ID)
- char *id_extb = "$Id: extbind.c,v 0.91 1994/02/20 00:53:17 zhao Pre-Release $";
- #endif
-
- #include "bit.h"
- #include "extern.h"
- #include "dmalloc.h"
-
- /*******************************************************************
- * External convolution kernels
- ****************************************************************{*/
-
- /******************* Limits **********************************/
-
- #define MAXCONV 35 /* max no. of extern matrices */
-
- /************************************************************
- * structures for external kernel and associated functions
- ************************************************************/
- typedef struct
- {
- char *name; /* name of the kernel */
- int rows, cols; /* matrix and its order(square) */
- int **m; /* the matrix */
- }
- ext_convolv_t;
-
- /*************************************************************
- * free an ext_convolve: name & matrix
- *************************************************************/
- static void
- ec_free(ext_convolv_t * p)
- {
- if (p->name)
- {
- free(p->name);
- p->name = 0;
- }
- p->rows = p->cols = 0;
- free_mat(p->m);
- p->m = 0;
- }
-
- /*************************************************************
- * ext_convolve struct copy
- ************************************************************/
-
- static void
- ec_dup(ext_convolv_t * to, const ext_convolv_t * from)
- {
- to->name = strdup(from->name);
- to->rows = from->rows;
- to->cols = from->cols;
- to->m = get_mat(to->rows, to->cols, sizeof(int));
- memcpy(to->m[0], from->m[0], sizeof(int) * to->rows * to->cols);
- }
-
- /**************************************************************
- * if two definations are identical
- **************************************************************/
- /* rather loose, if same name and same rank, consider same */
- static int
- ec_identical(const ext_convolv_t * a, const ext_convolv_t * b)
- {
- return (a->rows == b->rows &&
- a->cols == b->cols &&
- strcmp(a->name, b->name) == 0);
- }
-
- /************* Variables and functions ************************/
-
- static ext_convolv_t convolv[MAXCONV];
- static IPTR iptr; /* local copy of input image ptr */
-
- static int ec_scanner(void);
- static void ec_doit(long);
-
- /*************************************************************
- * The global entry point for external convolution
- *************************************************************/
-
- int
- do_ext_convolv(IPTR im)
- {
- static int nkernel, action = -1;
- int i;
-
- iptr = im;
-
- if (!image_ready(im, "ExtConvolv"))
- return -1;
-
- if (!nkernel && (nkernel = ec_scanner()) <= 0)
- {
- help_cb(0, HELP_CONVOLV);
- return -1;
- }
-
- /* make action table */
- if (action < 0)
- {
- action = define_action("Convolution", "convolv.hlp");
-
- for (i = 0; i < nkernel; i++)
- addto_action(action, convolv[i].name, ec_doit);
- }
-
- /* that is it */
- do_action(action);
- return 0;
- }
-
- /***************************************************************
- * do_ec actually does the convolution by calling img_convolve.
- * do_action will invoke ec_doit.
- ***************************************************************/
-
- static void
- ec_doit(long p)
- {
- ext_convolv_t *q = convolv + p;
-
- if (img_convolv(iptr, q->m, q->rows, q->cols, (int *) 0,
- img_rect(iptr), q->name) >= 0)
- {
- update_image_info(iptr);
- iptr->io->display(iptr, 4, 1);
- }
- }
-
-
- /****************************************************************
- * Free all ec
- ****************************************************************/
- void
- free_all_ext_convolv(void)
- {
- ext_convolv_t *ec = convolv + MAXCONV;
-
- while (--ec > convolv)
- ec_free(ec);
- }
-
- /*********************************************************************
- * remove redundant entries. Need to do this because external matrices
- * are loaded from SysDir and UserDir
- *********************************************************************/
-
- static int
- ec_uniq(void)
- {
- static int ok, uniq = 1; /* we have at least one uniq */
- ext_convolv_t *p = convolv, *ps;
- int i, found;
-
- if (ok)
- return uniq;
- p++;
-
- for (ps = p - 1 + MAXCONV; p < ps && p->name; p++)
- {
- /* search for in uniqued array */
- for (i = found = 0; !found && i < uniq; i++)
- found = ec_identical(p, convolv + i);
-
- if (!found)
- {
- if (convolv[i].name != p->name) /* not the same */
- {
- ec_free(convolv + uniq);
- ec_dup(convolv + uniq, p);
- ec_free(p);
- }
- uniq++;
- }
- else
- { /* redundant */
- ec_free(p);
- }
- }
- ok = 1;
-
- return uniq;
- }
-
-
- /******* scan string for matrix: n,n,n,n,n,n *****/
- static int **
- scan_matrix(int n, char *str)
- {
- int err = 0, c, k = 0, len = strlen(str);
- int **mm = get_mat(n, n, sizeof(int)), *m, *ms;
-
- if (mm)
- {
- m = mm[0];
- for (ms = m + n * n, err = k = 0; !err && m < ms && k < len; m++)
- {
- err = (sscanf(str + k, " %d ,%n", m, &c) < 1);
- k += c;
- }
- }
- if (err)
- {
- free_mat(mm);
- return 0;
- }
- return mm;
- }
-
- /****** read a external kernel defination file from stream fp ** **/
- #define ECFMT "@ %[^;]; %d ; %[^;];"
- static int
- ec_scanner_fp(FILE * fp, int start)
- {
- int order = 0, sofar = start, err = 0;
- char line[256], name[256], nm[256];
-
- while (fgets(line, sizeof(line), fp))
- {
- if (line[0] != '@')
- continue;
- err = (sscanf(line, ECFMT, name, &order, nm) < 3);
-
- /* skip if anything wrong */
- if (err || !name[0] || order <= 0 || order > 10 || !nm[0])
- {
- M_warn("EXTCONV", "Bad line %s\n \tname=%s\torder=%d",
- line, name, order);
- }
- else
- {
- convolv[sofar].name = strdup(name);
- convolv[sofar].rows = order;
- convolv[sofar].cols = order;
- if ((convolv[sofar].m = scan_matrix(order, nm)))
- {
- sofar++;
- }
- else
- {
- M_err("", "Bad matrix: %s", nm);
- }
- sofar %= MAXCONV;
- }
- }
-
- /* number of correct entries read */
- return sofar - start;
- }
-
- /******** Read definations from UserDir and SysDir */
- static int
- ec_scanner(void)
- {
- FILE *fp;
- int total = 0;
- static const char *convolvfile = "BIT_convolve";
-
- /* try the system directory first */
- if ((fp = get_HELPfile_fp(convolvfile, "r")))
- {
- total = ec_scanner_fp(fp, 0);
-
- #ifdef MDEBUG
- M_debug("ExtConvolv", "%d matrices read from %s", total, helppath);
- #endif
-
- fclose(fp);
- }
-
- /* try user directory */
- if ((fp = get_BITfile_fp(convolvfile, "r")))
- {
- total += ec_scanner_fp(fp, total >= 0 ? total : 0);
-
- #ifdef MDEBUG
- M_debug("ExtConvolv", "Total %d matrices read", total);
- #endif
-
- fclose(fp);
- }
-
- /* remove reduandant definations */
- if (total)
- {
- total = ec_uniq();
- }
- else
- {
- M_err("ExtConvolv", "error reading %s from %s", convolvfile, bitpath);
- M_err("ExtConvolv", "error reading %s from %s", convolvfile, helppath);
- Bark("ExtConvolv", "No valid convolution matrix found");
- }
- M_info("ExtConvolv", "Total %d unique matrices read", total);
- return total;
- }
-
-
- /*****************************************************************
- * END of External Convolution Kernel routine
- ************************************************************}***/
-
-
-
- /****************************************************************
- * Handle external filters as if the following is done:
- * dump | ext_filter | load
- *
- * the actual process is done in two steps
- * 1. external_filter > filtered_output
- * 2. load filtered_output
- *
- * This is still not strictly correct because what we really
- * want is a 3 step process:
- * 1. write currentimage > tmp
- * 2. external_filter tmp > output
- * 3. load output
- *
- * well, until someone complains
- ***************************************************************/
-
- /*************** Limits *****************************/
-
- #define MAX_B 35 /* no. of bindings */
- #define MAXFFMT 4 /* no. formats each B accepts */
- #define MAXTOK 125 /* max name, label, whatever */
-
-
- /********* Structure for bindings ****************/
- typedef struct
- {
- char *title, *pname, *opt; /* title, program, option */
- char *infmt[MAXFFMT + 1]; /* format, ppm, gif, etc */
- int in; /* index into the img_io struct */
- }
- ext_filter_t;
-
-
- /************ Variables and functions ***********/
- static ext_filter_t filter[MAX_B];
- static char *swapfile;
- static char *ef_cmd; /* current command */
-
- extern FILE *popen(const char *, const char *);
- #include <signal.h>
- #include <setjmp.h>
- static jmp_buf jpipe; /* for error recovery */
-
- #if defined (__STRICT_ANSI__) && !defined(__sgi__)
- typedef void (*SIG_PF) (int,...);
- #endif
-
- static SIG_PF opipe;
-
- static int ef_scanner(void);
- static void ef_pipe(int);
- static void ef_doit(long);
-
- /****************************************************
- * Global interface for external filters
- ******************************************************/
- int
- do_ext_filter(IPTR im)
- {
- static int nfs, bindex = -1;
-
- iptr = im;
-
- if (nfs <= 0 && (nfs = ef_scanner()) <= 0)
- {
- help_cb(0, HELP_FILTER);
- return -1;
- }
-
- /* make the action table */
- if (bindex < 0)
- {
- ext_filter_t *p = &filter[0], *ps;
- char *label;
-
- bindex = define_action("ExternFilter", "filter.hlp");
-
- for (ps = p + nfs; p < ps; p++)
- {
- label = p->title ? p->title : p->pname;
- if (addto_action(bindex, label, ef_doit) < 0)
- M_warn("Scanner", "addto_action failed for %s", label);
- }
- }
-
- if (bindex < 0)
- {
- Bark("ExtFilter", "Something is wrong");
- return -1;
- }
-
- /* take over the pipe handler */
-
- opipe = signal(SIGPIPE, ef_pipe);
- (void) setjmp(jpipe);
-
- /* fireworks here */
- do_action(bindex);
-
- /* restore old handler */
- (void) signal(SIGPIPE, opipe);
- return 0;
- }
-
- /*******************************************************************
- * The beef: actual work is done here. Really wish there were a
- * snprintf function which will make this routine much safer.
- *******************************************************************/
-
- static const char *pref = ".BIT";
- #ifdef __STRICT_ANSI__
- extern int pclose(FILE *);
- #endif
- static void
- ef_doit(long a)
- {
- char cmd[3 * MAXTOK], *opt;
- int in;
- IPTR local;
- ext_filter_t *p;
- IMG_IO *io;
-
- p = filter + a;
-
- /* find the best match from the list of needed formats */
- if ((in = best_format(iptr, p->infmt)) < 0)
- {
- Bark("ExtFilter", "BadFmt _%s_", p->infmt[0] ? p->infmt[0] : "None");
- return;
- }
-
- io = img_io + in;
-
- /* convert to the needed types if different */
- if (io->type != T_FLEX && iptr->type != io->type &&
- img_convert_type(iptr, io->type))
- return;
-
-
- if (!(swapfile = get_tmpf(pref)))
- {
- Bark("ExtBind", "unable to create tmpfile");
- return;
- }
-
- /* check if interactive command line options */
- if ((opt = p->opt) && strcmp(opt, "?") == 0)
- {
- const char *q;
- sprintf(cmd, "Options for %s", p->pname);
- if ((q = getstring(cmd, "", 1)))
- opt = strdup(q);
- check_emergency();
- }
-
- /* generate the shell command on the fly */
- ef_cmd = p->pname;
- sprintf(cmd, "%s %s > %s", p->pname, opt ? opt : "", swapfile);
-
- if (opt != p->opt)
- free(opt);
-
- M_info("pipe", "executing %s", cmd);
-
- if (!(iptr->fp = popen(cmd, "w")))
- return;
-
- /* need to save the original filename before dump */
- Strncpy(cmd, iptr->ifile, sizeof(cmd));
- io->dump(iptr);
-
- /**** wait until pipe closes ***************/
-
- show_busy("PleaseWait ...");
- (void) pclose(iptr->fp);
- end_busy();
-
- /******* So far so good, try to load it ****/
-
- set_current_window(win_id);
-
- /* service Q first before doing anything else */
- check_emergency();
-
- /* load the image and replace the old one if successful * */
- if ((local = load_image(swapfile)))
- { /* ok */
- free_image_mem(iptr); /* must not free iptr itself */
- memcpy(iptr, local, sizeof(*iptr));
- free(local);
- }
-
- del_tmpf(swapfile);
- Strncpy(iptr->ifile, cmd, TC_FL);
- update_filename(iptr->ifile);
- iptr->io->display(iptr, 3, 1);
- }
-
- /************** Free an ext binding ***************/
- static void
- ef_free(ext_filter_t * p)
- {
- char **q = p->infmt;
-
- Free(p->title);
- Free(p->pname);
- Free(p->opt);
-
- while (*q)
- {
- free(*q);
- *q = 0;
- q++;
- }
- }
-
- /************** Free all ext binding ***************/
- void
- free_all_ext_filter(void)
- {
- ext_filter_t *p = filter + MAX_B;
-
- while (--p >= filter)
- ef_free(p);
- }
-
-
- /******* make a copy of the ext_filter **************/
-
- static void
- ef_dup(ext_filter_t * to, ext_filter_t * from)
- {
- char **tof, **fromf;
-
- to->title = strdup(from->title);
- to->pname = strdup(from->pname);
- to->opt = strdup(from->opt);
- fromf = from->infmt;
- tof = to->infmt;
-
- while (*fromf)
- {
- *tof = strdup(*fromf);
- fromf++;
- tof++;
- }
- *tof = 0;
- }
-
- /******************************************************************
- * remove redundant definitions. we need to do this because BIT loads
- * definitions from sys dir and user dir
- *****************************************************************/
- static int
- ef_uniq(void)
- {
- ext_filter_t *p = filter, *ps;
- static int uniq = 1; /* will at least have on uniq entry */
- static int ok;
- int i, found;
-
- if (ok)
- return uniq;
-
- p++;
- for (ps = p + MAX_B - 1; p < ps && p->title; p++)
- {
- /* search thru uniq so far */
- for (i = found = 0; !found && i < uniq; i++)
- found = strcmp(p->title, filter[i].title) == 0 &&
- strcmp(p->pname, filter[i].pname) == 0;
-
- if (!found)
- { /* move it */
- if (filter[uniq].title != p->title)
- {
- ef_free(filter + uniq);
- ef_dup(filter + uniq, p);
- ef_free(p);
- }
- ++uniq;
- }
- else
- {
- ef_free(p);
- }
- }
- ok = 1;
- return uniq;
- }
-
-
- #define EFFMT "@%[^;];%[^;];%[^;];%[^;];%n"
- static int
- ef_scanner_fp(FILE * fp, int start)
- {
- char line[MAXTOK], blab[MAXTOK], prgm[MAXTOK];
- char opt[MAXTOK], inf[MAXTOK];
- ext_filter_t *p;
- int err = 0, in, n, kfmt, sofar = start;
-
-
- while (fgets(line, MAXTOK, fp))
- {
- if (line[0] != '@')
- continue;
- err = (sscanf(line, EFFMT, blab, prgm, opt, inf, &n) < 4);
-
- space_de(de_space(prgm));
- space_de(de_space(blab));
- space_de(de_space(opt));
- space_de(de_space(inf));
-
- #ifdef MTRACE
- M_trace("EB", "L=%s P=%s O=%s F=%s", blab, prgm, opt, inf);
- #endif
- err = err || (!prgm[0] || !inf[0]);
-
- if (!err)
- {
- p = &filter[sofar]; /* sofar will never out of bounds */
- p->title = strdup(blab[0] ? blab : prgm);
- p->pname = strdup(prgm);
- p->opt = opt[0] ? strdup(opt) : 0;
- p->infmt[0] = strdup(inf);
-
- /* now get alternate formats */
- err = 0;
- kfmt = 1;
- while (!err && kfmt < MAXFFMT && n < strlen(line) - 1)
- {
- err = sscanf(line + n, "%[^;];%n", inf, &in) <= 0;
- space_de(de_space(inf));
- n += in;
- if (!err)
- {
- p->infmt[kfmt] = strdup(inf);
- kfmt++;
- }
- }
- /* important. Best_format depends on this */
- p->infmt[MAXFFMT] = 0;
- sofar++;
- sofar %= MAX_B;
- }
- else
- {
- M_warn("EB", "bad line %s\n\ttitle: %s", line, blab);
- M_warn("EB", "\tpname:%s\n\t opt:%s\t inf:%s",
- prgm, opt, inf);
- }
- blab[0] = prgm[0] = opt[0] = inf[0] = '\0';
- }
- return sofar - start;
- }
-
- static int
- ef_scanner(void)
- {
- int sofar = 0;
- static const char *filterfile = "BIT_filters";
- FILE *fp;
-
- #ifdef MTRACE
- M_trace("EF_scanner", "Entering");
- #endif
-
- if ((fp = get_HELPfile_fp(filterfile, "r")))
- {
- sofar = ef_scanner_fp(fp, 0);
- (void) fclose(fp);
- M_info("ExtFilter", "%d bindings read from %s", sofar, helppath);
- }
-
- if ((fp = get_BITfile_fp(filterfile, "r")))
- {
- sofar += ef_scanner_fp(fp, sofar >= 0 ? sofar : 0);
- (void) fclose(fp);
- M_info("ExtFilter", "total %d bindings read from", sofar, bitpath);
- }
- #ifdef MTRACE
- M_trace("EF_scanner", "Exit");
- #endif
-
- /* check to make sure there are no repeat entries */
- if (sofar)
- {
- sofar = ef_uniq();
- }
- else
- {
- M_err("ExtFilter", "error reading %s from %s", filterfile, bitpath);
- M_err("ExtFilter", "error reading %s from %s", filterfile, helppath);
- Bark("ExtFilter", "No valid filters defined");
- }
- M_info("ExtFilter", "Total %d unique bindings read", sofar);
- return sofar;
- }
-
-
- /*************************************************************
- * All errors during execution of the filter will end-up here
- ************************************************************/
-
- static void
- ef_pipe(int sig)
- {
-
- #ifdef MTRACE
- M_trace("EB_pipe", "Entering");
- #endif
-
- if (sig != SIGPIPE)
- {
- Bark("EB_pipe", "Something is very wrong");
- clean_up();
- }
-
- Bark("ExtBind", "%s: Something is wrong in pipe", ef_cmd);
-
- remove_progress_report();
- fl_activate_all_forms();
- signal(SIGPIPE, ef_pipe);
- del_tmpf(swapfile);
-
- #ifdef MTRACE
- M_trace("EB_pipe", "Exit");
- #endif
- longjmp(jpipe, 1);
- }
-