/* File: gifcommand.c * Author: Fred Wobus (fw@sanger.ac.uk) * Copyright (C) J Thierry-Mieg and R Durbin, 1999 * ------------------------------------------------------------------- * Acedb is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * or see the on-line version at http://www.gnu.org/copyleft/gpl.txt * ------------------------------------------------------------------- * This file is part of the ACEDB genome database package, written by * Richard Durbin (Sanger Centre, UK) rd@sanger.ac.uk, and * Jean Thierry-Mieg (CRBM du CNRS, France) mieg@crbm.cnrs-mop.fr * * Description: * Exported functions: * gifControl - function that deals with giface-commands * gets called from command.c, if the kernel * command parser can't deal with a command * because it interact with graphical modules. * HISTORY: * Last edited: May 1 14:50 2003 (edgrif) * * Jan 27 16:05 1999 (fw): created this module to accomodate * the function gifControl() from gifacemain.c * Created: Wed Jan 27 16:04:40 1999 (fw) * CVS info: $Id: gifcommand.c,v 1.40 2003/05/01 13:50:47 edgrif Exp $ *------------------------------------------------------------------- */ #include #include #include #include #include #include #include #include #include #include /* for fMapGifXxx. */ #include /* for pepGifCommandXxxx */ #include /* #include cannot include because of clashes with MAP2GRAPH macros */ extern void gMapDrawGIF (ACEIN command_in, ACEOUT result_out); extern void pMapDrawGIF (ACEIN command_in, ACEOUT result_out); /*********************************/ /******** giface submenu ********/ enum {GIF_FMAP_RECALC = 400, GIF_DO_SMAP} ; enum {GIF_FEX_SEQGET = 600, GIF_FEX_SEQFEATURES} ; enum {GIF_SMAP_SEQGET = 700, GIF_SMAP_SEQFEATURES} ; enum {GIF_DASDNA = 800, GIF_DASTYPES, GIF_DASGFF} ; /* NOTE: If you change the functionality of these options * you have to update the documentation file whelp/Giface.html * to reflect your changes. * ALSO NOTE: If you add any new commands you must increment the number in the * first member of the options[] array to be the total number of commands. */ static FREEOPT options[] = { /* Total command number + cmdline prompt */ { 33, "acedb-gif" }, /* General functions. */ { -1, "Quit" }, /* quit command simulates EOF */ { '?', "? : this list of commands. Multiple commands ';' separated accepted" }, { 'd', "dimensions [-D displaytype] x y : image size in pixel for all or the specified displaytype" }, { 'D', "display [-D displaytype] [-view view] [class key] : graphic display [for the current key]" }, { 'B', "psdump [-e] [-c] filename : save active graph as postscript" }, { 'A', "gifdump filename : save active graph as a gif" }, { 'M', "mouseclick x y: simulate a left button click on the active graph" }, { 'm', "map map [-view view] [-coords x1 x2] [-hideheader] [-whole]: does not write - use gif after" }, { 'P', "pmap [-clone ] | [-contig ] : physical map" }, /* fmap/sequence operations. */ { 'S', "seqget [[class:]object [-coords x1 x2]] : sets current sequence for future ops on same line - if no name then get from active graph" }, { 'X', "seqdisplay [-visible_coords v1 v2] [-new] [-title title] : works on current sequence, use gif or ps to actually dump the display\n" "\t-new make a new sequence, current one is preserved (for use only with xremote currently)\n" "\t-title give your own title to the sequence"}, { 'n', "seqdna [-file fname] <-coords x1 x2> : works on current sequence " }, { 'f', "seqfeatures [-file fname] [-version 1|2] [-list [features | keys]] [-source source(s)] [-feature feature(s)] <-coords x1 x2> : works on current sequence, source(s)/feature(s) are '|' separated lists, " }, { 'g', "seqactions [-dna] [-gf_features] [-hide_header] [-rev_comp] : works on current sequence" }, { 'c', "seqcolumns {-on name} {-off name} {-list}: works on active sequence" }, /* NB seqcolumns will work BEFORE seqdisplay() now */ { 'a', "seqalign [-file fname] [-coords x1 x2] : must follow a seqdisplay " }, { 's', "sequence sequence [-coords x1 x2] : " }, { GIF_DO_SMAP, "smap -coords x1 x2 -from class:object -to class:object : maps cordinates between related sequences." }, { GIF_FMAP_RECALC, "seqrecalc causes the sequence to be recalculated for the active graph." }, { 'e', "EMBL filename : embl dump keyset to filename.embl" }, {500, "pepget [-coords x1 x2] : sets current protein for future ops on same line" }, {501, "pepseq [-file fname] <-coords x1 x2> : exports current petide sequence" }, {502, "pepalign [-file fname] <-coords x1 x2> : exports homols of current peptide" }, { 'K', "makemaps -gmap | -pmap | -cmap | -alpha | -all | -seqmap file | -seqclonemap file : makes cached maps and sorted class keysets" }, { 'U', "update [-all] : add one official update, or all" }, /* Trial code which allows choosing of sets of methods before the fmap is */ /* built, its made to use the new smap code so must be compiled with the */ /* smapConvert code not the fmapConvert code. */ { 'E', "edseqget [sequence [-coords x1 x2]] : sets current sequence for future ops on same line - if no name then get from active graph" }, /* Trial code using smap but NO fmap to get a sequence.... */ { GIF_SMAP_SEQGET, "smapseqget sequence [-coords x1 x2] : sets current sequence for future." }, { GIF_SMAP_SEQFEATURES, "smapseqfeatures [-file fname] [-version 1|2] [-list] [-source source(s)] [-feature feature(s)] <-coords x1 x2> : works on current sequence, source(s)/feature(s) are '|' separated lists, " }, /* Trial code to use the fex routines to do a gff dump. */ { GIF_FEX_SEQGET, "fexseqget [sequence [-coords x1 x2]] : sets current sequence for future ops on same line." }, { GIF_FEX_SEQFEATURES, "fexseqfeatures [-file fname] [-version 1|2] [-list] [-source source(s)] [-feature feature(s)] : works on current sequence, source(s)/feature(s) are '|' separated lists." }, /* To support DAS format output. */ {GIF_DASTYPES, "dastypes : gets types for current sequence.." }, {GIF_DASDNA, "dasdna : gets dna for current sequence.." }, {GIF_DASGFF, "dasgff : gets features for current sequence.." } } ; /* public, called by all gifnnnn programs. */ /* */ void gifControl (KEYSET ks, ACEIN fi, ACEOUT fo) { int option ; char *word = NULL ; FeatureMap seqLook = NULL ; PepGifCommand pepLook = NULL ; BOOL oldisGifDisplay = isGifDisplay ; void *fex_seq = NULL ; SMapFeatureMap smap_features = NULL ; #ifdef ED_G_NEVER_INCLUDE_THIS_CODE GTimer* timer ; timer = g_timer_new() ; g_timer_start(timer) ; #endif /* ED_G_NEVER_INCLUDE_THIS_CODE */ while (TRUE) { if (aceInOptPrompt (fi, &option, options)) switch (option) { /**** end of input / quit command ****/ case -1: goto finish ; /* only way to break out of while-loop */ case '?': /* help */ { int i ; for (i = 1 ; i <= options[0].key ; i++) aceOutPrint (fo, "// %s\n", options[i].text) ; } break ; case 'd': /* dimensions in pixels */ { KEY displayKey = 0; char *cp; int xpixels, ypixels; if ((cp = aceInWord(fi))) { if (strcmp(cp, "-D") == 0) { if ((cp = aceInWord (fi))) { if (displayIsObjectGeneric(cp, &displayKey)) { if (aceInInt (fi,&xpixels) && aceInInt (fi,&ypixels) && xpixels > 0 && ypixels > 0) { displaySetSize(name(displayKey), xpixels, ypixels); break; } } else { aceOutPrint (fo, "// Error : unsuitable display type %s\n", cp); break; } } else { aceOutPrint (fo, "// Error: -D must be followed by a display type\n") ; break ; } } else { aceInBack(fi); if (aceInInt (fi,&xpixels) && aceInInt (fi,&ypixels) && xpixels > 0 && ypixels > 0) { displaySetSizes(xpixels, ypixels); break; } } } aceOutPrint (fo, "// Usage: dimensions [-D displaytype] x y : " "image size in pixel for all or the specified displaytype\n") ; } break ; case 'D': /* display an object */ /* only displays single objects, multiple objects is an error. */ { KEYSET kA ; KEY classKey = 0, displayKey = 0, view = 0 ; char *cp ; KEY _VView, mm; lexaddkey("View", &mm, _VMainClasses); _VView = KEYKEY(mm); while ((cp = aceInWord(fi))) { if (*cp != '-') { aceInBack(fi) ; break ; } if (!strcmp(cp, "-D")) /* -D displaytype */ { if (!(cp = aceInWord(fi))) { aceOutPrint (fo, "// Error: -D must be followed by a display type\n") ; break ; } if (!displayIsObjectGeneric(cp, &displayKey)) { aceOutPrint (fo, "// Error: unsuitable display type %s\n", cp) ; break ; } } else if (!strcmp(cp, "-view")) /* -view view */ { if (!(cp = aceInWord(fi))) { aceOutPrint (fo, "// Error: -view must be followed by a view name\n") ; break ; } if (!lexword2key (cp, &view, _VView)) { aceOutPrint (fo, "// Error: unknown view %s\n", cp) ; break ; } } } if (aceInCheck (fi,"ww")) /* [class name] */ { cp = aceInWord(fi) ; if (!lexword2key (cp, &classKey, _VClass)) { aceOutPrint (fo, "// Error: bad class name %s\n", cp) ; break ; } kA = query(0, messprintf("Find %s \"%s\"", name(classKey), aceInWord(fi))) ; } else if (!ks) { aceOutPrint (fo, "// Error: no active list\n") ; break ; } else kA = ks ; if (!keySetMax (kA)) { aceOutPrint (fo, "// Error: active list is empty\n") ; break ; } if (keySetMax(kA) == 1) display (keySet(kA,0), view, displayKey ? name(displayKey) : 0) ; else aceOutPrint (fo, "// Error: can not display multiple objects\n") ; /* Only destroy the keySet if we created a new one, DON'T destroy */ /* the keyset we were passed in !! */ if (kA != ks) keySetDestroy (kA) ; } break; case 'B': /* dump the active graph as PostScript */ { BOOL colour = FALSE, EPSF = FALSE; word = aceInWord(fi) ; while ((strcmp(word, "-e") == 0) || (strcmp(word, "-c") == 0)) { if (strcmp(word, "-e") == 0) EPSF = TRUE; if (strcmp(word, "-c") == 0) colour = TRUE; word = aceInWord(fi); } if (!graphActive()) aceOutPrint (fo, "// psdump error : no active graph\n") ; if (!word || !*word) aceOutPrint (fo, "// Usage: psdump -e -c filename: dump the active graph in file as PostScript\n") ; else { char fileName[MAXPATHLEN] ; ACEOUT ps_out; BOOL rotation ; float scale ; int pages ; int err; char *fp = filGetFullPath(word, 0); strcpy (fileName, fp); messfree(fp); if (strcmp(filGetExtension(word), "ps") != 0) strcat (fileName, ".ps"); ps_out = aceOutCreateToFile(fileName, "w", 0); if (ps_out) { graphPSdefaults(graphActive(), PAPERTYPE_A4, &rotation, &scale, &pages) ; err = graphPS(graphActive(), ps_out, NULL, colour, EPSF, rotation, PAPERTYPE_A4, scale, pages) ; if (err == ESUCCESS) aceOutPrint (fo, "// I wrote the active graph " "to file %s\n", fileName) ; else aceOutPrint (fo, "// ERROR: Failed to write to " "file %s (%s)\n", fileName, messErrnoText(err)) ; aceOutDestroy(ps_out); } } } break; case 'A': /* dump a GIF of the active graph */ { word = aceInWord(fi) ; if (!graphActive()) aceOutPrint (fo, "// gifdump error : no active graph\n") ; else if (!word || !*word) aceOutPrint (fo, "// Usage gifdump filename: dump the active graph in file\n") ; else if (strcmp(word,"-") == 0) { /* LS 2 Mar 98 dump GIF to standard output */ if (graphGIF(graphActive(), fo, TRUE) == ESUCCESS) graphBoxInfoFile (fo); else aceOutPrint (fo, "// ERROR: Failed to write GIF data\n"); } else { char fileName[MAXPATHLEN]; ACEOUT gif_out, boxes_out; char *fp = filGetFullPath(word, 0); strcpy (fileName, fp); messfree(fp); if (strcmp(filGetExtension(fileName), "gif") == 0) fileName[strlen(fileName)-4] = '\0'; gif_out = aceOutCreateToFile(messprintf("%s.gif", fileName), "wb", 0); if (gif_out) { int err = graphGIF(graphActive(), gif_out, FALSE); if (err == ESUCCESS) aceOutPrint (fo, "// I wrote the active graph to file %s\n", fileName) ; else aceOutPrint (fo, "// ERROR: Failed to write to " "file %s (%s)\n", fileName, messErrnoText(err)) ; aceOutDestroy(gif_out); } boxes_out = aceOutCreateToFile(messprintf("%s.boxes", fileName), "w", 0); if (boxes_out) { graphBoxInfoFile (boxes_out) ; aceOutDestroy (boxes_out); } } } break; case 'M' : /* mouseclick x y */ { int xClick, yClick; if (!graphActive()) aceOutPrint (fo, "// mouseclick error : no active graph\n"); else if (!aceInInt (fi,&xClick) || !aceInInt (fi,&yClick)) aceOutPrint (fo, "// Usage: mouseclick x y - simulates a left button click in the active graph\n") ; else graphGIFLeftDown (xClick, yClick) ; } break; case 'm': /* map/view draw */ { gMapDrawGIF (fi, fo); } break ; case 'P': /* pmap draw */ { pMapDrawGIF (fi, fo); } break ; /* Sequence/fmap based operations. */ case 'S': /* get sequence, init fMap package */ seqLook = fMapGifGet (fi, fo, seqLook) ; /* destroys existing seqLook */ break ; case 'X': /* sequence display */ if (seqLook) fMapGifDisplay (fi, fo, seqLook) ; else aceOutPrint (fo, "// gif seqdisplay without active sequence\n") ; break ; case 'n': /* dna dump */ if (seqLook) fMapGifDNA (fi, fo, seqLook) ; else aceOutPrint (fo, "// gif seqdna without active sequence\n") ; break ; case 'f': /* feature dump */ if (seqLook) fMapGifFeatures(fi, fo, seqLook) ; else aceOutPrint (fo, "// gif seqfeatures without active sequence\n") ; break ; case 'g': /* actions */ if (seqLook) fMapGifActions (fi, fo, seqLook) ; else aceOutPrint (fo, "// gif seqactions without active sequence\n") ; break ; case 'c': /* column control */ if (seqLook) fMapGifColumns (fi, fo, seqLook) ; else aceOutPrint (fo, "// gif seqcolumns without active sequence\n") ; break ; case 'a': /* alignment */ if (seqLook) fMapGifAlign (fi, fo, seqLook) ; else aceOutPrint (fo, "// gif seqalign without displayed active sequence\n") ; break ; case 's': /* sequence draw - deprecated */ seqLook = fMapGifGet (fi, fo, seqLook) ; if (seqLook) fMapGifDisplay (fi, fo, seqLook) ; else aceOutPrint (fo, "// gif seqdisplay without active sequence\n") ; break ; case GIF_FMAP_RECALC: /* do recalculate of sequence. */ fMapGifRecalculate(fi, fo, seqLook) ; break ; case GIF_DO_SMAP: fMapGifsMap(fi, fo); break; case 500: /* get protein */ pepLook = pepGifCommandGet (fi, fo, pepLook) ; break ; case 501: /* dna dump */ if (pepLook) pepGifCommandSeq (fi, fo, pepLook) ; else aceOutPrint (fo, "// gif pepseq without active protein\n") ; break ; case 502: /* feature dump */ if (pepLook) pepGifCommandAlign (fi, fo, pepLook) ; else aceOutPrint (fo, "// gif pepalign without active protein\n") ; break ; /*------------------------------------------------------------*/ case 'e': /* EMBL dump */ { extern void emblDumpKeySetFile (KEYSET kset, char *fname) ; if ((word = aceInWord(fi))) emblDumpKeySetFile (ks, word) ; else aceOutPrint (fo, "// Usage: EMBL filename\n") ; } break ; /*------------------------------------------------------------*/ case 'K': /* make cached maps */ { extern void gMapMakeAll(void) ; extern void pMapMakeAll(void) ; extern void cMapMakeAll(void) ; extern void sMapMake (FILE *fil, BOOL isSeq) ; char *filname ; FILE *fil ; /* must save rest of free card, else sessionWriteAccess() destroys */ /* useless with aceIn cardKeep = strnew (freepos(), 0) ; */ if (!sessionGainWriteAccess()) { aceOutPrint (fo, "// Error: can't get write access\n") ; break ; } /* freeforcecard (cardKeep) ; messfree (cardKeep) ; */ while (aceInStep (fi, '-') && (word = aceInWord(fi))) { /* cardKeep = strnew (freepos(), 0) again useless now save because freesubs used in some *MakeAll */ if (!strcmp (word, "gmap")) gMapMakeAll () ; else if (!strcmp (word, "pmap")) pMapMakeAll () ; else if (!strcmp (word, "cmap")) cMapMakeAll () ; else if (!strcmp (word, "alpha")) lexAlphaMakeAll () ; else if (!strcmp (word, "all")) { pMapMakeAll () ; gMapMakeAll () ; cMapMakeAll () ; lexAlphaMakeAll () ; } else if (!strcmp (word, "seqmap")) { if (!(word = aceInWord(fi))) aceOutPrint (fo, "// Error: makemaps -seqmap " "requires a file name\n") ; else if (!(fil = fopen (word, "w"))) aceOutPrint (fo, "// Error: makemaps -seqmap " "failed to open file %s\n", word) ; else { filname = strnew (word, 0) ; sMapMake (fil, TRUE) ; aceOutPrint (fo, "// Sequence-* map file written to %s\n", filname) ; messfree (filname) ; fclose (fil) ; } } else if (!strcmp (word, "seqclonemap")) { if (!(word = aceInWord(fi))) aceOutPrint (fo, "// Error: makemaps -seqclonemap " "requires a file name\n") ; else if (!(fil = fopen (word, "w"))) aceOutPrint (fo, "// Error: makemaps -seqclonemap " "failed to open file %s\n", word) ; else { filname = strnew (word, 0) ; sMapMake (fil, FALSE) ; aceOutPrint (fo, "// Sequence-* Clone map file written to %s\n", filname) ; messfree (filname) ; fclose (fil) ; } } else aceOutPrint (fo, "// Usage: makemaps -gmap | -pmap | -cmap | -alpha | -all | -seqmap file | -seqclonemap file\n") ; /* freeforcecard (cardKeep) ; messfree (cardKeep) ; useless with aceIn */ } if (aceInWord(fi)) /* i.e. something not starting with '-' */ { aceOutPrint (fo, "// unrecognized option %s\n", word) ; aceOutPrint (fo, "// Usage: makemaps -gmap | -pmap | -cmap | -alpha | -all | -seqmap file | -seqclonemap file\n") ; } } break ; case 'U': /* add updates */ if ((word = aceInWord(fi))) { if (!strcmp (word, "-all")) updateDoAction (TRUE) ; else aceOutPrint (fo, "// Usage: update [-all]\n") ; } else updateDoAction (FALSE) ; break ; /* NEW FUNCTIONS TESTING... */ /* my new sequence smap convert type with choosing of features */ /* ahead of smapconvert. This is NOT fex based. */ case 'E': /* get sequence, init fMap package */ seqLook = fMapEdGifGet (fi, fo, seqLook) ; /* destroys existing seqLook */ break ; /* My new smap based functions to do gff dumping. */ case GIF_SMAP_SEQGET: /* Get the sequence. */ { smap_features = sMapFeaturesCreate(fi, fo, smap_features) ; /* destroys any existing fex_seq. */ break ; } case GIF_SMAP_SEQFEATURES: /* feature dump */ { if (smap_features) sMapFeaturesGFF(fi, fo, smap_features) ; else aceOutPrint (fo, "// gif smapseqfeatures without active sequence\n") ; break ; } /* My new fex based functions to do gff dumping. */ case GIF_FEX_SEQGET: /* Get the sequence. */ aceOutPrint (fo, "// not supported yet...\n") ; #ifdef ED_G_NEVER_INCLUDE_THIS_CODE fex_seq = gffFexGetSeq(fi, fo, fex_seq) ; /* destroys any existing fex_seq. */ #endif /* ED_G_NEVER_INCLUDE_THIS_CODE */ break ; case GIF_FEX_SEQFEATURES: /* Dump the features as GFF */ if (fex_seq) aceOutPrint (fo, "// not supported yet...\n") ; #ifdef ED_G_NEVER_INCLUDE_THIS_CODE gffFexFeatures(fi, fo, fex_seq) ; #endif /* ED_G_NEVER_INCLUDE_THIS_CODE */ else aceOutPrint (fo, "// gif fexseqfeatures without active sequence\n") ; break ; /* DAS functions. */ case GIF_DASTYPES: aceOutPrint (fo, "// DAS types command.\n") ; break ; case GIF_DASDNA: if (seqLook) dasDNA (fi, fo, seqLook) ; else aceOutPrint (fo, "// gif dasdna without active sequence\n") ; break ; case GIF_DASGFF: if (seqLook) dasGFF(fi, fo, seqLook) ; else aceOutPrint (fo, "// gif dasgff without active sequence\n") ; break ; } /* end-switch (key) */ } /* end-while(TRUE) */ #ifdef ED_G_NEVER_INCLUDE_THIS_CODE printf("Elapsed time: %g\n", g_timer_elapsed(timer, NULL)) ; g_timer_destroy(timer) ; #endif /* ED_G_NEVER_INCLUDE_THIS_CODE */ /* This function can be called in one of two ways: as a result of using */ /* giface/sgifaceserver, or using the xremote facility of xace. For the */ /* former it is crucial that the below stuff is freed, for the latter it */ /* should not be freed as this will leave xace with nothing to display. */ finish: #ifdef ED_G_NEVER_INCLUDE_THIS_CODE /* Currently the fex stuff will always be destroyed, its only intended for */ /* use from giface/server. */ if (fex_seq) gffFexDestroySeq(fex_seq) ; #endif /* ED_G_NEVER_INCLUDE_THIS_CODE */ if (smap_features) sMapFeaturesDestroy(smap_features) ; if (isGifDisplay) /* yuch global. */ { /* must kill seqLook before graphCleanup, else will not know if seqLook had a graph and is already destroyed */ if (seqLook) fMapDestroy (seqLook) ; if (pepLook) pepGifCommandDestroy (pepLook) ; graphCleanUp () ; /* kill all graphs except active graph */ graphDestroy () ; /* kill active graph */ } isGifDisplay = oldisGifDisplay ; return; } /* gifControl */ /**************************************************/ /**************************************************/