/* Output from p2c 1.21alpha-07.Dec.93, the Pascal-to-C translator */ /* From input file "instshift.p" */ #include /* instshift: shift coordinates of delila instructions by Rye Shultzaberger shultzab@ncifcrf.gov http://www.lecb.ncifcrf.gov/~shultzab/ modified by 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/ */ /* end of program */ /* begin module version */ #define version 1.63 /* of instshift.p 2009 Apr 27 2005 Sep 24, 1.51: proper version upgrade 2005 Sep 13, 1.50: spelling: asterisk 2004 Sep 9, 1.49: upgrade for GPC 2004 Jul 8, 1.48: handle name quotes on get line! allow 'piece' inside name. 2002 May 4, 1.47: pointer to glossary 2001 Oct 11, 1.43: Ignore quote marks in a piece instruction 2001 Oct 5, 1.42: single quotes exclude double quotes in proc quotecomment 2001 Aug 8, 1.40: create instruction complement 2001 Aug 3, 1.37: cleanup 2001 Aug 3, 1.36: inst -> instin so I don't go crazy. 2001 May 21, 1.33: fix documentation on what happens if direction not specified. 2001 May 21, 1.32: technical report: what happens if direction not specified. 2001 May 9, 1.31: bug: does not handle direction in r mode. 2000 Dec 6, 1.30: documentation upgrade (TDS) 2000 Dec 6, 1.29: range control, automatic upgrade of parameters (TDS) 2000 Dec 6, 1.28: reset trigger properly (TDS) 2000 Dec 6, 1.27: fix bug: 'get' inside strings - account for strings (TDS) 2000 Dec 5, 1.21: fix bug: comparen at eoln kills rest of inst! (TDS) 2000 Dec 5, 1.19: apply 'same' only if appropriate to instout (TDS) 2000 Dec 5, 1.18: rename variables to account for COMPLETE delila instruction (TDS) 2000 Dec 5, 1.17: bug fix, now reads double cr correctly. (TDS) 2000 Dec 4, 1.13: bug fix when from range was zero in writeshift. (TDS) 2000 Nov 28, 1.12: fix documentation (TDS) 2000 May 10, 1.08: read instructions free format (TDS) 2000 May 9, 1.07: output file renamed instout rather than shiftinst (TDS) 2000 Feb 23, 1.03: fix bug in reading inst comments origin 1999 July 2 */ #define updateversion 1.58 /* defines lowest acceptable current parameter file */ /* end module version */ /* begin module describe.instshift */ /* name instshift: shift coordinates of delila instructions synopsis instshift(instin: in, instshiftp: inout, instout: out, output: out) files instin: input: instruction file for delila instout: output: the shifted inst file instshiftp: parameters to control the program. The file must contain the following parameters, one per line: parameterversion: The version number of the program. This allows the user to be warned if an old parameter file is used. The program is smart enough to recognize that there is an old parameter file, and will upgrade the file to the latest version. numbtoshift (integer): The number of bases to shift, if you want the -9 position to be your new zero coordinate, then this number would be -9. If you want the +9 position to be be your new zero coordinate, then this number would be 9. rangechange (char) fromrange (integer) torange (integer) Range change control. If rangechange is: n: no change r: change both fromrange and torange to the given values f: change just fromrange to the given value t: change just torange to the given value s: change both fromrange and torange to match the shift Capital letters (NRFTS) mean to create the complementary Delila instruction after doing the rangechange (except N where only the complement is generated). The s mode allows the range to change so that only the zero base is altered but that sequence obtained is the same as before. This only matters if one is trying to avoid sequences on the edge of a binding site, for example a second copy of the same site that one does not want to show up in the primary sequence logo. output: messages to the user description Shift all the coordinates in an inst file, keeping the same logo but changing the zero coordinate. examples With a parameter numtoshift of 1000 and no range change, the instructions: get from 0 +100 to same -100; get from 4 -100 to 5 +100 direction +; get from 6 -100 to same +100 direction +; get from 7 +100 to 8 -100 direction -; get from 9 +100 to same -100 direction -; become: get from -1000 +100 to same -100; get from 1004 -100 to 1005 +100 direction +; get from 1006 -100 to same +100 direction +; get from -993 +100 to -992 -100 direction -; get from -991 +100 to same -100 direction -; example instshiftp: 1.29 version of instshift that this parameter file is designed for. +10 number of bases to shift the coordinate system r -10 +10 rangechange: nrft fromrange torange documentation see also {parameter file example:} instshiftp {the program that uses the instructions:} delila.p {program to remove comments:} nocom.p {The instshift program can be used to adjust delila instructions for binding sites with any symmetry. A treatise on binding site symmetries is available:} http://www.lecb.ncifcrf.gov/~toms/glossary.html#binding_site_symmetry author Rye Kent Shultzaberger additional features by Tom Schneider bugs * The program will fail on circular pieces. 2001 May 1: This may not be true anymore. * The delilacomment routine will trigger both comparen and comcurly error messages if a comcurly is not closed and there are more comparens after that. * A possible future option would be to complement the instructions so that one gets the complementary sequences. Is this ever useful? * It is standard practice to name some promoters with single quote marks. These were identified as quote strings, killing the rest of the inst. To solve this, once a piece instruction is identified, the rest of the Delila instruction, up to the semicolon, is not checked for quotes or comments. This COULD cause a problem IF someone has a semicolon inside a comment BEFORE the true semicolon end of the Delila instruction. piece bubba' (@ this would cause a problem ; get @) ; (where '@' is substitued for '*') technical notes * Starting with this inst file: get from 0 +100 to same -100; and using this instshift parameter file: 1.29 version of instshift that this parameter file is designed for. -10 number of bases to shift the coordinate system n -40 +5 rangechange: nrft fromrange torange instshift gives an instout file like this: get from -10 +100 to same -100 direction +; Since the user did not specify the direction, the program does not know the direction to put at the end of the instruction. In this case the user may think that the direction is negative, but on a circular piece this is a valid instruction. If you do not give the direction in the inst file, the program defaults to not giving a direction. MUTATION RATE COMPENSATION Since the mutations are generated by Delila instructions, they have to be of a form that does not require knowing the previous base. This is done by using the insertion form i79,81t. However, given a particular base b, this base will be generated 1/4 of the time. So the actual mutation rate would be lower than requested. To compensate for this the program multiplies the requested frequency by 4/3. Note that high mutation rates result in very long mutation string names that Delila cannot handle without increasing the parameter namelength. Note that if namelength is increased, it must be done in catal also and the delila catalogues must be rebuilt. */ /* end module describe.instshift */ /* module filler.const */ #define fillermax 50 /* the size of the filler array for a string */ /* module filler.const from prgmod.p 4.20 */ /* begin module string.const */ #define maxstring 2000 /* the maximum string */ /* end module string.const version = 4.86; (@ of prgmod.p 2004 Sep 8 */ /* 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 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.86; (@ of prgmod.p 2004 Sep 8 */ /* begin module filler.type */ /* the following is an array used to fill a string. it is convenient to have it much shorter than the maxstring, so that it is easy to fill the string using procedure fillstring. the user must declare the value of constant fillermax. */ typedef Char filler[fillermax]; /* end module filler.type version = 4.86; (@ of prgmod.p 2004 Sep 8 */ /* begin module trigger.type */ typedef struct trigger { /* an object to be searched for */ string seek; /* the characters looked for */ long state; /* how close to triggering we are */ boolean skip; /* trigger not found- skip the line */ /* the trigger was found */ boolean found; } trigger; /* end module trigger.type version = 4.86; (@ of prgmod.p 2004 Sep 8 */ /* begin module parameters */ typedef struct parameters { double parameterversion; /* parameter version number */ long numbtoshift; /* how many bases to shift */ Char rangechange; /* range change control: n: no change r: change both fromrange and torange f: change just fromrange t: change just torange */ long fromrange; /* new from range */ long torange; /* new to range */ } parameters; /* end module parameters */ /* begin module datetime.type */ /* array for dates */ typedef Char datetimearray[datetimearraylength]; /* end module datetime.type version = 'cdatemod.p 1.19 1999Dec13'; */ Static _TEXT instin; /* file used by this program */ Static _TEXT instshiftp; /* file used by this program */ Static _TEXT instout; /* file used by this program */ /* begin module skipblanks */ /* 2003 July 31: tab is considered a blank character */ Static boolean isblank(c) Char c; { /* is the character c blank or tab? */ return (c == ' ' || c == '\t'); } Static Void skipblanks(thefile) _TEXT *thefile; { /* skip over blanks until a non-blank, or end of line, is found */ while (isblank(P_peek(thefile->f)) & (!P_eoln(thefile->f))) getc(thefile->f); } Static Void skipnonblanks(thefile) _TEXT *thefile; { /* skip over nonblanks until a blank, or end of line, is found */ while ((!isblank(P_peek(thefile->f))) & (!P_eoln(thefile->f))) getc(thefile->f); } Static Void skipcolumn(thefile) _TEXT *thefile; { /* skip over a data column */ skipblanks(thefile); skipnonblanks(thefile); } Static jmp_buf _JL1; /* end module skipblanks version = 7.67; {of delmod.p 2004 Sep 8} */ /* 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 = 1.17; (@ of timegpc.p 2002 Oct 9 */ /* begin module copyaline */ /* for transfering header info */ 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.67; {of delmod.p 2004 Sep 8} */ /* 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.86; (@ of prgmod.p 2004 Sep 8 */ /* begin module filler.fillstring */ Static Void fillstring(s, a) string *s; Char *a; { /* this procedure makes it reasonably easy to fill the string s with characters. one calls the procedure as: */ /* 1 2 3 4 5 */ /* 12345678901234567890123456789012345678901234567890 */ /* fillstring(s, 'this-is-the-string '); the two comments make it easy to line the characters up. also, for this example, it was assumed that the length of filler as defined by the constant fillermax was 50. */ long length = fillermax; /* of the string without trailing blanks */ long index; /* of s */ clearstring(s); while (length > 1 && a[length-1] == ' ') length--; if (length == 1 && a[length-1] == ' ') { printf("fillstring: the string is empty\n"); halt(); } for (index = 0; index < length; index++) s->letters[index] = a[index]; s->length = length; s->current = 1; } /* fillstring */ /* end module filler.fillstring version = 7.67; {of delmod.p 2004 Sep 8} */ /* begin module filler.filltrigger */ Static Void filltrigger(t, a) trigger *t; Char *a; { /* fill the trigger t */ fillstring(&t->seek, a); } /* fillstring */ /* end module filler.filltrigger version = 7.67; {of delmod.p 2004 Sep 8} */ /* begin module trigger.proc */ /* this module allows one to scan a series of characters, as from an array or a file, and to "trigger" or detect a simple string in the series. the advantage of the trigger is that several triggers can "observe" a stream of characters at once, each looking for a different thing. some other modules required: interact.const, interact.type */ Static Void resettrigger(t) trigger *t; { /* reset the trigger to ground state */ t->state = 0; t->skip = false; t->found = false; } /* resettrigger */ Static Void testfortrigger(ch, t) Char ch; trigger *t; { /* look at the character ch. if it is part of the trigger (at the current trigger state), then the trigger state goes higher. if it is not part of the trigger then the trigger state is reset, skip is true and one should skip onward to find the trigger. if the trigger is found, found is true. 1996 Sep 12: Bug found! In the case of a trigger "ab", the program used to miss it for situations like "aab". This was because at the first a it would step up. Then it would see the second a and recognize that was not part of ab. It would fail to realize that it could be the start of a new one. The code now accounts for that possibility. */ t->state++; /* writestring(list,seek); writeln(list,'testfortrigger seek.letters[',state:1,']:', seek.letters[state],' ch:',ch); */ if (t->seek.letters[t->state - 1] == ch) { t->skip = false; if (t->state == t->seek.length) t->found = true; else t->found = false; return; } /* it failed. But wait! It could be the beginning of a NEW trigger string! */ if (t->seek.letters[0] == ch) { t->state = 1; t->skip = false; t->found = false; return; } t->state = 0; t->skip = true; t->found = false; /* reset trigger */ } /* testfortrigger */ /* end module trigger.proc version = 7.67; {of delmod.p 2004 Sep 8} */ /***************************************************************************/ /***************************************************************************/ /* begin module readshift */ Static Void readshift(inst, fromcoord, tocoord, fromrange, torange, orientation) _TEXT *inst; long *fromcoord, *tocoord, *fromrange, *torange, *orientation; { /* Read from-to coordinates from inst file. The routine now reads an entire delila instruction of the form: get from 7647 -100 to 7666 +100 direction +; or get from 8647 -100 to same +100 direction +; HOWEVER, the get must already have been read. This allows it to be found in the instructions. NOTE: orientation can be -1, +1 or 0. 0 simply means it was not read in. Generally positive orientation can be assumed in this case, but not always. For the range computation, assume it is positive. 2009 Apr 10, 1.62: allow inst without from-ranges This form now works: get from 8647 to same +100 direction +; */ _TEXT TEMP; /* skipcolumn(inst); (* skip 'get' *) */ skipcolumn(inst); /* skip 'from' */ fscanf(instin.f, "%ld", fromcoord); /* read 'from' coordinate */ /*copyaline(inst, output); halt;*/ /*writeln(output,'readshift: fromcoord is ',fromcoord:1);*/ skipblanks(inst); /* 2009 apr 10: skip to 'to' or fromrange */ if (P_peek(inst->f) == 't') *fromrange = 0; else fscanf(instin.f, "%ld", fromrange); /* read 'from' range */ /*writeln(output,'readshift: fromrange is ',fromrange:1);*/ skipblanks(inst); /* 2009 apr 27: skip to 'to' */ if (P_peek(inst->f) != 't') { printf("expected \"to\" instruction, but found this:\n"); TEMP.f = stdout; *TEMP.name = '\0'; copyaline(inst, &TEMP); halt(); } skipcolumn(inst); /* skip 'to' */ /* read the word 'same' and use the fromcoord or read the tocoord */ skipblanks(inst); /* prepare to test for 'same' in next letter */ if (P_peek(inst->f) == 's') { skipnonblanks(inst); /* skip 'same' */ *tocoord = *fromcoord; } else fscanf(instin.f, "%ld", tocoord); /*writeln(output,'readshift: inst^ is "',inst^,'"');*/ fscanf(instin.f, "%ld", torange); /* read 'to' range */ /*writeln(output,'readshift: torange is ', torange:1);*/ /* NOTE: semicolon is NOT READ */ skipblanks(inst); /* prepare to test for 'direction' in next letter */ if (P_peek(inst->f) != 'd') { *orientation = 0; /* 2001 May 21 bug fix */ /* for testing: if (fromcoord = 1286) or (fromcoord = 177) then begin writeln(output,'readshift: fromcoord is ',fromcoord:1); writeln(output,'readshift: fromrange is ',fromrange:1); writeln(output,'readshift: tocoord is ', tocoord:1); writeln(output,'readshift: torange is ', torange:1); writeln(output,'readshift: orientation is ', orientation:1); end; */ return; } skipnonblanks(inst); /* skip 'direction' */ skipblanks(inst); /* skip to direction */ /* writeln(output,'readshift: inst^ is "',inst^,'"');*/ if (P_peek(inst->f) == '-') *orientation = -1; else *orientation = 1; /* move past the orientation character */ getc(inst->f); } /* end module readshift */ /* begin module shift */ Static Void shift(fromcoord, tocoord, fromrange, torange, numbtoshift) long *fromcoord, *tocoord, fromrange, torange, numbtoshift; { /* shift from coordinate by amount numtoshift */ /* determine orientation */ if (fromrange < 0) { *fromcoord += numbtoshift; *tocoord += numbtoshift; return; } if (fromrange > 0) { *fromcoord -= numbtoshift; *tocoord -= numbtoshift; return; } if (torange >= 0) { /* allow for 0 wide */ *fromcoord += numbtoshift; *tocoord += numbtoshift; return; } if (torange < 0) { *fromcoord -= numbtoshift; *tocoord -= numbtoshift; /* fromrange = 0 */ } } Local Void signednumber(instout, i) _TEXT *instout; long i; { /* produce the number, signed */ if (i < 0) fprintf(instout->f, " %ld", i); else fprintf(instout->f, " +%ld", i); } /* end module shift */ /* begin module writeshift */ Static Void writeshift(instout, fromcoord, tocoord, fromrange, torange, orientation) _TEXT *instout; long fromcoord, tocoord, fromrange, torange, orientation; { /* Write out the shifted instructions. No carriage return is given at the end, to allow any remaining parts to be copied. The final semicolon (or other material) is to be copied from the inst file later. The word 'get' is NOT output because it is copied during reading. */ fprintf(instout->f, " from %ld", fromcoord); signednumber(instout, fromrange); fprintf(instout->f, " to "); if (fromcoord == tocoord) fprintf(instout->f, "same"); else fprintf(instout->f, "%ld", tocoord); signednumber(instout, torange); if (orientation == 0) return; fprintf(instout->f, " direction "); if (orientation == -1) putc('-', instout->f); else putc('+', instout->f); } #define asterisk '*' /* asterisk */ #define leftcurly '{' /* left curly parenthesis */ #define leftparen '(' /* left parenthesis */ #define rightcurly '}' /* right curly parenthesis */ #define rightparen ')' /* right parenthesis */ /* end module writeshift */ /* begin module delilacomment */ Static Void delilacomment(previous, current, comparen, comcurly) Char previous, current; boolean *comparen, *comcurly; { /* Detect delila comments. Given the previous and current characters, determine if we are inside either a parenthesis comment or a curly comment. */ if (previous == leftparen && current == asterisk) *comparen = true; if (*comparen && !*comcurly && previous == asterisk && current == rightparen) *comparen = false; if (!*comparen && current == leftcurly) *comcurly = true; if (*comcurly && !*comparen && current == rightcurly) *comcurly = false; } #undef asterisk #undef leftcurly #undef leftparen #undef rightcurly #undef rightparen #define single '\'' /* single quote */ #define double_ '"' /* double quote */ /* end module delilacomment */ /* begin module quotecomment */ Static Void quotecomment(previous, current, comparen, comcurly, singlequote, doublequote) Char previous, current; boolean *comparen, *comcurly, *singlequote, *doublequote; { /* Detect quotes and comments. Given the previous and current characters, determine if we are inside either a parenthesis comment or a curly comment, a single quote or a double quote. 2001 Oct 5, 1.42: single quotes exclude double quotes in proc quotecomment A delila title like title "Hanah Margalit's promoter database from-75 to 25"; made the program think that everything after the single quote was inside quotes! */ if (!(*comparen || *comcurly)) { /* 2001 Oct 5 Bad code: if current = single then singlequote := not singlequote; if current = double then doublequote := not doublequote; fix: */ if (current == single) { if (!*doublequote) *singlequote = !*singlequote; } if (current == double_) { if (!*singlequote) *doublequote = !*doublequote; } } if (!(*singlequote || *doublequote)) delilacomment(previous, current, comparen, comcurly); } #undef single #undef double_ /* end module quotecomment */ /* begin module copytheinst */ Static Void copytheinst(fin, fout, previous, c, comparen, comcurly, singlequote, doublequote, checkquotecomment) _TEXT *fin, *fout; Char *previous, *c; boolean *comparen, *comcurly, *singlequote, *doublequote, checkquotecomment; { /* Copy the current delila instruction from file fin to file fout until the end of the instruction. Check for comments using quotecomment while we go if checkquotecomment is true. */ while (!BUFEOF(fin->f) && *c != ';') { if (P_eoln(fin->f)) { fscanf(fin->f, "%*[^\n]"); getc(fin->f); putc('\n', fout->f); *c = ' '; *previous = *c; continue; } if (BUFEOF(fin->f)) break; *previous = *c; *c = getc(fin->f); if (*c == '\n') *c = ' '; putc(*c, fout->f); if (checkquotecomment) quotecomment(*previous, *c, comparen, comcurly, singlequote, doublequote); } } /* copytheinst */ #define pow14 16384 #define pow15 32768L #define pow22 4194304L #define pow23 8388608L /* end module copytheinst */ /* begin module random */ Static Void random(seed) double *seed; { /* random generator 2. version = 1.01 of random.2 1990 Oct 2 origin 1986 December 31 Test this routine with the program tstrnd. written by David Masternarde */ /* This random number generator is based on a shift register with a single bit of feedback, as described in Electronics for Neurobiologists, by Brown, Maxfield and Moraff, MIT press 1973, referencing Random Process Simulation and Measurement by Korn, McGraw-Hill 1966. The random seed rand, a number between 0 and 1 exclusive, is converted to an integer between 1 and 2**23-1, inclusive. This 23-bit number is shifted right one bit and the output of the last (23rd) bit and the 9th bit are added modulo 2 (exclusive orred) and fed back into the new first bit. This is done between 4 and 11 times, depending on the last 3 bits of the original number. The result is converted back to a real number between 0 and 1 from which the 23 bit integer can be recovered on the next call. The 23-bit shift register goes through all 2**23-1 values before repeating; the repetition frequency of this algorithm could be less or greater depending on the seed, because of the random number of multiple shifts per call. */ /* powers of 2 */ long iseed; /* integer shift register */ long i, nrep; /* index, number of times to do shift */ iseed = (long)floor(*seed * pow23 + 0.5); /* convert to 23 bit number */ if (iseed < 1 || iseed >= pow23) iseed = 1; nrep = (iseed & 7) + 4; /* do it 4 to 11 times based on last 3 bits */ for (i = 1; i <= nrep; i++) { /* if last bit and 9th bit are equal, feed back a 0, otherwise a 1 */ if ((iseed & 1) == ((iseed & (pow15 - 1)) >= pow14)) iseed /= 2; else iseed = iseed / 2 + pow22; } *seed = (double)iseed / pow23; } /* random */ #undef pow14 #undef pow15 #undef pow22 #undef pow23 /* end module random */ /* 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 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 */ #define mutationmax 1000 /* maximum length of sequences that can be mutated */ #define pwid 10 /* characters for reporting mutation fractions */ #define pdec 8 /* decimals for reporting mutation fractions */ /* end module timeseed version = 'cdatemod.p 1.19 1999Dec13'; */ /* begin module instloop */ Static Void instloop(instin, instout, params) _TEXT *instin, *instout; parameters params; { /* Read through inst file and produce instout file. Skip comments. */ long b; /* index to bases */ Char bases[4]; /* the bases */ Char c = ' '; /* generic character */ boolean comparen = false; /* if true, we are inside a standard comment */ boolean comcurly = false; /* if true, we are inside a curly comment */ Char previous = ' '; /* the previous value of c */ long fromcoord; /* coordinate of zero base (ie From part) */ long tocoord; /* coordinate of end base (ie To part) */ long fromrange; /* the lower bound of the interval grabbed */ long torange; /* the upper bound of the interval grabbed */ trigger gettrigger; /* trigger for get instruction */ trigger piecetrigger; /* trigger for piece instruction */ long orientation; /* orientation of the interval */ boolean singlequote = false, doublequote = false; /* single and double quote states */ boolean notfirst; /* first get in a set? */ /*mmm*/ /* variables for random mutations */ double seed; /* a random number, seed for the next random number */ Char mutationarray[mutationmax + 1]; /* storage for mutations */ long storepoint; /* storage point in the mutationarray */ boolean aremutations; /* are there mutations in this sequence? */ long countmutations = 0; /* count of mutations */ long countbases = 0; /* count of bases possibly mutated */ bases[0] = 'a'; bases[1] = 'c'; bases[2] = 'g'; bases[3] = 't'; /* set up variables for random mutations */ /*mmm*/ if (0 < params.initialseed && params.initialseed < 1) { /* p2c: instshift.p, line 963: * Warning: No field called INITIALSEED in that record [288] */ /* p2c: instshift.p, line 963: * Warning: No field called INITIALSEED in that record [288] */ seed = params.initialseed; /* p2c: instshift.p, line 964: * Warning: No field called INITIALSEED in that record [288] */ } else timeseed(&seed); /* 1 2 3 4 5 */ /* 12345678901234567890123456789012345678901234567890 */ filltrigger(&gettrigger, "get "); resettrigger(&gettrigger); filltrigger(&piecetrigger, "piece "); resettrigger(&piecetrigger); while (!BUFEOF(instin->f)) { if (P_eoln(instin->f)) { fscanf(instin->f, "%*[^\n]"); getc(instin->f); putc('\n', instout->f); previous = ' '; resettrigger(&gettrigger); resettrigger(&piecetrigger); if (singlequote) { printf("Multiline single quote string\n"); halt(); } if (doublequote) { printf("Multiline double quote string\n"); halt(); } continue; } previous = c; c = getc(instin->f); if (c == '\n') c = ' '; putc(c, instout->f); /* 2001 Oct 11 Ignore single or double quote marks in a piece instruction. */ testfortrigger(c, &piecetrigger); if (piecetrigger.found) { /* 2004 July 8: Wait a second! Don't do this if we are inside a quote!! */ if (!(comparen || comcurly || singlequote || doublequote)) copytheinst(instin, instout, &previous, &c, &comparen, &comcurly, &singlequote, &doublequote, false); continue; } quotecomment(previous, c, &comparen, &comcurly, &singlequote, &doublequote); /*zzz if comparen then write(instout,'P'); if comcurly then write(instout,'C'); if singlequote then write(instout,'S'); if doublequote then write(instout,'_D'); */ if (comparen || comcurly || singlequote || doublequote) continue; testfortrigger(c, &gettrigger); if (!gettrigger.found) continue; readshift(instin, &fromcoord, &tocoord, &fromrange, &torange, &orientation); switch (params.rangechange) { /* nrftNRFT */ case 'n': case 'N': /* no change to range */ break; case 'r': case 'R': if (orientation == 1 || orientation == 0) { /* assume positive orientation when orientation is not given */ fromrange = params.fromrange; torange = params.torange; } else { fromrange = -params.fromrange; torange = -params.torange; } break; case 'f': case 'F': fromrange = params.fromrange; break; case 't': case 'T': torange = params.torange; break; case 's': case 'S': if (orientation == 1 || orientation == 0) { /* assume positive orientation when orientation is not given */ fromrange -= params.numbtoshift; torange -= params.numbtoshift; } else { fromrange += params.numbtoshift; torange += params.numbtoshift; } break; } shift(&fromcoord, &tocoord, fromrange, torange, params.numbtoshift); /**************************************************************/ /* should one shift and then complement or the other way around? */ if (params.rangechange == 'S' || params.rangechange == 'T' || params.rangechange == 'F' || params.rangechange == 'R' || params.rangechange == 'N') { fromrange = -fromrange; torange = -torange; orientation = -orientation; } /**************************************************************/ /*uuu*/ writeshift(instout, fromcoord, tocoord, fromrange, torange, orientation); copytheinst(instin, instout, &previous, &c, &comparen, &comcurly, &singlequote, &doublequote, true); } if (comparen) printf("ERROR: unclosed (* *) comment\n"); if (comcurly) printf("ERROR: unclosed {} comment\n"); /*mmm*/ if (params.splatter != "m") return; /* p2c: instshift.p, line 1107: * Warning: No field called SPLATTER in that record [288] */ fprintf(instout->f, "{ Mutation results:\n"); fprintf(instout->f, "total bases: %ld\n", countbases); fprintf(instout->f, "total mutations: %ld\n", countmutations); fprintf(instout->f, "fraction, mutations/base: %*.*f\n", pwid, pdec, (double)countmutations / countbases); /* p2c: instshift.p, line 1114: * Warning: No field called MUTATIONS in that record [288] */ fprintf(instout->f, "requested mutations/base: %*ld\n", pwid, params.mutations); fprintf(instout->f, "}\n"); } #undef mutationmax #undef pwid #undef pdec /* Local variables for readparameters: */ struct LOC_readparameters { _TEXT *instshiftp; parameters *params; } ; Local Void upgradeto129(LINK) struct LOC_readparameters *LINK; { /* upgrade to version 1.29 parameters: ---- 1.29 version of instshift that this parameter file is designed for. +10 number of bases to shift the coordinate system n -10 +10 rangechange: nrft fromrange torange ---- */ parameters *WITH; WITH = LINK->params; printf("upgrading instshiftp to version 1.29 ...\n"); fscanf(LINK->instshiftp->f, "%ld%*[^\n]", &WITH->numbtoshift); getc(LINK->instshiftp->f); if (*LINK->instshiftp->name != '\0') { if (LINK->instshiftp->f != NULL) LINK->instshiftp->f = freopen(LINK->instshiftp->name, "w", LINK->instshiftp->f); else LINK->instshiftp->f = fopen(LINK->instshiftp->name, "w"); } else { if (LINK->instshiftp->f != NULL) rewind(LINK->instshiftp->f); else LINK->instshiftp->f = tmpfile(); } if (LINK->instshiftp->f == NULL) _EscIO2(FileNotFound, LINK->instshiftp->name); SETUPBUF(LINK->instshiftp->f, Char); fprintf(LINK->instshiftp->f, "1.29 version of instshift that this parameter file is designed for.\n"); if (WITH->numbtoshift > 0) putc('+', LINK->instshiftp->f); fprintf(LINK->instshiftp->f, "%ld number of bases to shift the coordinate system\n", WITH->numbtoshift); fprintf(LINK->instshiftp->f, "n -10 +10 rangechange: nrft fromrange torange\n"); } Local Void upgradeto134(LINK) struct LOC_readparameters *LINK; { /* upgrade to version 1.34 parameters: ---- 1.34 version of instshift that this parameter file is designed for. +10 number of bases to shift the coordinate system n -10 +10 rangechange: nrft fromrange torange (**) ---- */ _TEXT hold; /* for holding the current parameters */ parameters *WITH; hold.f = NULL; *hold.name = '\0'; WITH = LINK->params; printf("upgrading instshiftp to version 1.34 ...\n"); if (*LINK->instshiftp->name != '\0') { if (LINK->instshiftp->f != NULL) LINK->instshiftp->f = freopen(LINK->instshiftp->name, "r", LINK->instshiftp->f); else LINK->instshiftp->f = fopen(LINK->instshiftp->name, "r"); } else rewind(LINK->instshiftp->f); if (LINK->instshiftp->f == NULL) _EscIO2(FileNotFound, LINK->instshiftp->name); RESETBUF(LINK->instshiftp->f, Char); fscanf(LINK->instshiftp->f, "%*[^\n]"); getc(LINK->instshiftp->f); /* skip previous version number */ if (*hold.name != '\0') { if (hold.f != NULL) hold.f = freopen(hold.name, "w", hold.f); else hold.f = fopen(hold.name, "w"); } else { if (hold.f != NULL) rewind(hold.f); else hold.f = tmpfile(); } if (hold.f == NULL) _EscIO2(FileNotFound, hold.name); SETUPBUF(hold.f, Char); while (!BUFEOF(LINK->instshiftp->f)) copyaline(LINK->instshiftp, &hold); if (*LINK->instshiftp->name != '\0') { if (LINK->instshiftp->f != NULL) LINK->instshiftp->f = freopen(LINK->instshiftp->name, "w", LINK->instshiftp->f); else LINK->instshiftp->f = fopen(LINK->instshiftp->name, "w"); } else { if (LINK->instshiftp->f != NULL) rewind(LINK->instshiftp->f); else LINK->instshiftp->f = tmpfile(); } if (LINK->instshiftp->f == NULL) _EscIO2(FileNotFound, LINK->instshiftp->name); SETUPBUF(LINK->instshiftp->f, Char); fprintf(LINK->instshiftp->f, "1.34 version of instshift that this parameter file is designed for.\n"); if (*hold.name != '\0') { if (hold.f != NULL) hold.f = freopen(hold.name, "r", hold.f); else hold.f = fopen(hold.name, "r"); } else rewind(hold.f); if (hold.f == NULL) _EscIO2(FileNotFound, hold.name); RESETBUF(hold.f, Char); while (!BUFEOF(hold.f)) copyaline(&hold, LINK->instshiftp); if (hold.f != NULL) fclose(hold.f); } Local Void upgradeto158(LINK) struct LOC_readparameters *LINK; { /* upgrade to version 1.58 parameters: ---- 1.34 version of instshift that this parameter file is designed for. +10 number of bases to shift the coordinate system n -10 +10 rangechange: nrft fromrange torange (**) ---- */ _TEXT hold; /* for holding the current parameters */ parameters *WITH; hold.f = NULL; *hold.name = '\0'; WITH = LINK->params; printf("upgrading instshiftp to version 1.58 ...\n"); if (*LINK->instshiftp->name != '\0') { if (LINK->instshiftp->f != NULL) LINK->instshiftp->f = freopen(LINK->instshiftp->name, "r", LINK->instshiftp->f); else LINK->instshiftp->f = fopen(LINK->instshiftp->name, "r"); } else rewind(LINK->instshiftp->f); if (LINK->instshiftp->f == NULL) _EscIO2(FileNotFound, LINK->instshiftp->name); RESETBUF(LINK->instshiftp->f, Char); fscanf(LINK->instshiftp->f, "%*[^\n]"); getc(LINK->instshiftp->f); /* skip previous version number */ if (*hold.name != '\0') { if (hold.f != NULL) hold.f = freopen(hold.name, "w", hold.f); else hold.f = fopen(hold.name, "w"); } else { if (hold.f != NULL) rewind(hold.f); else hold.f = tmpfile(); } if (hold.f == NULL) _EscIO2(FileNotFound, hold.name); SETUPBUF(hold.f, Char); while (!BUFEOF(LINK->instshiftp->f)) copyaline(LINK->instshiftp, &hold); if (*LINK->instshiftp->name != '\0') { if (LINK->instshiftp->f != NULL) LINK->instshiftp->f = freopen(LINK->instshiftp->name, "w", LINK->instshiftp->f); else LINK->instshiftp->f = fopen(LINK->instshiftp->name, "w"); } else { if (LINK->instshiftp->f != NULL) rewind(LINK->instshiftp->f); else LINK->instshiftp->f = tmpfile(); } if (LINK->instshiftp->f == NULL) _EscIO2(FileNotFound, LINK->instshiftp->name); SETUPBUF(LINK->instshiftp->f, Char); fprintf(LINK->instshiftp->f, "1.58 version of instshift that this parameter file is designed for.\n"); if (*hold.name != '\0') { if (hold.f != NULL) hold.f = freopen(hold.name, "r", hold.f); else hold.f = fopen(hold.name, "r"); } else rewind(hold.f); if (hold.f == NULL) _EscIO2(FileNotFound, hold.name); RESETBUF(hold.f, Char); while (!BUFEOF(hold.f)) copyaline(&hold, LINK->instshiftp); if (hold.f != NULL) fclose(hold.f); } /* end module instloop */ /* begin module readparameters */ Static Void readparameters(instshiftp_, params_) _TEXT *instshiftp_; parameters *params_; { /* read the parameters. The routine will upgrade the parameter file if it is old. The original parameter file was: ---- 1.00 version of instshift that this parameter file is designed for. +10 number of bases to shift the coordinate system ---- */ struct LOC_readparameters V; parameters *WITH; V.instshiftp = instshiftp_; V.params = params_; WITH = V.params; if (*V.instshiftp->name != '\0') { if (V.instshiftp->f != NULL) V.instshiftp->f = freopen(V.instshiftp->name, "r", V.instshiftp->f); else V.instshiftp->f = fopen(V.instshiftp->name, "r"); } else rewind(V.instshiftp->f); if (V.instshiftp->f == NULL) _EscIO2(FileNotFound, V.instshiftp->name); RESETBUF(V.instshiftp->f, Char); fscanf(V.instshiftp->f, "%lg%*[^\n]", &WITH->parameterversion); getc(V.instshiftp->f); if ((long)floor(100 * WITH->parameterversion + 0.5) < (long)floor(100 * updateversion + 0.5)) { printf("You have an old parameter file!\n"); printf("UPGRADING parameter file!\n"); if (WITH->parameterversion < 1.29) upgradeto129(&V); if (WITH->parameterversion < 1.34) upgradeto134(&V); if (WITH->parameterversion < 1.58) upgradeto158(&V); if (*V.instshiftp->name != '\0') { if (V.instshiftp->f != NULL) V.instshiftp->f = freopen(V.instshiftp->name, "r", V.instshiftp->f); else V.instshiftp->f = fopen(V.instshiftp->name, "r"); } else rewind(V.instshiftp->f); if (V.instshiftp->f == NULL) _EscIO2(FileNotFound, V.instshiftp->name); RESETBUF(V.instshiftp->f, Char); fscanf(V.instshiftp->f, "%*[^\n]"); getc(V.instshiftp->f); /* skip the version number */ } fscanf(V.instshiftp->f, "%ld%*[^\n]", &WITH->numbtoshift); getc(V.instshiftp->f); fscanf(V.instshiftp->f, "%c%ld%ld%*[^\n]", &WITH->rangechange, &WITH->fromrange, &WITH->torange); getc(V.instshiftp->f); if (WITH->rangechange == '\n') WITH->rangechange = ' '; if (WITH->rangechange == 'S' || WITH->rangechange == 'T' || WITH->rangechange == 'F' || WITH->rangechange == 'R' || WITH->rangechange == 'N' || WITH->rangechange == 's' || WITH->rangechange == 't' || WITH->rangechange == 'f' || WITH->rangechange == 'r' || WITH->rangechange == 'n') return; printf("rangechange must be one of \"nrftsNRFTS\","); printf(" but it was \"%c\"\n", WITH->rangechange); halt(); } /* end module readparameters */ /* begin module instshift.themain */ Static Void themain(instin, instshiftp, instout) _TEXT *instin, *instshiftp, *instout; { /* the main procedure of the program */ parameters params; /* the parameters to be read in */ printf("instshift %4.2f\n", version); readparameters(instshiftp, ¶ms); if (*instin->name != '\0') { if (instin->f != NULL) instin->f = freopen(instin->name, "r", instin->f); else instin->f = fopen(instin->name, "r"); } else rewind(instin->f); if (instin->f == NULL) _EscIO2(FileNotFound, instin->name); RESETBUF(instin->f, Char); if (*instout->name != '\0') { if (instout->f != NULL) instout->f = freopen(instout->name, "w", instout->f); else instout->f = fopen(instout->name, "w"); } else { if (instout->f != NULL) rewind(instout->f); else instout->f = tmpfile(); } if (instout->f == NULL) _EscIO2(FileNotFound, instout->name); SETUPBUF(instout->f, Char); instloop(instin, instout, params); fprintf(instout->f, "(* instshift %4.2f", version); fprintf(instout->f, ", shifted %ld bases,", params.numbtoshift); switch (params.rangechange) { /* nrft */ case 'n': case 'N': fprintf(instout->f, " no change to range"); break; case 'r': case 'R': fprintf(instout->f, " range set to %ld to %ld", params.fromrange, params.torange); break; case 'f': case 'F': fprintf(instout->f, " from of range set to %ld", params.fromrange); break; case 't': case 'T': fprintf(instout->f, " to of range set to %ld", params.torange); break; case 's': case 'S': fprintf(instout->f, " range size kept constant, shifted"); break; } if (params.rangechange == 'T' || params.rangechange == 'F' || params.rangechange == 'R' || params.rangechange == 'N') fprintf(instout->f, " COMPLEMENT\n"); fprintf(instout->f, " *)\n"); } /* end module instshift.themain */ main(argc, argv) int argc; Char *argv[]; { PASCAL_MAIN(argc, argv); if (setjmp(_JL1)) goto _L1; instout.f = NULL; strcpy(instout.name, "instout"); instshiftp.f = NULL; strcpy(instshiftp.name, "instshiftp"); instin.f = NULL; strcpy(instin.name, "instin"); themain(&instin, &instshiftp, &instout); _L1: if (instin.f != NULL) fclose(instin.f); if (instshiftp.f != NULL) fclose(instshiftp.f); if (instout.f != NULL) fclose(instout.f); exit(EXIT_SUCCESS); } /* End. */