/* Output from p2c 1.21alpha-07.Dec.93, the Pascal-to-C translator */ /* From input file "search.p" */ #include /* search: search a book for strings by Thomas Schneider, modified by Gary Stormo some concepts from Jon McCabe and Stephen O'Haire Dr. Thomas D. Schneider National Institutes of Health National Cancer Institute Center for Cancer Research Nanobiology Program Molecular Information Theory Group Frederick, Maryland 21702-1201 toms@ncifcrf.gov permanent email: toms@alum.mit.edu (use only if first address fails) http://www.ccrnp.ncifcrf.gov/~toms/ module libraries: delman, delmods, prgmods */ /* end of program */ /* begin module version */ #define version 6.92 /* of search.p 2008 Apr 22 2008 Apr 21, 6.92: first base of mutation counting is zero of feature 2008 Apr 21, 6.91: duplication removal by lister when mutations identical 2008 Apr 21, 6.90: cleanup dofeatures 2008 Apr 21, 6.88: hoining dofeatures 2008 Apr 21, 6.87: negparts need adjusting ... done? 2008 Apr 21, 6.86: negparts need adjusting 2008 Apr 21, 6.85: posparts and negparts need adjusting 2008 Apr 21, 6.84: located the bug, fixing ... in dofeatures 2008 Apr 21, 6.83: search string inversion bug 2008 Apr 19, 6.82: avoid infinite loop when bad command - quit! 2008 Apr 16, 6.81: clean up 2008 Apr 16, 6.80: R and I commands 2006 May 09, 6.78: fix bug: "name" was ""name"" from procedure display at "name the piece into the delila instructions" 2005 Sep 15, 6.77: Infinite loop if no final 'q' command! This is hard to solve because the program needs to work both interactively and with 'search < searchp'. Recorded as a known bug. 2004 Sep 8, 6.76: fix bug in getcolorbackground (wrong call for newTparam) 2004 Aug 25, 6.75: searchp example built, delila subsystem takes comments 2004 Aug 5, 6.74: demo.colors.search.jpg 2004 Aug 5, 6.73: demo.colors.search directory (as tarball) 2004 Jul 21, 6.72: implement petal height control; document C command 2004 Jul 21, 6.71: implement petal height control; document C command 2004 Jul 18, 6.70: B command features written properly 2004 Jul 18, 6.69: B command reads ok. 2004 Jul 18, 6.68: module upgrades completed; new B and C commands 2004 Jul 18, 6.67: spelling; begin color named objects in searchfeatures 6.66 2002 Aug 28: add to wish list - Delila format mutations 6.65 2001 Sep 9: bug in ascii feature placement when complement: featureinserts 6.64 2001 Sep 7: work on spiechange 6.63 2001 Sep 7: fix bug: complement should accept (/) symbols 6.62 2001 Aug 23: variables for both book and searchinst (not debugged). 6.61 2000 Nov 6: set dnamax to 10,000,000 for speed (it had been reset) 6.60 2000 Jun 16: spell improve, doc upgrade 6.59 2000 Jun 26: absorb upgrades to delmod 6.57 2000 Jun 3: allow [ and ] in search patterns 6.50 1999 Dec 15: named searches go into searchinst as name "whatever"; 6.49 1999 Dec 13: delmod/y2k upgrade 6.44 1999 June 3: mark mismatches on features 6.42 1999 April 29: type 3 instructions 6.38 1999 April 28: delila instructions use 'same', fixed and in delmod 6.33 1999 April 8: delila instructions use 'same' 6.30 1999 April 7: "A" command resets objects to be arrows 6.29 1998 June 24: inst file renamed searchinst so as not to kill previous inst!! 6.25 1998 Jan 4: upgrade dnamax to 10 million base sequences for search of genomes 6.24 1997 Oct 10: strings made 2000 characters long 6.16 1997 May 8: relationship uses $ now, not ^ 6.12 1997 May 7: upgrade to searchfeatures origin before 1983 */ /* end module version */ /* begin module describe.search */ /* name search: search a book for strings synopsis search(book: in, searchinst: out, result: out, input: intty, searchfeatures: out, output: out) files book: any book from the Delila system searchinst: Delila instructions of the form 'get from 56 -5 to same +5;' that define the location of found strings. One must turn on printing to the searchinst file to obtain these (see below). If there are instructions with names inside double quotes, then these will be put out as Delila name instructions. See the searchfeatures file; this is turned on at the same time. See examples. result: a transcript of the results seen on the output file. Lines not containing numerical data begin with an '*' so that they can be ignored by other programs such as genhis and xyplo. input: typed input from the user, or a file of rules. searchfeatures: features for the lister program. To start the file, simply provide a name inside double quotes (eg "EcoRI"). Subsequent searches (eg gaattc) will be labeled with that name. To turn off the features, use an empty quote string, as "". The searchfeatures file can be concatenated with other features to create the features file for lister. output: messages, results and prompts to the user. description (note: in the following examples, do not type the quote marks.) the search program allows one to look for simple patterns in a book. the patterns can be like 'ggag', that is, with particular bases (always written 5' to 3') or it can include unknown 'spacing' bases, as in 'ggagnnnnnnnnnatg'. any base will be allowed in the n positions. one can shorten the instruction: 'ggag9natg', and one can make some of the spacing 'extentable' as in 'ggag5e4natg' which allows a 5 to 9 spacing between the two elements. one can obtain Delila instructions for the strings found by turning on printing, setting 'from' and 'to' values and searching. for example: 'd p f -5 t +10 q gga6e3n#atg' sets up printing, with from=-5, to=+10. the search will result in instructions for strings centered on the a of the atg (by the # symbol). the form '(a/g)ct' means to search for both 'act' and 'gct'. you may specify numbers of mismatches, and control how much is printed. you can type many commands on one line, separated by spaces. you can also search for relations between bases. currently the allowed relations are: identity, non-identity, complementarity and non-complementarity. see delman.use.search or type 'help' while inside the program to get more information. NOTE: Many commands now are capital letters to avoid confusion between commands. See the help function (H, ?) for details. 2004 July 21: There is a new command, B, which defines colors on seach features as displayed by the lister program. examples If one is working with an odd binding site (one with an odd number of bases) one should use the # symbol to obtain Delila instructions. The complement sequence will continue to number the central base. gaa#nttc complemented becomes gaa#nttc If one is working with an even binding site (one with an even number of bases) one should use the % symbol to obtain Delila instructions. The complement sequence will continue to number the following base. ga%attc complemented becomes ga#attc The program is pretty smart about writing the Delila instructions. If one searches for the complementary sequence, the instructions are automatically written to extract the complementary pattern found. Thus if one searches for #gtt in ex0bk (the example book file), there is one found in the positive direction of the fragment. Then if one takes the complement with the "~" command, one is searching for aa#c. Two of these are located in the piece. The instructions are written so that the gtt's all line up, as is easily checked by extracting the fragments with delila and looking with alist. To create searchfeatures, define the name of a search string by typing the name inside quotes (as: "EcoRI") and then search. Vertical bars or carets (| or ^) in the search string (as: g|aattc) will carry over to the feature. If you have search instructions: D from -200 to +200 q "aceB" agttatcaagtatttttaattaaaatggaaattgtttttgattttgcattttaaatgagtagtcttagtt#n q then the resulting Delila instructions in searchinst will look like: organism E.coli; chromosome E.coli; piece U00096; name "aceB"; get from 4212981 -200 to same +200 direction +; documentation delman.use.search see also {An example search parameter, searchp file:} searchp {A search parameter file for most restriction enzymes:} enzyme {Program to create input DNA sequences:} delila.p {Example book for input:} ex0bk {Program that takes the bookand the scan features as input to create a map of the DNA sequence:} lister.p ftp://ftp.ncifcrf.gov/pub/delila/demo.colors.search.jpg {Example of colored boxes in search results:} demo-colors-search.zip {A second colored box example:} search-bar-color.zip author Thomas D. Schneider, modified by Gary Stormo bugs There is overlap between the letters used as commands to the program and letters used as ambiguous bases. For instance, h can mean (a/c/t) or it can mean 'help'. The best way to avoid confusion is to always start search strings with either a,c,g,t,n or (. Warning: if you use a file for input, be sure that the rules include a quit command and have no errors in them. It is possible that errors will lead to an infinite loop, though this has never been observed. (This may be a general problem with interactive i/o in pascal on your computer.) The searchfeatures only work with rigid strings since only the first definition will be accepted by lister. It is not clear how to handle variable sizes (like gat3etag). A search for "incorrect.symmetry" cc#gg will be located correctly, but following that by ~ = (to get the complement and search again) will not give a correct display. Using cc%gg will because the % matches the symmetry of the site. Likewise, "ok" tc#nga ~ = "not.ok" tc%nga ~ = It is not yet clear whether the user can be protected against this. The variables orgchange, chrchange and piechange do not work properly. Probably they should be done for both the book being read AND for the delila instructions being written. HOWEVER it seems that since the book has a certain structure, the output instructions can follow it to some extent. 1999 June 2: It would be nice to record mismatches on the feature, but this would require changing the definition for every found piece! 2002 Aug 28: add to wish list - Delila format mutations --- * piece: U24170, #1, configuration: linear, direction: +, begin: 3158, end: 3238 * "atcctgggaatttctgggaa" "agactgggcatgtctgggca" " xx x x x " 5 mismatche(s) ^ 3194 * --- Have search spit out the "with"-type Delila instructions for these. 2005 Sep 15: The program will go into an infinite loop if one calls it non-interactively like this: search < searchp if there is no final 'q' command. It is not clear how to solve this because interactive input relys on detecting the eof. So just make sure that your searchp files end with 'q'! */ /* end module describe.search */ /* no longer pointed to: demo.colors.search.tar.Z {(See untarball in the toolkit,} http://www.lecb.ncifcrf.gov/~toms/toolkit.html {for unpackaging the tar file.)} */ /**************************************************** * programming note * search uses a period to end search strings rather * than the string length. this is a historical * artifact that must be lived with until a more * advanced search is written (preferably based on * a bnf). *****************************************************/ /* more constants: */ /* BEGIN module interact.const */ /* lock in place for larger strings ... */ #define maxstring 2000 /* the maximum string */ /* END module interact.const version = 'prgmod 3.96 85 mar 18 tds'; */ #define maxquotestring 2000 /* maximum length of a string inside "" */ #define answersmax 10 /* maximum number of times to try to get an answer from input. If the input is a file, we NEVER will get an answer and go into an infinite loop. To avoid that, count the number of answers. If it exceeds this constant, the program stops. */ /* LOCK begin module book.const */ /* constants needed for book manipulations */ #define dnamax 10000000L /* length of dna arrays */ #define namelength 100 /* maximum key name length */ #define linelength 80 /* maximum line readable in book */ /* LOCK end module book.const version = 7.47; {of delmod.p 2000 June 26} */ /* begin module datetime.const */ #define datetimearraylength 19 /* length of dataarray for dates, It is just long enough to include the 4 digit year - solving the year 2000 problem: 1980/06/09 18:49:11 123456789 123456789 1 2 */ /* end module datetime.const version = 'cdatemod.p 1.19 1999Dec13'; */ /* begin module info.const */ #define infofield 10 /* size of field for printing information in bits */ #define infodecim 6 /* number of decimal places for printing information */ /* these are used for conlist only */ #define nfield 8 /* size of field for printing n, the number of sites */ /* end module info.const version = 4.73; (@ of prgmod.p 2004 Jul 22 */ /* begin module ribl.const */ #define minribl (-2000) /* lowest ribl matrix from allowed */ #define maxribl 2000 /* highest ribl matrix to allowed */ #define defnegativeinfinity (-1000) /* default for negative infinity for the Ri(b,l) table */ /* end module ribl.const version = 4.73; (@ of prgmod.p 2004 Jul 22 */ /* begin module datetime.type */ /* array for dates */ typedef Char datetimearray[datetimearraylength]; /* end module datetime.type version = 'cdatemod.p 1.19 1999Dec13'; */ /* begin module book.type */ /* types needed for book manipulations */ typedef long chset[5]; /* types defined in book definition */ typedef Char alpha[namelength]; /* this is not alfa */ /* name is a left justified string with blanks following the characters */ typedef struct name { alpha letters; /* zero means an unspecified structure */ char length; } name; typedef struct line { /* a line of characters */ Char letters[linelength]; char length; struct line *next; } line; typedef enum { plus, minus, dircomplement, dirhomologous } direction; typedef enum { linear, circular } configuration; typedef enum { on, off } state; typedef struct header { /* header of key */ name keynam; /* key name of structure */ line *fulnam; /* full name of structure */ /* note key */ line *note; } header; /* begin module base.type */ /* define the four nucleotide bases */ typedef enum { a, c, g, t } base; /* end module base.type version = 7.64; {of delmod.p 2004 Jul 18} */ /* sequence types */ typedef long dnarange; /* p2c: search.p, line 365: * Note: Field width for seq assumes enum base has 4 elements [105] */ typedef uchar seq[(dnamax + 3) / 4]; typedef struct dnastring { seq part; dnarange length; struct dnastring *next; } dnastring; typedef struct orgkey { /* organism key */ header hea; /* genetic map units */ line *mapunit; } orgkey; typedef struct chrkey { /* chromosome key */ header hea; double mapbeg; /* number of genetic map beginning */ /* number of genetic map ending */ double mapend; } chrkey; typedef struct piekey { /* piece key */ header hea; double mapbeg; /* genetic map beginning */ configuration coocon; /* configruation (circular/linear) */ direction coodir; /* direction (+/-) relative to genetic map */ long coobeg; /* beginning nucleotide */ long cooend; /* ending nucleotide */ configuration piecon; /* configruation (circular/linear) */ direction piedir; /* direction (+/-) relative to coordinates */ long piebeg; /* beginning nucleotide */ long pieend; /* ending nucleotide */ } piekey; typedef struct piece { piekey key; dnastring *dna; } piece; typedef struct reference { name pienam; /* name of piece referred to */ double mapbeg; /* genetic map beginning */ direction refdir; /* direction relative to coordinates */ long refbeg; /* beginning nucleotide */ long refend; /* ending nucleotide */ } reference; typedef struct genkey { /* gene key */ header hea; reference ref; } genkey; typedef struct trakey { /* transcript key */ header hea; reference ref; } trakey; typedef struct markey { /* marker key */ header hea; reference ref; state sta; line *phenotype; struct marker *next; } markey; typedef struct marker { markey key; dnastring *dna; } marker; /* end module book.type version = 7.64; {of delmod.p 2004 Jul 18} */ /* begin module interact.type */ /* begin module string.type */ /* pointer to a string */ typedef struct string { /* a string of characters */ Char letters[maxstring]; /* the letters in the string */ long length; /* the number of characters in the string */ long current; /* the letter we are working on */ Char *next; /* the next string in a series */ } string; /* end module string.type version = 4.73; (@ of prgmod.p 2004 Jul 22 */ /* end module interact.type version = 4.73; (@ of prgmod.p 2004 Jul 22 */ /* ribltypeptr = integer; (* dummy to satisfy compiler NO GOOD!!!! *) */ /* begin module wave.type */ /* to link several wave definitions together */ typedef struct waveparam { /* parameters to define a cosine wave */ /* define a cosine wave: */ Char extreme; /* h or l, the high or low extreme to be defined */ double wavelocation; /* the location in bases of the extreme */ double wavebit; /* the location in bits of the extreme */ double waveamplitude; /* the amplitude of the wave in bits */ double wavelength; /* the wave length of the wave in bases */ /* 2000 Nov 1. This is difficult because the length of a curve is not simply multiplied by a scale factor. BASEdashon: real; (* dashon interval in bases *) BASEdashoff: real; (* dashon interval in bases *) BASEdashoffset: real; (* dashon interval in bases *) */ double dashon; /* the size of on dashes in cm. dashon <= 0 means no dashes */ double dashoff; /* the size of on dashes in cm */ double dashoffset; /* the size of off dashes in cm */ double thickness; /* thickness of the wave in cm. <= 0 means default */ struct waveparam *next; /* the next wave */ } waveparam; /* end module wave.type version = 4.73; (@ of prgmod.p 2004 Jul 22 */ /* begin module scan.type */ /* define the ribl matrix. Source library is prgmod.p REQUIRES ribl.const module REQUIRES base.type or book.type module REQUIRES wave.type module for wave definition! */ typedef double rblarray[(long)t - (long)a + 1][maxribl - minribl + 1]; /* real(B,L) */ typedef struct ribltype { string riblname; /* name of the weight matrix */ Char *riblheader; /* misc header information, starting with '*' */ rblarray data; /* real(B,L) */ long numbers[(long)t - (long)a + 1][maxribl - minribl + 1]; /* n(b,l) */ long frombase, tobase; /* range of the matrix */ double mean, stdev; /* mean and standard deviation of distribution */ double consensus; /* Ri value of consensus sequence */ double anticonsensus; /* Ri value of anticonsensus sequence */ double averageRi; /* average Ri for random sequence */ long n; /* number of sequences used to create matrix */ Char symmetry; /* the symmetry of the Riblmatrix */ waveparam *waves; /* cosine wave definitions for the matrix */ double cmperbase, cmperbit; /* required for wave dash definition */ double Ribound; /* the Ri boundary for this definition */ double Zbound; /* the Z boundary for this definition */ double Pbound; /* the probability boundary for this definition */ } ribltype; /* pointer to ribltype so it does not need to be created unless actually used */ /* end module scan.type version = 4.73; (@ of prgmod.p 2004 Jul 22 */ /* begin module definition.feature.type */ /* Features and their definitions for the lister program */ typedef struct petaltype { /* define parts of a colored rectangle around a walker */ long el; /* edgelinewidth: edge linewidth (integer) */ Char c_; /* color kind: how color is defined: r for RGB, h for HSB */ /* ---------------------------------------------- */ double eh; /* edgeh: edge hue OR red */ double es; /* edges: edge saturation OR blue */ double eb; /* edgeb: edge brightness OR green */ /* ---------------------------------------------- */ double fh; /* fillh: fill hue OR red */ double fs; /* fills: fill saturation OR blue */ double fb; /* fillb: fill brightness OR green */ /* ---------------------------------------------- */ double spare; /* spare variable */ } petaltype; /* pointer to definetype */ typedef struct definetype { /* store a definition */ /* define "Site" "-" "" -7 -3.5 0 +3.0 +5 */ string nametag; /* name of the feature */ string background; /* background padding characters */ string negparts; /* parts of the feature display */ string posparts; /* parts of the feature display */ double locations[maxstring]; /* locations of the marks of the feature */ /* ---------------------------- */ /* computed values: */ long marks; /* the number of marks used in this feature */ double min; /* one end of the feature (minimum location) */ double max; /* the other end of the feature (maximum location) */ long number; /* the number of the definition read in */ /*[[*/ ribltype *matrix; /* an ribl matrix if available */ /* The following boundaries are DIFFERENT from the originally defined boundaries of the matrix. This allows the matrix to keep its bounds (eg for default values for scanning AND it allows the lister program to define separate boundaries for displaying green versus red on the zero bar. */ double RiboundFeature; /* the Ri boundary for this feature */ double ZboundFeature; /* the Z boundary for this feature */ double PboundFeature; /* the probability boundary for this feature */ petaltype petal; /* color rectangle background */ /*]]*/ struct definetype *next; /* the next definition recorded */ } definetype; /* ---------------------------- */ /* pointer to featuretype */ typedef struct featuretype { /* store a feature */ /* @ K01789 270 +1 "Site" "Positive 270" @ K01789 270 -1 "Site" "Negative 270" @ K01789 280 +1 "Site" "Positive 280" [[ @ K01789 229.0 -1 "dnaA" "+12.2 bits " 12.200338 -0.473212 0.318031 ]] */ string id; /* name of the sequence piece the feature is on */ double coordinate; /* location of zero base */ long orientation; /* -1 or +1 is in direction of piece */ string nametag; /* the name tag - name of the feature */ string othertag; /* the other tag - another tag for misc use */ /* ---------------------------- */ definetype *definition; /* the definition of the feature */ /*[[*/ /* ---------------------------- */ /* the following three values are only defined when there is a definition for the feature matrix */ double Ri; /* individual information of this site */ double Z; /* Z score for this site */ double probability; /* probability for this site */ /* Three parameters replace Ri, Z and p when there is no matrix, Aparam, Bparam and Cparam. If there is a matrix, Tparam will be blank. Otherwise: */ Char Tparam; /* a parameter that defines the kind of parameter that the remainder parameters are. */ double Aparam; /* a parameter */ double Bparam; /* a parameter */ double Cparam; /* a parameter */ double Dparam; /* a parameter */ /* Since these parameters are now (2004 July 17) able to substitute for Ri, Z and probability, the Tparam cannot be placed in front of the three parameters in feature files. Tparamvalues: h = hsb feature colors: hue, saturation, brightness r = rgb feature colors: red, green, blue b = bit range for the feature ' ' = defaults to sequence walker Summary: Tparam Aparam Bparam Cparam Dparam For ' ' Ri Z P (none) walker 'h' hue saturation brightness (none) ascii lines 'r' red green blue (none) ascii lines 'H' hue saturation brightness thickness color bar 'R' red green blue thickness color bar In this scheme one can control the color of the bar as an ascii string OR one can control the colored rectangle behind the bar but NOT BOTH. */ /*zzz*/ /*]]*/ /* ---------------------------- */ double evencoordinate; /* location of zero base for asymmetric and odd symmetry sites, with 0.0 as the decimal. For even symmetry sites it's the point of symmetry, with 0.5 as the decimal. */ /* ---------------------------- */ /* computed values: */ boolean unsatisfied; /* true when the feature has not yet been used during printing a line */ double fromrange; /* the lower part of the feature */ double torange; /* the higher part of the feature */ long number; /* the number of the feature read in */ long desiredline; /* The line the feature wants to be printed on. Zero means any value. Line increases down the page. */ /* ---------------------------- */ struct featuretype *next; /* the next feature recorded */ } featuretype; /* end module definition.feature.type version = 4.73; (@ of prgmod.p 2004 Jul 22 */ /* for keeping track of related bases */ typedef long intarray[maxstring]; Static _TEXT book; /* the book being searched */ Static _TEXT searchinst; /* Delila instructions */ Static _TEXT result; /* for hardcopy output */ /* input, search instructions */ /* output, display to screen */ Static _TEXT searchfeatures; /* search features for lister program */ Static datetimearray datetime; /* the date and time of this search */ Static string buffer; /* a rule or typed line from input */ Static boolean gotten; /* whether a token desired was obtained */ Static Char command; /* a user's command */ /* user settable varibles */ /* variables defined in viewhelp: */ Static boolean viewt, viewe, viewi, viewf, views, viewp, viewd, viewm, viewb, viewnothing; /* a flag that the user is not viewing anything. if true, the user is prevented from doing a search for which no results will be shown */ Static long mismatches; /* maximum number of mismatches allowed */ Static boolean printinginstructions; /* true means that when a pattern is found, instructions for getting to it in the library are printed into searchinst */ Static long fromplace, toplace; /* what to get around a found pattern #'d base (Delila print command) */ Static long insttype; /* instruction type. insttype=1 means the form get from p -/+f to same +/-t dir +/-; insttype=2 means the form get from p1 -/+f to p2 +/-t dir +/-; where p or p2 are the current location, p1 is the previous location. insttype=3 means the form get from p1 -/+f to p2 +/-t dir +/-; where p1 is the current location 5' end, p2 is the 3' end */ Static boolean oktosearch; /* if true, searches are performed when the = command is given or when the pattern is typed. If false, searches are performed only when the = command is given */ Static boolean firstinput; /* this variable helps the user the first time, when, under unix operating systems, the first line is ignored */ /* user defined search start point and shift between search steps: */ Static long startpoint, shift; Static boolean ok; /* the pattern typed in was ok */ Static string pattern; /* the pattern to search for */ Static string exppattern; /* the pattern expanded */ Static string lastpattern; /* the pattern previously searched for */ Static long bookmatches; /* total matches in the book by a pattern */ /* relatedbase is an array of integer that tells what position in the pattern this base is related to */ Static intarray relatedbase; Static boolean relational; /* true if there is a relation in the pattern */ Static boolean flip; /* if true, reverse the direction of written Delila instructions. This is used when the fromposition is greater than the to position. */ Static boolean reusethepiece; /* if true, don't read the book anymore because there is only one sequence in the book! This should speed up searches. */ /* variables for searchfeatures */ Static boolean dosearchfeatures; /* whether to create the searchfeatures */ Static boolean featuredefwritten; /* whether the current feature definition has been written to searchfeatures */ Static definetype *thedefinition; /* the current definition */ Static featuretype *thefeature; /* the current feature */ Static boolean doarrow; /* the next feature will be an arrow */ Static boolean featureinserts; /* inserts to the feature defined or not. For historical reasons symbols like # are inserted into the feature at the final match stage. But if one searches with a string and takes the complement, then they must NOT be inserted again during the second search. I suppose the same thing could happen with mismatches. So this boolean makes sure that the symbols are inserted only one time. */ Static boolean poundsign; /* true if a # was used in the search string. Normally the search feature ends are just specified from the left edge. However, when a user requests #, it means that the feature is specified from the point given by the #. */ /* ooo */ /* 2001 Aug 23: I will DEFINE the following to be tracking the book state. See below for the new variables. */ Static boolean orgchange, chrchange, piechange; /* that any changed */ Static boolean orgopen, chropen, pieopen; /* used by getocp */ Static orgkey org; /* the current organism */ Static chrkey chr; /* the current chromosome */ Static piece *pie; /* the current piece */ Static long theline; /* tracking line number in book */ /* 2001 Aug 23: these variables track the state of the searchinst */ Static boolean sorgchange, schrchange, spiechange; /* that any changed */ Static boolean sorgopen, schropen, spieopen; /* which are open */ Static boolean patterncomplement; /* if false, then the pattern is as typed in. If true, then the pattern is the complement of that typed in. By keeping track of this, the orientation of the Delila instructions can be made correct. */ Static long answers; /* current number of answers to a question */ /* begin module book.var */ /* ************************************************************************ */ /* global variables needed for book manipulations */ /* free storage: */ Static line *freeline; /* unused lines */ Static dnastring *freedna; /* unused dnas */ Static boolean readnumber; /* whether to read a number from the notes, or to read in the notes */ Static long number; /* the number of the item just read */ Static boolean numbered; /* true when the item just read is numbered */ Static boolean skipunnum; Static jmp_buf _JL1; /* a control variable to allow skipping of un-numbered items in the book */ /* ************************************************************************ */ /* end module book.var version = 7.64; {of delmod.p 2004 Jul 18} */ /* procedure modules *****************************************************/ /* begin module package.primitive */ /* ************************************************************************ */ /* begin module halt */ Static Void halt() { /* stop the program. the procedure performs a goto to the end of the program. you must have a label: label 1; declared, and also the end of the program must have this label: 1: end. examples are in the module libraries. this is the only goto in the delila system. */ printf(" program halt.\n"); longjmp(_JL1, 1); } /* end module halt version = 7.64; {of delmod.p 2004 Jul 18} */ /* begin module copyaline */ Static Void copyaline(fin, fout) _TEXT *fin, *fout; { /* copy a line from file fin to file fout */ while (!P_eoln(fin->f)) { putc(P_peek(fin->f), fout->f); getc(fin->f); } fscanf(fin->f, "%*[^\n]"); getc(fin->f); putc('\n', fout->f); } /* copyaline */ /* end module copyaline version = 7.64; {of delmod.p 2004 Jul 18} */ /* begin module copylines */ Static long copylines(fin, fout, n) _TEXT *fin, *fout; long n; { /* copy n lines of file fin to file fout. the actual number of lines copied is returned. */ long index = 0; /* the current line number */ while (!BUFEOF(fin->f) && index < n) { copyaline(fin, fout); index++; } return index; } /* copylines */ /* end module copylines version = 7.64; {of delmod.p 2004 Jul 18} */ /* ************************************************************************ */ /* end module package.primitive version = 7.64; {of delmod.p 2004 Jul 18} */ /* begin module package.getocp */ /* ************************************************************************ */ /* begin module package.brpiece */ /* ************************************************************************ */ /* begin module book.basis */ /* procedures needed for book manipulations */ /* get procedures should be used for all linked lists of records */ Static Void getline(l) line **l; { /* obtain a line from the free line list or by making a new one */ if (freeline != NULL) { *l = freeline; freeline = freeline->next; } else *l = (line *)Malloc(sizeof(line)); (*l)->length = 0; (*l)->next = NULL; } Static Void getdna(l) dnastring **l; { if (freedna != NULL) { *l = freedna; freedna = freedna->next; } else *l = (dnastring *)Malloc(sizeof(dnastring)); (*l)->length = 0; (*l)->next = NULL; } /* clear procedures should be called each time the records are no longer needed failure to do this may result in a stack overflow. */ Static Void clearline(l) line **l; { /* return a line to the free line list */ line *lptr; if (*l == NULL) return; lptr = *l; *l = (*l)->next; lptr->next = freeline; freeline = lptr; } Static Void writeline(afile, l, carriagereturn) _TEXT *afile; line *l; boolean carriagereturn; { /* write a line to a file, with carriage return if carriagereturn is true. */ long index; /* index to characters in l */ long FORLIM; FORLIM = l->length; for (index = 0; index < FORLIM; index++) putc(l->letters[index], afile->f); if (carriagereturn) putc('\n', afile->f); } Static Void showfreedna() { /* show the freedna list */ long counter = 0; /* count of freedna list */ dnastring *l; /* pointer into freedna list */ l = freedna; while (l != NULL) { counter++; printf("%ld", counter); printf(", length = %ld\n", l->length); /* This is illegal according to gpc because one cannot write a pointer to a text file. It can be unearthed for debugging. write(output, ', pointer id: ',l:1); */ l = l->next; } } Static Void cleardna(l) dnastring **l; { dnastring *lptr; if (*l == NULL) return; lptr = *l; *l = (*l)->next; lptr->next = freedna; freedna = lptr; } Static Void clearheader(h) header *h; { /* clear the header h (remove lines to free storage) */ clearline(&h->fulnam); while (h->note != NULL) clearline(&h->note); } Static Void clearpiece(p) piece **p; { /* clear the dna of the piece */ while ((*p)->dna != NULL) cleardna(&(*p)->dna); clearheader(&(*p)->key.hea); } Static base chartobase(ch) Char ch; { /* convert a character into a base */ base Result; switch (ch) { case 'a': Result = a; break; case 'c': Result = c; break; case 'g': Result = g; break; case 't': Result = t; break; } return Result; } Static Char basetochar(ba) base ba; { /* convert a base into a character */ Char Result; switch (ba) { case a: Result = 'a'; break; case c: Result = 'c'; break; case g: Result = 'g'; break; case t: Result = 't'; break; } return Result; } Static base complement(ba) base ba; { /* take the complement of ba */ base Result; switch (ba) { case a: Result = t; break; case c: Result = g; break; case g: Result = c; break; case t: Result = a; break; } return Result; } Static Char chomplement(b) Char b; { /* create the character complement of base b. I must be getting hungry! */ return (basetochar(complement(chartobase(b)))); } Static long pietoint(p, pie) long p; piece *pie; { /* p is a coordinate on the piece. we want to transform p into a number from 1 to n: an internal coordinate system for easy manipulation of piece coordinates */ /* Note: the dirhomologous and dircomplement are treated as plus and minus directions, which MIGHT NOT BE RIGHT! */ long i; /* an intermediate value */ piekey *WITH; WITH = &pie->key; switch (WITH->piedir) { case dirhomologous: case plus: if (p >= WITH->piebeg) i = p - WITH->piebeg + 1; else i = p - WITH->coobeg + WITH->cooend - WITH->piebeg + 2; break; case dircomplement: case minus: if (p <= WITH->piebeg) i = WITH->piebeg - p + 1; else i = WITH->cooend - p + WITH->piebeg - WITH->coobeg + 2; break; } return i; } Static long inttopie(i, pie) long i; piece *pie; { /* i is in the range 1 to some maximum. it is an internal coordinate system for the program. we want to do a coordinate transformation to obtain a value in the range of the piece called pie: i=1 corresponds to piebeg and i=its maximum corresponds to pieend */ /* Note: the dirhomologous and dircomplement are treated as plus and minus directions, which MIGHT NOT BE RIGHT! */ long p; /* an intermediate value */ piekey *WITH; WITH = &pie->key; switch (WITH->piedir) { case dirhomologous: case plus: p = WITH->piebeg + i - 1; if (p > WITH->cooend) { if (WITH->coocon == circular) p += WITH->coobeg - WITH->cooend - 1; } break; case dircomplement: case minus: p = WITH->piebeg - i + 1; if (p < WITH->coobeg) { if (WITH->coocon == circular) p += WITH->cooend - WITH->coobeg + 1; } break; } return p; } Static long piecelength(pie) piece *pie; { /* return the length of the dna in pie */ return (pietoint(pie->key.pieend, pie)); } /* end module book.basis version = 7.64; {of delmod.p 2004 Jul 18} */ /* begin module book.getto */ Static Char getto(thefile, theline, ch) _TEXT *thefile; long *theline; long *ch; { /* search the file for a character in the first line which is a member of the set ch. Note: on 1999 March 10 the definition of this function was cleaned up. Instead of putting thefile on the line AFTER the charcter ch has been found, it puts thefile ON the line. Other routines like brdna and brpiece have to move to the next line themselves. This makes getto give the OBJECT. */ Char achar = ' '; /* a character in thefile */ boolean done = false; /* done finding achar */ while (!done) { if (BUFEOF(thefile->f)) { done = true; break; } achar = P_peek(thefile->f); if (P_inset(achar, ch)) { done = true; break; } fscanf(thefile->f, "%*[^\n]"); getc(thefile->f); (*theline)++; } if (P_inset(achar, ch)) return achar; else { return ' '; /* The old method - while (not(achar in ch)) and (not eof(thefile)) do begin readln(thefile,achar); theline := succ(theline) end; if (achar in ch) then getto:=achar else getto:=' ' */ } } /* end module book.getto version = 7.64; {of delmod.p 2004 Jul 18} */ /* begin module book.skipstar */ Static Void skipstar(thefile) _TEXT *thefile; { /* skip start of line (or star = '*'). */ if (BUFEOF(thefile->f)) { printf(" procedure skipstar: end of book found\n"); halt(); return; } if (P_peek(thefile->f) != '*') { printf(" procedure skipstar: bad book\n"); printf(" \"*\" expected as first character on the line, but \"%c\" was found\n", P_peek(thefile->f)); halt(); } getc(thefile->f); /* skip the star */ if (P_peek(thefile->f) != ' ') { /* skip the blank */ printf(" procedure skipstar: bad book\n"); printf(" \"* \" expected on a line but \"*%c\" was found\n", P_peek(thefile->f)); halt(); } getc(thefile->f); } /* skipstar */ /* end module book.skipstar version = 7.64; {of delmod.p 2004 Jul 18} */ /* begin module book.brreanum */ Static Void brreanum(thefile, theline, reanum) _TEXT *thefile; long *theline; double *reanum; { /* read a real number from the file */ skipstar(thefile); fscanf(thefile->f, "%lg%*[^\n]", reanum); getc(thefile->f); (*theline)++; } /* end module book.brreanum version = 7.64; {of delmod.p 2004 Jul 18} */ /* begin module book.brnumber */ Static Void brnumber(thefile, theline, num) _TEXT *thefile; long *theline, *num; { /* read a number from the file */ skipstar(thefile); fscanf(thefile->f, "%ld%*[^\n]", num); getc(thefile->f); (*theline)++; } /* end module book.brnumber version = 7.64; {of delmod.p 2004 Jul 18} */ /* begin module book.brname */ Static Void brname(thefile, theline, nam) _TEXT *thefile; long *theline; name *nam; { /* read a name from the file */ long i; /* an index to the name */ Char c_; /* a character read */ skipstar(thefile); nam->length = 0; do { nam->length++; c_ = getc(thefile->f); if (c_ == '\n') c_ = ' '; nam->letters[nam->length - 1] = c_; } while (!(P_eoln(thefile->f) || nam->length >= namelength || nam->letters[nam->length - 1] == ' ')); if (nam->letters[nam->length - 1] == ' ') nam->length--; if (nam->length < namelength) { for (i = nam->length; i < namelength; i++) nam->letters[i] = ' '; } fscanf(thefile->f, "%*[^\n]"); getc(thefile->f); (*theline)++; } /* brname */ /* end module book.brname version = 7.64; {of delmod.p 2004 Jul 18} */ /* begin module book.brline */ Static Void brline(thefile, theline, l) _TEXT *thefile; long *theline; line **l; { /* read a line from the file */ long i = 0; Char acharacter; skipstar(thefile); while (!P_eoln(thefile->f)) { i++; acharacter = getc(thefile->f); if (acharacter == '\n') acharacter = ' '; (*l)->letters[i-1] = acharacter; } (*l)->length = i; (*l)->next = NULL; fscanf(thefile->f, "%*[^\n]"); getc(thefile->f); (*theline)++; } /* end module book.brline version = 7.64; {of delmod.p 2004 Jul 18} */ /* begin module book.brdirect */ Static Void brdirect(thefile, theline, direct) _TEXT *thefile; long *theline; direction *direct; { /* read a direction */ Char ch; skipstar(thefile); fscanf(thefile->f, "%c%*[^\n]", &ch); getc(thefile->f); if (ch == '\n') ch = ' '; (*theline)++; if (ch == '+') *direct = plus; else *direct = minus; } /* end module book.brdirect version = 7.64; {of delmod.p 2004 Jul 18} */ /* begin module book.brconfig */ Static Void brconfig(thefile, theline, config) _TEXT *thefile; long *theline; configuration *config; { /* read a configuration */ Char ch; skipstar(thefile); fscanf(thefile->f, "%c%*[^\n]", &ch); getc(thefile->f); if (ch == '\n') ch = ' '; (*theline)++; if (ch == 'l') *config = linear; else *config = circular; } /* end module book.brconfig version = 7.64; {of delmod.p 2004 Jul 18} */ /* begin module book.brnotenumber */ Static Void brnotenumber(thefile, theline, note) _TEXT *thefile; long *theline; line **note; { /* book note reading to obtain the number of the object. the procedure returns the value of the number as a global. (this is not such a good practice, but we are stuck with it for now.) */ *note = NULL; numbered = false; number = 0; /* force number to zero if there is no number at all */ /* the next character is n or * depending on whether there are notes */ if (P_peek(thefile->f) != 'n') return; fscanf(thefile->f, "%*[^\n]"); getc(thefile->f); (*theline)++; if (P_peek(thefile->f) != 'n') { skipstar(thefile); if (!P_eoln(thefile->f)) { if (P_peek(thefile->f) == '#') { numbered = true; getc(thefile->f); /* move past the number symbol */ fscanf(thefile->f, "%ld", &number); } } do { fscanf(thefile->f, "%*[^\n]"); getc(thefile->f); (*theline)++; } while (P_peek(thefile->f) != 'n'); fscanf(thefile->f, "%*[^\n]"); getc(thefile->f); (*theline)++; return; } fscanf(thefile->f, "%*[^\n]"); getc(thefile->f); (*theline)++; } /* brnotenumber */ /* end module book.brnotenumber version = 7.64; {of delmod.p 2004 Jul 18} */ /* begin module book.brnote */ Static Void brnote(thefile, theline, note) _TEXT *thefile; long *theline; line **note; { /* read note key */ line *newnote; /* the new note */ line *previousnote; /* the last line of the notes */ *note = NULL; if (P_peek(thefile->f) != 'n') /* enter note */ return; fscanf(thefile->f, "%*[^\n]"); getc(thefile->f); (*theline)++; if (P_peek(thefile->f) != 'n') { /* abort null note (n/n) */ getline(note); newnote = *note; while (P_peek(thefile->f) != 'n') { /* wait until end of note */ brline(thefile, theline, &newnote); previousnote = newnote; /* get next note */ getline(&newnote->next); newnote = newnote->next; } /* last note was not used, so: */ clearline(&newnote); previousnote->next = NULL; fscanf(thefile->f, "%*[^\n]"); getc(thefile->f); (*theline)++; return; } fscanf(thefile->f, "%*[^\n]"); getc(thefile->f); (*theline)++; } /* brnote */ /* end module book.brnote version = 7.64; {of delmod.p 2004 Jul 18} */ /* begin module book.brheader */ Static Void brheader(thefile, theline, hea) _TEXT *thefile; long *theline; header *hea; { /* read the header of a key. */ fscanf(thefile->f, "%*[^\n]"); getc(thefile->f); /* move past the object name - new definition 1999 Mar 13 */ (*theline)++; /*bbb*/ /* read key name */ brname(thefile, theline, &hea->keynam); /* read full name */ getline(&hea->fulnam); brline(thefile, theline, &hea->fulnam); /* read note key */ if (readnumber) brnotenumber(thefile, theline, &hea->note); else brnote(thefile, theline, &hea->note); } /* end module book.brheader version = 7.64; {of delmod.p 2004 Jul 18} */ /* begin module book.copyheader */ Static Void copyheader(fromhea, tohea) header fromhea, *tohea; { /* copy the header fromhea into tohea. Note that the linked objects are NOT copied, but merely pointed to. */ memcpy(tohea->keynam.letters, fromhea.keynam.letters, sizeof(alpha)); tohea->keynam.length = fromhea.keynam.length; tohea->note = fromhea.note; tohea->fulnam = fromhea.fulnam; } /* end module book.copyheader version = 7.64; {of delmod.p 2004 Jul 18} */ /* begin module book.brpiekey */ Static Void brpiekey(thefile, theline, pie) _TEXT *thefile; long *theline; piekey *pie; { /* read piece key, track the line number */ brheader(thefile, theline, &pie->hea); brreanum(thefile, theline, &pie->mapbeg); brconfig(thefile, theline, &pie->coocon); brdirect(thefile, theline, &pie->coodir); brnumber(thefile, theline, &pie->coobeg); brnumber(thefile, theline, &pie->cooend); brconfig(thefile, theline, &pie->piecon); brdirect(thefile, theline, &pie->piedir); brnumber(thefile, theline, &pie->piebeg); brnumber(thefile, theline, &pie->pieend); } /* end module book.brpiekey version = 7.64; {of delmod.p 2004 Jul 18} */ /* begin module book.brdna */ Static Void brdna(thefile, theline, dna) _TEXT *thefile; long *theline; dnastring **dna; { /* read in dna from thefile, track the line */ /* note: if the dna were circularized, by linking the last dnastring to the first, then the cleardna routine could not clear properly, and would loop forever... there is no reason to do that, since a simple mod function will allow one to access the circle. */ Char ch; dnastring *workdna; long SET[5]; long TEMP; getdna(dna); workdna = *dna; ch = getto(thefile, theline, P_addset(P_expset(SET, 0L), 'd')); fscanf(thefile->f, "%*[^\n]"); getc(thefile->f); (*theline)++; ch = getc(thefile->f); /* skipstar */ if (ch == '\n') ch = ' '; while (ch == '*') { ch = getc(thefile->f); /* skip blank */ if (ch == '\n') ch = ' '; do { ch = getc(thefile->f); if (ch == '\n') ch = ' '; if (ch == 't' || ch == 'g' || ch == 'c' || ch == 'a') { if (workdna->length == dnamax) { getdna(&workdna->next); workdna = workdna->next; } workdna->length++; TEMP = workdna->length - 1; P_clrbits_B(workdna->part, TEMP, 1, 3); P_putbits_UB(workdna->part, TEMP, (int)chartobase(ch), 1, 3); } } while (!P_eoln(thefile->f)); fscanf(thefile->f, "%*[^\n]"); getc(thefile->f); /* go to next line */ (*theline)++; ch = getc(thefile->f); /* ch is either '*' or 'd' */ if (ch == '\n') ch = ' '; } fscanf(thefile->f, "%*[^\n]"); getc(thefile->f); /* read past the d */ (*theline)++; } /* end module book.brdna version = 7.64; {of delmod.p 2004 Jul 18} */ /* begin module book.brpiece */ Static Void brpiece(thefile, theline, pie) _TEXT *thefile; long *theline; piece **pie; { /* read in a piece, change theline to reflect the lines traversed */ /* readln(thefile); (* move past the word 'piece' - new definition 1999 Mar 13 *) theline := succ(theline); (* BUG: was below! *) bbb*/ brpiekey(thefile, theline, &(*pie)->key); if (numbered || !skipunnum) brdna(thefile, theline, &(*pie)->dna); fscanf(thefile->f, "%*[^\n]"); getc(thefile->f); /* move past the word 'piece' - new definition 1999 Mar 13 */ (*theline)++; } /* end module book.brpiece version = 7.64; {of delmod.p 2004 Jul 18} */ /* begin module book.brinit */ Static Void brinit(book, theline) _TEXT *book; long *theline; { /* check that the book is ok to read, and set up the global variables for br routines */ /* halt if the book is bad (first word is 'halt') or the first character is not * */ if (*book->name != '\0') { if (book->f != NULL) book->f = freopen(book->name, "r", book->f); else book->f = fopen(book->name, "r"); } else rewind(book->f); if (book->f == NULL) _EscIO2(FileNotFound, book->name); RESETBUF(book->f, Char); if (!BUFEOF(book->f)) { /* check for the date line */ if (P_peek(book->f) != '*') { if (P_peek(book->f) != 'h') printf(" this is not the first line of a book:\n"); else printf(" bad book:\n"); putchar(' '); while (!(P_eoln(book->f) | BUFEOF(book->f))) { putchar(P_peek(book->f)); getc(book->f); } putchar('\n'); halt(); } } else { printf(" book is empty\n"); halt(); } /* initialize free storage */ freeline = NULL; freedna = NULL; readnumber = true; /* usually we read in numbers for items */ number = 0; /* arbitrary value */ numbered = false; /* the piece has no number (none yet read in) */ skipunnum = false; *theline = 1; } /* brinit */ /* end module book.brinit version = 7.64; {of delmod.p 2004 Jul 18} */ /* ************************************************************************ */ /* end module package.brpiece version = 7.64; {of delmod.p 2004 Jul 18} */ /* begin module book.brorgkey */ Static Void brorgkey(thefile, theline, org) _TEXT *thefile; long *theline; orgkey *org; { /* read organism key */ /*bbb*/ brheader(thefile, theline, &org->hea); getline(&org->mapunit); brline(thefile, theline, &org->mapunit); } /* end module book.brorgkey version = 7.64; {of delmod.p 2004 Jul 18} */ /* begin module book.brchrkey */ Static Void brchrkey(thefile, theline, chr) _TEXT *thefile; long *theline; chrkey *chr; { /* read chromosome key */ /*bbb*/ brheader(thefile, theline, &chr->hea); brreanum(thefile, theline, &chr->mapbeg); brreanum(thefile, theline, &chr->mapend); } /* end module book.brchrkey version = 7.64; {of delmod.p 2004 Jul 18} */ /* begin module book.getocp */ Static Void getocp(thefile, theline, org, orgchange, orgopen, chr, chrchange, chropen, pie, piechange, pieopen) _TEXT *thefile; long *theline; orgkey *org; boolean *orgchange, *orgopen; chrkey *chr; boolean *chrchange, *chropen; piece **pie; boolean *piechange, *pieopen; { /* Get the next piece and its organism and chromosome keys. The three change variables indicate whether or not a new organism, chromosome or piece name was found. If a piece is not found, then pieopen will be false. orgopen, chropen and pieopen are used by getocp to tell when it has entered an organism, chromosome or piece. All booleans should be set to false initially. There should be one triplet for each book read. It is important to initialize ALL variables, including pie: orgchange := false; orgopen := false; chrchange := false; chropen := false; piechange := false; pieopen := false; pie := nil; theline := 0; 1999 June 2 The book reading routines now treat data objects more precisely. Rather than test for eof, the endo of book occurs when pieopen is returned as false. A book reading loop now looks like this: repeat getocp(book, theline, org, orgchange, orgopen, chr, chrchange, chropen, pie, piechange, pieopen); writeln(output,'pieopen: ',pieopen); if pieopen then begin writeln(output,'piece at line: ',theline:1); end; until not pieopen; */ Char ch = 'a'; chrkey newchr; orgkey neworg; piece *newpie; long SET[5]; while (ch != 'p' && ch != ' ') { P_addset(P_expset(SET, 0L), 'o'); P_addset(SET, 'c'); ch = getto(thefile, theline, P_addset(SET, 'p')); if (ch == ' ') { *pieopen = false; break; } switch (ch) { case 'o': if (*orgopen) { fscanf(thefile->f, "%*[^\n]"); getc(thefile->f); /* move past the word 'organism' - new definition 1999 Mar 13 */ *orgopen = false; /* close organism */ } else { brorgkey(thefile, theline, &neworg); if (strncmp(neworg.hea.keynam.letters, org->hea.keynam.letters, sizeof(alpha)) && neworg.hea.keynam.length != org->hea.keynam.length) { /* writeln(output,'--------orgchanged!'); write (output,'--------old org:"', org.hea.keynam.letters); writeln(output, '" ', org.hea.keynam.length:1); write (output,'--------new org:"',neworg.hea.keynam.letters); writeln(output, '" ',neworg.hea.keynam.length:1); */ /*ccc*/ *orgchange = true; copyheader(neworg.hea, &org->hea); /* move the mapunit over to the org! */ org->mapunit = neworg.mapunit; clearline(&neworg.mapunit); } else *orgchange = false; *orgopen = true; } break; case 'c': if (*chropen) { fscanf(thefile->f, "%*[^\n]"); getc(thefile->f); /* move past the word 'chromosome' - new definition 1999 Mar 13 */ *chropen = false; /* close chromosome */ } else { brchrkey(thefile, theline, &newchr); if (strncmp(newchr.hea.keynam.letters, chr->hea.keynam.letters, sizeof(alpha)) && newchr.hea.keynam.length != chr->hea.keynam.length) { /* writeln(output,'--------chrchanged!'); write (output,'--------old chr:"', chr.hea.keynam.letters); writeln(output, '" ', chr.hea.keynam.length:1); write (output,'--------new chr:"',newchr.hea.keynam.letters); writeln(output, '" ',newchr.hea.keynam.length:1); */ *chrchange = true; copyheader(newchr.hea, &chr->hea); /* move the map range over to the chr! */ chr->mapbeg = newchr.mapbeg; chr->mapend = newchr.mapend; } else *chrchange = false; *chropen = true; } break; case 'p': if (*pieopen) { *pieopen = false; /* close last piece */ ch = 'a'; /* prevent falling out of the loop */ } else { newpie = (piece *)Malloc(sizeof(piece)); brpiece(thefile, theline, &newpie); if (*pie == NULL) *piechange = true; else { if (strncmp(newpie->key.hea.keynam.letters, (*pie)->key.hea.keynam.letters, sizeof(alpha)) && newpie->key.hea.keynam.length != (*pie)->key.hea.keynam.length) *piechange = true; else *piechange = false; } *pieopen = true; /* we always have to switch over to the new piece, because although the name may be the same, the DNA sequence could be different. That is, the book may contain two pieces with the same name, and we want to be sure to search the new one, not the old one. */ if (*pie != NULL) { clearpiece(pie); /* save the links */ Free(*pie); /* close up shop */ } *pie = newpie; } break; } } } /* origin: search version = 6.39 */ /* end module book.getocp version = 7.64; {of delmod.p 2004 Jul 18} */ /* ************************************************************************ */ /* end module package.getocp version = 7.64; {of delmod.p 2004 Jul 18} */ /* begin module book.getbase */ Static base getbase(position, pie) long position; piece *pie; { /* Get a base from the position (internal coordinates) of the piece. Protection is made against positions outside the piece. In the case of circles it would be convenient to wrap around when requests are off the end. So the routine will do a modular wrap for positions outside the range 1 to the length. This is a new feature as of 2000 March 22. */ dnastring *workdna; /* pointer to the dna part of pie */ long p; /* current count of bases into the workdna */ long spot; /* the last base of the dna part */ long thelength; /* the length of the piece */ /* writeln(output,'NEW getbase: position=',position:1,'^^^^^^^^^^^^^^^^^^^^'); */ /* handle cases of position out of range by circular wrapping */ thelength = piecelength(pie); while (position < 1) position += thelength; while (position > thelength) position -= thelength; workdna = pie->dna; p = workdna->length; while (position > p) { /* writeln(output,' workdna^.length=',workdna^.length:1); */ workdna = workdna->next; if (workdna == NULL) { printf("error in function getbase!\n"); halt(); } p += workdna->length; } /* writeln(output,'p=',p:1); */ if (true) { spot = workdna->length - p + position; /* writeln(output,'spot=',spot:1); showdnasegment(output,workdna, spot); */ if (spot <= 0) { printf("error in getbase, spot (= %ld) must be positive\n", spot); halt(); } if (spot > workdna->length) { printf("error in getbase, spot (=%ld) must be less than length (=%ld)\n", spot, workdna->length); halt(); } /* writeln(output,'base = ', workdna^.part[spot]); */ return ((base)P_getbits_UB(workdna->part, spot - 1, 1, 3)); } printf("error in getbase: request off end of piece\n"); halt(); } /* end module book.getbase version = 7.64; {of delmod.p 2004 Jul 18} */ /* begin module book.stepbase */ Static base stepbase(startdna, dna, d) dnastring *startdna, **dna; dnarange *d; { /* advance d by one base in dna and then return the base at the new d. (this means that one should initialize d to zero) if we go past the last base, we restart at startdna. note: d is not the number of the base... it is used as a record for stepbase. do not mess with it, and do not use it to find out what base you are on. use a separate counter. */ long TEMP; if (*d != dnamax && *d != (*dna)->length) { (*d)++; TEMP = *d - 1; return ((base)P_getbits_UB((*dna)->part, TEMP, 1, 3)); } *d = 1; *dna = (*dna)->next; if (*dna == NULL) *dna = startdna; TEMP = *d - 1; return ((base)P_getbits_UB((*dna)->part, TEMP, 1, 3)); } /* end module book.stepbase version = 7.64; {of delmod.p 2004 Jul 18} */ /* begin module book.iwname */ Static Void iwname(thefile, thename) _TEXT *thefile; name thename; { /* write the name to the file */ long c_; for (c_ = 0; c_ < thename.length; c_++) putc(thename.letters[c_], thefile->f); } /* end module book.iwname version = 7.64; {of delmod.p 2004 Jul 18} */ /* begin module book.iworg */ Static Void iworg(afile, org) _TEXT *afile; orgkey org; { /* write an organism specification. no writeln is done to allow write orgchr to do this. */ fprintf(afile->f, "organism "); iwname(afile, org.hea.keynam); putc(';', afile->f); } /* end module book.iworg version = 7.64; {of delmod.p 2004 Jul 18} */ /* begin module book.iwchr */ Static Void iwchr(afile, chr) _TEXT *afile; chrkey chr; { /* write an chromosome specification. no writeln is done to allow write orgchr to do this. */ fprintf(afile->f, "chromosome "); iwname(afile, chr.hea.keynam); putc(';', afile->f); } /* end module book.iwchr version = 7.64; {of delmod.p 2004 Jul 18} */ /* begin module book.iwpie */ Static Void iwpie(afile, pie) _TEXT *afile; piekey pie; { /* write a piece specification */ fprintf(afile->f, "piece "); iwname(afile, pie.hea.keynam); fprintf(afile->f, ";\n"); } /* end module book.iwpie version = 7.64; {of delmod.p 2004 Jul 18} */ /* begin module book.iworgchr */ Static Void iworgchr(afile, org, orgchange, orgopen, chr, chrchange, chropen) _TEXT *afile; orgkey org; boolean orgchange, orgopen; chrkey chr; boolean chrchange, chropen; { /* write both organism and chromosome specifications, based on whether the organism or chromosome changed (orgchange and chrchange) and whether they are currently open (orgopen, chropen). See getocp in the br routines. */ if (orgchange && orgopen) iworg(afile, org); if (orgchange && chrchange && orgopen && chropen) putc(' ', afile->f); if (chrchange && chropen) iwchr(afile, chr); if (orgchange && orgopen || chrchange && chropen) putc('\n', afile->f); } /* Local variables for iwget: */ struct LOC_iwget { _TEXT *afile; piece *pie; long pieceplace, insttype; } ; /* Local variables for iwposition: */ struct LOC_iwposition { struct LOC_iwget *LINK; } ; Local Void iwrelative(relative, LINK) long relative; struct LOC_iwposition *LINK; { if (relative >= 0) fprintf(LINK->LINK->afile->f, " +%ld", relative); else if (relative < 0) fprintf(LINK->LINK->afile->f, " %ld", relative); } Local Void iwposition(relative, sameallowed, LINK) long relative; boolean sameallowed; struct LOC_iwget *LINK; { /* write the */ struct LOC_iwposition V; V.LINK = LINK; if (LINK->insttype == 1 && sameallowed) fprintf(LINK->afile->f, " same"); else fprintf(LINK->afile->f, " %ld", LINK->pieceplace); switch (LINK->pie->key.piedir) { case plus: iwrelative(relative, &V); break; case minus: iwrelative(-relative, &V); break; } } /* end module book.iworgchr version = 7.64; {of delmod.p 2004 Jul 18} */ /* begin module book.iwget */ Static Void iwget(afile_, pie_, fromplace, pieceplace_, toplace, flip, insttype_, carriagereturn) _TEXT *afile_; piece *pie_; long fromplace, pieceplace_, toplace; boolean flip; long insttype_; boolean carriagereturn; { /* print a get delila instruction in the orientation of pie, from fromplace to toplace pieceplace. +/- direction; If flip is false, the piece direction is as on the piece, if it is true, the it is the opposite direction. insttype: instruction type. insttype=1 means the form get from p -/+f to same +/-t dir +/-; insttype=2 means the form get from p1 -/+f to p2 +/-t dir +/-; where p, p1 and p2 are locations carriagereturn: if true, add a carriage return to the end of the line. */ struct LOC_iwget V; V.afile = afile_; V.pie = pie_; V.pieceplace = pieceplace_; V.insttype = insttype_; fprintf(V.afile->f, "get from"); iwposition(fromplace, false, &V); fprintf(V.afile->f, " to"); iwposition(toplace, true, &V); fprintf(V.afile->f, " direction"); switch (V.pie->key.piedir) { case dirhomologous: case plus: /* handle case, may not be right */ switch (flip) { case false: fprintf(V.afile->f, " +"); break; case true: fprintf(V.afile->f, " -"); break; } break; case dircomplement: case minus: /* handle case, may not be right */ switch (flip) { case false: fprintf(V.afile->f, " -"); break; case true: fprintf(V.afile->f, " +"); break; } break; } putc(';', V.afile->f); if (carriagereturn) putc('\n', V.afile->f); } /* Local variables for iwget2: */ struct LOC_iwget2 { _TEXT *afile; piece *pie; } ; /* Local variables for iwposition_: */ struct LOC_iwposition_ { struct LOC_iwget2 *LINK; } ; Local Void iwrelative_(relative, LINK) long relative; struct LOC_iwposition_ *LINK; { if (relative >= 0) fprintf(LINK->LINK->afile->f, " +%ld", relative); else if (relative < 0) fprintf(LINK->LINK->afile->f, " %ld", relative); } Local Void iwposition_(place, relative, LINK) long place, relative; struct LOC_iwget2 *LINK; { struct LOC_iwposition_ V; V.LINK = LINK; fprintf(LINK->afile->f, " %ld", place); switch (LINK->pie->key.piedir) { case plus: iwrelative_(relative, &V); break; case minus: iwrelative_(-relative, &V); break; } } /* end module book.iwget version = 7.64; {of delmod.p 2004 Jul 18} */ /* begin module book.iwget2 */ Static Void iwget2(afile_, pie_, fromplace, place1, toplace, place2, flip, carriagereturn) _TEXT *afile_; piece *pie_; long fromplace, place1, toplace, place2; boolean flip, carriagereturn; { /* print a get Delila instruction in the orientation of pie, The form of the instructions is: get from place1 +/-fromplace to place2 +/-toplace direction +/-; If flip is false, the piece direction is as on the piece, if it is true, the it is the opposite direction. carriagereturn: if true, add a carriage return to the end of the line. */ struct LOC_iwget2 V; V.afile = afile_; V.pie = pie_; fprintf(V.afile->f, "get from"); iwposition_(place1, fromplace, &V); fprintf(V.afile->f, " to"); iwposition_(place2, toplace, &V); fprintf(V.afile->f, " direction"); switch (V.pie->key.piedir) { case dirhomologous: case plus: /* handle case, may not be right */ switch (flip) { case false: fprintf(V.afile->f, " +"); break; case true: fprintf(V.afile->f, " -"); break; } break; case dircomplement: case minus: /* handle case, may not be right */ switch (flip) { case false: fprintf(V.afile->f, " -"); break; case true: fprintf(V.afile->f, " +"); break; } break; } putc(';', V.afile->f); if (carriagereturn) putc('\n', V.afile->f); } /* end module book.iwget2 version = 7.64; {of delmod.p 2004 Jul 18} */ /* begin module book.iwcombk */ Static Void iwcombk(book, afile) _TEXT *book, *afile; { /* make a comment in the file that says the name of the book */ fprintf(afile->f, "(* "); if (*book->name != '\0') { if (book->f != NULL) book->f = freopen(book->name, "r", book->f); else book->f = fopen(book->name, "r"); } else rewind(book->f); if (book->f == NULL) _EscIO2(FileNotFound, book->name); RESETBUF(book->f, Char); if (copylines(book, afile, 1L) == 0) { printf(" book is empty, can not write comment for instructions\n"); halt(); } fprintf(afile->f, "*)\n"); } /* end module book.iwcombk version = 7.64; {of delmod.p 2004 Jul 18} */ /* begin module package.datetime */ /* ************************************************************************ */ /* begin module getdatetime */ Static Void getdatetime(adatetime) Char *adatetime; { /* Get the date and time into a single array from the system clock. adatetime contains the date: 1980/06/09 18:49:11 ye mo da ho mi se (year, month, day, hour, minute, second) This version works after translation of the pascal by p2c to C and then compiling with gcc. */ Char adate[11], atime[11]; /* adate, atime: alfa; (* ie, packed array[1..10] of char; *) This old method won't work, since the last digit gets cut off! */ Char month[3]; long index; /* index for times */ /* 1 12345678901 adate[13-DEC-1999] atime[17:39:44.00] */ VAXdate(adate); VAXtime(atime); /* writeln(output,'br: adate[',adate,'] atime[',atime,']'); */ /* transfer the year */ for (index = 1; index <= 4; index++) adatetime[index-1] = adate[index+6]; adatetime[4] = '/'; for (index = 4; index <= 6; index++) month[index-4] = adate[index-1]; if (!strncmp(month, "JAN", 3)) { adatetime[5] = '0'; adatetime[6] = '1'; } else if (!strncmp(month, "FEB", 3)) { adatetime[5] = '0'; adatetime[6] = '2'; } else if (!strncmp(month, "MAR", 3)) { adatetime[5] = '0'; adatetime[6] = '3'; } else if (!strncmp(month, "APR", 3)) { adatetime[5] = '0'; adatetime[6] = '4'; } else if (!strncmp(month, "MAY", 3)) { adatetime[5] = '0'; adatetime[6] = '5'; } else if (!strncmp(month, "JUN", 3)) { adatetime[5] = '0'; adatetime[6] = '6'; } else if (!strncmp(month, "JUL", 3)) { adatetime[5] = '0'; adatetime[6] = '7'; } else if (!strncmp(month, "AUG", 3)) { adatetime[5] = '0'; adatetime[6] = '8'; } else if (!strncmp(month, "SEP", 3)) { adatetime[5] = '0'; adatetime[6] = '9'; } else if (!strncmp(month, "OCT", 3)) { adatetime[5] = '1'; adatetime[6] = '0'; } else if (!strncmp(month, "NOV", 3)) { adatetime[5] = '1'; adatetime[6] = '1'; } else if (!strncmp(month, "DEC", 3)) { adatetime[5] = '1'; adatetime[6] = '2'; } adatetime[7] = '/'; for (index = 7; index <= 8; index++) adatetime[index+1] = adate[index-7]; /* replace blanks with spaces in dates */ if (adatetime[5] == ' ') adatetime[5] = '0'; if (adatetime[8] == ' ') adatetime[8] = '0'; adatetime[10] = ' '; for (index = 10; index <= 17; index++) adatetime[index+1] = atime[index-10]; for (index = 19; index <= datetimearraylength + 1; index++) adatetime[index] = ' '; } /* end module getdatetime version = 'cdatemod.p 1.19 1999Dec13'; */ /* begin module readdatetime */ Static Void readdatetime(thefile, adatetime) _TEXT *thefile; Char *adatetime; { /* read the date and time from the file */ long index; /* to the udatetime */ /* the following is an unpacked date time array, to avoid reading into a packed array. reading into a packed array is not transportable */ Char udatetime[datetimearraylength]; for (index = 0; index < datetimearraylength; index++) { udatetime[index] = getc(thefile->f); if (udatetime[index] == '\n') udatetime[index] = ' '; } memcpy(adatetime, udatetime, sizeof(datetimearray)); if (adatetime[2] == '/' && adatetime[11] == ':') printf(" old datetime (only 2 year digits) read: %.*s\n", datetimearraylength, adatetime); /* p2c: search.p, line 1930: Note: * Format for packed-array-of-char will work only if width < length [321] */ /* if (adatetime[3]<>'/') or (adatetime[12]<>':') then begin writeln(output,' bad date time read: ',adatetime:1); halt end; for index:=18 to datetimearraylength do adatetime[index]:=' ' */ } /* end module readdatetime version = 'cdatemod.p 1.19 1999Dec13'; */ /* begin module writedatetime */ Static Void writedatetime(thefile, adatetime) _TEXT *thefile; Char *adatetime; { /* expand the date and time out and print in the file */ long index; /* index of datetime */ for (index = 0; index < datetimearraylength; index++) putc(adatetime[index], thefile->f); } /* end module writedatetime version = 'cdatemod.p 1.19 1999Dec13'; */ /* begin module timeseed */ Static Void addtoseed(seed, power, c_) double *seed, *power; Char c_; { /* add the digit represented by c to the seed at the power position */ long n; /* the character represented by c */ *power /= 10; /* writeln(output,'addtoseed, c = ',c); writeln(output,'addtoseed, ord(c) = ',ord(c)); */ switch (c_) { case ' ': printf("timeseed: error in datetime\n"); halt(); break; case '0': n = 0; break; case '1': n = 1; break; case '2': n = 2; break; case '3': n = 3; break; case '4': n = 4; break; case '5': n = 5; break; case '6': n = 6; break; case '7': n = 7; break; case '8': n = 8; break; case '9': n = 9; break; } /*writeln(output,'timeseed number is [',n:1,']'); (@ debug */ *seed += *power * n; } /* addtoseed */ Static Void makeseed(adatetime, seed) Char *adatetime; double *seed; { /* convert adatetime to a real number in seed, reversed order */ double power = 1.0; /* a digit of the seed such as 0.01 */ *seed = 0.0; addtoseed(seed, &power, adatetime[18]); addtoseed(seed, &power, adatetime[17]); /* : */ addtoseed(seed, &power, adatetime[15]); addtoseed(seed, &power, adatetime[14]); /* : */ addtoseed(seed, &power, adatetime[12]); addtoseed(seed, &power, adatetime[11]); /* */ addtoseed(seed, &power, adatetime[9]); addtoseed(seed, &power, adatetime[8]); /* / */ addtoseed(seed, &power, adatetime[6]); addtoseed(seed, &power, adatetime[5]); /* / */ addtoseed(seed, &power, adatetime[3]); addtoseed(seed, &power, adatetime[2]); } Static Void orderseed(adatetime, seed) Char *adatetime; double *seed; { /* convert adatetime to a real number in seed, normal order */ double power = 1.0; /* a digit of the seed such as 0.01 */ *seed = 0.0; addtoseed(seed, &power, adatetime[2]); addtoseed(seed, &power, adatetime[3]); addtoseed(seed, &power, adatetime[5]); addtoseed(seed, &power, adatetime[6]); /* / */ addtoseed(seed, &power, adatetime[8]); addtoseed(seed, &power, adatetime[9]); /* / */ addtoseed(seed, &power, adatetime[11]); addtoseed(seed, &power, adatetime[12]); /* */ addtoseed(seed, &power, adatetime[14]); addtoseed(seed, &power, adatetime[15]); /* : */ addtoseed(seed, &power, adatetime[17]); addtoseed(seed, &power, adatetime[18]); } Static Void timeseed(seed) double *seed; { /* read the computer date and time. reverse the order of the digits and put a decimal point in front. this gives a fraction between zero and one that varies quite quickly, and is always unique (if the computer has sufficient accuracy). it is to be used as a seed to a random number generator. */ datetimearray adatetime; /* a date and time */ getdatetime(adatetime); /* writeln(output,'timeseed: adatetime: ',adatetime); */ makeseed(adatetime, seed); } /* timeseed */ /* end module timeseed version = 'cdatemod.p 1.19 1999Dec13'; */ /* begin module limitdate */ Static Void limitdate(a_, b, c_, d, limitdatetime_) Char a_, b, c_, d; Char *limitdatetime_; { /* test whether the current time is before the limit. If it is later, halt the program */ datetimearray limitdatetime, adatetime; /* a date and time */ double Dday; /* the critical day */ double now; /* this very moment */ memcpy(limitdatetime, limitdatetime_, sizeof(datetimearray)); getdatetime(adatetime); orderseed(adatetime, &now); if (limitdatetime[0] != ' ' || limitdatetime[1] != ' ' || limitdatetime[2] != ' ' || limitdatetime[3] != ' ') halt(); limitdatetime[0] = a_; limitdatetime[1] = b; limitdatetime[2] = c_; limitdatetime[3] = d; orderseed(limitdatetime, &Dday); /* writeln(output,'now: ',now:20:8); writeln(output,'Dday: ',Dday:20:8); */ if (now > Dday) { /* writeln(output,'This program expired on ',limitdatetime); leave no clues */ halt(); } } /* end module limitdate version = 'cdatemod.p 1.19 1999Dec13'; */ /* ************************************************************************ */ /* end module package.datetime version = 'cdatemod.p 1.19 1999Dec13'; */ /* begin module package.interact */ /* ************************************************************************ */ /* begin module interact.prompt */ Static Void prompt(afile) _TEXT *afile; { /* prompt a file. the prompt is sent to the output file, and a line is read into the pascal line buffer. (for the cyber system this means to readln afile.) guarantee no bomb */ if (BUFEOF(afile->f)) { if (*afile->name != '\0') { if (afile->f != NULL) afile->f = freopen(afile->name, "r", afile->f); else afile->f = fopen(afile->name, "r"); } else rewind(afile->f); if (afile->f == NULL) _EscIO2(FileNotFound, afile->name); RESETBUF(afile->f, Char); } fscanf(afile->f, "%*[^\n]"); getc(afile->f); } /* prompt */ /* end module interact.prompt version = 4.73; (@ of prgmod.p 2004 Jul 22 */ /* begin module interact.readchar */ Static Void readchar(afile, ch) _TEXT *afile; Char *ch; { /* read a character from afile, guarantee no bomb */ if (BUFEOF(afile->f)) prompt(afile); *ch = getc(afile->f); /*writeln(output,'"',ch,'"') */ if (*ch == '\n') *ch = ' '; } /* readchar */ /* end module interact.readchar version = 4.73; (@ of prgmod.p 2004 Jul 22 */ /* begin module clearstring */ Static Void clearstring(ribbon) string *ribbon; { /* empty the string */ long index; /* to the ribbon */ for (index = 0; index < maxstring; index++) ribbon->letters[index] = ' '; ribbon->length = 0; ribbon->current = 0; } /* clearstring */ Static Void initializestring(ribbon) string *ribbon; { /* start the string with a nil pointer. This routine should be called before doing linked list work. This allows the standard string routines to clear the string without killing the pointer. */ clearstring(ribbon); ribbon->next = NULL; } /* initializestring */ /* end module clearstring version = 4.73; (@ of prgmod.p 2004 Jul 22 */ /* begin module interact.readstring */ Static Void readstring(afile, line_) _TEXT *afile; string *line_; { /* read in a string from afile, protect against bombing */ long index; /* for line */ Char cha; /* a character read in */ boolean done; /* used for removing trailing blanks from the line */ boolean acceptable; /* was the line typed short enough? */ do { clearstring(line_); prompt(afile); index = 0; /* we now count characters */ while (!P_eoln(afile->f) && index < maxstring) { index++; readchar(afile, &cha); line_->letters[index-1] = cha; } if (!P_eoln(afile->f)) { printf("type lines shorter than %ld characters. please retype the line...\n", maxstring + 1L); acceptable = false; } else acceptable = true; } while (!acceptable); line_->length = index; if (line_->length > 0) { done = false; do { /* remove blanks from the line. note that a while loop can not be used because one must avoid letters[0], since that position does not exist... */ if (line_->letters[line_->length - 1] == ' ') line_->length--; else done = true; if (line_->length == 0) done = true; } while (!done); } if (line_->length > 0) line_->current = 1; else line_->current = 0; } /* readstring */ /* Local variables for figurestring: */ struct LOC_figurestring { string *line_; long power; /* of 10 representing a place value in the number */ } ; Local long figureinteger(first, last, LINK) long first, last; struct LOC_figurestring *LINK; { /* figure the integer in the token */ long i; /* index */ long sum = 0; long increment; LINK->power = 1; /* start at ones place */ /* start sum at zero */ for (i = last - 1; i >= first - 1; i--) { switch (LINK->line_->letters[i]) { case '0': increment = 0; break; case '1': increment = 1; break; case '2': increment = 2; break; case '3': increment = 3; break; case '4': increment = 4; break; case '5': increment = 5; break; case '6': increment = 6; break; case '7': increment = 7; break; case '8': increment = 8; break; case '9': increment = 9; break; } sum += LINK->power * increment; LINK->power *= 10; } return sum; } /* figureinteger */ /* end module interact.readstring version = 4.73; (@ of prgmod.p 2004 Jul 22 */ /* begin module interact.figurestring */ Static Void figurestring(line__, first, last, whzat, c_, i, r) string *line__; long *first, *last; Char *whzat, *c_; long *i; double *r; { /* a string of characters to figure out */ /* first found non-blank character in the line */ /* last character before a blank after first */ /* what the token is */ /* the first character of the token */ /* integer value of token if it is integer; or 0 */ /* the real value if it is real; or 0.0 */ /* figurestring figures out the tokens in a string. it recognizes words, integers, reals and poorly formed numbers. you can easily use it to parse lines. our goal is to figure out what thing is on a string. start looking at the current place on the line. first and last are the first 'token' in line after start. the current place is updated to the letter after last. the thing found is described by the value of whzat: 'c': character (when the token does not begin with a digit, '+', or '-') 'i': integer 'r': real ' ': blank line 'g': garbage, cannot figure it out and the value of the thing found is the appropriate variable */ struct LOC_figurestring V; long numbers[3]; long sign; /* sign of a number */ long numberstart; /* the point a number starts, beyond its sign, if any */ long point = 0; /* location of decimal point */ long l; /* an index for dissecting numbers */ string *WITH; long FORLIM; V.line_ = line__; P_addset(P_expset(numbers, 0L), '0'); P_addset(numbers, '1'); P_addset(numbers, '2'); P_addset(numbers, '3'); P_addset(numbers, '4'); P_addset(numbers, '5'); P_addset(numbers, '6'); P_addset(numbers, '7'); P_addset(numbers, '8'); P_addset(numbers, '9'); /* c:=' '; i:=0; r:=0.0; do not affect these variables unless necessary */ *whzat = '.'; /* assume that we have someting to work on */ /* now to see if that is true: */ WITH = V.line_; if (WITH->length == 0 || WITH->current < 1 || WITH->current > WITH->length) *whzat = ' '; else { /* figure out where the first token is in the line */ *first = V.line_->current; while (V.line_->letters[*first - 1] == ' ' && *first < V.line_->length) (*first)++; if (*first == V.line_->length && V.line_->letters[*first - 1] == ' ') *whzat = ' '; } if (*whzat == ' ') return; *last = *first; while (V.line_->letters[*last - 1] != ' ' && *last < V.line_->length) (*last)++; if (V.line_->letters[*last - 1] == ' ') (*last)--; /* the token is between inclusive first and last */ *c_ = V.line_->letters[*first - 1]; if (P_inset(*c_, numbers) || *c_ == '-' || *c_ == '+') { if (*c_ == '-' || *c_ == '+') { switch (*c_) { case '+': sign = 1; break; case '-': sign = -1; break; } numberstart = *first + 1; } else { sign = 1; numberstart = *first; } *whzat = 'i'; FORLIM = *last; for (l = numberstart; l <= FORLIM; l++) { if (!P_inset(V.line_->letters[l-1], numbers)) { if (V.line_->letters[l-1] == '.') { /* we found a period */ if (*whzat == 'i') { /* if so far it is numbers */ *whzat = 'r'; /* it is actually real */ point = l; } else *whzat = 'g'; /* it is a second '.', ie garbage */ } else *whzat = 'g'; /* it is garbage */ } } /* if it is only numbers, it is integer */ /* build number */ /* if it ends in a period, it is integer */ if (*whzat == 'r' && point == *last) *whzat = 'i'; if (*whzat == 'i') { if (point == *last) /* had an ending decimal point */ *i = sign * figureinteger(numberstart, *last - 1, &V); else *i = sign * figureinteger(numberstart, *last, &V); *r = *i; } else if (*whzat == 'r') { *i = figureinteger(numberstart, point - 1, &V); *r = sign * (*i + (double)figureinteger(point + 1, *last, &V) / V.power); *i *= sign; } } else *whzat = 'c'; /* move the start to just beyond the last character of the token */ V.line_->current = *last + 1; } /* figurestring */ /* end module interact.figurestring version = 4.73; (@ of prgmod.p 2004 Jul 22 */ /* ************************************************************************ */ /* end module package.interact version = 4.73; (@ of prgmod.p 2004 Jul 22 */ /* begin module copystring */ Static Void copystring(a_, b) string a_, *b; { /* copy string a to b */ long l; /* index to the string */ b->length = a_.length; for (l = 0; l < a_.length; l++) b->letters[l] = a_.letters[l]; } /* end module copystring version = 4.73; (@ of prgmod.p 2004 Jul 22 */ /* begin module nametostring */ Static Void nametostring(a_, b) name a_; string *b; { /* copy delila type name a to string b */ long l; /* index to the strings */ b->length = a_.length; for (l = 0; l < a_.length; l++) b->letters[l] = a_.letters[l]; } /* Local variables for nostring: */ struct LOC_nostring { string *buffer; boolean answer; /* the answer returned */ } ; Local Void kill(LINK) struct LOC_nostring *LINK; { /* destroy the line */ LINK->answer = true; /* blood and gore */ /* total death */ clearstring(LINK->buffer); } /* kill */ /* end module nametostring */ /* begin module package.interact.gets */ /* ************************************************************************ */ /* begin module interact.nostring */ Static boolean nostring(buffer_) string *buffer_; { /* true if there are no characters in the rest of the buffer; false if there are characters. also, if there is no buffer, then buffer.length is set to 0 */ struct LOC_nostring V; string *WITH; V.buffer = buffer_; WITH = V.buffer; if (WITH->length <= 0) { kill(&V); return V.answer; } if (WITH->length < maxstring) { while (WITH->letters[WITH->current - 1] == ' ' && WITH->current < WITH->length) WITH->current++; } if (WITH->current > maxstring) { kill(&V); return V.answer; } if (WITH->letters[WITH->current - 1] == ' ') kill(&V); else V.answer = false; return V.answer; } /* nostring */ /* end module interact.nostring version = 4.73; (@ of prgmod.p 2004 Jul 22 */ /* begin module writestring */ Static Void writestring(tofile, s) _TEXT *tofile; string *s; { /* write the string s to file tofile, no writeln */ long i; /* index to s */ long FORLIM; FORLIM = s->length; for (i = 0; i < FORLIM; i++) putc(s->letters[i], tofile->f); } /* writestring */ /* end module writestring version = 4.73; (@ of prgmod.p 2004 Jul 22 */ /* begin module interact.flagstring */ Static Void flagstring(afile, buffer) _TEXT *afile; string *buffer; { /* flag an error in the buffer at the current place, and clear the buffer */ /* chop off the rest of the buffer */ buffer->length = buffer->current; writestring(afile, buffer); /* show the buffer */ fprintf(afile->f, "? "); clearstring(buffer); } /* flagstring */ /* end module interact.flagstring version = 4.73; (@ of prgmod.p 2004 Jul 22 */ /* begin module interact.getchar */ Static Void getchar_(afile, buffer, cha, gotten) _TEXT *afile; string *buffer; Char *cha; boolean *gotten; { /* get a character from the buffer, or refill the buffer and let the calling program figure out whether the buffer has non blank characters in it. */ /* variables for calling figurestring: */ long first, last; Char what; long int_; double rea; if (buffer->length == 0) { *gotten = false; readstring(afile, buffer); } else { figurestring(buffer, &first, &last, &what, cha, &int_, &rea); *gotten = (what != ' '); } } /* getchar */ /* end module interact.getchar version = 4.73; (@ of prgmod.p 2004 Jul 22 */ /* begin module interact.getinteger */ Static Void getinteger(afile, buffer, int_, gotten) _TEXT *afile; string *buffer; long *int_; boolean *gotten; { /* get the integer int from the buffer or interactive file afile */ /* variables for calling figurestring: */ long first, last; Char what, cha; double rea; _TEXT TEMP; if (buffer->length == 0) { *gotten = false; readstring(afile, buffer); return; } figurestring(buffer, &first, &last, &what, &cha, int_, &rea); if (what == 'i') { *gotten = true; return; } TEMP.f = stdout; *TEMP.name = '\0'; flagstring(&TEMP, buffer); printf(" please type an integer\n"); *gotten = false; } /* getinteger */ /* end module interact.getinteger version = 4.73; (@ of prgmod.p 2004 Jul 22 */ /* begin module interact.getreal */ Static Void getreal(afile, buffer, rea, gotten) _TEXT *afile; string *buffer; double *rea; boolean *gotten; { /* get the real rea from the buffer or interactive file afile integer values are also accepted. */ /* variables for calling figurestring: */ long first, last; Char what, cha; long int_; _TEXT TEMP; if (buffer->length == 0) { *gotten = false; readstring(afile, buffer); } else { figurestring(buffer, &first, &last, &what, &cha, &int_, rea); if (what != 'i' && what != 'r') { TEMP.f = stdout; *TEMP.name = '\0'; flagstring(&TEMP, buffer); printf(" please type a real number\n"); *gotten = false; } else *gotten = true; } /* handle integers */ if (what == 'i') *rea = int_; } /* getreal */ /* end module interact.getreal version = 4.73; (@ of prgmod.p 2004 Jul 22 */ /* begin module interact.token */ Static Void token(buffer, atoken, gotten) string *buffer, *atoken; boolean *gotten; { /* get a token from the buffer */ /* variables for calling figurestring: */ long first, last; Char what, cha; long int_; double rea; long index; /* to the buffer */ figurestring(buffer, &first, &last, &what, &cha, &int_, &rea); if (what == ' ') { *gotten = false; return; } clearstring(atoken); for (index = first; index <= last; index++) atoken->letters[index - first] = buffer->letters[index-1]; atoken->length = last - first + 1; atoken->current = 1; *gotten = true; } /* end module interact.token version = 4.73; (@ of prgmod.p 2004 Jul 22 */ /* begin module interact.gettoken */ Static Void gettoken(afile, buffer, atoken, gotten) _TEXT *afile; string *buffer, *atoken; boolean *gotten; { /* get a token from the buffer or interactive file afile */ if (buffer->length == 0) { *gotten = false; readstring(afile, buffer); } else token(buffer, atoken, gotten); } /* gettoken */ /* end module interact.gettoken version = 4.73; (@ of prgmod.p 2004 Jul 22 */ /* ************************************************************************ */ /* end module package.interact.gets version = 4.73; (@ of prgmod.p 2004 Jul 22 */ /************************************************************************/ /************************************************************************/ /************************************************************************/ /* begin module writename */ Static Void writename(afile, s) _TEXT *afile; name s; { /* write the string s to afile */ long i; /* index to the string s */ for (i = 0; i < s.length; i++) putc(s.letters[i], afile->f); } #define tabcharacter 9 /* the ordinal of the tab character */ /* end module writename version = 8.47; (@ of lister.p 1997 May 7 */ /* (* begin module clearquotestring *) procedure clearquotestring(var s: quotestring); (* clear the quotestring s. If there is a program error, an exclamation mark will appear on the output. *) var i: integer; (* index to s *) begin for i := 1 to maxquotestring do s.string[i] := '!'; s.length := 0; end; (* end module clearquotestring version = 8.47; (@ of lister.p 1997 May 7 *) */ /* begin module detabstring */ Static Void detabstring(s) string *s; { /* Tabs are converted to blanks. This allows the tab to be a special "solid" kind of blank, but the string written won't vary with position on the line depending on the tabstops. */ Char c_; /* a character write out */ long i; /* index to the string s */ long FORLIM; FORLIM = s->length; for (i = 0; i < FORLIM; i++) { c_ = s->letters[i]; if (c_ == tabcharacter) /* tab converted to blank */ c_ = ' '; s->letters[i] = c_; } } #undef tabcharacter /* end module detabstring version = 4.73; (@ of prgmod.p 2004 Jul 22 */ /* begin module writequotestring */ Static Void writequotestring(afile, s) _TEXT *afile; string s; { /* Write the string s to afile, surrounded by double quote marks. Tabs are converted to blanks. This allows the tab to be a special "solid" kind of blank, but the string written won't vary with position on the line depending on the tabstops. */ detabstring(&s); putc('"', afile->f); writestring(afile, &s); putc('"', afile->f); } /* end module writequotestring version = 4.73; (@ of prgmod.p 2004 Jul 22 */ /* begin module writeadefinition */ Static Void writeadefinition(afile, d) _TEXT *afile; definetype *d; { /* write the definition d to file afile */ long i; /* index to the string s */ long FORLIM; fprintf(afile->f, "define"); putc(' ', afile->f); writequotestring(afile, d->nametag); putc(' ', afile->f); writequotestring(afile, d->background); putc(' ', afile->f); writequotestring(afile, d->negparts); putc(' ', afile->f); writequotestring(afile, d->posparts); FORLIM = d->marks; for (i = 0; i < FORLIM; i++) fprintf(afile->f, " %1.1f", d->locations[i]); /*writeln(afile,'WHOOPPPIIIIEEE!'); yyy*/ putc('\n', afile->f); /* (* don't do this here - it's awkward if one wants to just write the parts above. Just rember to write the matrix after the definition! *) writeln(afile); putriblmatrix(afile, matrix); */ } /* end module writeadefinition version = 4.73; (@ of prgmod.p 2004 Jul 22 */ /* begin module clearfeature */ Static Void clearfeature(f) featuretype **f; { /* clear out the feature f */ featuretype *WITH; WITH = *f; initializestring(&WITH->id); WITH->coordinate = 0.0; WITH->orientation = 1; initializestring(&WITH->nametag); initializestring(&WITH->othertag); WITH->definition = NULL; /*[[*/ WITH->Ri = 0.0; WITH->Z = 0.0; WITH->probability = 0.0; /*]]*/ WITH->Tparam = ' '; WITH->Aparam = 0.0; WITH->Bparam = 0.0; WITH->Cparam = 0.0; WITH->Dparam = 0.0; WITH->evencoordinate = 0.0; WITH->unsatisfied = true; WITH->fromrange = 0.0; WITH->torange = 0.0; WITH->number = 0; WITH->desiredline = 0; WITH->next = NULL; } /* end module clearfeature version = 4.73; (@ of prgmod.p 2004 Jul 22 */ /* begin module writeafeature */ Static Void writeafeature(afile, f) _TEXT *afile; featuretype *f; { /* write the feature f to file afile in the format: @ K00000 36 +1 "nametag" "othertag" 12.200338 -0.473212 0.318031 where the last three numbers are the Ri, Z and p. Do not carriage return. */ fprintf(afile->f, "@ "); writestring(afile, &f->id); fprintf(afile->f, " %1.1f", f->coordinate); putc(' ', afile->f); if (f->orientation > 0) fprintf(afile->f, "+%ld", f->orientation); else fprintf(afile->f, "%ld", f->orientation); putc(' ', afile->f); writequotestring(afile, f->nametag); putc(' ', afile->f); writequotestring(afile, f->othertag); /*[[*/ /*zzz*/ if (f->definition->matrix != NULL) { fprintf(afile->f, " %*.*f", infofield, infodecim, f->Ri); fprintf(afile->f, " %*.*f", infofield, infodecim, f->Z); fprintf(afile->f, " %*.*f", infofield, infodecim, f->probability); return; } fprintf(afile->f, " %c", f->Tparam); fprintf(afile->f, " %*.*f", infofield, infodecim, f->Aparam); fprintf(afile->f, " %*.*f", infofield, infodecim, f->Bparam); fprintf(afile->f, " %*.*f", infofield, infodecim, f->Cparam); fprintf(afile->f, " %*.*f", infofield, infodecim, f->Dparam); /* parameters, new as of 2004 July 17 */ /* 2004 July 17: I went ahead and removed this. As far as I know it is NOT used in feature files: if evencoordinate <> coordinate then write(afile,' ',evencoordinate:1:1); */ /*]]*/ } /* originally from 9.29; (@ of lister.p 1999 July 5 */ /* end module writeafeature version = 4.73; (@ of prgmod.p 2004 Jul 22 */ /************************************************************************/ /************************************************************************/ /************************************************************************/ /* end of procedure modules **********************************************/ Static Void addtoquotestring(q, c_) string *q; Char c_; { /* add the character c to the end of q */ /* 2004 Jul 18: no longer using quotestring. */ /*zzz*/ _TEXT TEMP; if (q->length < maxquotestring) { q->length++; q->letters[q->length - 1] = c_; return; } printf("addtoquotestring: string cannot be extended:\n"); putchar(' '); /*bug 2006 May 09*/ TEMP.f = stdout; *TEMP.name = '\0'; writequotestring(&TEMP, *q); } /*zzzFFF*/ /*zzzfff*/ Static Void numtoquotestring(q, i) string *q; long i; { /* add the number i to the end of q */ /* digit: integer; (* one digit of i as a number *) */ char digit; /* one digit of i as a number */ char newdigit; /* ord(digit) */ long c_; /* index to hold */ long count; /* how many digits were inserted */ Char chardigit; /* one digit of i as a character */ string hold; /* for switching the digits around */ /* writeln(searchfeatures,'numtoquotestring: i = ',i:1); clearquotestring(hold); */ clearstring(&hold); while (i > 0) { digit = i % 10; /* p2c: search.p, line 2750: * Note: Using % for possibly-negative arguments [317] */ /* gpc: warning: type casts are a Borland Pascal extension */ /* chardigit := char(digit + ord('0')); */ newdigit = digit + '0'; /* gpc: warning: type casts are a Borland Pascal extension */ chardigit = (Char)newdigit; /* 2001 Sep 10: it is rather puzzling why this is being objected to ... */ addtoquotestring(&hold, chardigit); count++; i /= 10; /* writeln(searchfeatures,'i = ',i:1); */ } /* We got the digits from smallest to largest, so reverse them: */ for (c_ = hold.length - 1; c_ >= 0; c_--) addtoquotestring(q, hold.letters[c_]); } #define debug false /* turn on to test code */ /*zzzFFF*/ /*zzzfff*/ Static Void dofeatures(searchfeatures, mismatches, pattern, mispattern, thefeature, thedefinition, patterncomplement) _TEXT *searchfeatures; long mismatches; string pattern, mispattern; featuretype *thefeature; definetype *thedefinition; boolean patterncomplement; { /* write out the features. If there are mismatches, define a new feature with them marked. 2008 Apr 22: rebuild the logic. The original code did not allow for additional marks besides the mutation. That is, aacta|tactgtatataaaaacagta|tcaat ~ = has '|' whch was not being placed correctly. */ Char holdNPend; /* hold negative part end */ Char holdPPend; /* hold negative part end */ double holdLOCATIONend; /* hold location end */ long m; /* index to mismatches */ /* there is a change at the end of the feature. In this case we do not want to overwrite the end with the original symbol. */ definetype *tmpdefinition; /* the current definition with x changes */ featuretype *tmpfeature; /* the current feature with x changes */ long reversespot; /* index to mismatches, the complement of m */ /*yyy*/ boolean done; /* done moving stuff */ long mm; /* the location of the place to put the base, moved across the sequence until it is in the right spot. */ long thelocation; _TEXT TEMP; /* location of a mutation to record in the feature. The first base is now defined to be zero! */ if (mismatches == 0) { writeafeature(searchfeatures, thefeature); putc('\n', searchfeatures->f); /* writeln(output,'WRITEAFEATURE ---------- BEGIN'); writeafeature(output,thefeature); writeln(output); writeln(output,'WRITEAFEATURE ---------- END'); */ return; } fprintf(searchfeatures->f, "* %ld mismatch", mismatches); if (mismatches != 1) putc('s', searchfeatures->f); fprintf(searchfeatures->f, "\n* "); writestring(searchfeatures, &pattern); fprintf(searchfeatures->f, "\n* "); writestring(searchfeatures, &mispattern); putc('\n', searchfeatures->f); tmpfeature = (featuretype *)Malloc(sizeof(featuretype)); clearfeature(&tmpfeature); tmpdefinition = (definetype *)Malloc(sizeof(definetype)); /* copy thefeature to tmpfeature so that the changes don't affect the next result */ *tmpfeature = *thefeature; *tmpdefinition = *thedefinition; /* write(output,'y-thedefinition '); {yyy} writeadefinition(output,thedefinition); {yyy} */ /* Handle the ends of the feature */ /* yyy neutralize old method 2008 apr 22 with tmpdefinition^ do begin (* Do the end first: remove to make space for change marks *) if mispattern.letters[mispattern.length] = 'x' then begin (* throw away end character *) stuffatend := true; end else begin (* take off the end and hold it *) stuffatend := false; holdNPend := negparts.letters[2]; holdPPend := posparts.letters[2]; holdLOCATIONend := locations[2]; end; marks := pred(marks); posparts.length := marks; negparts.length := marks; (* Now do the begin *) if mispattern.letters[1] = 'x' then begin (* remove now to never add later since there is X *) marks := pred(marks); posparts.length := marks; negparts.length := marks; end end; */ tmpfeature->definition = tmpdefinition; /* if debug then writeln(searchfeatures,'* holdLOCATIONend ',holdLOCATIONend:1:1); if debug then writeln(searchfeatures,'* stuffatend ',stuffatend); */ /*QQQ*/ if (patterncomplement) fprintf(searchfeatures->f, "* patterncomplement!!\n"); for (m = 1; m <= mispattern.length; m++) { if (debug) printf("*yyy %2ld %c%c\n", m, pattern.letters[m-1], mispattern.letters[m-1]); if (mispattern.letters[m-1] == 'x') { /* the first feature position is the zero coordinate, not 1: */ /*QQQ*/ if (patterncomplement) /* first base is zero! */ thelocation = mispattern.length - m; else thelocation = m - 1; addtoquotestring(&tmpfeature->nametag, '.'); numtoquotestring(&tmpfeature->nametag, thelocation); addtoquotestring(&tmpdefinition->nametag, '.'); numtoquotestring(&tmpdefinition->nametag, thelocation); tmpdefinition->marks++; if (tmpdefinition->marks > maxstring) { /* 2008 apr 22 */ printf("dofeatures: too many parts to a feature\n"); halt(); } /* first feature position is the zero coordinate, not 1: */ tmpdefinition->negparts.length = tmpdefinition->marks; tmpdefinition->posparts.length = tmpdefinition->marks; tmpdefinition->posparts.letters[tmpdefinition->posparts.length - 1] = '!'; /*yyy*/ /* move the negative parts to the right to create space */ for (mm = tmpdefinition->marks; mm >= 2; mm--) tmpdefinition->negparts.letters[mm-1] = tmpdefinition->negparts.letters[mm-2]; tmpdefinition->negparts.letters[0] = '!'; /* new 2008 Apr 22: move the locations up */ /* mm is the hole location */ mm = tmpdefinition->marks - 1; if (debug) printf("initial mm=%3ld\n", mm); done = false; if (debug) /*yyy*/ printf("A-tmpdefinition "); if (debug) { /*yyy*/ TEMP.f = stdout; *TEMP.name = '\0'; writeadefinition(&TEMP, tmpdefinition); } /* initialize upper location: */ tmpdefinition->locations[tmpdefinition->marks - 1] = tmpdefinition-> locations[tmpdefinition->marks - 2]; if (debug) /*yyy*/ printf("a-tmpdefinition "); if (debug) { /*yyy*/ TEMP.f = stdout; *TEMP.name = '\0'; writeadefinition(&TEMP, tmpdefinition); } while (!done) { if (debug) printf("m=%3ld", m); if (debug) printf(" mm=%3ld", mm); if (debug) printf(" locations[mm]=%3.1f\n", tmpdefinition->locations[mm-1]); if (tmpdefinition->locations[mm-1] <= m || mm < 1) { if (debug) fprintf(searchfeatures->f, "* mm = %ld\n", mm); if (debug) fprintf(searchfeatures->f, "* m = %ld\n", m); if (debug) fprintf(searchfeatures->f, "* marks = %ld\n", tmpdefinition->marks); if (debug) fprintf(searchfeatures->f, "* mispattern.length = %ld\n", mispattern.length); if (debug) /*yyy*/ printf("(marks-mm)+1=%ld\n", tmpdefinition->marks - mm + 1); if (!patterncomplement) { tmpdefinition->posparts.letters[mm] = pattern.letters[m-1]; /*REVERSE!*/ tmpdefinition->negparts.letters[tmpdefinition->marks - mm - 1] = chomplement(pattern.letters[m-1]); tmpdefinition->locations[mm] = thelocation; /* first base is zero! */ /*QQQ*/ } else { tmpdefinition->posparts.letters[mm] = chomplement(pattern.letters[m-1]); /*REVERSE!*/ tmpdefinition->negparts.letters[tmpdefinition->marks - mm - 1] = pattern.letters[m-1]; tmpdefinition->locations[mm] = thelocation; /* first base is zero! */ } done = true; } else { if (debug) { if (mm + 1 > tmpdefinition->marks) printf("mm+1>marks%ld>%ld\n", mm + 1, tmpdefinition->marks); } tmpdefinition->posparts.letters[mm] = tmpdefinition->posparts.letters[mm-1]; if (debug) /*yyy*/ printf("zzz(marks-mm)+1=%ld\n", tmpdefinition->marks - mm + 1); if (debug) /*yyy*/ printf("zzz(marks-mm)=%ld\n", tmpdefinition->marks - mm); /*REVERSE!!*/ tmpdefinition->negparts.letters[tmpdefinition->marks - mm - 1] = tmpdefinition->negparts.letters[tmpdefinition->marks - mm]; tmpdefinition->locations[mm] = tmpdefinition->locations[mm-1]; tmpdefinition->locations[mm-1] = -1.0; /* track the open spot */ tmpdefinition->posparts.letters[mm-1] = '_'; /*REVERSE!!*/ tmpdefinition->negparts.letters[tmpdefinition->marks - mm] = '_'; mm--; } if (debug) /*yyy*/ printf("B-tmpdefinition "); if (debug) { /*yyy*/ TEMP.f = stdout; *TEMP.name = '\0'; writeadefinition(&TEMP, tmpdefinition); } } if (debug) /*yyy*/ printf("C-tmpdefinition "); if (debug) { /*yyy*/ TEMP.f = stdout; *TEMP.name = '\0'; writeadefinition(&TEMP, tmpdefinition); } if (debug) /*yyy*/ printf("negparts.length=%ld\n", tmpdefinition->negparts.length); if (debug) /*yyy*/ printf("posparts.length=%ld\n", tmpdefinition->posparts.length); /*halt;*/ /*QQQ*/ /* original old code: if not patterncomplement then begin negparts.letters[marks] := pattern.letters[m]; end else begin reversespot := mispattern.length - m + 1; posparts.letters[marks] := pattern.letters[reversespot]; negparts.letters[marks] := pattern.letters[reversespot]; end */ } if (debug) putc('\n', searchfeatures->f); } /*zzzfff*/ /*zzzFFF*/ if (debug) /*yyy*/ printf("x-tmpdefinition "); if (debug) { /*yyy*/ TEMP.f = stdout; *TEMP.name = '\0'; writeadefinition(&TEMP, tmpdefinition); } /*yyy 2008 apr 22 old code removed: (* If needed, put the end back on *) if not stuffatend then with tmpdefinition^ do begin addtoquotestring(negparts,holdNPend); addtoquotestring(posparts,holdPPend); marks := succ(marks); locations[marks] := holdLOCATIONend; end; */ /* write out the new definition and feature */ /*yyy*/ if (debug) /*yyy*/ printf("tmpdefinition marks = %ld\n", tmpdefinition->marks); if (debug) /*yyy*/ printf("y-tmpdefinition "); if (debug) { /*yyy*/ TEMP.f = stdout; *TEMP.name = '\0'; writeadefinition(&TEMP, tmpdefinition); } writeadefinition(searchfeatures, tmpdefinition); putc('\n', searchfeatures->f); writeafeature(searchfeatures, tmpfeature); putc('\n', searchfeatures->f); /* clean up memory */ Free(tmpfeature); Free(tmpdefinition); /* halt; {yyy} */ } #undef debug /************************************************************************/ /************************************************************************/ /************************************************************************/ Static Void answercheck(answers) long *answers; { /* if the number of answers exceeds answersmax, we are probably in an infinite loop from a file input so we halt. */ (*answers)++; if (*answers > answersmax) { printf("too many tries, quitting\n"); halt(); } } /* answercheck */ Static Void searchhelp(f) _TEXT *f; { /* write out all the commands to file f */ /* for extra cirricular services contact minerva baldwin */ Char answer; _TEXT TEMP; fprintf(f->f, "commands:\n"); fprintf(f->f, "A: set the next named feature to be an arrows like [--->\n"); /* writeln(f,' This must be done following the " command.'); */ fprintf(f->f, "C: Define colors for the features in lister.\n"); fprintf(f->f, " The form is:\n"); fprintf(f->f, " C Tparam Aparam Bparam Cparam Dparam\n"); fprintf(f->f, " where\n"); fprintf(f->f, " Tparam is one of hHrR\n"); fprintf(f->f, " h color the letters using HSB colors\n"); fprintf(f->f, " r color the letters using RGB colors\n"); fprintf(f->f, " H put a colored rectangle behind the letter, HSB\n"); fprintf(f->f, " R put a colored rectangle behind the letter, RGB\n"); fprintf(f->f, " Aparam is either Hue or Red\n"); fprintf(f->f, " Bparam is either Saturation or Green\n"); fprintf(f->f, " Cparam is either Brightness or Blue\n"); fprintf(f->f, " Dparam is the scale to multiply the rectangle height by\n"); fprintf(f->f, " Tparam determines the state used for Aparam, Bparam and Cparam\n"); /*ppp*/ fprintf(f->f, "D: enter Delila subsystem for writing instructions"); fprintf(f->f, " (help is available there)\n"); fprintf(f->f, "H: help (this list)\n"); fprintf(f->f, "?: help (this list)\n"); fprintf(f->f, "L: the single letters that correspond to the (x/y) forms\n"); fprintf(f->f, "M: set maximum number of mismatches allowed (currently %ld)\n", mismatches); fprintf(f->f, "N: a toggle switch:\n"); fprintf(f->f, " If true, searches are performed when\n"); fprintf(f->f, " the = command is given or when the pattern is typed.\n"); fprintf(f->f, " If false, searches are performed only when the = command is given.\n"); fprintf(f->f, " (currently "); if (oktosearch == true) fprintf(f->f, "true).\n"); else fprintf(f->f, "false).\n"); fprintf(f->f, "P: set start point (phase) and shift between search steps\n"); fprintf(f->f, "q: quit\n"); fprintf(f->f, "Q: quit\n"); fprintf(f->f, "V: view: set viewing parameters (help is available there)\n"); fprintf(f->f, "*: the rest of the line is a comment sent to"); fprintf(f->f, " the searchinst and result files\n"); fprintf(f->f, "=: search for the last typed search pattern\n"); fprintf(f->f, "~: complement the search pattern\n"); fprintf(f->f, " This reverses the order AND complements each character.\n"); fprintf(f->f, "\": create searchfeatures file\n"); fprintf(f->f, " * To create searchfeatures, define the name of a search string\n"); fprintf(f->f, " by typing the name inside double quotes (as: \"EcoRI\") and then\n"); fprintf(f->f, " do the search (eg type: gaattc).\n"); fprintf(f->f, " * Vertical bars or carets (| or ^) in the search string (as:\n"); fprintf(f->f, " g|aattc) will carry over to the feature.\n"); fprintf(f->f, " * All subsequent searches will be labeled with the same name\n"); fprintf(f->f, " until you give a new one.\n"); fprintf(f->f, " * To turn off the features, use an empty quote string, as \"\".\n"); fprintf(f->f, " * Because space is used to parse, no spaces are allowed in\n"); fprintf(f->f, " * the names. However, the lister program will treat a tab.\n"); fprintf(f->f, " * as a space, so this can be used instead.\n"); fprintf(f->f, " * The searchfeatures file can be concatenated with other\n"); fprintf(f->f, " features to create the features file for the lister program.\n"); fprintf(f->f, " * Before using the name command, use the \"A\" command to \n"); fprintf(f->f, " have the feature be an arrow.\n"); fprintf(f->f, "I: invert: complement the characters in the search string.\n"); fprintf(f->f, " This DOES NOT change the order of the characters.\n"); fprintf(f->f, "R: reverse the order of the characters in the search string.\n"); fprintf(f->f, " This reverses the order BUT DOES NOT complement characters.\n"); /*qqq*/ /*zzz*/ fprintf(f->f, "one can type several commands on one line separated by spaces.\n"); fprintf(f->f, "example (without quotes): \"M 1 V n V s V d V p gaattc * ecori\"\n\n"); answers = 0; do { if (nostring(&buffer)) printf("do you want to see the patterns allowed? (y/n)\n"); TEMP.f = stdin; *TEMP.name = '\0'; getchar_(&TEMP, &buffer, &answer, &gotten); gotten = (answer == 'y' || answer == 'n'); answercheck(&answers); } while (!gotten); if (answer == 'y') { fprintf(f->f, "anything else recognizable is a pattern."); fprintf(f->f, " (the 's are not needed):\n"); fprintf(f->f, "the simplest pattern contains only \"a\", \"c\", \"g\", or \"t\".\n"); fprintf(f->f, "one can also ask for purines (\"r\") or pyrimidines (\"y\").\n"); fprintf(f->f, "the form \"(x/y)\" or \"(x/y/z)\" allows search for \"x or y\" or\n"); fprintf(f->f, "\"x or y or z\". x, y, and z must be \"a\", \"c\", \"g\", or \"t\".\n\n"); fprintf(f->f, "\"n\" means any base.\n"); fprintf(f->f, "\"e\" means an extension: the scan is made with and without\n"); fprintf(f->f, " the e. during the scan, e is treated like an \"n\".\n"); fprintf(f->f, "one may ask for several letters, by stating the number. \n"); fprintf(f->f, " so \"5a\" is the same as \"aaaaa\".\n"); fprintf(f->f, "\"#\" the number of the next base is returned on a match.\n"); fprintf(f->f, " default: the first base beyond n's and e's\n"); fprintf(f->f, " Position of # is changed when complement (~) is taken.\n"); fprintf(f->f, "\"%%\" the number of the base before the current one is given.\n"); fprintf(f->f, " %% is like #, but does NOT change position when ~ is taken.\n"); fprintf(f->f, "\"<\" allow no mismatches until \">\"\n"); fprintf(f->f, "\">\" allow mismatches until \"<\" (the default)\n"); fprintf(f->f, " \"aa\" makes \"cag\" searched for exactly.\n"); fprintf(f->f, "\"string\" Double quoted string is a name.\n"); fprintf(f->f, " It starts searchfeatures. Empty string turns it off.\n"); fprintf(f->f, "\"|\" symbol that will be put into searchfeatures BETWEEN bases\n"); fprintf(f->f, "\"^\" symbol that will be put into searchfeatures BETWEEN bases\n"); fprintf(f->f, "\"[\" symbol that will be put into searchfeatures BETWEEN bases\n"); fprintf(f->f, "\"]\" symbol that will be put into searchfeatures BETWEEN bases\n"); fprintf(f->f, "example: \"acag(t/c/a)5e#2a<3r3y>\".\n\n"); answers = 0; do { answer = ' '; if (nostring(&buffer)) printf("do you want to see the relational patterns allowed? (y/n)\n"); TEMP.f = stdin; *TEMP.name = '\0'; getchar_(&TEMP, &buffer, &answer, &gotten); gotten = (answer == 'y' || answer == 'n'); answercheck(&answers); } while (!gotten); if (answer == 'y') { fprintf(f->f, "\"$\" specifies a relation between two bases. the format is:\n"); fprintf(f->f, " \"$#r\", where # is a position in the pattern (preceding\n"); fprintf(f->f, " this position) that is related to this position by r.\n"); fprintf(f->f, " r must be one of the following: i (identity);\n"); fprintf(f->f, " ni (non-identity); c (complement); nc (non-complement).\n"); fprintf(f->f, " w (complement including g-t pair); nw (non-w).\n\n"); fprintf(f->f, "examples: \"n$1i\" would search for aa, cc, gg and tt.\n"); fprintf(f->f, " \"5n$1c\" would search for complementary bases \n"); fprintf(f->f, " separated by 4 unspecified bases.\n"); fprintf(f->f, " NOTE: this was formerly [before 1997] the ^ symbol.\n"); } } clearstring(&buffer); /* make sure the buffer does not propagate */ } /* searchhelp */ Static Void showletters(f) _TEXT *f; { /* show to file f the letter conversions of forms like "(x/y)" */ fprintf(f->f, "a is a \n"); fprintf(f->f, "c is c \n"); fprintf(f->f, "m is ac \n"); fprintf(f->f, "g is g \n"); fprintf(f->f, "r is a g \n"); fprintf(f->f, "s is cg \n"); fprintf(f->f, "v is acg \n"); fprintf(f->f, "t is t\n"); fprintf(f->f, "w is a t\n"); fprintf(f->f, "y is c t\n"); fprintf(f->f, "h is ac t\n"); fprintf(f->f, "k is gt\n"); fprintf(f->f, "d is a gt\n"); fprintf(f->f, "b is cgt\n"); fprintf(f->f, "n is acgt\n"); fprintf(f->f, "e is acgt or nothing\n"); fprintf(f->f, "warning: some of these ambiguous nucleotide symbols overlap \n"); fprintf(f->f, " some of the search command symbols. for instance, h\n"); fprintf(f->f, " can mean \"a or c or t\" or it can mean \"help\".\n"); fprintf(f->f, " to avoid problems, begin search patterns with a, c, g,\n"); fprintf(f->f, " t or n, or use the (x/y/z) form for ambiguous bases.\n"); } /* showletters */ Static Void Delilahelp(f) _TEXT *f; { /* write out commands in Delila subsystem to file f */ fprintf(f->f, "this is a search subsystem for creating Delila\n"); fprintf(f->f, "instructions based on search results.\n\n"); fprintf(f->f, "q: quit to search.\n"); fprintf(f->f, "p: print Delila instructions on/off switch.\n"); fprintf(f->f, " when on, instructions will be printed in searchinst for each\n"); fprintf(f->f, " pattern found. if n is the value of the numbered (#'d)\n"); fprintf(f->f, " base, f and t are the values from and to, then the\n"); fprintf(f->f, " instruction is a get of the form:\n"); fprintf(f->f, " get from n +f to n +t;\n"); fprintf(f->f, " organism, chromosome and piece specifications are\n"); fprintf(f->f, " automatically taken care of.\n\n"); fprintf(f->f, "f: set from: number of bases before #'d base to get from\n"); fprintf(f->f, "t: set to: number of bases after #'d base to get to\n"); fprintf(f->f, " both from and to are with respect to the piece,\n"); fprintf(f->f, " so you do not need to worry about orientations.\n"); fprintf(f->f, "i set instruction type: one or two places in get.\n"); fprintf(f->f, " insttype=1 means the form get from p -/+f to same +/-t dir +/-;\n"); fprintf(f->f, " insttype=2 means the form get from p1 -/+f to p2 +/-t dir +/-;\n"); fprintf(f->f, " where p or p2 are the current location, p1 is the previous,\n"); fprintf(f->f, " f is the from range and t is the to range.\n"); fprintf(f->f, " insttype=3 means the form get from p1 -/+f to p2 +/-t dir +/-;\n"); fprintf(f->f, " where p1 is the current location 5' end, p2 is the 3' end,\n"); fprintf(f->f, "w: to write your own Delila instructions.\n"); fprintf(f->f, " warning: they are not checked at all.\n"); fprintf(f->f, " q to quit. common uses: title and defaults.\n"); fprintf(f->f, "s: show all current Delila instructions\n"); fprintf(f->f, "k: kill all current Delila instructions\n"); fprintf(f->f, "h: help (this list).\n"); fprintf(f->f, "*: the rest of the line is a comment sent to"); fprintf(f->f, " the searchinst and result files\n"); } /* Delilahelp */ /* Local variables for viewhelp: */ struct LOC_viewhelp { _TEXT *f; } ; Local Void state_(a_, LINK) boolean a_; struct LOC_viewhelp *LINK; { /* write the state of a out */ if (a_) fprintf(LINK->f->f, " on "); else fprintf(LINK->f->f, " "); } /* state */ Static Void viewhelp(f_) _TEXT *f_; { /* write to file f the sub-commands for the view command */ struct LOC_viewhelp V; V.f = f_; fprintf(V.f->f, "the view command sets the amount of search results made visible.\n"); fprintf(V.f->f, "the parts correspond to the order of printed results.\n"); fprintf(V.f->f, "the current state of the toggle switches available\n"); fprintf(V.f->f, "is shown below, along with the commands:\n"); state_(viewt, &V); fprintf(V.f->f, "t: typed pattern\n"); state_(viewe, &V); fprintf(V.f->f, "e: expanded pattern\n"); state_(viewi, &V); fprintf(V.f->f, "i: identification information (organism, etc)\n"); state_(viewf, &V); fprintf(V.f->f, "f: forms of patterns (with variable e)\n"); state_(views, &V); fprintf(V.f->f, "s: sequence found\n"); state_(viewp, &V); fprintf(V.f->f, "p: position of matches on piece\n"); state_(viewd, &V); fprintf(V.f->f, "d: distance between matches\n"); state_(viewm, &V); fprintf(V.f->f, "m: matches per piece\n"); state_(viewb, &V); fprintf(V.f->f, "b: matches per book\n\n"); state_(false, &V); fprintf(V.f->f, "a: all results viewed\n"); state_(false, &V); fprintf(V.f->f, "n: nothing viewed (even total matches)\n"); state_(false, &V); fprintf(V.f->f, "q: quit view process (do nothing)\n"); state_(false, &V); fprintf(V.f->f, "h: help (this list)\n"); } /* viewhelp */ Static long patternlength(pattern) string pattern; { /* showpattern */ /* give the length of the pattern. */ long p = 1; /* index to pattern */ while (pattern.letters[p-1] != '.') { /* write(afile,pattern.letters[p]); */ p++; } return (p - 1); } /* patternlength */ Static Void showpattern(afile, pattern, ln) _TEXT *afile; string pattern; boolean ln; { /* write the pattern to the file. do line feed depending on ln. */ long p = 1; /* index to pattern */ putc('"', afile->f); while (pattern.letters[p-1] != '.') { putc(pattern.letters[p-1], afile->f); p++; } putc('"', afile->f); if (ln) putc('\n', afile->f); } /* showpattern */ /* Local variables for expandpattern: */ struct LOC_expandpattern { string *p; boolean *ok; long *pp, rbase; /* position of related base */ long numbers[3]; Char letter; /* the letter to put into t */ } ; Local Void getnumber(p, pp, number, LINK) string p; long *pp, *number; struct LOC_expandpattern *LINK; { /* pull out a number from p starting at pp. move pp past the number */ long n; /* a second position in p */ long power = 1; /* power of 10 */ /* used to calculate the number */ long increment; boolean done = false; /* are we done yet? */ *number = 0; while (P_inset(p.letters[*pp - 1], LINK->numbers)) (*pp)++; /* pp is now past the number */ n = *pp - 1; /* n is at the lowest digit */ do { switch (p.letters[n-1]) { case '0': increment = 0; break; case '1': increment = 1; break; case '2': increment = 2; break; case '3': increment = 3; break; case '4': increment = 4; break; case '5': increment = 5; break; case '6': increment = 6; break; case '7': increment = 7; break; case '8': increment = 8; break; case '9': increment = 9; break; } *number += power * increment; power *= 10; n--; if (n == 0) done = true; else done = !P_inset(p.letters[n-1], LINK->numbers); } while (!done); if (p.letters[*pp - 1] == '.') *LINK->ok = false; if (*number == 0) *LINK->ok = false; } /* getnumber */ Local Void getrelation(LINK) struct LOC_expandpattern *LINK; { /* we now have a pattern symbol ('$') that specifies a relation between the base at this position and another base. we will now determine what that relation is and to what position it refers. */ boolean non = false; /* means the negation of a specific relation */ relational = true; (*LINK->pp)++; /* get the next letter */ if (P_inset(LINK->p->letters[*LINK->pp - 1], LINK->numbers)) getnumber(*LINK->p, LINK->pp, &LINK->rbase, LINK); else { *LINK->ok = false; printf(" number required after relation symbol\n"); } if (LINK->p->letters[*LINK->pp - 1] == 'n') { non = true; /* the negation of the relation */ (*LINK->pp)++; } if (LINK->p->letters[*LINK->pp - 1] == 'i') { /* identity */ if (non) LINK->letter = 'p'; else LINK->letter = 'l'; return; } if (LINK->p->letters[*LINK->pp - 1] == 'c') { /* complementarity */ if (non) LINK->letter = 'q'; else LINK->letter = 'j'; return; } if (LINK->p->letters[*LINK->pp - 1] == 'w') { /* complementarity including g-t pairs */ if (non) LINK->letter = 'z'; else LINK->letter = 'x'; return; } *LINK->ok = false; if (LINK->p->letters[*LINK->pp - 1] == '.') printf("early end to pattern, relation expected\n"); else printf("illegal relation specified: %c\n", LINK->p->letters[*LINK->pp - 1]); } Static Void expandpattern(p_, ok_, pp_) string *p_; boolean *ok_; long *pp_; { /* make p into an expanded pattern: all or's and numbers become characters. if ok is false then pp is the position of an error in the pattern p, otherwise it is an aribitrary position in p. */ struct LOC_expandpattern V; string t_; /* temporary string for building absolute format */ long tp = 0; /* the position in t */ long number; /* the number of times to repeat the unit */ Char binary[4]; /* represents "(x/y)" forms */ boolean expecting; /* a letter is expected after "(" or "/" */ V.p = p_; V.ok = ok_; V.pp = pp_; P_addset(P_expset(V.numbers, 0L), '0'); P_addset(V.numbers, '1'); P_addset(V.numbers, '2'); P_addset(V.numbers, '3'); P_addset(V.numbers, '4'); P_addset(V.numbers, '5'); P_addset(V.numbers, '6'); P_addset(V.numbers, '7'); P_addset(V.numbers, '8'); P_addset(V.numbers, '9'); *V.pp = 1; *V.ok = true; relational = false; /* until we see a relation in the pattern */ while (V.p->letters[*V.pp - 1] != '.' && *V.ok) { if (P_inset(V.p->letters[*V.pp - 1], V.numbers)) getnumber(*V.p, V.pp, &number, &V); else number = 1; if (!*V.ok) break; if (V.p->letters[*V.pp - 1] == '(') { /* begin "(x/y..." */ expecting = true; (*V.pp)++; if (V.p->letters[*V.pp - 1] != '.') { memcpy(binary, " ", 4L); while (V.p->letters[*V.pp - 1] != ')' && *V.ok) { expecting = false; if (V.p->letters[*V.pp - 1] == 't' || V.p->letters[*V.pp - 1] == 'g' || V.p->letters[*V.pp - 1] == 'c' || V.p->letters[*V.pp - 1] == 'a') { switch (V.p->letters[*V.pp - 1]) { case 'a': binary[0] = V.p->letters[*V.pp - 1]; break; case 'c': binary[1] = V.p->letters[*V.pp - 1]; break; case 'g': binary[2] = V.p->letters[*V.pp - 1]; break; case 't': binary[3] = V.p->letters[*V.pp - 1]; break; } } else if (V.p->letters[*V.pp - 1] == '.') { expecting = true; *V.ok = false; } else { *V.ok = false; printf("character not in acgt\n"); } if (!*V.ok) break; (*V.pp)++; if (V.p->letters[*V.pp - 1] == ')') break; if (V.p->letters[*V.pp - 1] == '/') { (*V.pp)++; expecting = true; /* need char after / */ } else { *V.ok = false; printf("i expected / or )\n"); } } } else { *V.ok = false; printf("unclosed (\n"); } if (expecting) { *V.ok = false; printf("i expect more after ( or /\n"); (*V.pp)--; } if (*V.ok) { if (!strncmp(binary, " ", 4)) *V.ok = false; else if (!strncmp(binary, "a ", 4)) V.letter = 'a'; else if (!strncmp(binary, " c ", 4)) V.letter = 'c'; else if (!strncmp(binary, "ac ", 4)) V.letter = 'm'; else if (!strncmp(binary, " g ", 4)) V.letter = 'g'; else if (!strncmp(binary, "a g ", 4)) V.letter = 'r'; else if (!strncmp(binary, " cg ", 4)) V.letter = 's'; else if (!strncmp(binary, "acg ", 4)) V.letter = 'v'; else if (!strncmp(binary, " t", 4)) V.letter = 't'; else if (!strncmp(binary, "a t", 4)) V.letter = 'w'; else if (!strncmp(binary, " c t", 4)) V.letter = 'y'; else if (!strncmp(binary, "ac t", 4)) V.letter = 'h'; else if (!strncmp(binary, " gt", 4)) V.letter = 'k'; else if (!strncmp(binary, "a gt", 4)) V.letter = 'd'; else if (!strncmp(binary, " cgt", 4)) V.letter = 'b'; else if (!strncmp(binary, "acgt", 4)) V.letter = 'n'; } } /* close "(x/y...)" */ else { if (V.p->letters[*V.pp - 1] == 'b' || V.p->letters[*V.pp - 1] == 'd' || V.p->letters[*V.pp - 1] == 'h' || V.p->letters[*V.pp - 1] == 'v' || V.p->letters[*V.pp - 1] == 'k' || V.p->letters[*V.pp - 1] == 'y' || V.p->letters[*V.pp - 1] == 's' || V.p->letters[*V.pp - 1] == 'w' || V.p->letters[*V.pp - 1] == 'r' || V.p->letters[*V.pp - 1] == 'm' || V.p->letters[*V.pp - 1] == '$' || V.p->letters[*V.pp - 1] == ']' || V.p->letters[*V.pp - 1] == '[' || V.p->letters[*V.pp - 1] == '^' || V.p->letters[*V.pp - 1] == '|' || V.p->letters[*V.pp - 1] == '%' || V.p->letters[*V.pp - 1] == '#' || V.p->letters[*V.pp - 1] == 'e' || V.p->letters[*V.pp - 1] == 'n' || V.p->letters[*V.pp - 1] == 't' || V.p->letters[*V.pp - 1] == 'g' || V.p->letters[*V.pp - 1] == 'c' || V.p->letters[*V.pp - 1] == 'a' || V.p->letters[*V.pp - 1] == '<' || V.p->letters[*V.pp - 1] == '>' || V.p->letters[*V.pp - 1] == '^') /* p2c: search.p, line 3526: * Note: Line breaker spent 0.0 seconds, 5000 tries on line 4550 [251] */ V.letter = V.p->letters[*V.pp - 1]; else { *V.ok = false; printf("funny character\n"); } } /* if letter = '$' we need to find what relation is specified and to what base it applies */ if (V.letter == '$') getrelation(&V); else V.rbase = 0; if (!*V.ok) /* we have the letter now */ break; while (number != 0 && *V.ok) { tp++; if (tp >= maxstring) { *V.ok = false; printf("expanded pattern too long\n"); continue; } t_.letters[tp-1] = V.letter; if (tp > V.rbase) relatedbase[tp-1] = V.rbase; else { printf(" related base must preceed relation\n"); *V.ok = false; } number--; } /* store in t */ if (*V.ok) (*V.pp)++; } if (*V.ok) { *V.p = t_; /* replace pattern from temporary pattern */ V.p->letters[tp] = '.'; /* must end on period */ } } /* expandpattern */ Static Char complementbase(c_) Char c_; { /* complement the base */ Char Result; if (c_ != '9' && c_ != '8' && c_ != '7' && c_ != '6' && c_ != '5' && c_ != '4' && c_ != '3' && c_ != '2' && c_ != '1' && c_ != '0' && c_ != ')' && c_ != '/' && c_ != '(' && c_ != '^' && c_ != '|' && c_ != ']' && c_ != '[' && c_ != '#' && c_ != 'e' && c_ != '>' && c_ != '<' && c_ != '%' && c_ != 'n' && c_ != 'b' && c_ != 'd' && c_ != 'k' && c_ != 'h' && c_ != 'y' && c_ != 'w' && c_ != 't' && c_ != 'v' && c_ != 's' && c_ != 'r' && c_ != 'g' && c_ != 'm' && c_ != 'c' && c_ != 'a') { /* p2c: search.p, line 3569: * Note: Line breaker spent 0.0 seconds, 5000 tries on line 4608 [251] */ printf("bad character \"%c\" found during complement\n", c_); return Result; } switch (c_) { case 'a': /* is a */ Result = 't'; break; case 'c': /* is c */ Result = 'g'; break; case 'm': /* is ac */ Result = 'k'; break; case 'g': /* is g */ Result = 'c'; break; case 'r': /* is a g */ Result = 'y'; break; case 's': /* is cg */ Result = 'w'; break; case 'v': /* is acg */ Result = 'b'; break; case 't': /* is t */ Result = 'a'; break; case 'w': /* is a t */ Result = 's'; break; case 'y': /* is c t */ Result = 'r'; break; case 'h': /* is ac t */ Result = 'd'; break; case 'k': /* is gt */ Result = 'm'; break; case 'd': /* is a gt */ Result = 'h'; break; case 'b': /* is cgt */ Result = 'v'; break; case 'n': /* is acgt */ Result = 'n'; break; case '<': /* start of match */ Result = '>'; break; case '>': /* end of match */ Result = '<'; break; case 'e': /* expand */ Result = 'e'; break; case '(': /* parens reverse */ Result = ')'; break; case ')': /* parens reverse */ Result = '('; break; case '%': case '#': case '|': case '^': case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case '[': case ']': case '/': /* bracket does not change */ /*zzz*/ Result = c_; break; /* slash does not change */ } return Result; } /* complementbase */ Static Void stringcomplement(p) string *p; { /* create the complement of the string p */ /* when numbered strings of the form 32n or #5 (not %) are found, the substring (32n or #5) must not be reversed in order. The machinery below does this by keeping track of the start and stop points of every string found. */ string h; /* for holding the p string */ long i; /* index to the strings */ long j; /* index to the strings */ boolean endofflip; /* true if the end of a numbered region is found */ boolean flipnumber = false; /* true if there is a number to be flipped */ long upper; /* a constant to make things a bit faster */ long start; /* start of a flipped region */ long stop; /* stop of a flipped region */ long FORLIM; _TEXT TEMP; clearstring(&h); h.length = p->length; upper = p->length + 1; FORLIM = p->length; for (i = 1; i <= FORLIM; i++) { endofflip = true; stop = i; h.letters[upper - i - 1] = complementbase(p->letters[i-1]); if (p->letters[i-1] == '9' || p->letters[i-1] == '8' || p->letters[i-1] == '7' || p->letters[i-1] == '6' || p->letters[i-1] == '5' || p->letters[i-1] == '4' || p->letters[i-1] == '3' || p->letters[i-1] == '2' || p->letters[i-1] == '1' || p->letters[i-1] == '0' || p->letters[i-1] == '#') { endofflip = false; if (!flipnumber) { flipnumber = true; start = i; } } /* write(output,'before flip: "');writestring(output,h); writeln(output,'"'); */ if (endofflip && flipnumber) { /* move the entire number and the next base without turning it around */ /* writeln(output,'endofflip'); */ for (j = start - 1; j < stop; j++) h.letters[upper - stop + j - start] = complementbase(p->letters[j]); flipnumber = false; } /* ;write(output,' after flip: "');writestring(output,h); writeln(output,'"'); */ } copystring(h, p); printf("* the complementary search string is now: \""); TEMP.f = stdout; *TEMP.name = '\0'; writestring(&TEMP, p); printf("\"\n"); fprintf(result.f, "* the complementary search string is now: \""); writestring(&result, p); fprintf(result.f, "\"\n"); if (!printinginstructions) return; /*yyy*/ /* halt; */ fprintf(searchinst.f, "(* the complementary search string is now: \""); writestring(&searchinst, p); fprintf(searchinst.f, "\" *)\n"); } /*qqq*/ Static Void stringreverse(p) string *p; { /* Reverse the order of the string p WITHOUT taking the complement. No symbols are altered. */ long upper; /* a constant to make things a bit faster */ long i; /* index to the string */ long midpoint; /* half of the string length */ Char hold; /* a character in the string */ _TEXT TEMP; upper = p->length + 1; midpoint = p->length / 2; for (i = 1; i <= midpoint; i++) { hold = p->letters[i-1]; p->letters[i-1] = p->letters[upper - i - 1]; p->letters[upper - i - 1] = hold; } printf("* the reversed search string is now: \""); TEMP.f = stdout; *TEMP.name = '\0'; writestring(&TEMP, p); printf("\"\n"); fprintf(result.f, "* the reversed search string is now: \""); writestring(&result, p); fprintf(result.f, "\"\n"); if (!printinginstructions) return; fprintf(searchinst.f, "(* the reversed search string is now: \""); writestring(&searchinst, p); fprintf(searchinst.f, "\" *)\n"); } /* stringreverse */ /*qqq*/ Static Void stringinvert(p) string *p; { /* complement each letter in the string. The order is not changed. */ long i; /* index to the string */ long FORLIM; _TEXT TEMP; FORLIM = p->length; for (i = 0; i < FORLIM; i++) p->letters[i] = complementbase(p->letters[i]); printf("* the inverted (complement only) search string is now: \""); TEMP.f = stdout; *TEMP.name = '\0'; writestring(&TEMP, p); printf("\"\n"); fprintf(result.f, "* the inverted (complement only) search string is now: \""); writestring(&result, p); fprintf(result.f, "\"\n"); if (!printinginstructions) return; fprintf(searchinst.f, "(* the inverted (complement only) search string is now: \""); writestring(&searchinst, p); fprintf(searchinst.f, "\" *)\n"); } /* stringinvert */ Static Void analysepattern(p, e, ok) string *p, *e; boolean *ok; { /* the pattern is forced to end in a blank, and it is expanded into e. ok is true when no errors were found. */ long n; /* position in p */ boolean elate; /* e on end of pattern */ long numofnums = 0; /* number of # symbols */ string error; /* used to show an error */ long FORLIM; _TEXT TEMP; clearstring(&error); *ok = true; FORLIM = p->length; /* locate periods in pattern */ for (n = 0; n < FORLIM; n++) { if (p->letters[n] == '.') { *ok = false; /* The original convention in search.p was to define the end of the string with '.'. Make it possible to change/upgrade this by supplying the length */ p->length = n; } } /*zzzsss*/ if (!*ok) printf("no periods (.) allowed in the search pattern\n"); if (p->length + 1 <= maxstring) p->letters[p->length] = '.'; else { *ok = false; printf("search string is too long\n"); } /* begin expansion */ *e = *p; /* find last possible e */ /* do it now since we know end: length */ n = p->length; while (n != 1 && (e->letters[n-1] == '9' || e->letters[n-1] == '8' || e->letters[n-1] == '7' || e->letters[n-1] == '6' || e->letters[n-1] == '5' || e->letters[n-1] == '4' || e->letters[n-1] == '3' || e->letters[n-1] == '2' || e->letters[n-1] == '1' || e->letters[n-1] == '0' || e->letters[n-1] == '#' || e->letters[n-1] == '%' || e->letters[n-1] == '<' || e->letters[n-1] == '>' || e->letters[n-1] == '|' || e->letters[n-1] == '^' || e->letters[n-1] == '[' || e->letters[n-1] == ']')) n--; if (e->letters[n-1] == 'e') { *ok = false; error.letters[n-1] = 'e'; elate = true; } else elate = false; if (*ok) { expandpattern(e, ok, &n); if (!*ok) error.letters[n-1] = '^'; } /* find first possible e. this is done here since expandpattern removes numbers, making it easy to spot a prefixed e */ n = 1; while ((e->letters[n-1] == '#' || e->letters[n-1] == '%' || e->letters[n-1] == '<' || e->letters[n-1] == '>' || e->letters[n-1] == '|' || e->letters[n-1] == '^' || e->letters[n-1] == '[' || e->letters[n-1] == ']' || e->letters[n-1] == '(' || e->letters[n-1] == ')' || e->letters[n-1] == '$' || e->letters[n-1] == '/') && n < maxstring) /*zzzddd*/ n++; if (e->letters[n-1] == 'e') error.letters[n-1] = 'e'; if (e->letters[n-1] == 'e' || elate) { *ok = false; printf("no e's allowed on ends\n"); } /* check that # is correct */ n = 1; while (e->letters[n-1] != '.') { if (e->letters[n-1] == '#' || e->letters[n-1] == '%') numofnums++; n++; } if (numofnums > 1) { printf("extra # or %% symbols\n"); *ok = false; error.letters[n-2] = '#'; } if (e->letters[n-2] == '#' || e->letters[n-2] == '%') { printf("# or %% symbol found at end: adding n to end\n"); if (p->length + 1 > maxstring) { printf("... that makes the string too long\n"); *ok = false; error.letters[n-2] = '#'; } else { p->length++; p->letters[p->length - 1] = 'n'; p->letters[p->length] = '.'; e->length = p->length; e->letters[e->length - 1] = 'n'; e->letters[e->length] = '.'; } } /* writeln(output,'# symbol not allowed at end'); ok:=false; error.letters[n-1]:='#'; */ /* make sure it is not all n's, e's, <'s, >'s, #'s and %'s */ n = 1; while (e->letters[n-1] == 'e' || e->letters[n-1] == 'n' || e->letters[n-1] == '$' || e->letters[n-1] == '<' || e->letters[n-1] == '>' || e->letters[n-1] == '#' || e->letters[n-1] == '%' || e->letters[n-1] == '|' || e->letters[n-1] == '^' || e->letters[n-1] == '[' || e->letters[n-1] == ']' || e->letters[n-1] == '(' || e->letters[n-1] == ')' || e->letters[n-1] == '/') /*zzzddd*/ n++; if (e->letters[n-1] == '.') { *ok = false; error.letters[n-2] = '&'; printf("You must have other characters in addition to: ne$<>#%%|^[]\n"); } if (*ok) { if (viewt) { printf("\n typed pattern: "); TEMP.f = stdout; *TEMP.name = '\0'; showpattern(&TEMP, *p, true); fprintf(result.f, "* typed pattern: "); showpattern(&result, *p, true); } if (viewe) { printf("expanded pattern: "); TEMP.f = stdout; *TEMP.name = '\0'; showpattern(&TEMP, *e, true); fprintf(result.f, "* expanded pattern: "); showpattern(&result, *e, true); } if (!printinginstructions) return; fprintf(searchinst.f, "\n(* typed pattern: "); showpattern(&searchinst, *p, false); fprintf(searchinst.f, " *)\n"); return; } /* get . for error from pattern */ n = 1; while (e->letters[n-1] != '.') n++; error.letters[n-1] = '.'; TEMP.f = stdout; *TEMP.name = '\0'; showpattern(&TEMP, *e, true); TEMP.f = stdout; *TEMP.name = '\0'; showpattern(&TEMP, error, false); printf(" unusable pattern\n"); /* ignore further commands on the line: */ clearstring(&buffer); /* write a message out for errors */ } /* analysepattern */ Static Void compress(p, s, rb) string *p; long s; long *rb; { /* remove from p the character pointed to by s and shift the rest of the pattern to the left */ long ss; /* successor of s */ while (p->letters[s-1] != '.') { ss = s + 1; p->letters[s-1] = p->letters[ss-1]; rb[s-1] = rb[ss-1]; s = ss; } p->length = ss; } /* compress */ Static boolean related(b1, b2, r) base b1, b2; Char r; { /* true if b1 and b2 are related as specified by r */ boolean Result; switch (r) { /* identity */ case 'l': Result = (b1 == b2); break; /* non-identity */ case 'p': Result = (b1 != b2); break; /* complementarity */ case 'j': Result = (b1 == complement(b2)); break; /* non-complementary */ case 'q': Result = (b1 != complement(b2)); break; /* complementarity including g-t pairs */ case 'x': Result = (b1 == complement(b2) || b1 == g && b2 == t || b1 == t && b2 == g); break; /* non-complementarity, including g-t pairs */ case 'z': Result = (b1 != complement(b2) && (b1 != g || b2 != t) && (b1 != t || b2 != g)); break; } return Result; } /* Local variables for match: */ struct LOC_match { long mismax; string realpattern; /* the dna in the piece corresponding to pattern */ long theplace; /* the actual place on the pattern recorded # and % */ long pieceplace; /* like theplace, but on the piece */ long distance; /* the distance to last match or -1 */ long mismatches; /* the actual number of mismatches */ string mispattern; /* the places mismatches occured */ } ; Local Void display(afile, LINK) _TEXT *afile; struct LOC_match *LINK; { /* display the match. global variables used: realpattern, mismatches, theposition, pieceplace */ long p, FORLIM; if (views) { fprintf(afile->f, " "); showpattern(afile, LINK->realpattern, true); /* show mismatches */ if (LINK->mismax != 0) { fprintf(afile->f, " "); showpattern(afile, LINK->mispattern, false); /* writeln(afile,' ',mismatches:1,' mismatche(s)') */ fprintf(afile->f, " %ld mismatch", LINK->mismatches); if (LINK->mismatches != 1) putc('s', afile->f); putc('\n', afile->f); } if (viewp) { fprintf(afile->f, " "); FORLIM = LINK->theplace; for (p = 1; p <= FORLIM; p++) /* 0->1 1990 Sep 4 */ putc(' ', afile->f); fprintf(afile->f, "^ %ld ", LINK->pieceplace); /*yyy*/ } /* mark location */ } else if (viewp) fprintf(afile->f, " %6ld", LINK->pieceplace); if (viewd) { if (LINK->distance > 0) fprintf(afile->f, " %6ld bases from last match ", LINK->distance); } if (views || viewd || viewp) fprintf(afile->f, "*\n"); } /* display */ Static Void match(pattern, mismax_, relatedbase_, org, orgchange, chr, chrchange, pie, piechange, patterncomplement) string pattern; long mismax_; long *relatedbase_; orgkey *org; boolean *orgchange; chrkey *chr; boolean *chrchange; piece **pie; boolean *piechange, patterncomplement; { /* if true, reverse inst's */ /* match this exact pattern in pie, allow mismax mismatches */ struct LOC_match V; intarray relatedbase; /* for scanning piece */ long i; /* internal position on piece */ long length; /* length of this piece */ long searchlength; /* the actual length of dna to search */ base ba; /* a base in the piece */ boolean equal; /* the pattern is equal to the piece at this place */ dnastring *startdna; /* the first dnastring in the piece */ dnastring *currentdna; /* where we are */ dnarange cd = 0; /* index to currentdna */ dnastring *subcurrentdna; /* the place we are checking */ dnarange subcd; /* index to subcurrentdna */ /* pointers in pattern */ long patstart = 1; long patstop; /* the pattern with n's and e's removed from ends */ /* the location in between (inclusive) patstart and patstop or a spot in general on the pattern */ long patspot = 1; /* for matches */ long patmatches = 0; /* number of pattern matches on this piece */ long j; /* internal coordinate position of first letter in pattern */ boolean blank; /* put a blank at that spot (when outside the piece) */ boolean circle; /* configuration of the piece (for speed) */ long locrecord = 1; /* the location in pattern to record: # and % command */ long internalplace; /* internal coordinate location for pieceplace */ long firstinternalplace; /* the internal coordinate of the first match */ long lastinternalplace = 0; /* the internalplace matched before this one */ /* for mismatches */ boolean fail; /* fail to match the piece */ string blankpattern; /* for clearing mispattern rapidly */ /* where mismatches are allowed: */ uchar allowmismatch[(maxstring + 7) / 8]; boolean allowed = true; /* used to build allowmismatch */ boolean firsttime = true; /* the first time a match is found, the piece name instruction is written; otherwise be silent */ long r; /* index for reversing feature string */ definetype *WITH, *WITH1; string *WITH2; long FORLIM; _TEXT TEMP; V.mismax = mismax_; memcpy(relatedbase, relatedbase_, sizeof(intarray)); /* In this part we check the special case in which a search string begins with [ or ends with ]. In these cases, remove the given so that it can be replaced BETWEEN letters */ /* showpattern(output,pattern,false); zzzsss this seems unnecessary! */ if (pattern.letters[0] == '[') { WITH = thedefinition; WITH->posparts.letters[0] = '-'; } /*zzzNNN*/ /* Do the same thing for the right side */ /* find the end of the string in patspot */ while (pattern.letters[patspot-1] != '.') patspot++; if (pattern.letters[patspot-2] == ']') { WITH = thedefinition; WITH->posparts.letters[1] = '-'; /*zzzsss*/ /* writeln(output); write(output,'BEFORE ---> "'); writeadefinition(output,thedefinition); writeln(output,'"'); */ /* extract # and % command and mismatch areas */ } patspot = 1; poundsign = false; while (pattern.letters[patspot-1] != '.') { if (pattern.letters[patspot-1] != '<' && pattern.letters[patspot-1] != '>' && pattern.letters[patspot-1] != '#' && pattern.letters[patspot-1] != '%' && pattern.letters[patspot-1] != '|' && pattern.letters[patspot-1] != '^' && pattern.letters[patspot-1] != '[' && pattern.letters[patspot-1] != ']') { P_clrbits_B(allowmismatch, patspot - 1, 0, 3); P_putbits_UB(allowmismatch, patspot - 1, allowed, 0, 3); patspot++; continue; } if (pattern.letters[patspot-1] == '#') poundsign = true; /*if poundsign then writeln(output,'POUNDSIGN FOUND') else writeln(output,'no POUNDSIGN found'); zzzsss*/ if (pattern.letters[patspot-1] == '#') locrecord = patspot; else if (pattern.letters[patspot-1] == '%') locrecord = patspot - 1; else if (pattern.letters[patspot-1] == '<') allowed = false; else if (pattern.letters[patspot-1] == '>') allowed = true; if (dosearchfeatures) { WITH = thedefinition; if (pattern.letters[patspot-1] == '#' || pattern.letters[patspot-1] == '%' || pattern.letters[patspot-1] == '|' || pattern.letters[patspot-1] == '^' || pattern.letters[patspot-1] == '[' || pattern.letters[patspot-1] == ']') { if (!featureinserts) { WITH1 = thedefinition; WITH1->marks++; WITH2 = &WITH1->posparts; /* move end mark out */ WITH2->length++; WITH2->letters[WITH2->length - 1] = WITH2->letters[WITH2->length - 2]; WITH2->letters[WITH2->length - 2] = pattern.letters[patspot-1]; /* the location is relative to the current one For '%', the location to put the % is between bases hence there is a subtraction of 0.5. */ if (pattern.letters[patspot-1] == '%' || pattern.letters[patspot-1] == '[' || pattern.letters[patspot-1] == ']') WITH1->locations[WITH1->posparts.length - 2] = patspot - locrecord - 0.5; else WITH1->locations[WITH1->posparts.length - 2] = patspot - locrecord; /* Note: "EcoRI0" #gaattc "EcoRI1" g#aattc "EcoRI2" ga#attc "EcoRI3" gaa#ttc "EcoRI4" gaat#tc "EcoRI5" gaatt#c "EcoRI6" gaattc# The last two of this series are handled a bit oddly. Ecori5 gives no # and 6 extends the length. This may never matter... */ /* vertical bar is between bases */ if (pattern.letters[patspot-1] == '|' || pattern.letters[patspot-1] == '^') WITH1->locations[WITH1->posparts.length - 2] -= 0.5; /* do negparts here */ WITH2 = &WITH1->negparts; /* move end mark out */ WITH2->length++; WITH2->letters[WITH2->length - 1] = WITH2->letters[WITH2->length - 2]; WITH2->letters[WITH2->length - 2] = pattern.letters[patspot-1]; FORLIM = WITH1->posparts.length; /* the middle part of the string has to be reversed */ for (r = 2; r < FORLIM; r++) WITH1->negparts.letters[WITH1->posparts.length - r] = WITH1->posparts.letters[r-1]; } } } compress(&pattern, patspot, relatedbase); } pattern.length = patspot; /* that's the current length */ /*zzzsss*/ /* write(output,'AFTER ---> "'); writeadefinition(output,thedefinition); writeln(output,'"'); */ if (dosearchfeatures) { WITH = thedefinition; /* pattern.length includes ".", the definition runs from zero up, so subtract 1: */ /* zzzsss*/ /* writeln(output,'****> locrecord: ',locrecord:1); writeln(output,'****> locations[1]: ',locations[1]:1:1); writeln(output,'****> marks: ',marks:1); writeln(output,'****> pattern.length: ',pattern.length:1); */ /* only do this once per feature! */ if (!featureinserts) { /* writeln(output,'***** DONE'); */ WITH->locations[0] = 1.0 - locrecord; WITH->locations[WITH->marks - 1] = pattern.length - locrecord - 1.0; } featureinserts = true; /* */ /*zzzfff*/ /* writeln(searchfeatures,'in match'); writeln(searchfeatures,'pattern.length = ',pattern.length:1); writeln(searchfeatures,'length = ',length:1); writeln(searchfeatures); writeln(searchfeatures,'* THE CURRENT FEATURE DEFINITION at match IS:'); write(output,'DOUBLE AFTER ---> "'); writeadefinition(output,thedefinition); writeln(output,'"'); */ } /* display pattern form */ if (viewf) { printf(" "); /* spaces to match the comment in results */ TEMP.f = stdout; *TEMP.name = '\0'; showpattern(&TEMP, pattern, true); fprintf(result.f, "* "); showpattern(&result, pattern, true); } /* find pattern w/o n's or e's on ends */ /* find start of pattern */ /* if this search contains a relation, we must use all of it, even beginning n's, otherwise we can skip them */ if (!relational) { while (pattern.letters[patstart-1] == 'e' || pattern.letters[patstart-1] == 'n') patstart++; } /* find end of pattern */ patstop = patstart; while (pattern.letters[patstop-1] != '.') patstop++; /* find end of pattern without n's or e's */ while (pattern.letters[patstop-1] == 'e' || pattern.letters[patstop-1] == 'n' || pattern.letters[patstop-1] == '.') patstop--; /* calculate length of dna */ if (*pie == NULL) { printf("PROGRAM ERROR: empty DNA POINTER!\n"); halt(); } length = pietoint((*pie)->key.pieend, *pie); /* calculate length of dna to search */ switch ((*pie)->key.piecon) { case linear: searchlength = length - patstop + patstart; break; case circular: searchlength = length; break; } /* set up dna for stepbase */ startdna = (*pie)->dna; currentdna = startdna; /* decide configuration */ circle = ((*pie)->key.piecon == circular); /* clear blank pattern */ patspot = 1; while (pattern.letters[patspot-1] != '.') { blankpattern.letters[patspot-1] = ' '; patspot++; } blankpattern.letters[patspot-1] = '.'; /* last one */ blankpattern.length = patspot - 1; /*FFF*/ /* search the piece for the pattern */ /* start nowhere */ V.distance = -1; /* no previous match to calculate distance with */ FORLIM = startpoint; /* now move to the correct start */ for (i = 2; i <= FORLIM; i++) ba = stepbase(startdna, ¤tdna, &cd); i = startpoint; /* the user defined start */ while (i <= searchlength) { patspot = patstart; subcurrentdna = currentdna; subcd = cd; fail = false; V.mismatches = 0; V.mispattern = blankpattern; V.realpattern = blankpattern; do { /* until the pattern matches or doesn't */ ba = stepbase(startdna, &subcurrentdna, &subcd); if (relational) V.realpattern.letters[patspot-1] = basetochar(ba); if (pattern.letters[patspot-1] == 'z' || pattern.letters[patspot-1] == 'x' || pattern.letters[patspot-1] == 'q' || pattern.letters[patspot-1] == 'j' || pattern.letters[patspot-1] == 'p' || pattern.letters[patspot-1] == 'l') equal = related(ba, chartobase(V.realpattern.letters[relatedbase[patspot-1] - 1]), pattern.letters[patspot-1]); else { switch (ba) { case a: equal = (pattern.letters[patspot-1] == 'e' || pattern.letters[patspot-1] == 'n' || pattern.letters[patspot-1] == 'd' || pattern.letters[patspot-1] == 'h' || pattern.letters[patspot-1] == 'w' || pattern.letters[patspot-1] == 'v' || pattern.letters[patspot-1] == 'r' || pattern.letters[patspot-1] == 'm' || pattern.letters[patspot-1] == 'a'); break; case c: equal = (pattern.letters[patspot-1] == 'e' || pattern.letters[patspot-1] == 'n' || pattern.letters[patspot-1] == 'b' || pattern.letters[patspot-1] == 'h' || pattern.letters[patspot-1] == 'y' || pattern.letters[patspot-1] == 'v' || pattern.letters[patspot-1] == 's' || pattern.letters[patspot-1] == 'm' || pattern.letters[patspot-1] == 'c'); break; case g: equal = (pattern.letters[patspot-1] == 'e' || pattern.letters[patspot-1] == 'n' || pattern.letters[patspot-1] == 'b' || pattern.letters[patspot-1] == 'd' || pattern.letters[patspot-1] == 'k' || pattern.letters[patspot-1] == 'v' || pattern.letters[patspot-1] == 's' || pattern.letters[patspot-1] == 'r' || pattern.letters[patspot-1] == 'g'); break; case t: equal = (pattern.letters[patspot-1] == 'e' || pattern.letters[patspot-1] == 'n' || pattern.letters[patspot-1] == 'b' || pattern.letters[patspot-1] == 'd' || pattern.letters[patspot-1] == 'k' || pattern.letters[patspot-1] == 'h' || pattern.letters[patspot-1] == 'y' || pattern.letters[patspot-1] == 'w' || pattern.letters[patspot-1] == 't'); break; } } if (!equal) { V.mismatches++; V.mispattern.letters[patspot-1] = 'x'; /* mispattern.length := patspot; zzzFFF */ if (P_getbits_UB(allowmismatch, patspot - 1, 0, 3)) fail = (V.mismatches > V.mismax); else fail = true; } patspot++; } while (!(fail || patspot == patstop + 1)); if (!fail) { /* yahoo got un */ patmatches++; /* tally up */ V.theplace = locrecord; patspot = 1; /* pull out the real pattern */ do { /* internal coordinate position at a letter in pattern */ j = i - patstart + patspot; blank = false; /* take care of pattern off end of piece */ if (j < 1) { if (circle) { while (j < 1) j += length; } else blank = true; } else if (j > length) { if (circle) { while (j > length) j -= length; } else blank = true; } /* get the real pattern */ if (blank) V.realpattern.letters[patspot-1] = ' '; else V.realpattern.letters[patspot-1] = basetochar(getbase(j, *pie)); if (patspot == locrecord) { V.theplace = patspot; if (blank) { if (patspot < patstart) V.theplace = patstart; else V.theplace = patstop; } if (viewd || insttype == 2) lastinternalplace = internalplace; internalplace = i - patstart + V.theplace; V.pieceplace = inttopie(internalplace, *pie); } patspot++; } while (pattern.letters[patspot-1] != '.'); V.realpattern.letters[patspot-1] = '.'; /* close pattern */ if (viewd || insttype == 2) { if (V.distance < 0) { V.distance = 0; /* no distance on first match */ firstinternalplace = internalplace; /* for circular case */ } else V.distance = internalplace - lastinternalplace; } TEMP.f = stdout; *TEMP.name = '\0'; display(&TEMP, &V); display(&result, &V); /* writeln(output,'printinginstructions: ', printinginstructions); writeln(output,'distance: ', distance:1); */ if (printinginstructions) { /*zzz I can't believe that the iworgchr did NOT do the write here - the reason must be that the important thing is that when delila instructions are turned on, orgchange and chrchange should be set true!*/ /*force these for all instructions: */ /*zzziii 1999 apr 29*/ /*1999 dec 24 zzzccc christmas changes: orgchange := true; chrchange := true; iworgchr(searchinst,org,orgchange,chr,chrchange); (* at this point, so far as we are concerned, the organism and chromosome changes are not important because we have written instructions out about them. So we set them false. *) orgchange := false; chrchange := false; */ /*or firsttime?*/ if (*orgchange || *chrchange) { /*zzzttt*/ /* 2000 June 26 I added orgopen, chropen here. This may well solve the problems! */ iworgchr(&searchinst, *org, *orgchange, orgopen, *chr, *chrchange, chropen); } if (firsttime || *piechange) iwpie(&searchinst, (*pie)->key); if (firsttime) firsttime = false; /* name the piece into the delila instructions */ if (dosearchfeatures) { fprintf(searchinst.f, "name "); /*zzznnn*/ /* NOTE: the quotes are give by the writequotestring procedure! */ writequotestring(&searchinst, thedefinition->nametag); /*writeln(searchinst,'";'); bug 2006 May 09*/ fprintf(searchinst.f, ";\n"); } /*write(searchinst,'name "'); bug 2006 May 09*/ /*zzz*/ /* writeln(searchinst,' (* theeeespot *)'); if piechange then writeln(searchinst,' (* piechange = true *)'); if firsttime then writeln(searchinst,' (* firsttime = true *)'); */ switch (insttype) { case 1: if (patterncomplement) { iwget(&searchinst, *pie, -fromplace, V.pieceplace, -toplace, !flip, insttype, true); /* writeln(output,'first iwget2 not flip'); */ } else { iwget(&searchinst, *pie, fromplace, V.pieceplace, toplace, flip, insttype, true); /* writeln(output,'first iwget2 flip'); */ } break; case 2: if (V.distance > 0) { if (patterncomplement) { iwget2(&searchinst, *pie, -fromplace, inttopie(lastinternalplace, *pie), -toplace, V.pieceplace, !flip, true); /* writeln(output,'second iwget2 not flip'); */ } else { iwget2(&searchinst, *pie, fromplace, inttopie(lastinternalplace, *pie), toplace, V.pieceplace, flip, true); /* writeln(output,'second iwget2 flip'); */ } } /* this instruction type gives distances between sites */ break; /* if patterncomplement then iwget2(searchinst,pie, fromplace,inttopie(lastinternalplace,pie), toplace, pieceplace, not flip, true) else iwget2(searchinst,pie, fromplace,inttopie(lastinternalplace,pie), toplace, pieceplace, flip, true); */ case 3: if (patterncomplement) { iwget2(&searchinst, *pie, -fromplace, V.pieceplace, -toplace, inttopie(pietoint(V.pieceplace, *pie) + patternlength(pattern) - 1, *pie), !flip, true); /*writeln(output,'second iwget2 not flip');*/ } /*zzzbbb to be done*/ /* iwget2(searchinst,pie, -fromplace,inttopie(lastinternalplace,pie), -toplace, pieceplace, not flip); */ else { iwget2(&searchinst, *pie, fromplace, V.pieceplace, toplace, inttopie(pietoint(V.pieceplace, *pie) + patternlength(pattern) - 1, *pie), flip, true); /* writeln(output,'second iwget2 flip'); */ } break; /* this instruction type gives the current search string */ } } /* writeln(output,'patternlength(e) = ',patternlength(e):1); writeln(output,'currentpatternlength = ',currentpatternlength:1); writeln(output,'patternlength(pattern) = ',patternlength(pattern):1); */ if (dosearchfeatures) { /* only put out named features */ if (thedefinition->nametag.length > 0) { /* put out the definition if this is the first time */ if (!featuredefwritten) { fprintf(searchfeatures.f, "\n* "); /* show the string */ writestring(&searchfeatures, &pattern); putc('\n', searchfeatures.f); writeadefinition(&searchfeatures, thedefinition); putc('\n', searchfeatures.f); featuredefwritten = true; } /* put out the searchfeatures file */ nametostring((*pie)->key.hea.keynam, &thefeature->id); /* 2004 July 18: This compiled before gpcc, but the types are different!! thefeature^.id := pie^.key.hea.keynam; */ /* The orientation of the feature as searched is the same as the orientation of the piece UNLESS WE FLIPPED TO COMPLEMENT!! */ if (patterncomplement) { if ((*pie)->key.piedir == plus) thefeature->orientation = -1; else thefeature->orientation = 1; } else { if ((*pie)->key.piedir == plus) thefeature->orientation = 1; else thefeature->orientation = -1; } /* we have to keep track of whether the feature was in the same or a different orientation from the piece so that its end coordinate can be set correctly */ /* original code: if ((thefeature^.orientation = +1) and (pie^.key.piedir = minus)) or ((thefeature^.orientation = -1) and (pie^.key.piedir = plus)) if poundsign then writeln(output,'POUNDSIGN FOUND') else writeln(output,'no POUNDSIGN found'); */ if ((thefeature->orientation == 1 && (*pie)->key.piedir == minus || thefeature->orientation == -1 && (*pie)->key.piedir == plus) && !poundsign) { /* shift it so it covers the right region */ /* writeln(output,'~~~~~~thefeature^.definition^.marks:', thefeature^.definition^.marks:1); writeln(output,'~~~~~~thefeature^.definition^.locations[1]:', thefeature^.definition^.locations[1]:1:1); writeln(output,'~~~~~~thefeature^.definition^.locations[thefeature^.definition^.marks]:', thefeature^.definition^.locations[thefeature^.definition^.marks]:1:1); */ /*zzzsss*/ thefeature->coordinate = inttopie(internalplace + (long)floor(thefeature->definition-> locations[thefeature->definition->marks - 1] - thefeature->definition->locations[0] + 0.5), *pie); /* p2c: search.p, line 4619: * Note: Line breaker spent 0.0 seconds, 5000 tries on line 5837 [251] */ /* writeln(output,'~~~~~~thefeature^.coordinate:', thefeature^.coordinate:1:1); */ /* writeln(output,'=================>flip'); */ } /* THERE IS NO NEED TO SHIFT IF THE # MECHANISM IS IN PLAY! In that case the exact location has already been determined. */ /*zzzaaa*/ else thefeature->coordinate = inttopie(internalplace, *pie); /* write(output,'thedefinition:::::::::'); writeadefinition(output, thedefinition); writeln(output); --- writeln(output,'thefeature^.coordinate = ', thefeature^.coordinate:1:1); writeln(output,'thefeature^.definition^.min = ', thefeature^.definition^.min:1:1); writeln(output,'thefeature^.definition^.max = ', thefeature^.definition^.max:1:1); writeln(output,'thefeature^.definition^.locations[1] = ', thefeature^.definition^.locations[1]:1:1); writeln(output,'thefeature^.definition^.locations[2] = ', thefeature^.definition^.locations[2]:1:1); writeln(output,'thedefinition^.min = ', thedefinition^.min:1:1); writeln(output,'thedefinition^.max = ', thedefinition^.max:1:1); writeln(output,'thedefinition:'); writeadefinition(output, thedefinition); writeln(output); writeln(output); */ /* if patterncomplement then thefeature^.orientation := -thefeature^.orientation; the above is not the right code to use */ dofeatures(&searchfeatures, V.mismatches, pattern, V.mispattern, thefeature, thedefinition, patterncomplement); printf("dofeatures ===========================\n"); /*yyy*/ } } } /* move to next position in piece */ i += shift; FORLIM = shift; for (j = 1; j <= FORLIM; j++) /* use j as an index to advance the position */ ba = stepbase(startdna, ¤tdna, &cd); } bookmatches += patmatches; /* handle circular case for distances */ if (viewd) { if ((*pie)->key.piecon == circular && patmatches > 0) { V.distance = piecelength(*pie) - internalplace + firstinternalplace; printf("circle closing distance: %ld\n", V.distance); fprintf(result.f, "* circle closing distance: %ld\n", V.distance); } } if (!viewm) return; printf(" %ld", patmatches); if (patmatches == 1) printf(" match in piece\n"); else printf(" matches in piece\n"); putchar('\n'); fprintf(result.f, " %ld", patmatches); if (patmatches == 1) fprintf(result.f, " match in piece\n"); else fprintf(result.f, " matches in piece\n"); fprintf(result.f, "*************\n"); } /* match */ /* Local variables for multi: */ struct LOC_multi { long mismax; orgkey *org; boolean *orgchange; chrkey *chr; boolean *chrchange; piece **apiece; boolean *piechange, patterncomplement; } ; Local Void reduce(pattern, place, relatedbase_, LINK) string pattern; long place; long *relatedbase_; struct LOC_multi *LINK; { /* reduce the pattern by some e's, and recurse */ intarray relatedbase; long subplace; /* at an e */ memcpy(relatedbase, relatedbase_, sizeof(intarray)); while (pattern.letters[place-1] != '.' && pattern.letters[place-1] != 'e') place++; if (pattern.letters[place-1] == '.') { /* no more e's */ match(pattern, LINK->mismax, relatedbase, LINK->org, LINK->orgchange, LINK->chr, LINK->chrchange, LINK->apiece, LINK->piechange, LINK->patterncomplement); return; } do { /* removing e's and recursing */ subplace = place; /* find end of e's */ while (pattern.letters[subplace-1] == 'e') subplace++; /* do everything to the right */ reduce(pattern, subplace, relatedbase, LINK); /* remove one e */ compress(&pattern, place, relatedbase); } while (pattern.letters[place-1] == 'e'); reduce(pattern, place, relatedbase, LINK); /* do pattern without e's */ } /* reduce */ Static Void multi(pattern, mismax_, relatedbase, org_, orgchange_, chr_, chrchange_, apiece_, piechange_, patterncomplement_) string pattern; long mismax_; long *relatedbase; orgkey *org_; boolean *orgchange_; chrkey *chr_; boolean *chrchange_; piece **apiece_; boolean *piechange_, patterncomplement_; { /* if true, reverse delila inst's */ /* make multiple calls to match, allow mismax mismatches */ struct LOC_multi V; V.mismax = mismax_; V.org = org_; V.orgchange = orgchange_; V.chr = chr_; V.chrchange = chrchange_; V.apiece = apiece_; V.piechange = piechange_; V.patterncomplement = patterncomplement_; reduce(pattern, 1L, relatedbase, &V); } /* multi */ /* count the number of pieces in the book. If there is only one, then set reusethepiece true so that we no longer read the book */ /* ooo */ /* org: orgkey; (* the current organism *) chr: chrkey; (* the current chromosome *) orgchange, chrchange: boolean; (* that either changed *) orgopen, chropen, pieopen: boolean; (* used by getocp *) pie: pieceptr; */ Local Void showpiece(afile, pie) _TEXT *afile; piece *pie; { /* show the information for the piece */ piekey *WITH; name *WITH1; WITH = &pie->key; WITH1 = &WITH->hea.keynam; fprintf(afile->f, " piece: %.*s,", WITH1->length, WITH1->letters); /* p2c: search.p, line 4687: Note: * Format for packed-array-of-char will work only if width < length [321] */ if (numbered) fprintf(afile->f, " #%ld,", number); fprintf(afile->f, " configuration: "); if (WITH->piecon == linear) fprintf(afile->f, "linear,"); else fprintf(afile->f, "circular,"); fprintf(afile->f, " direction: "); if (WITH->piedir == plus) fprintf(afile->f, "+,"); else fprintf(afile->f, "-,"); fprintf(afile->f, " begin: %ld, end: %ld\n", WITH->piebeg, WITH->pieend); } /* showpiece */ Static Void multimatch(pattern, book, mismax, org, chr, pie, orgchange, chrchange, piechange, orgopen, chropen, pieopen, sorgchange, schrchange, spiechange, sorgopen, schropen, spieopen, patterncomplement) string pattern; _TEXT *book; long mismax; orgkey *org; chrkey *chr; piece **pie; boolean *orgchange, *chrchange, *piechange, *orgopen, *chropen, *pieopen, *sorgchange, *schrchange, *spiechange, *sorgopen, *schropen, *spieopen, patterncomplement; { /* the current organism */ /* the current chromosome */ /* the current piece */ /* that either changed */ /* used by getocp */ /* that either changed */ /* who is open in searchinst */ /* if true, reverse delila inst's */ /* try to match the pattern to each piece in book allow mismax mismatches */ long piecesinbook = 0; _TEXT TEMP; if (*book->name != '\0') { if (book->f != NULL) book->f = freopen(book->name, "r", book->f); else book->f = fopen(book->name, "r"); } else rewind(book->f); if (book->f == NULL) _EscIO2(FileNotFound, book->name); RESETBUF(book->f, Char); /*ooo new(pie); orgopen:=false; chropen:=false; pieopen:=false; */ *sorgopen = false; *schropen = false; *spieopen = false; bookmatches = 0; theline = 1; while (((!reusethepiece) & (!BUFEOF(book->f))) || reusethepiece && piecesinbook < 1) { /*writeln(output,'multimatch 1: piechange=',piechange);*/ if (!reusethepiece) getocp(book, &theline, org, orgchange, orgopen, chr, chrchange, chropen, pie, piechange, pieopen); else { /*writeln(output,'all change variables MADE FALSE'); zzz*/ /*christmas zzzccc the effect of deleting these is that the org/chr/pie insts are now given when not needed! */ *orgchange = false; *chrchange = false; *piechange = false; } /*zzz writeln(output,'multimatch 2: piechange=',piechange);*/ if (BUFEOF(book->f)) continue; piecesinbook++; if (viewi) { TEMP.f = stdout; *TEMP.name = '\0'; /* show organism and chromosome */ /*OOO*/ iworgchr(&TEMP, *org, *sorgchange, *sorgopen, *chr, *schrchange, *schropen); if (*sorgchange || *schrchange) fprintf(result.f, "* "); /* (* 2001 Sep 7 *) if sorgchange or schrchange then spiechange := true else spiechange := false; */ iworgchr(&result, *org, *sorgchange, *sorgopen, *chr, *schrchange, *schropen); TEMP.f = stdout; *TEMP.name = '\0'; /* show piece */ showpiece(&TEMP, *pie); fprintf(result.f, "*\n"); /* put space from the previous one */ putc('*', result.f); /* removed space 1990 Sep 4 */ showpiece(&result, *pie); } /* write the org, chr and pie instructions ONLY once the first one has been found!!! So the following is not used: if printinginstructions writeln(searchinst,'(','* iworgchr being called from multimatch zzz *',')'); iworgchr(searchinst,org,orgchange,chr,chrchange); if piechange then iwpie(searchinst,pie^.key) end; */ if (*orgchange) clearheader(&org->hea); if (*chrchange) /* pass to allow silence when not found */ clearheader(&chr->hea); multi(pattern, mismax, relatedbase, org, orgchange, chr, chrchange, pie, piechange, patterncomplement); /* the old location: clearpiece(pie) */ } if (!reusethepiece) { if (piecesinbook == 1) { reusethepiece = true; printf("(reusing the single piece in the book for efficiency)\n"); if (*book->name != '\0') { if (book->f != NULL) book->f = freopen(book->name, "r", book->f); else book->f = fopen(book->name, "r"); } else rewind(book->f); if (book->f == NULL) _EscIO2(FileNotFound, book->name); RESETBUF(book->f, Char); /* fool it into doing the loop above ... */ } } /* the old location: dispose(pie); */ if (!viewb) return; printf(" %ld", bookmatches); if (bookmatches == 1) printf(" match in book\n"); else printf(" matches in book\n"); putchar('\n'); fprintf(result.f, "* %ld", bookmatches); if (bookmatches == 1) fprintf(result.f, " match in book\n"); else fprintf(result.f, " matches in book\n"); fprintf(result.f, "**********************\n"); /* space result file a bit */ } /* multimatch */ Static Void instheader() { /* make header for instruction file */ if (*searchinst.name != '\0') { if (searchinst.f != NULL) searchinst.f = freopen(searchinst.name, "w", searchinst.f); else searchinst.f = fopen(searchinst.name, "w"); } else { if (searchinst.f != NULL) rewind(searchinst.f); else searchinst.f = tmpfile(); } if (searchinst.f == NULL) _EscIO2(FileNotFound, searchinst.name); SETUPBUF(searchinst.f, Char); fprintf(searchinst.f, "title \""); writedatetime(&searchinst, datetime); fprintf(searchinst.f, " search %4.2f\";\n", version); iwcombk(&book, &searchinst); /* no longer needed - these are defaults for delila writeln(searchinst,'default numbering piece;'); writeln(searchinst,'default numbering 1;'); */ fprintf(searchinst.f, "set out-of-range reduce-range;\n"); } /* instheader */ Static Void copyfile(fromfile, tofile, space) _TEXT *fromfile, *tofile; boolean space; { /* copy one file into the other. no resets or rewrites are done. if space is true, then put an '* ' before each line. */ while (!BUFEOF(fromfile->f)) { if (space) fprintf(tofile->f, "* "); copyaline(fromfile, tofile); } } /* copyfile */ Static Void getmismatches() { /* obtain a new value of the global variable, mismatches */ long newmismatches; /* the value the person typed */ _TEXT TEMP; answers = 0; do { if (nostring(&buffer)) printf("mismatches were %ld, type new:\n", mismatches); TEMP.f = stdin; *TEMP.name = '\0'; getinteger(&TEMP, &buffer, &newmismatches, &gotten); if (gotten) { if (newmismatches < 0) { printf("type zero or a positive integer\n"); clearstring(&buffer); gotten = false; } } answercheck(&answers); } while (!gotten); mismatches = newmismatches; fprintf(result.f, "* maximum number of mismatches now allowed: %ld\n", mismatches); } /* getmismatches */ /*ppp*/ Static Void getcolorbackground() { /* obtain a new value of the color background for letters. This is called by the C command */ Char newTparam; /* the value the person typed */ double newparam; /* the value the person typed */ featuretype *WITH; _TEXT TEMP; WITH = thefeature; /* Tparam */ answers = 0; do { if (nostring(&buffer)) printf("Tparam was \"%c\", type new (allowed: \"hrHR\"):\n", WITH->Tparam); TEMP.f = stdin; *TEMP.name = '\0'; getchar_(&TEMP, &buffer, &newTparam, &gotten); if (gotten) { if (newTparam != 'R' && newTparam != 'H' && newTparam != 'r' && newTparam != 'h') { printf("Tparam must be one of \" hrHR\"\n"); clearstring(&buffer); gotten = false; } } answercheck(&answers); } while (!gotten); WITH->Tparam = newTparam; fprintf(result.f, "* Tparam colorbackground: %c\n", WITH->Tparam); /* Aparam */ answers = 0; do { if (nostring(&buffer)) printf("Aparam was %*.*f, type new:\n", infofield, infodecim, WITH->Aparam); TEMP.f = stdin; *TEMP.name = '\0'; getreal(&TEMP, &buffer, &newparam, &gotten); if (gotten) { if (newparam < 0) { printf("type zero or a positive integer\n"); clearstring(&buffer); gotten = false; } } answercheck(&answers); } while (!gotten); WITH->Aparam = newparam; fprintf(result.f, "* Aparam colorbackground: %*.*f\n", infofield, infodecim, WITH->Aparam); /* Bparam */ answers = 0; do { if (nostring(&buffer)) printf("Bparam was %*.*f, type new:\n", infofield, infodecim, WITH->Bparam); TEMP.f = stdin; *TEMP.name = '\0'; getreal(&TEMP, &buffer, &newparam, &gotten); if (gotten) { if (newparam < 0) { printf("type zero or a positive integer\n"); clearstring(&buffer); gotten = false; } } answercheck(&answers); } while (!gotten); WITH->Bparam = newparam; fprintf(result.f, "* Bparam colorbackground: %*.*f\n", infofield, infodecim, WITH->Bparam); /* Cparam */ answers = 0; do { if (nostring(&buffer)) printf("Cparam was %*.*f, type new:\n", infofield, infodecim, WITH->Cparam); TEMP.f = stdin; *TEMP.name = '\0'; getreal(&TEMP, &buffer, &newparam, &gotten); if (gotten) { if (newparam < 0) { printf("type zero or a positive integer\n"); clearstring(&buffer); gotten = false; } } answercheck(&answers); } while (!gotten); WITH->Cparam = newparam; fprintf(result.f, "* Cparam colorbackground: %*.*f\n", infofield, infodecim, WITH->Cparam); /* Dparam */ answers = 0; do { if (nostring(&buffer)) printf("Dparam was %*.*f, type new:\n", infofield, infodecim, WITH->Dparam); TEMP.f = stdin; *TEMP.name = '\0'; getreal(&TEMP, &buffer, &newparam, &gotten); if (gotten) { if (newparam < 0) { printf("type zero or a positive integer\n"); clearstring(&buffer); gotten = false; } } answercheck(&answers); } while (!gotten); WITH->Dparam = newparam; fprintf(result.f, "* Dparam colorbackground: %*.*f\n", infofield, infodecim, WITH->Dparam); } /* getcolorbackground */ /* un built procedure - could dump 2004 jul 18 procedure getcolorletters; (* obtain a new value of the color letters for letters. This is called by the C command *) var newcolorletters: integer; (* the value the person typed *) begin (* getcolorletters *) answers := 0; repeat if nostring(buffer) then writeln(output,'colorletters were ', colorletters:1,', type new:'); getinteger(input,buffer,newmismatches,gotten); if gotten then if newmismatches < 0 then begin writeln(output,'type zero or a positive integer'); clearstring(buffer); gotten := false end; answercheck(answers); until gotten; colorletters := newcolorletters; writeln(result,'* maximum number of colorletters now allowed: ', colorletters:1) end; (* getcolorletters *) */ Static Void toggleoktosearch() { /* toggle the oktosearch variable */ oktosearch = !oktosearch; if (oktosearch) { fprintf(result.f, "* searches will proceed when pattern is input or with the = command\n"); printf("* searches will proceed when pattern is input or with the = command\n"); } else { fprintf(result.f, "* searches will proceed only when = is input\n"); printf("* searches will proceed only when = is input\n"); } } Static Void acomment() { /* the rest of the input buffer is a commment. the entire line must be written to the result, and perhaps the searchinst files */ /* send it to result file */ fprintf(result.f, "* "); writestring(&result, &buffer); putc('\n', result.f); if (printinginstructions) { fprintf(searchinst.f, "(* "); writestring(&searchinst, &buffer); fprintf(searchinst.f, " *)\n"); } /* send it to the searchinst file */ /* remove the rest of the line */ clearstring(&buffer); } /* acomment */ /******************************************************************************/ /******************************************************************************/ /* Routines for handline features */ Static Void setfeaturename() { /* set the feature name: define the feature and prepare for writing to file searchfeatures. */ long i; /* location in a string */ definetype *WITH; long FORLIM; _TEXT TEMP; featuretype *WITH1; string *WITH2; if (!dosearchfeatures) { if (*searchfeatures.name != '\0') { if (searchfeatures.f != NULL) searchfeatures.f = freopen(searchfeatures.name, "w", searchfeatures.f); else searchfeatures.f = fopen(searchfeatures.name, "w"); } else { if (searchfeatures.f != NULL) rewind(searchfeatures.f); else searchfeatures.f = tmpfile(); } if (searchfeatures.f == NULL) _EscIO2(FileNotFound, searchfeatures.name); SETUPBUF(searchfeatures.f, Char); fprintf(searchfeatures.f, "* search %4.2f\n", version); dosearchfeatures = true; } featuredefwritten = false; WITH = thedefinition; /* */ /*zzzaaa*/ /* transfer the string from pattern */ /* remove final quote (if there is one): */ if (pattern.letters[pattern.length - 1] == '"') pattern.length--; FORLIM = pattern.length; for (i = 2; i <= FORLIM; i++) WITH->nametag.letters[i-2] = pattern.letters[i-1]; WITH->nametag.length = pattern.length - 1; /* tell the user about this */ if (WITH->nametag.length > 0) { printf("feature: \""); TEMP.f = stdout; *TEMP.name = '\0'; writequotestring(&TEMP, WITH->nametag); /*write(output,'" will be written to searchfeatures'); bug 2006 May 09*/ printf(" will be written to searchfeatures"); if (doarrow) printf(" as an arrow.\n"); putchar('\n'); fprintf(result.f, "* feature: "); /*bug 2006 May 09*/ writequotestring(&result, WITH->nametag); fprintf(result.f, " will be written to searchfeatures"); /*bug 2006 May 09*/ if (doarrow) fprintf(result.f, " as an arrow.\n"); putc('\n', result.f); } /*write(output,'feature: "'); bug 2006 May 09*/ else { printf("No more features will be written to searchfeatures\n"); fprintf(result.f, "* No more features will be written to searchfeatures\n"); } if (doarrow) { WITH->background.letters[0] = '-'; WITH->background.length = 1; WITH->negparts.length = 2; WITH->negparts.letters[0] = '<'; WITH->negparts.letters[1] = ']'; WITH->posparts.length = 2; WITH->posparts.letters[0] = '['; WITH->posparts.letters[1] = '>'; doarrow = false; /* reset */ /*zzzaaa*/ /*zzzfff*/ } else { WITH->background.letters[0] = '-'; WITH->background.length = 1; WITH->negparts.length = 2; WITH->negparts.letters[0] = '['; WITH->negparts.letters[1] = ']'; WITH->posparts.length = 2; WITH->posparts.letters[0] = '['; WITH->posparts.letters[1] = ']'; /*zzzNNN*/ } WITH->locations[0] = 0.0; WITH->locations[1] = 1.0; WITH->marks = 2; WITH->min = 0.0; /*zzz?*/ WITH->max = 0.0; /*zzz?*/ WITH->number = 1; /*[[*/ WITH->matrix = NULL; /* Ribound := 0; Zbound := 0; Pbound := 0; */ /*]]*/ WITH->next = NULL; fprintf(searchfeatures.f, "\n* THE CURRENT FEATURE DEFINITION IS:\n"); fprintf(searchfeatures.f, "* "); writeadefinition(&searchfeatures, thedefinition); putc('\n', searchfeatures.f); /* 2004 Jul 18: I THINK this is a good place to clear the feature! */ /* clearfeature(thefeature); */ WITH1 = thefeature; WITH2 = &WITH1->id; WITH2->letters[0] = '!'; WITH2->length = 1; /* This is handled in clearfeature: coordinate := 0.0; orientation := +1; */ thefeature->nametag = thedefinition->nametag; /* This is handled in clearfeature: with othertag do begin letters[1] := '?'; length := 0; end; */ WITH1->definition = thedefinition; /* This is handled in clearfeature: (*[[*) Ri := 0.0; Z := 0.0; probability := 0.0; (*]]*) unsatisfied := true; fromrange := 0.0; torange := 0.0; number := 1; desiredline := 1; next := nil; */ WITH1->number = 1; WITH1->desiredline = 1; /* writeln(searchfeatures); write(searchfeatures,'* INITIAL FEATURE: '); write(searchfeatures,'* '); writeafeature(searchfeatures,thefeature); writeln(searchfeatures); */ featureinserts = false; /* inserts to the feature not defined yet */ /*zzzfff*/ } Static Void setarrowfeature() { /* reset the feature to be an arrow */ doarrow = !doarrow; /*zzzaaa*/ /* if doarrow then writeln(output,'Doing arrows for features') else writeln(output,'Doing rectangles for features') */ } /******************************************************************************/ /******************************************************************************/ Static Void writeDelilainst() { /* a search subsystem for creating Delila instructions based on search results. see Delilahelp. */ _TEXT copy; /* internal file for showing searchinst */ _TEXT TEMP; copy.f = NULL; *copy.name = '\0'; printf("Entering Delila sub system\n"); if (!printinginstructions) { /* if we were not printing instructions, then we must make sure that instructions printed from this point have the org, chr or pie information. We force it by resetting the variables. */ /*hhh*/ orgchange = true; chrchange = true; piechange = true; instheader(); printf("Any previous instructions were destroyed.\n"); printf("A title has been provided.\n"); printf("Defaults have been set.\n"); } else { printf("The searchinst file is not empty.\n"); printf("use the show command to see them and\n"); printf("use the kill command to restart them\n"); } printinginstructions = true; printf("Delila instruction printing has been automatically turned ON.\n"); printf("from place is %ld\n", fromplace); printf(" to place is %ld\n", toplace); do { answers = 0; do { if (nostring(&buffer)) printf("Delila "); TEMP.f = stdin; *TEMP.name = '\0'; getchar_(&TEMP, &buffer, &command, &gotten); answercheck(&answers); } while (!gotten); if (command != '*' && command != 'i' && command != 'h' && command != 'k' && command != 's' && command != 'w' && command != 't' && command != 'f' && command != 'p' && command != 'q') { TEMP.f = stdout; *TEMP.name = '\0'; flagstring(&TEMP, &buffer); answers = 0; do { if (nostring(&buffer)) printf("do you need help? (y/n)\n"); TEMP.f = stdin; *TEMP.name = '\0'; getchar_(&TEMP, &buffer, &command, &gotten); answercheck(&answers); } while (!gotten); if (command != 'n') { TEMP.f = stdout; *TEMP.name = '\0'; Delilahelp(&TEMP); } } else if (command == 'h') { TEMP.f = stdout; *TEMP.name = '\0'; Delilahelp(&TEMP); } else if (command == 'i') { answers = 0; do { if (nostring(&buffer)) printf("instruction type was %ld, type new:\n", insttype); TEMP.f = stdin; *TEMP.name = '\0'; getinteger(&TEMP, &buffer, &insttype, &gotten); if (gotten) { if (insttype < 1 && insttype > 3) printf(" instruction type must be 1, 2 or 3 \n"); } answercheck(&answers); } while (!(gotten && (insttype == 1 || insttype == 2 || insttype == 3))); fprintf(result.f, "* instruction type: %ld\n", insttype); } else if (command == 'p') { printinginstructions = !printinginstructions; printf("now"); if (!printinginstructions) printf(" NOT"); printf(" printing Delila instructions\n"); fprintf(result.f, "* now"); if (!printinginstructions) fprintf(result.f, " NOT"); fprintf(result.f, " printing Delila instructions\n"); } else if (command == 'f') { answers = 0; do { if (nostring(&buffer)) printf("from place was %ld, type new:\n", fromplace); TEMP.f = stdin; *TEMP.name = '\0'; getinteger(&TEMP, &buffer, &fromplace, &gotten); answercheck(&answers); } while (!gotten); fprintf(result.f, "* bases from: %ld\n", fromplace); } else if (command == 't') { answers = 0; do { if (nostring(&buffer)) printf("to place was %ld, type new:\n", toplace); TEMP.f = stdin; *TEMP.name = '\0'; getinteger(&TEMP, &buffer, &toplace, &gotten); answercheck(&answers); } while (!gotten); fprintf(result.f, "* bases to: %ld\n", toplace); } else if (command == 'w') { printf("write Delila instructions (q to quit):\n"); do { TEMP.f = stdin; *TEMP.name = '\0'; readstring(&TEMP, &buffer); /* pick up a fresh line */ command = buffer.letters[0]; if (command != 'q') { writestring(&searchinst, &buffer); putc('\n', searchinst.f); fprintf(result.f, "* "); writestring(&result, &buffer); putc('\n', result.f); } } while (command != 'q'); TEMP.f = stdin; *TEMP.name = '\0'; gettoken(&TEMP, &buffer, &pattern, &gotten); /* that gets us past the 'quit', pattern is not used so we are safe, and the user may type commands after the quit */ command = 'w'; /* prevent falling out of Delila */ } else if (command == 's') { printf("current Delila instructions:\n"); fprintf(result.f, "* current Delila commands:\n"); if (*searchinst.name != '\0') { if (searchinst.f != NULL) searchinst.f = freopen(searchinst.name, "r", searchinst.f); else searchinst.f = fopen(searchinst.name, "r"); } else rewind(searchinst.f); if (searchinst.f == NULL) _EscIO2(FileNotFound, searchinst.name); RESETBUF(searchinst.f, Char); if (*copy.name != '\0') { if (copy.f != NULL) copy.f = freopen(copy.name, "w", copy.f); else copy.f = fopen(copy.name, "w"); } else { if (copy.f != NULL) rewind(copy.f); else copy.f = tmpfile(); } if (copy.f == NULL) _EscIO2(FileNotFound, copy.name); SETUPBUF(copy.f, Char); copyfile(&searchinst, ©, false); /* get back searchinst: */ if (*searchinst.name != '\0') { if (searchinst.f != NULL) searchinst.f = freopen(searchinst.name, "w", searchinst.f); else searchinst.f = fopen(searchinst.name, "w"); } else { if (searchinst.f != NULL) rewind(searchinst.f); else searchinst.f = tmpfile(); } if (searchinst.f == NULL) _EscIO2(FileNotFound, searchinst.name); SETUPBUF(searchinst.f, Char); if (*copy.name != '\0') { if (copy.f != NULL) copy.f = freopen(copy.name, "r", copy.f); else copy.f = fopen(copy.name, "r"); } else rewind(copy.f); if (copy.f == NULL) _EscIO2(FileNotFound, copy.name); RESETBUF(copy.f, Char); copyfile(©, &searchinst, false); /* show copy: */ if (*copy.name != '\0') { if (copy.f != NULL) copy.f = freopen(copy.name, "r", copy.f); else copy.f = fopen(copy.name, "r"); } else rewind(copy.f); if (copy.f == NULL) _EscIO2(FileNotFound, copy.name); RESETBUF(copy.f, Char); TEMP.f = stdout; *TEMP.name = '\0'; copyfile(©, &TEMP, false); if (*copy.name != '\0') { if (copy.f != NULL) copy.f = freopen(copy.name, "r", copy.f); else copy.f = fopen(copy.name, "r"); } else rewind(copy.f); if (copy.f == NULL) _EscIO2(FileNotFound, copy.name); RESETBUF(copy.f, Char); copyfile(©, &result, true); command = 's'; /* prevent falling out */ } else if (command == 'k') { answers = 0; do { if (nostring(&buffer)) printf("shall I kill all Delila instructions?\n"); TEMP.f = stdin; *TEMP.name = '\0'; getchar_(&TEMP, &buffer, &command, &gotten); answercheck(&answers); } while (!gotten); if (command == 'y') { instheader(); fprintf(result.f, "* all previous Delila instructions killed\n"); printf("aaaARRRRGGgg!!\n"); } else printf("Scardy Cat!\n"); } else if (command == '*') acomment(); if (command == 'q') { if (fromplace > toplace) flip = true; else flip = false; } } while (command != 'q'); command = 'd'; /* prevent falling out of search */ printf("Delila instruction printing is "); if (printinginstructions) printf("ON\n"); else printf("OFF\007\n"); if (copy.f != NULL) fclose(copy.f); } /* writeDelilainst */ Static Void setstartshift() { /* set the search startpoint and shift between search positions */ _TEXT TEMP; answers = 0; do { if (nostring(&buffer)) printf("start point was %ld type a new one:\n", startpoint); TEMP.f = stdin; *TEMP.name = '\0'; getinteger(&TEMP, &buffer, &startpoint, &gotten); if (gotten) { if (startpoint <= 0) { printf("give a positive integer\n"); gotten = false; } } answercheck(&answers); } while (!gotten); answers = 0; do { if (nostring(&buffer)) printf("shift was %ld type a new one:\n", shift); TEMP.f = stdin; *TEMP.name = '\0'; getinteger(&TEMP, &buffer, &shift, &gotten); if (gotten) { if (shift <= 0) { printf("give a positive integer\n"); gotten = false; } } answercheck(&answers); } while (!gotten); fprintf(result.f, "* start (phase): %ld shift: %ld\n", startpoint, shift); } /* setstartshift */ Static Void viewvariables() { /* view */ /* set the characteristics one wants to see */ Char ch; /* user typed command character */ _TEXT TEMP; answers = 0; do { if (nostring(&buffer)) printf("view (type h for help)\n"); TEMP.f = stdin; *TEMP.name = '\0'; getchar_(&TEMP, &buffer, &ch, &gotten); if (gotten) gotten = (ch == 'q' || ch == 'a' || ch == 'n' || ch == 'h' || ch == 'b' || ch == 'm' || ch == 'd' || ch == 'p' || ch == 's' || ch == 'f' || ch == 'i' || ch == 'e' || ch == 't'); answercheck(&answers); } while (!gotten); if (ch == 'h') { TEMP.f = stdout; *TEMP.name = '\0'; viewhelp(&TEMP); } else if (ch == 'a') { viewt = true; viewe = true; viewi = true; viewf = true; views = true; viewp = true; viewd = true; viewm = true; viewb = true; } else if (ch == 'n') { viewt = false; viewe = false; viewi = false; viewf = false; views = false; viewp = false; viewd = false; viewm = false; viewb = false; } else { switch (ch) { case 't': viewt = !viewt; break; case 'e': viewe = !viewe; break; case 'i': viewi = !viewi; break; case 'f': viewf = !viewf; break; case 's': views = !views; break; case 'p': viewp = !viewp; break; case 'd': viewd = !viewd; break; case 'm': viewm = !viewm; break; case 'b': viewb = !viewb; break; case 'q': /* blank case */ break; } } viewnothing = !(viewt || viewe || viewi || viewf || views || viewp || viewd || viewm || viewb); } /* view */ main(argc, argv) int argc; Char *argv[]; { _TEXT TEMP; PASCAL_MAIN(argc, argv); if (setjmp(_JL1)) goto _L1; searchfeatures.f = NULL; strcpy(searchfeatures.name, "searchfeatures"); result.f = NULL; strcpy(result.name, "result"); searchinst.f = NULL; strcpy(searchinst.name, "searchinst"); book.f = NULL; strcpy(book.name, "book"); if (*result.name != '\0') { if (result.f != NULL) result.f = freopen(result.name, "w", result.f); else result.f = fopen(result.name, "w"); } else { if (result.f != NULL) rewind(result.f); else result.f = tmpfile(); } if (result.f == NULL) _EscIO2(FileNotFound, result.name); SETUPBUF(result.f, Char); /* get the date */ getdatetime(datetime); printf("* "); TEMP.f = stdout; *TEMP.name = '\0'; writedatetime(&TEMP, datetime); printf(" search %4.2f\n", version); fprintf(result.f, "* "); writedatetime(&result, datetime); fprintf(result.f, " search %4.2f\n", version); brinit(&book, &theline); if (*book.name != '\0') { if (book.f != NULL) book.f = freopen(book.name, "r", book.f); else book.f = fopen(book.name, "r"); } else rewind(book.f); if (book.f == NULL) _EscIO2(FileNotFound, book.name); RESETBUF(book.f, Char); TEMP.f = stdout; *TEMP.name = '\0'; copyaline(&book, &TEMP); if (*book.name != '\0') { if (book.f != NULL) book.f = freopen(book.name, "r", book.f); else book.f = fopen(book.name, "r"); } else rewind(book.f); if (book.f == NULL) _EscIO2(FileNotFound, book.name); RESETBUF(book.f, Char); copyaline(&book, &result); /* don't touch the instructions until Delila subsystem starts!!! instheader; */ clearstring(&pattern); clearstring(&lastpattern); /* defaults for user settable variables */ viewt = true; viewe = true; viewi = true; viewf = true; views = true; viewp = true; viewd = true; viewm = true; viewb = true; viewnothing = false; mismatches = 0; oktosearch = true; startpoint = 1; shift = 1; printinginstructions = false; fromplace = -100; toplace = 100; insttype = 1; firstinput = true; dosearchfeatures = false; featuredefwritten = false; flip = false; patterncomplement = false; /* ooo */ org.hea.keynam.length = 0; chr.hea.keynam.length = 0; pie = NULL; /*OOO*/ orgopen = false; chropen = false; pieopen = false; orgchange = true; chrchange = true; piechange = true; sorgopen = false; schropen = false; spieopen = false; sorgchange = true; schrchange = true; spiechange = true; theline = 0; /* initialize feature names */ thefeature = (featuretype *)Malloc(sizeof(featuretype)); thedefinition = (definetype *)Malloc(sizeof(definetype)); clearfeature(&thefeature); reusethepiece = false; clearstring(&buffer); printf(" NOTE: Your first typed line will be ignored.\n"); do { answers = 0; do { if (firstinput) { printf("(type a carriage return now. Your next line will be listened to.)"); firstinput = false; rewind(stdin); } else if (nostring(&buffer)) printf("search "); TEMP.f = stdin; *TEMP.name = '\0'; gettoken(&TEMP, &buffer, &pattern, &gotten); answercheck(&answers); } while (!gotten); command = pattern.letters[0]; if (command == 'D') { /*ppp*/ writeDelilainst(); } else if (command == 'C') getcolorbackground(); else if (command == 'H') { TEMP.f = stdout; *TEMP.name = '\0'; searchhelp(&TEMP); } else if (command == '?') { TEMP.f = stdout; *TEMP.name = '\0'; searchhelp(&TEMP); } else if (command == 'L') { TEMP.f = stdout; *TEMP.name = '\0'; showletters(&TEMP); } else if (command == 'M') getmismatches(); else if (command == 'N') toggleoktosearch(); else if (command == 'P') setstartshift(); else if (command == 'Q') printf("quit\n"); else if (command == 'q') printf("quit\n"); else if (command == 'V') viewvariables(); else if (command == '"') setfeaturename(); else if (command == 'A') { /*zzzaaa*/ setarrowfeature(); } else if (command == '*') acomment(); else if (viewnothing) { TEMP.f = stdout; *TEMP.name = '\0'; flagstring(&TEMP, &buffer); printf("\n your search command was ignored because\n"); printf(" no results would be displayed.\n"); printf(" use the view command to turn displays on.\n"); } else if (command == '~') { if (lastpattern.length != 0) { stringcomplement(&lastpattern); patterncomplement = !patterncomplement; if (patterncomplement) printf("now complement to typed pattern\n"); else printf("now homologous to typed pattern\n"); } else printf("no previous pattern\n"); } else if (command == 'R') { if (lastpattern.length != 0) { stringreverse(&lastpattern); /*qqq*/ } else printf("no previous pattern\n"); } else if (command == 'I') { if (lastpattern.length != 0) { stringinvert(&lastpattern); /*qqq*/ } else printf("no previous pattern\n"); } else if (command == '=') { if (lastpattern.length != 0) { analysepattern(&lastpattern, &exppattern, &ok); if (ok) multimatch(exppattern, &book, mismatches, &org, &chr, &pie, &orgchange, &chrchange, &piechange, &orgopen, &chropen, &pieopen, &sorgchange, &schrchange, &spiechange, &sorgopen, &schropen, &spieopen, patterncomplement); } else { printf("no previous pattern\n"); /* these are the other allowed first letters. note that some commands above exclude their use */ } } else if (command != 'e' && command != 'n' && command != 'b' && command != 'd' && command != 'k' && command != 'h' && command != 'y' && command != 'w' && command != 'v' && command != 's' && command != 'r' && command != 'm' && command != 't' && command != 'g' && command != 'c' && command != 'a' && command != '9' && command != '8' && command != '7' && command != '6' && command != '5' && command != '4' && command != '3' && command != '2' && command != '1' && command != '0' && command != '(' && command != '#' && command != '%' && command != '<' && command != '>' && command != '|' && command != '^' && command != '[' && command != ']') { /* p2c: search.p, line 5632: * Note: Line breaker spent 0.0 seconds, 5000 tries on line 7295 [251] */ TEMP.f = stdout; *TEMP.name = '\0'; flagstring(&TEMP, &buffer); answers = 0; do { if (nostring(&buffer)) printf("do you need help? (y/n)\n"); TEMP.f = stdin; *TEMP.name = '\0'; getchar_(&TEMP, &buffer, &command, &gotten); answercheck(&answers); } while (!gotten); if (command != 'n') { TEMP.f = stdout; *TEMP.name = '\0'; searchhelp(&TEMP); } command = ' '; /* this prevents the program from stopping if the answer was 'q' */ } else { analysepattern(&pattern, &exppattern, &ok); if (ok) { patterncomplement = false; /* reset at type in */ lastpattern = pattern; if (oktosearch) multimatch(exppattern, &book, mismatches, &org, &chr, &pie, &orgchange, &chrchange, &piechange, &orgopen, &chropen, &pieopen, &sorgchange, &schrchange, &spiechange, &sorgopen, &schropen, &spieopen, patterncomplement); } } } while (command != 'q'); _L1: if (book.f != NULL) fclose(book.f); if (searchinst.f != NULL) fclose(searchinst.f); if (result.f != NULL) fclose(result.f); if (searchfeatures.f != NULL) fclose(searchfeatures.f); exit(EXIT_SUCCESS); } /* search */ /* End. */