acedb-4.9.39+dfsg.01/0000775000175000017500000000000011430060720013667 5ustar moellermoelleracedb-4.9.39+dfsg.01/makefile0000777000175000017500000000000011430060716020173 2wmake/makefileustar moellermoelleracedb-4.9.39+dfsg.01/w1/0000755000175000017500000000000011430060720014214 5ustar moellermoelleracedb-4.9.39+dfsg.01/w1/acein.c0000444000175000017500000017401510147533432015456 0ustar moellermoeller/* File: acein.c * Author: Richard Durbin (rd@mrc-lmb.cam.ac.uk) * Copyright (C) J Thierry-Mieg and R Durbin, 1991 *------------------------------------------------------------------- * This file is part of the ACEDB genome database package, written by * Richard Durbin (MRC LMB, UK) rd@mrc-lmb.cam.ac.uk, and * Jean Thierry-Mieg (CRBM du CNRS, France) mieg@kaa.cnrs-mop.fr * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Description: threadsafe version of freesubs * HISTORY: * Last edited: Oct 18 10:48 2002 (edgrif) * * May 8 13:12 2000 (edgrif): Added optimisation of aceInGetChar, see * comments on aceInGetCharMacro() for further info. * * Jan 6 11:51 2000 (edgrif): Reinsert crash for exceeding MAXSTREAM. * * Nov 1 15:25 1999 (srk): added readline prompt * * Oct 18 13:35 1999 (fw): removed aceInSelect (unused) * the proper function aceInLevelSelect * * Oct 18 10:48 1999 (fw): removed aceInRead/fi->filAss (unused) * * Oct 14 17:23 1999 (fw): rewrite constructor/destructor * aceInSetFile/Pipe etc. now private * * Oct 6 13:34 1999 (fw): tidy up memory handling of AceInStruct * add assertions * Created: Sun Aug 30 1999 (mieg) * CVS info: $Id: acein.c,v 1.41 2004/11/20 03:16:42 mieg Exp $ *------------------------------------------------------------------- */ #include #include /* our public API */ #include #include #ifndef NO_READLINE #include #endif /*NO_READLINE */ /* #define DEBUG_STREAMLEVEL */ /************************************************************/ enum {MAXSTREAM = 80, /* highest streamlevel possible * Number must be at least 1 */ MAXNPAR = 80, MAXCARD = 1024, MAXSPECIAL = 24 } ; typedef struct { FILE *fil ; char *text ; char *text_start ; /* Needed for streamPos on text stream */ char *RLtext ; char *prompt ; char special[MAXSPECIAL] ; int npar ; int parMark[MAXNPAR] ; int line ; BOOL isPipe ; int streamlevel ; char *fname; /* remember the file name, e.g. to debug */ } STREAM ; static magic_t ACEIN_MAGIC = "ACEIN"; struct AceInStruct /* complete the opaque type locally */ { magic_t *magic; /* == &ACEIN_MAGIC */ STORE_HANDLE handle ; int streamlevel ; STREAM stream[MAXSTREAM + 1] ; int maxcard ; unsigned char special[256] ; char *card; char *pos; char *cardEnd; char *word ; Stack parStack ; Array buf ; int id; /* count the number of created ACEIN's */ BOOL debug; /* to trace open/close */ BOOL useReadLine; /* private: using readline to get chars from STDIN */ BOOL isInteractive; /* public: clearing this inhibits use of readline and stops prompts from being created (set by the -noprompt option in tace and friends */ FILE *curr_fil ; /* if curr level acein is a file, this */ /* is the FILE, NULL otherwise. */ }; /***********************/ #define _losewhite(fi) while (*(fi->pos) == ' '|| *(fi->pos) == '\t') ++(fi->pos) #define _stepover(fi,x) (*(fi->pos) == x && ++(fi->pos)) /* 4_7 got input chars using a macro (_FREECHAR), this was replaced in 4_8 */ /* with a call to aceInGetChar(), this is too slow because it is called for */ /* EVERY single char read. This has been corrected with two changes: */ /* */ /* - the below macro 'inlines' the aceInGetChar() code for files */ /* */ /* - curr_fil now gives direct access to the input file instead of having to */ /* use massive indirection: fi->stream[fi->streamlevel].fil) */ /* */ /* These changes brought 4_8 performance to within 8 or 9% of 4_7. */ /* */ #define aceInGetCharMacro(FI, RESULT) \ { \ if (fi->curr_fil) \ { \ int c = getc(fi->curr_fil); \ if (c == EOF) \ RESULT = '\0'; \ else \ RESULT = (char)c; \ } \ else \ RESULT = aceInGetChar(FI) ; \ } /***********************/ static ACEIN aceInCreate (STORE_HANDLE handle); static void aceInSetText (ACEIN fi, char *string, char *parms); static void aceInSetReadLine (ACEIN fi, char *parms); static void aceInSetFile (ACEIN fi, FILE *fil, char *fname, char *parms); static void aceInSetPipe (ACEIN fi, FILE *fil, char *parms); static void aceInClose(ACEIN fi, int level); static void aceInExtend (ACEIN fi, char **pin) ; static void aceInNewStream (ACEIN fi, char *parms); static void aceInFinalise (void *block); static BOOL aceInExists (ACEIN fi); static char aceInGetChar (ACEIN fi); /* get next char */ static void aceInUnGetChar (ACEIN fi, char ch); /* push back a char */ static int aceInKeyMatch (ACEIN fi, char *cp, KEY *keyp, FREEOPT *options); ACEIN aceInCreateFromCompressedFile (char *filename, char *params, STORE_HANDLE handle); static char *doUnprotect(ACEIN fi, char *text, BOOL just_quotes) ; /****************************************************************** ************************* public functions *********************** ******************************************************************/ ACEIN aceInCreateFromFile (char *filename, const char *spec, char *params, STORE_HANDLE handle) { FILE *fil; ACEIN fi = NULL; if (!filename) messcrash("aceInCreateFromFile() - NULL filename"); if (!spec) messcrash("aceInCreateFromFile() - NULL spec"); if (spec[0] != 'r') messcrash("aceInCreateFromFile() - non-'r' spec"); fi = aceInCreateFromCompressedFile (filename, params, handle); if (fi) ; else /* uncompressed file */ { fil = filopen(filename, "", (char*)spec); if (fil) { fi = aceInCreate (handle); aceInSetFile (fi, fil, filename, params); /* cannot fail */ } } return fi; } /* aceInCreateFromFile */ ACEIN aceInCreateFromURL (char *url, const char *spec, char *params, STORE_HANDLE handle) { ACEIN fi = NULL; if (!url) messcrash("aceInCreateFromURL() - NULL url"); if (!spec) messcrash("aceInCreateFromURL() - NULL spec"); if (spec[0] != 'r') messcrash("aceInCreateFromURL() - non-'r' spec"); if (strcmp (url, "stdin://") == 0) { fi = aceInCreateFromStdin (FALSE, params, handle); } else if (strcmp (url, "readline://") == 0) { fi = aceInCreateFromStdin (TRUE, params, handle); } else if (strcmp (url, "text://") == 0) { messerror ("Cannot re-open an input that was " "reading from a text-buffer"); } else if (strcmp (url, "pipe://") == 0) { char *command; command = url + 8; fi = aceInCreateFromPipe (command, spec, params, handle); } else if (strcmp (url, "script://") == 0) { char *url_copy = strnew (url, 0); char *script; char *args; script = url_copy + 9; args = strstr (url_copy, "#"); if (!args) messcrash("aceInCreateFromURL() - " "script:// URL has no # character"); *args = '\0'; args++; fi = aceInCreateFromScriptPipe (script, args, params, handle); messfree (url_copy); } return fi; } /* aceInCreateFromURL */ ACEIN aceInCreateFromChooser (char *prompt, char *directory, char *filename, const char *extension, const char *spec, STORE_HANDLE handle) /* Note that extension is const char - it doesn't get changed * but the user can edit it and it is incoporated into the * filename-buffer */ { FILE *fil; ACEIN fi = NULL; char path[MAXPATHLEN]; if (!directory) messcrash("aceInCreateFromChooser() - NULL directory"); if (!filename) messcrash("aceInCreateFromChooser() - NULL filename"); if (!spec) messcrash("aceInCreateFromChooser() - NULL spec"); if (spec[0] != 'r') messcrash("aceInCreateFromChooser() - non-'r' spec"); fil = filqueryopen (directory, filename, (char*)extension, (char*)spec, prompt); if (!fil) return NULL; /* user clicked "Cancel" etc. */ /* Assemble pathname : * Note, the assembled filename will be / * the filename will incorporate the extension, as it was * editable by the user. */ sprintf (path, "%s%s%s", directory, SUBDIR_DELIMITER_STR, filename); fi = aceInCreateFromCompressedFile (path, "", handle); if (fi) { filclose (fil); /* return value from * filechooser not needed */ } else /* uncompressed file */ { fi = aceInCreate (handle); aceInSetFile (fi, fil, path, ""); /* cannot fail */ } return fi; } /* aceInCreateFromChooser */ ACEIN aceInCreateFromPipe (char *command, const char *spec, char *params, STORE_HANDLE handle) { FILE *fil; ACEIN fi = NULL; if (!command) messcrash("aceInCreateFromPipe() - NULL command"); if (!spec) messcrash("aceInCreateFromPipe() - NULL spec"); fil = popen((const char*)command, spec); /* will be closed in * aceInFinalise() */ if (fil) { fi = aceInCreate (handle); aceInSetPipe (fi, fil, params); /* cannot fail */ { /* assemble url */ Stack s = stackCreate(100); pushText(s, "pipe://"); catText(s, command); fi->stream[fi->streamlevel].fname = strnew(stackText(s, 0), fi->handle); stackDestroy (s); } if (fi->debug) printf ("DEBUG open stream %d(%d) : %s\n", fi->id, fi->streamlevel, fi->stream[fi->streamlevel].fname); } return fi; } /* aceInCreateFromPipe */ ACEIN aceInCreateFromScriptPipe (char *script, char *args, char *params, STORE_HANDLE handle) { FILE *fil; ACEIN fi = NULL; if (!script) messcrash("aceInCreateFromScriptPipe() - NULL script"); if (!args) messcrash("aceInCreateFromScriptPipe() - NULL args"); fil = callScriptPipe(script, args); /* will be closed in * aceInFinalise() */ if (fil) { fi = aceInCreate (handle); aceInSetPipe (fi, fil, params); /* cannot fail */ { /* assemble url */ Stack s = stackCreate(100); pushText(s, "script://"); catText(s, script); catText(s, "#"); catText(s, args); fi->stream[fi->streamlevel].fname = strnew (stackText(s, 0), fi->handle); stackDestroy (s); } if (fi->debug) printf ("DEBUG open stream %d(%d) : %s\n", fi->id, fi->streamlevel, fi->stream[fi->streamlevel].fname); } return fi; } /* aceInCreateFromScriptPipe */ ACEIN aceInCreateFromStdin (BOOL isInteractive, char *params, STORE_HANDLE handle) { /* Clearing isInteractive does two things. 1) It stops prompts from being created. 2) It inhibits the use of readline under all circumstances. If IsInteractive is true, readline is used iff stdin is a tty */ ACEIN fi; fi = aceInCreate (handle); fi->isInteractive = isInteractive; #ifndef NO_READLINE if (isInteractive && (isatty(fileno(stdin)) == 1)) aceInSetReadLine (fi, params); /* cannot fail */ else #endif /*NO_READLINE */ aceInSetFile (fi, stdin, "stdin://", params); /* cannot fail */ return fi; } /* aceInCreateFromStdin */ ACEIN aceInCreateFromText (char *text, char *params, STORE_HANDLE handle) /* NOTE: caller remains responsible for the text buffer */ { ACEIN fi = NULL; if (!text) messcrash("aceInCreateFromFile() - NULL text"); fi = aceInCreate (handle); aceInSetText (fi, text, params); return fi; } /* aceInCreateFromText */ /************************************************/ /* Reinitialise an acein struct with some text, use this if you want to reuse * an acein rather than constantly allocate/deallocate one. */ void aceInSetNewText(ACEIN fi, char *text, char *params) { messAssert(text != NULL || !aceInExists(fi)) ; aceInClose (fi, 1) ; /* close all levels */ aceInSetText(fi, text, params) ; return ; } /************************************************/ char *aceInGetURL (ACEIN fi) { char *url = NULL; /* Return the filename of the first streamlevel on this stream. * If it has multiple levels, then we need to remember to * file at the bottom of the stack to reporduce the same result. */ if (!aceInEOF(fi)) url = fi->stream[1].fname; return url; } /* aceInGetURL */ /************************************************/ void uAceInDestroy (ACEIN fi) /* use only aceInDestroy macro! */ { if (!aceInExists(fi)) messcrash("aceInDestroy() - received invalid fi pointer"); /* just a stub - you could just call messfree * cleanup is taken care of by finalisation */ messfree (fi); } /* uAceInDestroy */ /*******************/ BOOL aceInPrompt (ACEIN fi, char *prompt) { char *cp = 0 ; if (fi->stream[fi->streamlevel].prompt) messfree(fi->stream[fi->streamlevel].prompt); fi->stream[fi->streamlevel].prompt = strnew (prompt, fi->handle); /* NB. if isInteractive is clear, we don't want a prompt. if we are using readline readline generates the prompt itself so we don't need to do it here. */ if (fi->isInteractive && !fi->useReadLine && fi->stream[fi->streamlevel].prompt && *fi->stream[fi->streamlevel].prompt ) fputs(fi->stream[fi->streamlevel].prompt, stdout); /* fputs so no \n */ cp = aceInCard (fi); if (aceInEOF(fi)) return FALSE; return TRUE; } /* aceInPrompt */ BOOL aceInOptPrompt (ACEIN fi, int *keyp, FREEOPT *options) /* Using a prompt we get a selection from the user * fi - (only used if text-I/O) * input used to get the choice from the user (e.g. STDIN) * * kpt - pointer in which the choice is returned, * refers to the option's KEY in the FREEOPT-options * options - FREEOPT array of possible choices * The text of the first entry is the prompt-text * Any option that would have the same effect as * an EOF on the input should have the option-key (-1) * * RETURNS: * TRUE - if a choice was made. The choice is returned * in *keyp. * FALSE - choice was ambiguous or didn't match anything in * options. *keyp is left untouched. */ { BOOL answer; char *cp; messfree(fi->stream[fi->streamlevel].prompt); fi->stream[fi->streamlevel].prompt = halloc(strlen(options[0].text)+3, fi->handle); strcpy(fi->stream[fi->streamlevel].prompt, options[0].text); strcat(fi->stream[fi->streamlevel].prompt, "> "); /* NB. if isInteractive is clear, we don't want a prompt. if we are using readline readline generates the prompt itself so we don't need to do it here. */ if (fi->isInteractive && !fi->useReadLine && fi->stream[fi->streamlevel].prompt && *fi->stream[fi->streamlevel].prompt ) fputs(fi->stream[fi->streamlevel].prompt,stdout ); /* fputs so no \n */ cp = aceInCard (fi); if (aceInEOF(fi)) /* input stream is finished (e.g. EOF character on STDIN) */ { *keyp = -1; /* we return true to recognise the EOF as an explicit * command. In this case we set the option to -1 * so the calling code can recognise this as the EOF * command, just like an explicit quit-command. */ answer = TRUE; } else { KEY key; /* Get the next word in the card and match it against the options * Note: if there's no word in the card it'll return FALSE */ answer = aceInKey (fi, &key, options) ; if (answer) *keyp = (int)key; } return answer; } /* aceInOptPrompt */ /************/ /* Returns TRUE if acein is a tty and caller did _not_ set interactive FALSE,*/ /* returns FALSE otherwise. */ /* */ /* Hence returns TRUE when: */ /* 1) readline is being used, readline can only be used with a tty). */ /* 2) readline is not used but acein is a tty and the caller did not set */ /* interactive false. */ /* The corollary of this is that pipes will _not_ be interactive, even if */ /* the acein was created with interactive TRUE, this is IMPORTANT for calling*/ /* tace from scripts, see tacemain.c where it decides whether to save the */ /* database. */ /* */ BOOL aceInIsInteractive (ACEIN fi) { BOOL interactive ; if (!aceInExists(fi)) messcrash("aceInIsInteractive() - received invalid fi pointer"); if (fi->useReadLine) interactive = TRUE ; else if (fi->isInteractive && fi->curr_fil && (isatty(fileno(fi->curr_fil)) == 1)) interactive = TRUE ; else interactive = FALSE ; return interactive ; } /* aceInIsInteractive */ /*******************/ BOOL aceInEOF (ACEIN fi) /* TRUE if we're at the end of the input */ /* Notice that stream level maybe 0, but there is still one card * left, this happens when fi is text-based for instance. */ { BOOL isEOF = FALSE; if (!aceInExists(fi)) messcrash("aceInEOF() - received invalid fi pointer"); if (fi->card == NULL) /* set to NULL by aceInCard, if streamlevel reaches 0 */ isEOF = TRUE; else if (fi->useReadLine && fi->streamlevel == 0) /* The ZERO streamlevel was generated by receiving * EOF on an interactive STDIN. We have to query useReadLine * because that's decided upon whether it is a real tty-device * rather than what the user decides */ /* This clause is important in deciding when the interactive * stream ends, because fi->card wouldn't be NULL until * aceInCard is called the next time round */ isEOF = TRUE; return isEOF; } /* aceInEOF */ /*******************/ void aceInSpecial (ACEIN fi, char* text) /* The text contains all characters that have special meaning in aceInCard(). * * Possible choices are "\n\t;/%\\@$" * The following actions will be performed upon inclusion * of the characters in the special-text for a particular stream. * \n - NEWLINE will terminate card (when parsing line-based text-files). * \t - TAB will be expanded to 8 spaces * ; - NEWLINE can be used a line-break, if multiline input is given on one command-line * / - COMMENT text after // until the enf-of-line will be ignored * % - PARAMETER, e.g. %1 will be replaced by the first parameter * \\ - if last char on line - used to break up single line input over multiple lines * and when "\n" (2 chars) should be treated as '\n' (1 newline char) */ { if (!aceInExists(fi)) messcrash("aceInSpecial() - received invalid fi pointer"); if (!text) messcrash ("aceInSpecial() - received NULL text") ; if (strlen(text) > 23) messcrash ("aceInSpecial() - received a string longer than 23") ; if (text != fi->stream[fi->streamlevel].special) strcpy (fi->stream[fi->streamlevel].special, text) ; memset (fi->special, 0, (mysize_t) 256) ; while (*text) fi->special [((int) *text++) & 0xFF] = TRUE ; fi->special[0] = TRUE ; /* ensures EOF recognition */ return; } /* aceInSpecial */ /********************/ void aceInForceCard (ACEIN fi, char *string) { if (!aceInExists(fi)) messcrash("aceInForceCard() - received invalid fi pointer"); aceInSetText (fi, string, "") ; aceInSpecial (fi, "") ; aceInCard (fi) ; return; } /* aceInForceCard */ /********************/ char* aceInCard (ACEIN fi) /* returns NULL when EOF is reached */ { char *in; char ch; char *cp ; int kpar ; FILE *fil ; BOOL acceptShell, acceptCommand ; if (!aceInExists(fi)) messcrash("aceInCard() - received invalid fi pointer"); restart : if (fi->streamlevel == 0) { fi->card = 0; /* important to recognise aceInEOF() */ return 0 ; } in = fi->card ; --in ; acceptCommand = fi->special['@'] ; acceptShell = fi->special['$'] ; while (TRUE) { if (++in >= fi->cardEnd) aceInExtend (fi, &in) ; aceInGetCharMacro(fi, *in) /* returns 0 if end-of-text or end-of-file */ lao: if (fi->special[((int) *in) & 0xFF] && *in != '$' && *in != '@' ) switch (*in) { case '\n': /* == '\x0a' */ case ';': /* card break for multiple commands on one line */ goto got_line ; case '\0': if (fi->stream[fi->streamlevel].fil && fi->stream[fi->streamlevel].fil != stdin && ! fi->stream[fi->streamlevel].isPipe) { /* mieg 20 nov 2004 */ long nn1, nn2 ; nn1 = ftell (fi->stream[fi->streamlevel].fil) ; fseek (fi->stream[fi->streamlevel].fil, 0, SEEK_END) ; nn2 = ftell (fi->stream[fi->streamlevel].fil) ; if (nn1 != nn2) messerror ("File %s aceincard hit an EOF at %ld before true EOF %ld" , fi->stream[fi->streamlevel].fname ? fi->stream[fi->streamlevel].fname : "" , nn1, nn2) ; } aceInClose(fi, fi->streamlevel) ; goto got_line; case '\t': /* tabs should get rounded to 8 spaces */ *in++ = ' ' ; while ((in - fi->card) % 8) { if (in >= fi->cardEnd) aceInExtend (fi, &in) ; *in++ = ' ' ; } --in ; continue ; case '/': /* // means start of comment */ aceInGetCharMacro(fi, ch) ; if (ch == '/') { do { /* skip the rest of this line */ aceInGetCharMacro(fi, ch) ; } while (ch != '\n' && ch != '\0'); goto got_line ; /* it'll return "" - an empty string */ } else { aceInUnGetChar (fi, ch); /* if (fi->stream[fi->streamlevel].fil) ungetc (ch, fi->stream[fi->streamlevel].fil) ; else --(fi->stream[fi->streamlevel].text) ; */ } break ; case '%': /* possible parameter */ --in ; kpar = 0 ; while ( isdigit ((int)(ch = aceInGetChar(fi))) ) kpar = kpar*10 + (ch - '0') ; if (kpar > 0 && kpar <= fi->stream[fi->streamlevel].npar) for (cp = stackText (fi->parStack, fi->stream[fi->streamlevel].parMark[kpar-1]) ; *cp ; ++cp) { if (++in >= fi->cardEnd) aceInExtend (fi, &in) ; *in = *cp ; } else messout ("Parameter %%%d cannot be substituted", kpar) ; if (++in >= fi->cardEnd) aceInExtend (fi, &in) ; *in = ch ; goto lao ; /* mieg */ case '\\': /* escapes next character - interprets \n */ *in = aceInGetChar(fi) ; if (*in == '\n') /* fold continuation lines */ { while ((ch = aceInGetChar(fi)) == ' ' || ch == '\t') ; /* remove whitespace at start of next line */ aceInUnGetChar (fi, ch); /* if (fi->stream[fi->streamlevel].fil) ungetc (ch, fi->stream[fi->streamlevel].fil) ; else --(fi->stream[fi->streamlevel].text) ; */ fi->stream[fi->streamlevel].line++ ; --in ; } #ifndef WIN32 else if (*in == 'n') /* reinterpret \n as a format */ { *in = '\n' ; } #endif /* !WIN32 */ else /* keep the \ till aceinword is called */ { *(in+1) = *in ; *in = '\\' ; if (++in >= fi->cardEnd) aceInExtend (fi, &in) ; } break ; default: messerror ("aceinsubs got unrecognised special character 0x%x = %c\n", *in, *in) ; } else { if (!isprint((int)*in) && *in != '\t' && *in != '\n') /* mieg dec 15 94 */ --in ; } } /* while TRUE loop */ got_line: fi->stream[fi->streamlevel].line++ ; *in = 0 ; fi->pos = fi->card ; _losewhite (fi) ; if (acceptCommand && _stepover (fi, '@')) /* command file */ { char *name ; if ((name = aceInWord (fi)) && (fil = filopen (name, "", "r"))) aceInSetFile (fi, fil, name, fi->pos) ; goto restart; } /* mieg - ?? can we accept shells in thread safe way ?? */ if (acceptShell && _stepover (fi, '$')) /* shell command */ { system ((char*)fi->pos) ; goto restart ; } if (fi->debug) fprintf (stderr, "aceInCard returns #%s#\n", fi->card ? fi->card : "zero") ; return fi->card ; } /* aceInCard */ /************************************************/ void aceInCardBack (ACEIN fi) /* goes back one card */ { if (!aceInExists(fi)) messcrash("aceInCardBack() - received invalid fi pointer"); fi->stream[fi->streamlevel].line-- ; aceInSetText (fi, fi->card, "") ; } /************************************************/ int aceInStreamLine (ACEIN fi) { if (!aceInExists(fi)) messcrash("aceInStreamLine() - received invalid fi pointer"); return fi->stream[fi->streamlevel].line ; } /************************************************/ BOOL aceInStreamLength (ACEIN fi, long int *length) { long int oldPos, endPos; if (!aceInExists(fi)) messcrash("aceInStreamLength() - received invalid fi pointer"); if (!length) messcrash("aceInStreamLength() - received NULL length pointer"); if (fi->stream[fi->streamlevel].isPipe) /* can't determine length of streams from pipes */ return FALSE; if (fi->stream[fi->streamlevel].text) /* stream comes from text-buffer, report its size */ { *length = (long int)strlen(fi->stream[fi->streamlevel].text); return TRUE; } if (fi->stream[fi->streamlevel].fil == NULL) return FALSE; if (fi->stream[fi->streamlevel].fil == stdin) return FALSE; oldPos = ftell (fi->stream[fi->streamlevel].fil); if (oldPos == -1) return FALSE; /* we should report ERRNO */ if (fseek (fi->stream[fi->streamlevel].fil, 0L, SEEK_END) == -1) return FALSE; /* we should report ERRNO */ endPos = ftell (fi->stream[fi->streamlevel].fil); if (endPos == -1) return FALSE; /* we should report ERRNO */ if (fseek (fi->stream[fi->streamlevel].fil, oldPos, SEEK_SET) == -1) return FALSE; /* we should report ERRNO */ *length = endPos; return TRUE; } /* aceInStreamLength */ BOOL aceInStreamPos (ACEIN fi, long int *pos) { long int filPos; if (!aceInExists(fi)) messcrash("aceInStreamLength() - received invalid fi pointer"); if (!pos) messcrash("aceInStreamLength() - received NULL pos pointer"); if (fi->stream[fi->streamlevel].isPipe) /* can't determine file-pos of streams from pipes */ return FALSE; if (fi->stream[fi->streamlevel].text) { *pos = (long int)(fi->stream[fi->streamlevel].text - fi->stream[fi->streamlevel].text_start); return TRUE; } if (fi->stream[fi->streamlevel].fil == NULL) return FALSE; if (fi->stream[fi->streamlevel].fil == stdin) return FALSE; filPos = ftell (fi->stream[fi->streamlevel].fil); if (filPos == -1) return FALSE; /* we should report ERRNO */ *pos = filPos; return TRUE; } /* aceInStreamPos */ /********************************************/ /* aceinword(), aceinwordcut() and aceinstep() are the only calls that directly move pos forward -- all others act via aceinword(). aceinback() moves pos back one word. */ char *aceInWord (ACEIN fi) { char *cw ; if (!aceInExists(fi)) messcrash("aceInWord() - received invalid fi pointer"); _losewhite (fi) ; /* needed in case of intervening aceinstep() */ if (_stepover (fi, '"')) { for (cw = fi->word ; !_stepover(fi, '"') && *(fi->pos) ; *cw++ = *(fi->pos)++) if (_stepover(fi, '\\')) /* accept next char unless end of line */ if (*fi->pos == '\0') break ; _losewhite (fi) ; *cw = 0 ; return (char*) fi->word ; /* always return a word, even if empty */ } /* default: break on space and \t, not on comma */ for (cw = fi->word ; isgraph ((int)*(fi->pos)) && *(fi->pos) != '\t' ; *cw++ = *(fi->pos)++) if (_stepover(fi, '\\')) /* accept next char unless end of line */ if (!*(fi->pos)) break ; _losewhite (fi) ; *cw = 0 ; if (*(fi->word)) return (char *)fi->word; return (char*)NULL; } /* aceInWord */ /************************************************/ char *aceInPath (ACEIN fi) { #ifdef __CYGWIN__ char *cw ; #endif /* __CYGWIN__ */ if (!aceInExists(fi)) messcrash("aceInPath() - received invalid fi pointer"); #ifdef __CYGWIN__ _losewhite (fi) ; /* needed in case of intervening aceinstep() */ if (_stepover (fi, '"')) { for (cw = fi->word ; !_stepover(fi, '"') && *(fi->pos) ; *cw++ = *(fi->pos)++) if (_stepover(fi, '\\')) /* accept next char unless end of line */ if (!*(fi->pos)) break ; _losewhite(fi) ; *cw = 0 ; return (char*) fi->word ; /* always return a word, even if empty */ } /* default: break on space, \t or end of line, not on comma also, does not skip over backslashes which are assumed to be MS DOS/Windows path delimiters */ for (cw = fi->word ; ( *(fi->pos) == '\\' || isgraph (*(fi->pos)) ) && *(fi->pos) != '\t' ; *cw++ = *(fi->pos)++) ; _losewhite(fi) ; *cw = 0 ; #else /* !__CYGWIN__*/ aceInWord(fi) ; #endif /* !__CYGWIN__ */ if (*fi->word) { char *cp = filGetFullPath (fi->word, 0); if (cp) { strncpy (fi->word, cp, fi->maxcard); fi->word[fi->maxcard-1] = '\0'; messfree(cp); } return (char*)fi->word; } return (char*)NULL; } /* aceInPath */ /************************************************/ char *aceInWordCut (ACEIN fi, char *cutset, char *cutter) /* Moves along card, looking for a character from cut, which is a * 0-terminated char list of separators. * Returns everything up to but not including the first match. * pos is moved one char beyond the character. * *cutter contains the char found, or if end of card is reached, 0. */ { char *cc,*cw ; if (!aceInExists(fi)) messcrash("aceInWordCut() - received invalid fi pointer"); for (cw = fi->word ; *fi->pos ; *cw++ = *fi->pos++) for (cc = cutset ; *cc ; ++cc) if (*cc == *fi->pos) goto wcut ; wcut: *cutter = *fi->pos ; if (*fi->pos) ++(fi->pos) ; _losewhite (fi) ; *cw = 0 ; if (*fi->word) return (char*)fi->word; return (char*)NULL; } /* aceInWordCut */ /************************************************/ void aceInBack (ACEIN fi) /* goes back one word - inefficient but reliable */ { char *now = fi->pos ; char *old = fi->pos ; if (!aceInExists(fi)) messcrash("aceInBack() - received invalid fi pointer"); fi->pos = fi->card ; _losewhite (fi) ; while (fi->pos < now) { old = fi->pos ; aceInWord (fi) ; } fi->pos = old ; return; } /* aceInBack */ /************************************************/ /* Read a word representing an int from wherever acein is pointing to. */ /* */ /* If there is no word OR the word cannot be converted to an int, reset */ /* the acein pos, don't set the int param. and return FALSE */ /* If the word is "NULL" set int param to the POSIX "too small" int value */ /* and return TRUE */ /* Otherwise set the int param to the converted int and return TRUE */ /* */ /* Note that valid range of ints is INT_MIN < valid < INT_MAX */ /* otherwise UT_NON_INT doesn't work. */ /* */ BOOL aceInInt (ACEIN fi, int *p) { BOOL result = FALSE ; char *keep ; enum {DECIMAL_BASE = 10} ; char *endptr ; long int bigint ; if (!aceInExists(fi)) messcrash("aceInInt() - received invalid fi pointer"); keep = fi->pos ; if (aceInWord (fi)) { /*printf ("aceInInt got '%s'\n", word) ;*/ if (strcmp((const char*)fi->word, "NULL") == 0) { *p = UT_NON_INT ; result = TRUE ; } else { errno = 0 ; bigint = strtol((char *)fi->word, &endptr, DECIMAL_BASE) ; if ((bigint == 0 && endptr == fi->word) /* first character wrong */ || (endptr != fi->word + strlen((const char*)fi->word)) /* some other character wrong */ || (errno == ERANGE) /* number too small/big for long int */ || (bigint <= INT_MIN || bigint >= INT_MAX)) /* number too small/big for int */ { fi->pos = keep ; return FALSE ; } else { *p = (int)bigint ; result = TRUE ; } } } else { fi->pos = keep ; result = FALSE ; } return result ; } /* aceinInt */ /*****************************/ /* Read a word representing a float from wherever acein is pointing to. */ /* */ /* If there is no word OR the word cannot be converted to a float, reset */ /* the acein pos, don't set the float param. and return FALSE */ /* If the word is "NULL" set float param to the POSIX "too small" float value*/ /* and return TRUE */ /* Otherwise set the float param to the converted float and return TRUE */ /* */ /* Note that valid range of floats is: */ /* -ve -FLT_MAX < valid < -FLT_MIN */ /* +ve FLT_MIN < valid < FLT_MAX */ /* otherwise UT_NON_FLOAT doesn't work as a range check for applications. */ /* */ BOOL aceInFloat (ACEIN fi, float *p) { BOOL result = FALSE ; char *keep ; double bigfloat ; char *endptr ; if (!aceInExists(fi)) messcrash("aceInFloat() - received invalid fi pointer"); keep = fi->pos ; if (aceInWord (fi)) { if (strcmp ((const char*)fi->word, "NULL") == 0) { *p = UT_NON_FLOAT ; /* UT_NON_FLOAT = -FLT_MAX */ result = TRUE ; } else { errno = 0 ; bigfloat = strtod((const char*)fi->word, &endptr) ; if ((bigfloat == +0.0 && endptr == fi->word) /* first character wrong */ || (endptr != fi->word + strlen((const char*)fi->word)) /* some other character wrong */ || (errno == ERANGE) /* number too small/big for double */ || (bigfloat < 0 && (bigfloat >= -FLT_MIN || bigfloat <= -FLT_MAX)) || (bigfloat > 0 && (bigfloat <= FLT_MIN || bigfloat >= FLT_MAX))) { /* number too small/big for float */ fi->pos = keep ; result = FALSE ; } else { *p = (float)bigfloat ; result = TRUE ; } } } else { fi->pos = keep ; result = FALSE ; } return result ; } /* aceinFloat */ /**************************************************/ /* Read a word representing a double from wherever acein is pointing to. */ /* */ /* If there is no word OR the word cannot be converted to a double, reset */ /* the acein pos, don't set the double param. and return FALSE */ /* Otherwise set the double param to the converted double and return TRUE */ /* */ /* Note that valid range of doubles is: */ /* -ve -DBL_MAX < valid < -DBL_MIN */ /* +ve DBL_MIN < valid < DBL_MAX */ /* otherwise UT_NON_DOUBLE doesn't work as a range check for applications. */ /* */ /* Note that because double is the largest number we can only check to see */ /* if the converted number is equal to this, not >= as in the case of floats.*/ /* */ BOOL aceInDouble (ACEIN fi, double *p) { BOOL result = FALSE ; char *keep ; double bigfloat ; char *endptr ; if (!aceInExists(fi)) messcrash("aceInDouble() - received invalid fi pointer"); keep = fi->pos ; if (aceInWord(fi)) { if (strcmp ((const char*)fi->word, "NULL") == 0) { *p = UT_NON_DOUBLE ; /* UT_NON_DOUBLE = -DBL_MAX */ result = TRUE ; } else { errno = 0 ; bigfloat = strtod((const char*)fi->word, &endptr) ; if ((bigfloat == +0.0 && endptr == fi->word) /* first character wrong */ || endptr != fi->word + strlen((const char*)fi->word) /* some other character wrong */ || (errno == ERANGE) /* number too small/big for double */ || (bigfloat < 0 && (bigfloat == -DBL_MIN || bigfloat == -DBL_MAX)) || (bigfloat > 0 && (bigfloat == DBL_MIN || bigfloat == DBL_MAX))) { /* number too small/big. */ fi->pos = keep ; result = FALSE ; } else { *p = bigfloat ; result = TRUE ; } } } else { fi->pos = keep ; result = FALSE ; } return result ; } /* aceInDouble */ /*************************************************/ BOOL aceInKey (ACEIN fi, KEY *keyp, FREEOPT *options) { char *keep; int n = 0 ; if (!aceInExists(fi)) messcrash("aceInKey() - received invalid fi pointer"); keep = fi->pos ; if (!aceInWord(fi)) return FALSE ; n = aceInKeyMatch (fi, fi->word, keyp, options) ; switch (n) { case 2: return TRUE; case 1: messout ("Keyword %s is ambiguous\n", fi->word) ; break ; case 0: messout ("Keyword %s does not match\n", fi->word) ; break ; } fi->pos = keep ; return FALSE ; } /* aceInKey */ /*****************/ /* Return the text corresponding to the key */ char *aceInKey2Text (KEY k, FREEOPT *o) { int i = o->key ; char *title = o->text ; if (i<0) messcrash("aceInKey2Text() - Negative number of options") ; while (o++, i--) if (o->key == k) return (o->text) ; return title ; } /* aceInKey2Text */ /***************************************************/ BOOL aceInQuery (ACEIN fi, ACEOUT fo, char *query) { if (!aceInExists(fi)) messcrash("aceInQuery() - received invalid fi pointer"); if (fi->debug) fprintf (stderr,"aceInQuery %s\n", query) ; if (aceInIsInteractive(fi)) { int retval; char answer; aceOutPrint (fo, "%s (y or n) ",query) ; answer = aceInGetChar(fi) ; retval = (answer == 'y' || answer == 'Y') ? TRUE : FALSE ; while (answer != '\0' && answer != '\n') answer = aceInGetChar(fi) ; return retval ; } return TRUE ; } /* aceInQuery */ /*************************************/ int aceInFmtLength (char *fmt) { char *cp ; int length = 0 ; if (isdigit((int)*fmt)) { sscanf (fmt,"%d",&length) ; return length ; } for (cp = fmt ; *cp ; ++cp) switch (*cp) { case 'i' : case 'f' : case 'd' : length += 8 ; break ; case 'w' : length += 32 ; break ; case 't' : length += 80 ; break ; case 'o' : if (*++cp) messcrash ("'o' can not end acein format %s",fmt) ; length += 2 ; break ; } if (!length) length = 40 ; return length ; } /* aceInFmtlength */ /****************/ BOOL aceInCheck (ACEIN fi, char *fmt) /* checks that whatever is in card fits specified format note that 't' format option changes card by inserting a '"' */ { char *keep; union {int i ; float r ; double d ;} target ; char *fp ; char *start ; int nquote = 1 ; if (!aceInExists(fi)) messcrash("aceInCheck() - received invalid fi pointer"); keep = fi->pos; for (fp = fmt ; *fp ; ++fp) switch (*fp) { case 'w' : if (aceInWord (fi)) break ; else goto retFALSE ; case 'i' : if (aceInInt (fi, &target.i)) break ; else goto retFALSE ; case 'f' : if (aceInFloat (fi, &target.r)) break ; else goto retFALSE ; case 'd' : if (aceInDouble (fi, &target.d)) break ; else goto retFALSE ; case 't' : /* must insert '"' and escape any remaining '"'s or '\'s */ for (start = fi->pos ; *fi->pos ; ++(fi->pos)) if (*(fi->pos) == '"' || *(fi->pos) == '\\') ++nquote ; *(fi->pos + nquote + 1) = '"' ; /* end of line */ for ( ; fi->pos >= start ; --(fi->pos)) { *(fi->pos + nquote) = *(fi->pos) ; if (*(fi->pos) == '"' || *(fi->pos) == '\\') *(fi->pos + --nquote) = '\\' ; } *start = '"' ; goto retTRUE ; case 'z' : if (aceInWord (fi)) goto retFALSE ; else goto retTRUE ; case 'o' : if (!*++fp) messcrash ("'o' can not end acein format %s",fmt) ; aceInStep (fi, *fp) ; break ; case 'b' : break; /* special for graphToggleEditor no check needed il */ default : if (!isdigit((int)*fp) && !isspace((int)*fp)) messerror ("unrecognised char %d = %c in acein format %s", *fp, *fp, fmt) ; } retTRUE: fi->pos = keep ; return TRUE ; retFALSE: fi->pos = keep ; return FALSE ; } /* aceInCheck */ /************************ little routines ************************/ BOOL aceInStep (ACEIN fi, char x) { if (!aceInExists(fi)) messcrash("aceInStep() - received invalid fi pointer"); return (*(fi->pos) && aceInUpper (*(fi->pos)) == x && (fi->pos)++) ; } void aceInNext (ACEIN fi) { _losewhite (fi) ; } char ACEIN_UPPER[] = { 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, 16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31, 32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47, 48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63, 64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79, 80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95, 96,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79, 80,81,82,83,84,85,86,87,88,89,90,123,124,125,126,127 } ; char ACEIN_LOWER[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127 } ; char* aceInPos (ACEIN fi) /* cheat to give pos onwards - i.e. returns rest-of-line */ { if (!aceInExists(fi)) messcrash("aceInPos() - received invalid fi pointer"); return (char*) fi->pos ; } /* aceInPos */ /****************** little arithmetic routines ************************/ /* 1.3 -> 1 ; 1.7 -> 2 * -1.3 -> -1 ; -1.7 -> -2 */ int aceInArrondi (float x) { if (x >= 0) return (int) (x + 0.5) ; else return (int) (x - 0.5) ; } /* aceInArrondi */ /********************************************/ /* returns 1, 2, 5, 10, 20, 50, 100 etc * in absolute value the returned number is smaller than p * 19 -> 10 ; -19 -> -10 */ int aceMainPart (float p) { register int i = 1, sign = 1; if (!p) return 0 ; if (p < 0) { sign = -1 ; p = -p ; } while(i <= p + .00001) i = 10 * i; i /= 10 ; if (2 * i > p) return i * sign; if(5 * i > p) return 2 * i * sign; return 5*i*sign; } /* aceInMainPart */ /********************************************/ /* returns 1, 2, 5, 10, 20, 50, 100 etc * but the returned number may be a bit bigger than p * 19 -> 20 ; -19 -> -20 */ int aceMainRoundPart (float p) { register int i = 1, sign = 1; if (!p) return 0 ; if (p < 0) {sign = -1 ; p = -p ; } /* RD: ambiguous without spaces on SGI */ while (i < p + .1) i = 10 * i; if (4 * i < 5 * p) return i * sign; i /= 2; if (4 * i < 5 * p) return i * sign; i = (2 * i) / 5; if (4 * i < 5 * p) return i * sign; i = i/2; return i * sign; } /* aceInMainRoundPart */ /*************************************************************************/ /* returns 1 , 2 , 5 ,10 , 20, 50 ,100 etc */ double aceDoubleMainPart (double p) { register double i = 1, sign = 1; if (!p) return 0.; if(p < 0) {sign = -1; p = -p;} i = (double) exp(log((double)10.0) * (double)(1 + (int)(log10((double)p)))) ; if (4 * i < 5 * p) return i * sign; i /= 2; if (4 * i < 5 * p) return i * sign; i = (2 * i) / 5; if (4 * i < 5 * p) return i*sign; i = i/2; return i*sign; } /* aceInDoubleMainPart */ /*************************************************************************/ /*************************************************************************/ /* It's sometimes necessary to quote parts of the text so it doesn't get */ /* interpreted too literally (i.e. you may want to keep \n as "\n"). The */ /* aceInProtect() routine will do this. But then you will probably need to */ /* unquote the text at some time. */ /* */ /* Quoting protects text by putting \" at the start and end of the text and */ /* \\ in front of any special chars. */ /* - sometimes you want to completely reverse this - use aceInUnprotect() */ /* to do this. */ /* - sometimes you just want to remove the leading and trailing \", use */ /* aceInUnprotectQuote() to do this. */ /* */ char* aceInUnprotect(ACEIN fi, char *text) { char *result = NULL ; result = doUnprotect(fi, text, FALSE) ; return result ; } char *aceInUnprotectQuote(ACEIN fi, char *text) { char *result = NULL ; result = doUnprotect(fi, text, TRUE) ; return result ; } static char *doUnprotect(ACEIN fi, char *text, BOOL just_quotes) { Array a; char *cp, *cp0, *cq ; int n = 2*(1+strlen(text)) ; if (!aceInExists(fi)) messcrash("aceInUnprotect() - received invalid fi pointer"); a = fi->buf; if (a) a = arrayReCreate (a, n + 1, char) ; else a = fi->buf = arrayHandleCreate (n + 1, char, fi->handle) ; array (a, n, char) = 0 ; /* ensure long enough */ strcpy (arrp(a, 0, char), text) ; /* remove leading white space, first quotes and any more white space. */ cp = arrp(a, 0, char) ; while (*cp == ' ' || *cp == '\t') cp++ ; if (*cp == '"') cp++ ; while (*cp == ' ' || *cp == '\t') cp++ ; /* remove trailing white space, last quotes and any more white space. */ cq = cp + strlen(cp) - 1 ; while (cq > cp && (*cq == ' ' || *cq == '\t')) *cq-- = 0 ; if (*cq == '"') /* remove one unprotected quote */ { int i = 0 ; char *cr = cq - 1 ; while (cr > cp && *cr == '\\') { i++ ; cr-- ; } if ( i%2 == 0) *cq-- = 0 ; /* discard */ } while (cq > cp && (*cq == ' ' || *cq == '\t')) *cq-- = 0 ; /* Optionally gobble the \ as well as the " */ if (just_quotes) cp0 = cp ; else { cp0 = cq = cp-- ; while (*++cp) switch (*cp) { case '\\': if (*(cp+1) == '\\') { cp++ ; *cq++ = '\\' ; break ;} if (*(cp+1) == '\n') { cp ++ ; break ; } /* skip backslash-newline */ if (*(cp+1) == 'n') { cp ++ ; *cq++ = '\n' ; break ; } break ; default: *cq++ = *cp ; } *cq = 0 ; /* terminate the string */ } return cp0 ; } /* aceInUnprotect */ /****************************************/ char* aceInProtect (ACEIN fi, char* text) /* aceinword will read result back as text */ { Array a; char *cp, *cq ; int n = 2*(1+strlen(text)) ; if (!aceInExists(fi)) messcrash("aceInProtect() - received invalid fi pointer"); a = fi->buf; if (a) a = arrayReCreate (a, n + 1, char) ; else a = fi->buf = arrayHandleCreate (n + 1, char, fi->handle) ; array (a, n, char) = 0 ; /* ensure long enough */ cq = arrp (a, 0, char) ; *cq++ = '"' ; for (cp = text ; *cp ; *cq++ = *cp++) { if (*cp == '\\' || *cp == '"' || /* protect these */ *cp == '/' || *cp == '%' || *cp == ';' || *cp == '\t' || *cp == '\n') *cq++ = '\\' ; if (*cp == '\n') {*cq++ = 'n' ; *cq++ = '\\' ; } /* -> /n/n (text then real) */ } *cq++ = '"' ; *cq = 0 ; return arrp (a, 0, char) ; } /* aceInProtect */ /****************************************/ char* aceInJavaProtect (ACEIN fi, char* text) { Array a; char *cp, *cq ; int n = 2*(1+strlen(text)) ; if (!aceInExists(fi)) messcrash("aceInJavaProtect() - received invalid fi pointer"); a = fi->buf; if (a) a = arrayReCreate (a, n + 1, char) ; else a = fi->buf = arrayHandleCreate (n + 1, char, fi->handle) ; array (a, n, char) = 0 ; /* ensure long enough */ cq = arrp (a, 0, char) ; cp = text; while (*cp) switch (*cp) { case '\n': *cq++ = '\\'; *cq++ = 'n'; cp++; break; case '\\': case '?': *cq++ = '\\' ; /* fall thru */ default: *cq++ = *cp++; } *cq = 0 ; return arrp (a, 0, char) ; } /* aceInJavaProtect */ /****************************************************************** ************************ private functions *********************** ******************************************************************/ static ACEIN aceInCreate (STORE_HANDLE handle) /* generic constructor isn't public - we can only make an * ACEIN object from a file/pipe or the like */ { static int total_num_created = 0; /* for debug */ ACEIN fi; fi = (ACEIN)halloc (sizeof (struct AceInStruct), handle); blockSetFinalise (fi, aceInFinalise); fi->magic = &ACEIN_MAGIC; fi->handle = handleCreate(); /* killed in aceInFinalise */ fi->id = ++total_num_created; fi->streamlevel = 0 ; fi->stream[fi->streamlevel].fil = NULL ; fi->stream[fi->streamlevel].text = fi->stream[fi->streamlevel].text_start = NULL ; fi->stream[fi->streamlevel].RLtext = NULL ; fi->stream[fi->streamlevel].prompt = NULL ; fi->maxcard = MAXCARD ; aceInSpecial (fi, "\n\t\\/@") ; fi->card = (char *)halloc (fi->maxcard, fi->handle) ; fi->cardEnd = fi->card + fi->maxcard - 1 ; fi->pos = fi->card ; fi->word = (char *)halloc (fi->maxcard, fi->handle) ; fi->parStack = stackHandleCreate (128, fi->handle) ; fi->useReadLine = FALSE; fi->isInteractive = FALSE; fi->curr_fil = NULL ; #ifdef DEBUG_STREAMLEVEL fi->debug = TRUE; #else /* !DEBUG_STREAMLEVEL */ fi->debug = FALSE; #endif /* !DEBUG_STREAMLEVEL */ return fi ; } /* aceInCreate */ static void aceInSetText (ACEIN fi, char *string, char *parms) /* switch fi to parse from a text-buffer */ { if (!aceInExists(fi)) messcrash("aceInSetText() - received invalid fi pointer"); aceInNewStream (fi, parms) ; fi->stream[fi->streamlevel].text = fi->stream[fi->streamlevel].text_start = string ; fi->stream[fi->streamlevel].fname = strnew("text://", fi->handle); if (fi->debug) printf ("DEBUG open stream %d(%d) : %s\n", fi->id, fi->streamlevel, fi->stream[fi->streamlevel].fname); fi->curr_fil = NULL ; return ; } /* aceInSetText */ #ifndef NO_READLINE static void aceInSetReadLine (ACEIN fi, char *parms) { if (!aceInExists(fi)) messcrash("aceInSetReadLine() - received invalid fi pointer"); aceInNewStream (fi, parms) ; fi->stream[fi->streamlevel].text = ""; fi->stream[fi->streamlevel].fname = strnew("readline://", fi->handle); fi->useReadLine = TRUE; if (fi->debug) printf ("DEBUG open stream %d(%d) : %s\n", fi->id, fi->streamlevel, fi->stream[fi->streamlevel].fname); fi->curr_fil = NULL ; return ; } /* aceInSetReadLine */ #endif /*NO_READLINE */ static void aceInSetFile (ACEIN fi, FILE *fil, char *fname, char *parms) /* switch fi to read from the contents of a file */ { if (!aceInExists(fi)) messcrash("aceInSetFile() - received invalid fi pointer"); if (!fil) messcrash("aceInSetFile() - NULL fil"); if (!fname) messcrash("aceInSetFile() - NULL fname"); aceInNewStream (fi, parms) ; fi->stream[fi->streamlevel].fil = fil ; fi->stream[fi->streamlevel].fname = strnew(fname, fi->handle); if (fi->debug) printf ("DEBUG open stream %d(%d) : %s\n", fi->id, fi->streamlevel, fi->stream[fi->streamlevel].fname); fi->curr_fil = fil ; return ; } /* aceInSetFile */ static void aceInSetPipe (ACEIN fi, FILE *fil, char *parms) /* switch fi to read contents of a pipe - parse program results etc. */ { if (!aceInExists(fi)) messcrash("aceInSetPipe() - received invalid fi pointer"); if (!fil) messcrash("aceInSetPipe() - NULL fil"); aceInNewStream (fi, parms) ; fi->stream[fi->streamlevel].fil = fil ; fi->stream[fi->streamlevel].isPipe = TRUE ; fi->curr_fil = fil ; return ; } /* aceInSetPipe */ /*******************/ static void aceInFinalise (void *block) /* called when an ACEIN struct is cleaned up, either it is being * messfree'd explicitly or its parent handle is being destroyed */ { ACEIN fi = (ACEIN)block; if (!aceInExists(fi)) messcrash("aceInFinalise() - received invalid block pointer"); aceInClose (fi, 1); /* close all levels */ /* the handle contains all its associated stacks, buffers etc. */ messfree(fi->handle); fi->magic = 0; /* taint this memory area as freed * future access to this memory block * will trap aceInExists-assertions */ return ; } /* aceInFinalise */ static BOOL aceInExists (ACEIN fi) /* verify the validity of an ACEIN pointer */ { if (fi && fi->magic == &ACEIN_MAGIC) return TRUE; return FALSE; } /* aceInExists */ static void aceInNewStream (ACEIN fi, char *parms) { int kpar ; if (fi->streamlevel == MAXSTREAM) messcrash("Maximum number of streams (%d) exceeded in ACEIN", MAXSTREAM) ; else { fi->streamlevel++; memset (&(fi->stream[fi->streamlevel]), 0, sizeof(STREAM)) ; strcpy (fi->stream[fi->streamlevel].special, fi->stream[fi->streamlevel-1].special) ; fi->stream[fi->streamlevel].npar = 0 ; fi->stream[fi->streamlevel].line = 1 ; if (parms && strlen(parms) > 0) { fi->pos = parms ; /* abuse aceinword() to get parms */ for (kpar = 0 ; kpar < MAXNPAR && aceInWord (fi) ; kpar++) /* read parameters */ { fi->stream[fi->streamlevel].parMark[kpar] = stackMark (fi->parStack); pushText (fi->parStack, fi->word) ; } fi->stream[fi->streamlevel].npar = kpar ; fi->stream[fi->streamlevel].isPipe = FALSE ; fi->pos = fi->card ; /* restore pos to start of blank card */ *(fi->card) = 0 ; } } return ; } /* aceInNewStream */ /******************************/ static void aceInClose (ACEIN fi, int level) { int kpar ; if (!aceInExists(fi)) messcrash("aceInClose() - received invalid fi pointer"); while (fi->streamlevel >= level) { if (fi->debug) printf ("DEBUG close stream %d(%d) : %s%s\n", fi->id, fi->streamlevel, fi->stream[fi->streamlevel].isPipe ? "PIPE " : "", fi->stream[fi->streamlevel].fname); if (fi->stream[fi->streamlevel].fil) { if (fi->stream[fi->streamlevel].isPipe) pclose (fi->stream[fi->streamlevel].fil) ; else filclose (fi->stream[fi->streamlevel].fil) ; } if (fi->stream[fi->streamlevel].RLtext) free(fi->stream[fi->streamlevel].RLtext); for (kpar = fi->stream[fi->streamlevel].npar ; kpar-- ;) popText (fi->parStack) ; --(fi->streamlevel) ; if (fi->streamlevel >= 0) aceInSpecial (fi, fi->stream[fi->streamlevel].special) ; } /* Must reset for current level of acein */ if (fi->stream[fi->streamlevel].fil) fi->curr_fil = fi->stream[fi->streamlevel].fil ; else fi->curr_fil = NULL ; return; } /* aceInClose */ /******************************/ static void aceInExtend (ACEIN fi, char **pin) { /* only happens when getting card */ char *oldCard = fi->card ; fi->maxcard *= 2 ; fi->card = (char *)halloc (fi->maxcard, fi->handle); if (oldCard) /* jtm june 22, 1992 */ memcpy (fi->card, oldCard, fi->maxcard/2) ; fi->cardEnd = fi->card + fi->maxcard - 1 ; *pin += (int)(fi->card - oldCard) ; messfree (oldCard) ; messfree (fi->word) ; fi->word = (char *)halloc (fi->maxcard, fi->handle); return; } /* aceInExtend */ static char aceInGetChar (ACEIN fi) /* read another character from 'fi'. * We have to make sure only to return valid 'char'-values. * therefore EOF has to be cast to NULL-character, because * EOF is typically -1, which is not a valid 'char'-value. */ { char ch; if (fi->curr_fil) { int c = getc(fi->curr_fil); if (c == EOF) ch = '\0'; else ch = (char)c; } else if (*(fi->stream[fi->streamlevel].text)) { ch = *(fi->stream[fi->streamlevel].text++); } #ifndef NO_READLINE else if (fi->useReadLine) { if (fi->stream[fi->streamlevel].RLtext) { /* reached on on readline: return /n and set up for new call */ free(fi->stream[fi->streamlevel].RLtext); fi->stream[fi->streamlevel].RLtext = 0; fi->stream[fi->streamlevel].text = ""; ch = '\n'; } else { /* new call to readline */ fi->stream[fi->streamlevel].text = fi->stream[fi->streamlevel].RLtext = readline(fi->stream[fi->streamlevel].prompt ? fi->stream[fi->streamlevel].prompt : ""); if (!fi->stream[fi->streamlevel].RLtext) /* EOF typed */ { fi->stream[fi->streamlevel].text = ""; ch = '\0'; } else if (!(*(fi->stream[fi->streamlevel].RLtext))) /* empty line typed */ { /* make sure we get called straight away again */ fi->stream[fi->streamlevel].text = ""; free(fi->stream[fi->streamlevel].RLtext); fi->stream[fi->streamlevel].RLtext = 0; ch = '\n'; } else { add_history(fi->stream[fi->streamlevel].text); ch = *(fi->stream[fi->streamlevel].text++); } } } #endif /*NO_READLINE */ else ch = '\0'; return ch; } /* aceInGetChar */ static void aceInUnGetChar (ACEIN fi, char ch) /* push back a character */ { if (fi->stream[fi->streamlevel].fil) /* NOTE: only 4 bytes of pushback are guaranteed */ ungetc ((int)ch, fi->stream[fi->streamlevel].fil) ; else --(fi->stream[fi->streamlevel].text) ; return; } /* aceInUnGetChar */ /* This routine compares *cp to the first word (i.e. the keyword) of each * option->text string. The routine can return the follwing values: * * 0 : no match at all. * 1 : ambiguous, *cp matches more then one options keyword. * 2 : exact between *cp and an options keyword or just one inexact match, * in this case *keyp is filled with the options->key for that match. */ static int aceInKeyMatch (ACEIN fi, char *cp, KEY *keyp, FREEOPT *options) { char *io, *iw ; int nopt = (int)options->key ; KEY key ; BOOL finished ; int match ; if (!aceInExists(fi) || !cp || !keyp || !nopt) messcrash("aceInKeyMatch() - received bad parameters: %s%s%s%s", !aceInExists(fi) ? "invalid fi pointer" : "", !cp ? " NULL *cp pointer" : "", !keyp ? " NULL *keyp pointer" : "", !nopt ? " empty FREEOPT array" : "") ; key = KEY_UNDEFINED ; match = 0 ; /* default is no match. */ finished = FALSE ; while (!finished) { iw = cp ; io = (++options)->text ; while (aceInUpper (*iw++) == aceInUpper(*io++)) { if (!*iw) { if (*io != ' ') { if (key == KEY_UNDEFINED) { match = 2 ; /* possible single inexact match. */ key = options->key ; } else { match = 1 ; /* More than one inexact match. */ } } else { match = 2 ; /* exact match. */ finished = TRUE ; key = options->key ; } break ; } } if (!--nopt) finished = TRUE ; } /* Only return key for exact match or SINGLE inexact match. */ if (match == 2) *keyp = key ; return match ; } /************************************************************/ ACEIN aceInCreateFromCompressedFile (char *filename, char *params, STORE_HANDLE handle) { int n; char type = '\0'; ACEIN fi = NULL; char args[MAXPATHLEN+10]; if (!filename) messcrash("aceInCreateFromCompressedFile() - NULL filename"); n = strlen(filename); if (n > 4 && strcmp(filename+n-4, ".zip") == 0) type = 'z' ; if (n > 3 && strcmp(filename+n-3, ".gz") == 0) type = 'g' ; else if (n > 2 && strcmp(filename+n-2, ".Z") == 0) type = 'Z' ; switch (type) { case 'z': /* .zip - winzip */ sprintf (args, " -p %s", filename); fi = aceInCreateFromScriptPipe ("unzip", args, params, handle); if (!fi) fi = aceInCreateFromScriptPipe ("pkunzip", args, params, handle); break; case 'g': /* .gz - gzip */ sprintf (args, " -dc %s", filename); fi = aceInCreateFromScriptPipe ("gzip", args, params, handle); if (!fi) { sprintf (args, " -c %s", filename); fi = aceInCreateFromScriptPipe ("gunzip", args, params, handle); } break; case 'Z': /* .Z - compress */ sprintf (args, " -dc %s", filename); fi = aceInCreateFromScriptPipe ("gzip", args, params, handle); if (!fi) { sprintf (args, " -c %s", filename); fi = aceInCreateFromScriptPipe ("gunzip", args, params, handle); } if (!fi) { sprintf (args, " %s", filename); fi = aceInCreateFromScriptPipe ("zcat", args, params, handle); } break; default:; /* not a compressed file */ } /* even if we recognised a compression extension, this may still * be NULL if the scriptPipe failed */ return fi; } /* aceInCreateFromCompressedFile */ /*********** end of file *****************/ acedb-4.9.39+dfsg.01/w1/aceout.c0000444000175000017500000006320307716653021015660 0ustar moellermoeller/* File: aceout.c * Author: Danielle et jean Thierry-Mieg (mieg@mrc-lmba.cam.ac.uk) * Copyright (C) J Thierry-Mieg and R Durbin, 1995 * ------------------------------------------------------------------- * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * ------------------------------------------------------------------- * This file is part of the ACEDB genome database package, written by * Richard Durbin (MRC LMB, UK) rd@sanger.ac.uk, and * Jean Thierry-Mieg (CRBM du CNRS, France) mieg@crbm.cnrs-mop.fr * * Description: threadsafe version of freeout * Exported functions: see aceio.h * HISTORY: * Last edited: Aug 1 12:02 2003 (rnc) * * Dec 8 14:15 2000 (edgrif): Replace the static buffer with a * dynamic resizing one, needed because sometimes we * have to output single huge strings (e.g. dna object). * Created: Sun Aug 30 1999 (mieg) * CVS info: $Id: aceout.c,v 1.27 2003/08/14 09:27:45 rnc Exp $ *------------------------------------------------------------------- */ #include #include #include /* provide incomplete (public) type */ /************************************************************/ /* We used to have a huge buffer within the aceout struct because we didn't */ /* want to fail all the time. Now, with dynamic buffers we can afford to be */ /* more parimonious I think. */ /* */ enum {ACEOUT_INITIAL_BUFSIZE = 16384} ; static magic_t ACEOUT_MAGIC = "ACEOUT"; struct AceOutStruct /* complete opaque type */ { magic_t *magic ; /* == &ACEOUT_MAGIC */ FILE *fil; /* internal - belongs to this struct */ char *filename; Stack s ; /* belongs to calling code */ int buf_len ; char *buf ; int line ; /* line number */ int pos ; /* char number in line */ long int byte ; /* total byte length */ STORE_HANDLE handle; } AceOutRec ; static magic_t ACETMP_MAGIC = "ACETMP"; struct AceTmpStruct { magic_t *magic; /* == &ACETMP_MAGIC */ ACEOUT fo; char *filename; /* the actual tmp filename. */ BOOL remove ; /* default TRUE => remove tmp files when ACETMP is destroyed. */ }; /***************/ static BOOL aceOutExists (ACEOUT fo); static ACEOUT aceOutSetFileStack (FILE *fil, Stack s, STORE_HANDLE handle); static void aceOutCloseFileStack(ACEOUT fo) ; static void aceOutFinalise (void *block); static int aceOutBuffer (ACEOUT fo, char *text); /* returns errno */ static void aceTmpFinalise (void *block); static BOOL aceTmpExists (ACETMP atmp); static void increaseBuffer(ACEOUT fo, int bytes_needed) ; /****************************************************************** ************************* public functions *********************** ******************************************************************/ ACEOUT aceOutCreateToFile (char *filename, const char *spec, STORE_HANDLE handle) /* spec is one of "w", "wb", "a" or "ab" */ { FILE *fil; ACEOUT fo = NULL; if (!filename) messcrash("aceOutCreateToFile() - NULL filename"); if (!spec) messcrash("aceOutCreateToFile() - NULL spec"); if (!(spec[0] == 'w' || spec[0] == 'a')) messcrash("aceOutCreateToFile() - non-'w' or 'a' spec"); fil = filopen(filename, "", (char*)spec); /* NOTE, will messerror on failure */ if (fil) { fo = aceOutSetFileStack (fil, 0, handle); fo->filename = strnew (filename, handle); } return fo; } /* aceOutCreateToFile */ ACEOUT aceOutCreateToURL (char *url, const char *spec, STORE_HANDLE handle) { ACEOUT fo = NULL; if (!url) messcrash("aceOutCreateToURL() - NULL url"); if (!spec) messcrash("aceOutCreateToURL() - NULL spec"); if (!(spec[0] == 'w' || spec[0] == 'a')) messcrash("aceOutCreateToURL() - non-'w' or 'a' spec"); if (strlen(url) > 8 && strncmp(url, "mailto:", 7) == 0) { char *address = url + 7; fo = aceOutCreateToMail (address, handle); } else if (strcmp(url, "stdout://") == 0) { fo = aceOutCreateToStdout (handle); } else if (strcmp(url, "stderr://") == 0) { fo = aceOutCreateToStderr (handle); } else if (strcmp(url, "stack://") == 0) { /* The word stack may be misleading, and after all it only * represents an extensible text-buffer */ messerror ("Cannot re-open output that was " "printing to a text-buffer"); } else /* filename */ { fo = aceOutCreateToFile (url, spec, handle); } return fo; } /* aceOutCreateToURL */ ACEOUT aceOutCreateToChooser (char *prompt, char *directory, char *filename, const char *extension, const char *spec, STORE_HANDLE handle) { FILE *fil; ACEOUT fo = NULL; if (!directory) messcrash("aceOutCreateToChooser() - NULL directory"); if (!filename) messcrash("aceOutCreateToChooser() - NULL filename"); if (!spec) messcrash("aceOutCreateToChooser() - NULL spec"); if (!(spec[0] == 'w' || spec[0] == 'a')) messcrash("aceOutCreateToChooser() - non-'w' or 'a' spec"); fil = filqueryopen (directory, filename, (char*)extension, (char*)spec, prompt); if (!fil) return NULL; /* user clicked "Cancel" etc. */ fo = aceOutSetFileStack (fil, 0, handle); /**** now set the URL *****/ /* until filqueryopen can tell us in a better way whether it * wrote to a mailaddress we have to hack here */ { extern Associator mailAddress ; char *address; if (mailAddress && assFind (mailAddress, fil, &address)) { fo->filename = halloc(strlen("mailto:") + strlen(address) + 1, fo->handle); sprintf (fo->filename, "mailto:%s", address); return fo; } } /* Assemble pathname : * Note, the assembled filename will be * /. * the filename will NOT incorporate the extension, * because on a Save-FileChooser it isn't editable by the user. */ fo->filename = halloc (strlen(directory) + strlen(SUBDIR_DELIMITER_STR) + strlen(filename) + strlen(extension) + 2, fo->handle); strcpy (fo->filename, directory); strcat (fo->filename, SUBDIR_DELIMITER_STR); strcat (fo->filename, filename); if (extension != NULL && strlen(extension) > 0) { strcat (fo->filename, "."); strcat (fo->filename, extension); } return fo; } /* aceOutCreateToChooser */ ACEOUT aceOutCreateToMail (char *address, STORE_HANDLE handle) { FILE *fil; ACEOUT fo = NULL; if (!address) messcrash("aceOutCreateToMail() - NULL address"); fil = filmail(address); if (fil) { fo = aceOutSetFileStack (fil, 0, handle); fo->filename = halloc (strlen("mailto:") + strlen(address) + 1, fo->handle); sprintf(fo->filename, "mailto:%s", address); } return fo; } /* aceOutCreateToMail */ ACEOUT aceOutCreateToStdout (STORE_HANDLE handle) { ACEOUT fo = NULL; fo = aceOutSetFileStack (stdout, 0, handle); fo->filename = strnew("stdout://", fo->handle); return fo; } /* aceOutCreateToStdout */ ACEOUT aceOutCreateToStderr (STORE_HANDLE handle) { ACEOUT fo = NULL; fo = aceOutSetFileStack (stderr, 0, handle); fo->filename = strnew("stderr://", fo->handle); return fo; } /* aceOutCreateToStderr */ ACEOUT aceOutCreateToStack (Stack s, STORE_HANDLE handle) { ACEOUT fo = NULL; if (!stackExists(s)) messcrash("aceOutCreateToStack() - bad stack"); fo = aceOutSetFileStack (0, s, handle); fo->filename = strnew("stack://", fo->handle); return fo; } /************************************************/ ACEOUT aceOutCopy (ACEOUT source_fo, STORE_HANDLE handle) { ACEOUT new_fo; if (source_fo->fil) new_fo = aceOutSetFileStack (source_fo->fil, 0, handle); else new_fo = aceOutSetFileStack (0, source_fo->s, handle); new_fo->filename = strnew(source_fo->filename, handle); return new_fo; } /* aceOutCopy */ /* Rather than constantly allocate/deallocate an entire ACEOUT because you are * perhaps looping and need top reuse one, you can just set a new stack with * this function. */ void aceOutSetNewStack(ACEOUT fo, Stack s) { messAssert(aceOutExists(fo) && stackExists(s)) ; aceOutCloseFileStack(fo) ; fo->s = s ; return ; } /************************************************/ char *aceOutGetURL (ACEOUT fo) { return fo->filename; } /************************************************/ char *aceOutGetFilename(ACEOUT fo) { return fo->filename; } /************************************************/ void uAceOutDestroy (ACEOUT fo) /* only to be called via macro */ { if (!aceOutExists(fo)) messcrash("uAceOutDestroy() - received invalid fo pointer"); messfree (fo) ; /* trigger aceOutFinalise */ return ; } /* uAceOutDestroy */ /************************************************/ BOOL aceOutRewind (ACEOUT fo) /* will only work on files */ { BOOL result = FALSE; if (!aceOutExists(fo)) messcrash("aceOutRewind() - received invalid fo pointer"); if (fo->fil && fo->fil != stdout && fo->fil != stderr) { if (fseek(fo->fil, 0, SEEK_SET) == 0) result = TRUE; else messerror ("Cannot fseek file %s (%s)", fo->filename, messSysErrorText()); } return result; } /* aceOutRewind */ /************************************************/ BOOL aceOutFlush (ACEOUT fo) /* will only work on files */ { BOOL result = FALSE; if (!aceOutExists(fo)) messcrash("aceOutRewind() - received invalid fo pointer"); if (fo->fil) { if (fflush(fo->fil) == 0) result = TRUE; else messerror ("Cannot fflush file %s (%s)", fo->filename, messSysErrorText()); } return result; } /* aceOutRewind */ /************************************************/ BOOL aceOutStreamPos (ACEOUT fo, long int *posp) { BOOL result = FALSE; if (fo->fil && fo->fil != stdout && fo->fil != stderr) { long int pos; pos = ftell (fo->fil); if (pos != -1) { *posp = pos; result = TRUE; } else { messerror ("Cannot ftell file %s (%s)", fo->filename, messSysErrorText()); } } else if (fo->s) { *posp = (long int)stackPos (fo->s); result = TRUE; } return result; } /* aceOutStreamPos */ /*************************************************************/ int aceOutBinary (ACEOUT fo, char *data, int size) /* copy a binary structure onto a text stack * RETURNS errno */ { int errno_result = ESUCCESS; int num_bytes_written = 0; if (!aceOutExists(fo)) messcrash("aceOutBinary() - received invalid fo pointer"); if (fo->fil) { num_bytes_written = fwrite(data,size,1,fo->fil); if (ferror (fo->fil) != 0) errno_result = errno; /* error occurred */ } else if (fo->s) { catBinary (fo->s,data,size); fo->pos = 0; fo->line++; } fo->byte += (long int)num_bytes_written; return errno_result; } /* aceOutBinary */ /*************************************************************/ /* Print output at specified position in a "teletext"-like way. */ /* */ int aceOutxy (ACEOUT fo, char *text, int x, int y) /* returns errno */ { int errno_result = ESUCCESS; int i, j, k ; int bytes_needed ; if (!aceOutExists(fo)) messcrash("aceOutxy() - received invalid fo pointer"); /* displacement from where we are now. */ i = x - fo->pos , j = y - fo->line, k = 0 ; /* The most we can write into buf is (i + j), so the buffer had better be */ /* at least that big (- terminating null). */ bytes_needed = i + j ; if (bytes_needed >= fo->buf_len) increaseBuffer(fo, bytes_needed) ; /* In theory we shouldn't need to do this but its very good for catching */ /* bugs... */ memset (fo->buf, 0, fo->buf_len) ; /* "move" to the right x,y position in the output stream using a combin- */ /* ation of blanks and newlines. */ if (i || j) { if (j > 0) { while (j--) fo->buf[k++] = '\n' ; i = x ; } if (i < 0) { fo->buf[k++] = '\n' ; i = x ; fo->line-- ; /* kludge, user should ignore this line feed */ } if (i > 0) { while (i--) fo->buf[k++] = ' ' ; } if (k >= fo->buf_len) messcrash("Internal coding error, aceOutxy has overwritten its buffer," "buffer length: %d, num bytes written: %d, positions: x=%d, y=%d", fo->buf_len, k, x, y) ; if (k) errno_result = aceOutBuffer (fo, fo->buf) ; } /* Now output the callers text at x,y */ if (errno_result == ESUCCESS) errno_result = aceOutBuffer (fo, text) ; return errno_result; } /* aceOutxy */ /************************************************/ /* Print simple text to stdout/file/whatever. * returns errno - ESUCCESS if all is OK */ int aceOutPrintStr(ACEOUT fo, char *simple_string) { int errno_result ; if (!aceOutExists(fo) || !simple_string) messcrash("aceOutPrintStr() - received %s %s", !aceOutExists(fo) ? "invalid fo pointer" : "", !simple_string ? "null string" : ""); errno_result = aceOutBuffer(fo, simple_string) ; return errno_result; } /************************************************/ /* Print text to stout/file/whatever. */ /* returns errno - ESUCCESS if all is OK */ /* */ int aceOutPrint(ACEOUT fo, char *format,...) { int errno_result ; int bytes_needed, bytes_written ; va_list args1, args2 ; if (!aceOutExists(fo)) messcrash("aceOutPrint() - received invalid fo pointer"); /* We would like to check that if there are no arguments after the format string, * then the format string should not contain a single "%" on its own. But this * is not possible with the va_args interface. */ va_start(args1, format) ; G_VA_COPY(args2, args1) ; /* check size of buffer required, if not big enough then allocate a buffer */ /* quite a bit bigger. NOTE, this is the absolute maximum...bytes written */ /* may be less, this includes terminating null. */ bytes_needed = g_printf_string_upper_bound(format, args1) ; if (bytes_needed > fo->buf_len) increaseBuffer(fo, bytes_needed) ; /* In theory we shouldn't need to do this but its very good for catching */ /* bugs... */ memset(fo->buf, 0, fo->buf_len) ; /* OK, format the string using this much better call which limits the */ /* chars written to our buffer length. Note bytes_written does _not_ */ /* include terminating null so max bytes_written = fo->buf_len - 1 */ bytes_written = g_vsnprintf(fo->buf, fo->buf_len, format, args2) ; if (bytes_written >= bytes_needed || bytes_written >= fo->buf_len) messcrash("A call to g_vsnprintf() failed - " "buffer size: %d, predicted bytes required: %d, bytes actually written: %d", fo->buf_len, bytes_needed, bytes_written) ; va_end(args1) ; va_end(args2) ; errno_result = aceOutBuffer(fo, fo->buf) ; return errno_result; } /* aceOutPrint */ /************************************************/ int aceOutLine (ACEOUT fo) /* how many lines have been written */ { if (!aceOutExists(fo)) messcrash("aceOutLine() - received invalid fo pointer"); return fo->line ; } long int aceOutByte (ACEOUT fo) /* how many bytes have been written */ { if (!aceOutExists(fo)) messcrash("aceOutByte() - received invalid fo pointer"); return fo->byte ; } int aceOutPos (ACEOUT fo) { if (!aceOutExists(fo)) messcrash("aceOutPos() - received invalid fo pointer"); return fo->pos ; } /********* ACETMP - writing to temporary files using ACEOUT ********/ /* Simply a cover func. for aceTmpCreateDir() */ /* */ ACETMP aceTmpCreate (const char *spec, STORE_HANDLE handle) { ACETMP result = NULL ; result = aceTmpCreateDir(NULL, spec, handle) ; return result ; } /* aceTmpCreate */ /* Creates a unique tmp file in one of: */ /* if dir is NULL the file is created in the system tmp dir, */ /* if dir is relative, then dir will be created under the system tmp dir */ /* if it doesn't exist and the file created there, */ /* if dir is absolute, then dir is created if it doesn't exist and the */ /* file created there. */ /* */ /* spec is one of "w" or "wb" */ ACETMP aceTmpCreateDir(const char *dir, const char *spec, STORE_HANDLE handle) { ACEOUT fo = NULL; ACETMP atmp = NULL, result = NULL ; char *dirname = NULL ; char *nameptr = NULL ; BOOL status = TRUE ; char *tmpfile = getenv("TEMP"); /* allow user to override location of temp files */ if (!spec) messcrash("aceTmpCreate() - received NULL spec"); if (spec[0] != 'w') messcrash("aceTmpCreate() - non-'w' spec"); if (!dir || !(*dir) || *dir != '/') { char *basename = #if defined(SUN) || defined(SOLARIS) (tmpfile ? tmpfile : "/var/tmp") ; #elif defined(__CYGWIN__) (tmpfile ? tmpfile : "/cygdrive/c/Temp") ; #else (tmpfile ? tmpfile : "/tmp") ; #endif dirname = hprintf(0, "%s%s%s", basename, ((dir && *dir && *dir == '/') ? "" : "/"), ((dir && *dir) ? dir : "")) ; } else dirname = strnew(dir, 0) ; if (!filCheckName(dirname, NULL, "x")) { if (mkdir(dirname, S_IRUSR | S_IWUSR | S_IXUSR) == -1) { messerror ("Failed to create parent directory \"%s\" for temporary files (%s)", dirname, messSysErrorText()) ; status = FALSE ; } } if (!(nameptr = tempnam(dirname, "ACEDB"))) { messerror ("Failed to create temporary file in directory \"%s\" (%s)", dirname, messSysErrorText()) ; status = FALSE ; } /* first check if we can actually create the file */ if (status) { fo = aceOutCreateToFile (nameptr, spec, 0); if (!fo) { messerror ("Failed to create ACEIN for temporary file \"%s\" (%s)", nameptr, messSysErrorText()) ; status = FALSE ; } } if (status) { atmp = halloc (sizeof(struct AceTmpStruct), handle); blockSetFinalise (atmp, aceTmpFinalise); atmp->magic = &ACETMP_MAGIC; atmp->fo = fo; atmp->filename = strnew (nameptr, 0); atmp->remove = TRUE ; result = atmp ; } /* tidy up */ if (nameptr) free(nameptr); /* N.B. was allocated by tempname using malloc */ if (dirname) messfree(dirname) ; return result ; } void uAceTmpDestroy (ACETMP atmp) { if (!aceTmpExists(atmp)) messcrash("aceTmpDestroy() - called with invalid ACETMP pointer"); messfree (atmp); /* trigger aceTmpFinalise */ return; } /* uAceTmpDestroy */ void aceTmpClose (ACETMP atmp) { /* NOTE: this zeroes the fo field */ aceOutDestroy (atmp->fo); return; } /* aceTmpClose */ ACEOUT aceTmpGetOutput (ACETMP atmp) /* The returned ACEOUT stream may be destroyed by the * calling code before this ACETMP is finalised. * This enables the user to close the tmp-file * before removing it. */ { if (!aceTmpExists (atmp)) messcrash("aceOutGetOutput() - received invalid atmp pointer"); return atmp->fo; } /* aceTmpGetOutput */ char *aceTmpGetFileName (ACETMP atmp) { if (!aceTmpExists (atmp)) messcrash("aceOutGetFileName() - received invalid atmp pointer"); return atmp->filename; } /* aceTmpGetFileName */ /* Set state so that tmp files will/will not be removed when the ACETMP is */ /* destroyed (contorted logic is because default state is to _remove_. */ void aceTmpNoRemove(ACETMP atmp, BOOL no_remove) { atmp->remove = !no_remove ; return ; } /****************************************************************** ************************ private functions *********************** ******************************************************************/ /* Increase size of our output buffer. */ /* Policy here is that if we need to make the buffer bigger, we make it 1.5x */ /* what is needed to try and avoid constant reallocation just because the */ /* next string is a bit bigger than the last. I don't think we need the */ /* usual malloc policy of doubling because much of what we use is strings */ /* which tend to be of a certain size depending on the objects/dna being */ /* looked at. */ static void increaseBuffer(ACEOUT fo, int bytes_needed) { fo->buf_len = bytes_needed + (bytes_needed / 2) ; messfree(fo->buf) ; fo->buf = (char *)halloc(fo->buf_len, fo->handle) ; return ; } static ACEOUT aceOutSetFileStack(FILE *fil, Stack s, STORE_HANDLE handle) { ACEOUT fo; fo = (ACEOUT)halloc(sizeof(AceOutRec), handle); blockSetFinalise (fo, aceOutFinalise); fo->magic = &ACEOUT_MAGIC ; fo->handle = handleCreate(); if (fil) fo->fil = fil ; else if (s) fo->s = s ; else messcrash("aceOutSetFileStack() - fil and s is NULL"); fo->buf_len = ACEOUT_INITIAL_BUFSIZE ; fo->buf = (char *)halloc(fo->buf_len, fo->handle) ; fo->line = fo->pos = fo->byte = 0 ; fo->filename = 0; return fo ; } /* aceOutSetFileStack */ /************************************************/ /* Just close everything, leave the ACEOUT otherwise intact. Note that if there * is a stack, it belongs to the caller so we don't free it. */ static void aceOutCloseFileStack(ACEOUT fo) { messAssert(aceOutExists(fo)) ; /* it'll check for stdout/stderr needed here to make sure the eventual filMail * is actually being sent */ if (fo->fil) filclose (fo->fil); fo->fil = NULL ; if (fo->filename) messfree(fo->filename) ; fo->filename = NULL ; fo->line = fo->pos = fo->byte = 0 ; return ; } /************************************************/ static void aceOutFinalise (void *block) { ACEOUT fo = (ACEOUT)block; if (!aceOutExists(fo)) messcrash("aceOutFinalise() - received invalid block pointer"); if (fo->fil) filclose (fo->fil); /* it'll check for stdout/stderr * needed here to make sure the eventual * filMail is actually being sent */ handleDestroy(fo->handle); fo->magic = 0; /* taint this memory segment as free'd * this will catch assertions if we * try to access this free'd bit * of memory */ return; } /* aceOutFinalise */ /************************************************/ static BOOL aceOutExists (ACEOUT fo) { if (fo && fo->magic == &ACEOUT_MAGIC) return TRUE; return FALSE; } /* aceOutExists */ /************************************************/ static int aceOutBuffer (ACEOUT fo, char *text) /* return errno, which is ESUCCESS, if all is OK */ { int errno_result = ESUCCESS; char *cp ; int pos = 0, line = 0, ln ; if (!aceOutExists(fo)) messcrash("aceOut() - received invalid fo pointer"); cp = text ; ln = strlen(text) ; while (*cp) if (*cp++ == '\n') { pos = 0 ; line++ ;} else pos++ ; if (fo->fil) { int num_bytes_written; /* Output the text, n.b. text may contain "%" which we don't want to */ /* be interpreted, hence our "%s" format string. */ num_bytes_written = fprintf(fo->fil, "%s", text) ; if (num_bytes_written < 0) errno_result = errno ; else ln = num_bytes_written ; } else if (fo->s) { catText(fo->s, text) ; } else messcrash("aceOutBuffer() - fo struct has neither ->fil nor ->s"); fo->byte += (long int)ln ; if (line) { fo->line += line ; fo->pos = pos ; } else fo->pos += pos ; return errno_result; } /* aceOutBuffer */ /************** ACETMP **********************/ static BOOL aceTmpExists (ACETMP atmp) { if (atmp && atmp->magic == &ACETMP_MAGIC) return TRUE; return FALSE; } /* aceTmpExists */ static void aceTmpFinalise (void *block) /* Note that the ACETMP structure has a longer life-time * than its output stream (atmp->fo). * The life-time of the ACETMP struct is the lifetime of the * tmp-file itself. The file _may_ be deleted upon destruction. * depending on the setting of remove */ { ACETMP atmp = (ACETMP)block; if (!aceTmpExists (atmp)) messcrash("aceTmpFinalise() - received invalid block pointer"); /* finish output to close the file, if not done already */ if (atmp->fo) aceOutDestroy (atmp->fo); /* remove the file */ if (atmp->remove) { if (unlink (atmp->filename) == -1) messerror ("Failed to remove tmp-file %s (%s)", atmp->filename, messSysErrorText()); } /* free the filename buffer */ messfree (atmp->filename); atmp->magic = 0; /* taint memory block as free'd */ return; } /* aceTmpFinalise */ /*********************** eof ********************************/ acedb-4.9.39+dfsg.01/w1/acethread.c0000444000175000017500000000346706776222042016326 0ustar moellermoeller#include "regular.h" #include "acethread.h" static Array mutexArray = 0 ; typdef struct AceThreadStruct { Array mArray ; } ; BOOL getMutex (TH th, int nn) { pthread_mutex_t *mm = 0 ; int n1, n2 ; if (!th) return TRUE ; if (mutexArray) messcrash ("getMutex called before threadMutexInit") ; if (nn >= arrayMax(mutexArray)) messcrash ("getMutex call on excessive nn=%d", nn) ; if (!th->mArray) th->mArray = arrayCreate (12, int) ; n1 = arrayMax(th->mArray) ; n2 = n1 ? array(th->mArray, n1 - 1, int) : 0 ; if (nn < n2) messcrash ("Requesting a lower mutex") ; if (nn > n2) { array(th->mArray, arrayMax(th->mArray), int) = nn ; mm = arrayp (mutexArray, nn, pthread_mutex_t) ; if (!mm) pthread_mutex_init (mm, 0) ; pthread_mutex_lock (mm) ; } return TRUE ; } BOOL releaseMutex (TH th, int nn) { int n1, n2 ; if (!th) return TRUE ; if (mutexArray) messcrash ("releaseMutex called before threadMutexInit") ; if (nn >= arrayMax(mutexArray)) messcrash ("releaseMutex call on excessive nn=%d", nn) ; if (!th->mArray) th->mArray = arrayCreate (12, int) ; n1 = th->mArray ? arrayMax(th->mArray) : 0 ; n2 = n1 ? array(th->mArray, n1 - 1, int) : 0 ; if (nn > n2) messcrash ("Releasing an unlocked mutex") ; if (nn < n2) messcrash ("Releasing in disorder") ; arrayMax(th->mArray)-- ; mm = arrayp (mutexArray, nn, pthread_mutex_t) ; if (!mm) messcrash ("releasing a non initialised mutex") ; pthread_mutex_unlock (mm) ; return TRUE ; } static void threadMutextInit (void) { if (mutexArray) messcrash ("Double call to threadMutextInit") ; mutexArray = arrayCreate (64, pthread_mutex_t) ; array (mutexArray, LASTMUTEX, pthread_mutex_t) = 0 ; } void aceThreadInit (void) { threadMutextInit () ; } acedb-4.9.39+dfsg.01/w1/arraysub.c0000444000175000017500000010743210045064236016224 0ustar moellermoeller/* File: arraysub.c * Author: Jean Thierry-Mieg (mieg@mrc-lmba.cam.ac.uk) * Copyright (C) J Thierry-Mieg and R Durbin, 1991 * ------------------------------------------------------------------- * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * ------------------------------------------------------------------- * This file is part of the ACEDB genome database package, written by * Richard Durbin (MRC LMB, UK) rd@mrc-lmba.cam.ac.uk, and * Jean Thierry-Mieg (CRBM du CNRS, France) mieg@crbm.cnrs-mop.fr * * Description: * Arbitrary length arrays, stacks, associators * line breaking and all sorts of other goodies * These functions are declared in array.h * (part of regular.h - the header for libfree.a) * Exported functions: * See Header file: array.h (includes lots of macros) * HISTORY: * Last edited: Mar 14 13:53 2003 (rnc) * * May 19 13:51 1999 (fw): make MEM_DEBUG the default for all * ops that demand memory, so we can track where the * code made that request. * * Nov 1 16:11 1996 (srk) * - MEM_DEBUG code clean-up * (some loose ends crept in from WIN32) * - int (*order)(void*,void*) prototypes used * uniformly throughout * * Jun 5 00:48 1996 (rd) * * May 2 22:33 1995 (mieg): killed the arrayReport at 20000 otherwise it swamps 50 Mbytes of RAM * * Jan 21 16:25 1992 (mieg): messcrash in uArrayCreate(size<=0) * * Dec 17 11:40 1991 (mieg): stackTokeniseTextOn() tokeniser. * * Dec 12 15:45 1991 (mieg): Stack magic and stackNextText * Created: Thu Dec 12 15:43:25 1989 (mieg) *------------------------------------------------------------------- */ /* $Id: arraysub.c,v 1.71 2004/05/02 03:18:54 mieg Exp $ */ /* Warning : if you modify Array or Stack structures or procedures in this file or array.h, you may need to modify accordingly the persistent array package asubs.c. */ #include "regular.h" #include extern BOOL finalCleanup ; /* in memsubs.c */ /********** Array : class to implement variable length arrays **********/ static int totalAllocatedMemory = 0 ; static int totalNumberCreated = 0 ; static int totalNumberActive = 0 ; static Array reportArray = 0 ; static void uArrayFinalise (void *cp) ; Array uArrayCreate_dbg (int n, int size, STORE_HANDLE handle, const char *hfname,int hlineno) { int id = totalNumberCreated++ ; Array new = (Array) handleAlloc_dbg (uArrayFinalise, handle, sizeof (struct ArrayStruct), hfname, hlineno) ; if (!reportArray) { reportArray = (Array)1 ; /* prevents looping */ reportArray = arrayCreate (512, Array) ; } if (size <= 0) messcrash("negative size %d in uArrayCreate", size) ; if (n < 1) n = 1 ; totalAllocatedMemory += n * size ; /* base-mem isn't allocated upon handle, it's free'd by finalisation */ new->base = halloc_dbg (n*size, 0, hfname, hlineno) ; new->dim = n ; new->max = 0 ; new->size = size ; new->id = ++id ; new->magic = ARRAY_MAGIC ; totalNumberActive++ ; if (reportArray != (Array)1) { if (new->id < 20000) array (reportArray, new->id, Array) = new ; else { Array aa = reportArray ; reportArray = (Array)1 ; /* prevents looping */ arrayDestroy (aa) ; } } return new ; } /**************/ int arrayReportMark (void) { return reportArray != (Array)1 ? arrayMax(reportArray) : 0 ; } /**************/ void arrayReport (int j) { int i ; Array a ; if (reportArray == (Array)1) { fprintf(stderr, "\n\n %d active arrays, %d created, %d kb allocated\n\n ", totalNumberActive, totalNumberCreated , totalAllocatedMemory/1024) ; return ; } fprintf(stderr,"\n\n") ; i = arrayMax (reportArray) ; while (i-- && i > j) { a = arr (reportArray, i, Array) ; if (arrayExists(a)) fprintf (stderr, "Array %d size=%d max=%d\n", i, a->size, a->max) ; } } /**************/ void arrayStatus (int *nmadep, int *nusedp, int *memAllocp, int *memUsedp) { int i ; Array a, *ap ; *nmadep = totalNumberCreated ; *nusedp = totalNumberActive ; *memAllocp = totalAllocatedMemory ; *memUsedp = 0 ; if (reportArray == (Array)1) return ; i = arrayMax(reportArray) ; ap = arrp(reportArray, 0, Array) - 1 ; while (ap++, i--) if (arrayExists (*ap)) { a = *ap ; *memUsedp += a->max * a->size ; } } /**************/ Array uArrayReCreate_dbg (Array a, int n, int size, const char *hfname, int hlineno) { if (!arrayExists(a)) return uArrayCreate_dbg(n, size, 0, hfname, hlineno) ; if(a->size != size) uMessSetErrorOrigin(hfname, hlineno), uMessCrash ("Type missmatch in arrayReCreate, you should always " "call recreate using the same type") ; if (n < 1) n = 1 ; if (a->dim < n || (a->dim - n)*size > (1 << 19) ) /* free if save > 1/2 meg */ { totalAllocatedMemory -= a->dim * size ; messfree (a->base) ; a->dim = n ; totalAllocatedMemory += a->dim * size ; /* base-mem isn't alloc'd on handle, it's free'd by finalisation */ a->base = halloc_dbg (a->dim*size, 0, hfname, hlineno) ; } memset(a->base,0,(mysize_t)(a->dim*size)) ; a->max = 0 ; return a ; } /**************/ void uArrayDestroy_dbg (Array a, const char *hfname, int hlineno) /* Note that the finalisation code attached to the memory does the work, see below */ { if (!a) return; if (a->magic != ARRAY_MAGIC) uMessSetErrorOrigin(hfname, hlineno), uMessCrash ("arrayDestroy received corrupt array->magic"); messfree(a); } static void uArrayFinalise (void *cp) { Array a = (Array)cp; totalAllocatedMemory -= a->dim * a->size ; if (!finalCleanup) messfree (a->base) ; a->magic = 0 ; totalNumberActive-- ; if (!finalCleanup && reportArray != (Array)1) arr(reportArray, a->id, Array) = 0 ; return; } /* uArrayFinalise */ /******************************/ void arrayExtend_dbg (Array a, int n, const char *hfname,int hlineno) { char *new ; if (!a || n < a->dim) return ; totalAllocatedMemory -= a->dim * a->size ; if (a->dim*a->size < 1 << 23) /* 2 megs of keys, or 8 megs of ram */ a->dim *= 2 ; else a->dim += 1024 + ((1 << 23) / a->size) ; if (n >= a->dim) a->dim = n + 1 ; totalAllocatedMemory += a->dim * a->size ; /* base-mem isn't allocated upon handle, it's free'd by finalisation */ new = halloc_dbg (a->dim*a->size, 0, hfname, hlineno) ; memcpy (new,a->base,a->size*a->max) ; messfree (a->base) ; a->base = new ; return; } /* arrayExtend_dbg */ /***************/ char *uArray_dbg (Array a, int i, const char *hfname, int hlineno) { if (i < 0) uMessSetErrorOrigin(hfname, hlineno), uMessCrash ("referencing array element %d < 0", i) ; if (!a) uMessSetErrorOrigin(hfname, hlineno), uMessCrash ("uArray called with NULL Array struc"); if (i >= a->max) { if (i >= a->dim) arrayExtend (a,i) ; a->max = i+1 ; } return a->base + i*a->size ; } /***************/ char *uArrayCheck_dbg (Array a, int i, const char *hfname,int hlineno) { if (i < 0) uMessSetErrorOrigin(hfname, hlineno), uMessCrash ("referencing array element %d < 0", i) ; return uArray_dbg(a, i, hfname, hlineno) ; } /***************/ char *uArrCheck_dbg (Array a, int i, const char *hfname, int hlineno) { if (i >= a->max || i < 0) uMessSetErrorOrigin(hfname, hlineno), uMessCrash ("array index %d out of bounds [0,%d]", i, a->max - 1) ; return a->base + i*a->size ; } /**************/ Array arrayCopy_dbg(Array old, STORE_HANDLE handle, const char *hfname, int hlineno) { Array new ; if (arrayExists (old) && old->size) { new = uArrayCreate_dbg (old->dim, old->size, handle, hfname, hlineno) ; memcpy(new->base, old->base, old->dim * old->size); new->max = old->max ; return new; } return (Array)0 ; } /* arrayCopy_dbg */ /**************/ Array arrayTruncatedCopy_dbg (Array a, int x1, int x2, const char *hfname, int hlineno) { Array b = 0 ; if (x1 < 0 || x2 < x1 || x2 > a->max) messcrash ("Bad coordinates x1 = %d, x2 = %d in arrayTruncatedCopy", x1, x2) ; if (arrayExists (a) && a->size) { if (x2 - x1) { b = uArrayCreate_dbg (x2 - x1, a->size, 0, hfname, hlineno) ; b->max = x2 - x1 ; memcpy(b->base, a->base + x1, b->max * b->size); } else b = uArrayCreate_dbg (10, a->size, 0, hfname, hlineno) ; } return b; } /**************/ void arrayCompress(Array a) { int i, j, k , as ; char *x, *y, *ab ; if (!a || !a->size || arrayMax(a) < 2 ) return ; ab = a->base ; as = a->size ; for (i = 1, j = 0 ; i < arrayMax(a) ; i++) { x = ab + i * as ; y = ab + j * as ; for (k = a->size ; k-- ;) if (*x++ != *y++) goto different ; continue ; different: if (i != ++j) { x = ab + i * as ; y = ab + j * as ; for (k = a->size ; k-- ;) *y++ = *x++ ; } } arrayMax(a) = j + 1 ; } /****************/ /* 31.7.1995 dok408 added arraySortPos() - restricted sorting to tail of array */ void arraySort(Array a, int (*order)(void*, void*)) { arraySortPos(a, 0, order) ; return ; } void arraySortPos (Array a, int pos, int (*order)(void*, void*)) { typedef int (*CONSTORDER)(const void*, const void*) ; unsigned int n = a->max - pos, s = a->size ; void *v = a->base + pos * a->size ; if (pos < 0) messcrash("arraySortPos: pos = %d", pos); if (n > 1) { #ifdef SOLARIS /* Jean reported that qsort() crashes on solaris 5.7 */ mSort (v, n, s, order) ; #else qsort (v, n, s, (CONSTORDER)order) ; #endif } return ; } /***********************************************************/ BOOL arrayIsEntry_dbg (Array a, int i, void *s, const char *hfname, int hlineno) { char *cp = uArray_dbg(a,i, hfname, hlineno), *cq = s ; int j = a->size; while (j--) if (*cp++ != *cq++) return FALSE ; return TRUE; } /***********************************************/ /* Finds Entry s from Array a * sorted in ascending order of order() * If found, returns TRUE and sets *ip * if not, returns FALSE and sets *ip one step left */ BOOL arrayFind(Array a, void *s, int *ip, int (* order)(void*, void*)) { int ord; int i = 0 , j = arrayMax(a), k; if(!j || (ord = order(s,uArray_dbg(a,0, __FILE__, __LINE__)))<0) { if (ip) *ip = -1; return FALSE; } /* not found */ if (ord == 0) { if (ip) *ip = 0; return TRUE; } if ((ord = order(s,uArray_dbg(a,--j, __FILE__, __LINE__)))>0 ) { if (ip) *ip = j; return FALSE; } if (ord == 0) { if (ip) *ip = j; return TRUE; } while(TRUE) { k = i + ((j-i) >> 1) ; /* midpoint */ if ((ord = order(s, uArray_dbg(a,k, __FILE__, __LINE__))) == 0) { if (ip) *ip = k; return TRUE; } if (ord > 0) (i = k); else (j = k) ; if (i == (j-1) ) break; } if (ip) *ip = i ; return FALSE; } /**************************************************************/ /* Removes Entry s from Array a * sorted in ascending order of order() */ BOOL arrayRemove (Array a, void * s, int (* order)(void*, void*)) { int i; if (arrayFind(a, s, &i,order)) { /* memcpy would be faster but regions overlap * and memcpy is said to fail with some compilers */ char *cp = uArray_dbg(a,i, __FILE__, __LINE__), *cq = cp + a->size ; int j = (arrayMax(a) - i)*(a->size) ; while(j--) *cp++ = *cq++; arrayMax(a) --; return TRUE; } else return FALSE; } /**************************************************************/ /* Insert Segment s in Array a * in ascending order of s.begin */ BOOL arrayInsert(Array a, void * s, int (*order)(void*, void*)) { int i, j, arraySize; if (arrayFind(a, s, &i,order)) return FALSE; /* no doubles */ arraySize = arrayMax(a); j = arraySize + 1; uArray_dbg(a,j-1,__FILE__,__LINE__) ; /* to create space */ /* avoid memcpy for same reasons as above */ { char *cp, *cq; int k; if (arraySize > 0) { cp = uArray_dbg(a,j - 1,__FILE__,__LINE__) + a->size - 1; cq = cp - a->size ; k = (j - i - 1)*(a->size); while(k--) *cp-- = *cq--; } cp = uArray_dbg(a,i+1,__FILE__,__LINE__); cq = (char *) s; k = a->size; while(k--) *cp++ = *cq++; } return TRUE; } /********* BitSet - inherits from Array **********/ /* mieg 2001, turn these into function to systematically make room allowing to use bit() without errors which is ok since anyway bitSetMax is not a defined method */ Array bitSetCreate (int n, STORE_HANDLE h) { Array bb = 0 ; if (n < 256) n = 256 ; bb = arrayHandleCreate (1 + (n >> 5), unsigned int, h) ; array (bb, (n >> 5), unsigned int) = 0 ; return bb ; } Array bitSetReCreate (Array bb, int n) { if (n < 256) n = 256 ; bb = arrayReCreate (bb, 1 + (n >> 5), unsigned int) ; array (bb, (n >> 5), unsigned int) = 0 ; return bb ; } void bitExtend (Array bb, int n) { if (n < 256) n = 256 ; arrayExtend(bb, n >> 5) ; array (bb, (n >> 5), unsigned int) = 0 ; } /* Returns the number of set bits */ int bitSetCount (BitSet a) { register unsigned int *cp ; register unsigned int i, i1; register int j = arrayExists(a) ? arrayMax(a) : 0 , n = 0 ; if(!j) return 0 ; cp = arrp(a,0,unsigned int) ; while (j--) { if(!*cp) n+=32 ; else if(*cp != 0xff) for (i=1, i1 = 0 ; i1 < 32 ; i1++, i <<= 1) if(~(*cp) & i) n++; cp++; } return 32*arrayMax(a) - n ; } /******** Stack : arbitrary Stack class - inherits from Array *********/ static void uStackFinalise (void *cp) ; Stack stackHandleCreate_dbg (int n, /* n is initial size */ STORE_HANDLE handle, const char *hfname, int hlineno) { Stack s = (Stack) handleAlloc_dbg (uStackFinalise, handle, sizeof (struct StackStruct), hfname, hlineno) ; s->magic = STACK_MAGIC ; /* array is not allocated upon handle, it's free'd by finalisation */ s->a = arrayCreate (n,char) ; s->pos = s->ptr = s->a->base ; s->safe = s->a->base + s->a->dim - 16 ; /* safe to store objs up to size 8 */ s->textOnly = FALSE; return s ; } /* stackHandleCreate_dbg */ void stackTextOnly(Stack s) { if (!stackExists(s)) messcrash("StackTextOnly given non-exisant stack."); s->textOnly = TRUE; } /* performs b1 = b1 & b2, returns count (b1) */ int bitSetAND (BitSet b1, BitSet b2) { register unsigned int *cp, *cq ; register unsigned int ii, i1; register int n = 0 ; register int i = arrayExists(b1) ? arrayMax(b1) : 0 ; register int j = arrayExists(b2) ? arrayMax(b2) : 0 ; if (i > j) i = j ; arrayMax (b1) = i ; if (i == 0) return 0 ; cp = arrp(b1,0,unsigned int) ; cq = arrp(b2,0,unsigned int) ; while (i--) { *cp &= *cq ; if(!*cp) n+=32 ; else if(*cp != 0xff) for (ii=1, i1 = 0 ; i1 < 32 ; i1++, ii <<= 1) if(~(*cp) & ii) n++; cp++; cq++ ; } return 32*arrayMax(b1) - n ; } /* bitSetAND */ /* performs b1 = b1 & b2, returns count (b1) */ int bitSetOR (BitSet b1, BitSet b2) { register unsigned int *cp, *cq ; register unsigned int ii, i1; register int n = 0 ; register int i = arrayExists(b1) ? arrayMax(b1) : 0 ; register int j = arrayExists(b2) ? arrayMax(b2) : 0 ; if (i < j) { i = j ; array(b1,i - 1,unsigned int) = 0 ; } if (i > j) array(b2, i - 1,unsigned int) = 0 ; if (i == 0) return 0 ; cp = arrp(b1,0,unsigned int) ; cq = arrp(b2,0,unsigned int) ; while (i--) { *cp |= *cq ; /* *cp OR *cq */ if(!*cp) n+=32 ; else if(*cp != 0xff) for (ii=1, i1 = 0 ; i1 < 32 ; i1++, ii <<= 1) if(~(*cp) & ii) n++; cp++; cq++ ; } return 32*arrayMax(b1) - n ; } /* bitSetOR */ /* performs b1 = b1 & b2, returns count (b1) */ int bitSetXOR (BitSet b1, BitSet b2) { register unsigned int *cp, *cq ; register unsigned int ii, i1; register int n = 0 ; register int i = arrayExists(b1) ? arrayMax(b1) : 0 ; register int j = arrayExists(b2) ? arrayMax(b2) : 0 ; if (i < j) { i = j ; array(b1,i - 1,unsigned int) = 0 ; } if (i > j) array(b2, i - 1,unsigned int) = 0 ; if (i == 0) return 0 ; cp = arrp(b1,0,unsigned int) ; cq = arrp(b2,0,unsigned int) ; while (i--) { *cp ^= *cq ; /* *cp XOR *cq */ if(!*cp) n+=32 ; else if(*cp != 0xff) for (ii=1, i1 = 0 ; i1 < 32 ; i1++, ii <<= 1) if(~(*cp) & ii) n++; cp++; cq++ ; } return 32*arrayMax(b1) - n ; } /* bitSetXOR */ /* performs b1 = b1 & b2, returns count (b1) */ int bitSetMINUS (BitSet b1, BitSet b2) { register unsigned int *cp, *cq ; register unsigned int ii, i1; register int n = 0 ; register int i = arrayExists(b1) ? arrayMax(b1) : 0 ; register int j = arrayExists(b2) ? arrayMax(b2) : 0 ; if (i < j) { i = j ; array(b1,i - 1,unsigned int) = 0 ; } if (i > j) array(b2, i - 1,unsigned int) = 0 ; if (i == 0) return 0 ; cp = arrp(b1,0,unsigned int) ; cq = arrp(b2,0,unsigned int) ; while (i--) { *cp = *cp ^ (*cp & *cq) ; /* *cp XOR ( *cp AND *cq) */ if(!*cp) n+=32 ; else if(*cp != 0xff) for (ii=1, i1 = 0 ; i1 < 32 ; i1++, ii <<= 1) if(~(*cp) & ii) n++; cp++; cq++ ; } return 32*arrayMax(b1) - n ; } /* bitSetMINUS */ Stack stackReCreate_dbg (Stack s, int n, /* n is initial size */ const char *hfname, int hlineno) { if (!stackExists(s)) return stackHandleCreate_dbg(n, 0, hfname, hlineno) ; /* array is not allocated upon handle, it's free'd by finalisation */ s->a = uArrayReCreate_dbg (s->a,n,sizeof(char), hfname, hlineno) ; s->pos = s->ptr = s->a->base ; s->safe = s->a->base + s->a->dim - 16 ; /* safe to store objs up to size 8 */ return s ; } /* stackReCreate_dbg */ Stack stackCopy_dbg (Stack old, STORE_HANDLE handle, const char *hfname, int hlineno) { Stack new ; int ptr, pos; if (!stackExists(old)) return 0 ; ptr = old->ptr - old->a->base; pos = old->pos - old->a->base; new = (Stack) handleAlloc_dbg (uStackFinalise, handle, sizeof (struct StackStruct), hfname, hlineno) ; new->magic = STACK_MAGIC; /* array is not allocated upon handle, it's free'd by finalisation */ new->a = arrayCopy_dbg (old->a, 0, hfname, hlineno) ; new->ptr = new->a->base + ptr; new->pos = new->a->base + pos; new->safe = new->a->base + new->a->dim - 16 ; new->textOnly = old->textOnly; return new ; } /* stackCopy_dbg */ #ifdef FW_990519_NOT_DECLARED_OR_USED_ANYWHERE Stack arrayToStack (Array a) { Stack s ; int n ; if (!arrayExists(a) || a->size != 1 ) return 0 ; n = arrayMax(a) ; s = stackCreate(n + 32) ; memcpy(s->a->base, a->base, n) ; s->pos = s->a->base ; s->ptr = s->a->base + n ; s->safe = s->a->base + s->a->dim - 16 ; /* safe to store objs up to size 8 */ while ((long)s->ptr % STACK_ALIGNMENT) *(s->ptr)++ = 0 ; return s ; } #endif /* FW_990519_NOT_DEFINE_OR_USED_ANYWHERE */ void uStackDestroy(Stack s) { if (s && s->magic == STACK_MAGIC) messfree(s); } /* the rest is done below as a consequence */ static void uStackFinalise (void *cp) { Stack s = (Stack)cp; if (!finalCleanup) arrayDestroy (s->a) ; s->magic = 0 ; } void stackExtend_dbg (Stack s, int n, const char *hfname, int hlineno) { int ptr, pos; if (!stackExists(s)) uMessSetErrorOrigin (hfname, hlineno), uMessCrash("stackExtend() - called with invalid stack"); ptr = s->ptr - s->a->base; pos = s->pos - s->a->base ; s->a->max = s->a->dim ; /* since only up to ->max copied over */ arrayExtend_dbg (s->a,ptr+n+16, hfname, hlineno); /* relies on arrayExtend mechanism */ s->ptr = s->a->base + ptr ; s->pos = s->a->base + pos ; s->safe = s->a->base + s->a->dim - 16 ; return; } /* stackExtend_dbg */ int stackMark (Stack s) { int mark; if (!stackExists(s)) messcrash("stackMark() - received invalid stack"); mark = (s->ptr - s->a->base); return mark; } /* stackMark */ int stackPos (Stack s) { int pos; if (!stackExists(s)) messcrash("stackPos() - received invalid stack"); pos = (s->pos - s->a->base); return pos; } /* stackPos */ void stackCursor (Stack s, int mark) { if (!stackExists(s)) messcrash("stackCursor() - received invalid stack"); s->pos = s->a->base + mark ; return; } /* stackCursor */ char *stackText_dbg (Stack s, int mark, const char *hfname, int hlineno) { char *text; if (!stackExists(s)) uMessSetErrorOrigin (hfname, hlineno), uMessCrash("stackText() - called with invalid stack"); text = (char*)(s->a->base + mark); return text; } /* stackText */ /************************************************************/ /* access doubles on the stack by steam on systems where we don't align the stack strictly enough, this code assumes that ints are 32bits and doubles 64 */ union mangle { double d; struct { int i1; int i2; } i; }; void uStackDoublePush(Stack stk, double x) { union mangle m; m.d = x; push(stk, m.i.i1, int); push(stk, m.i.i2, int); } double uStackDoublePop(Stack stk) { union mangle m; m.i.i2 = pop(stk, int); m.i.i1 = pop(stk, int); return m.d; } double uStackDoubleNext(Stack stk) { union mangle m; m.i.i1 = stackNext(stk, int); m.i.i2 = stackNext(stk, int); return m.d; } void pushText (Stack s, char* text) { while (s->ptr + strlen(text) > s->safe) stackExtend (s,strlen(text)+1) ; while ((*(s->ptr)++ = *text++)) ; if (!s->textOnly) while ((long)s->ptr % STACK_ALIGNMENT) *(s->ptr)++ = 0 ; } char* popText (Stack s) { char *base = s->a->base ; while (s->ptr > base && !*--(s->ptr)) ; while (s->ptr >= base && *--(s->ptr)) ; return ++(s->ptr) ; } void catText (Stack s, char* text) { while (s->ptr + strlen(text) > s->safe) stackExtend (s,strlen(text)+1) ; *s->ptr = 0 ; while (s->ptr >= s->a->base && *s->ptr == 0) s->ptr -- ; s->ptr ++ ; while ((*(s->ptr)++ = *text++)) ; if (!s->textOnly) while ((long)s->ptr % STACK_ALIGNMENT) *(s->ptr)++ = 0 ; } void catBinary (Stack s, char* data, int size) { int total; total = size + 1; while (s->ptr + total > s->safe) stackExtend (s,size+1) ; memcpy(s->ptr,data,size); s->ptr += size; } char* stackNextText (Stack s) { char *text = s->pos ; if (text>= s->ptr) return 0 ; /* JTM, so while stackNextText makes sense */ while (*s->pos++) ; if (!s->textOnly) while ((long)s->pos % STACK_ALIGNMENT) ++s->pos ; return text ; } /*********/ /* Push text in stack s, after breaking it on delimiters */ /* You can later access the tokens with command while (token = stackNextText(s)) work on your tokens ; */ void stackTokeniseTextOn(Stack s, char *text, char *delimiters) { char *cp, *cq , *cend, *cd, old, oldend ; int i, n ; if(!stackExists(s) || !text || !delimiters) messcrash("stackTextOn received some null parameter") ; n = strlen(delimiters) ; cp = cq = text ; while(TRUE) { while(*cp == ' ') cp++ ; cq = cp ; old = 0 ; while(*cq) { for (cd = delimiters, i = 0 ; i < n ; cd++, i++) if (*cd == *cq) { old = *cq ; *cq = 0 ; goto found ; } cq++ ; } found: cend = cq ; while(cend > cp && *--cend == ' ') ; if (*cend != ' ') cend++ ; oldend = *cend ; *cend = 0 ; if (*cp && cend > cp) pushText(s,cp) ; *cend = oldend ; if(!old) { stackCursor(s, 0) ; return ; } *cq = old ; cp = cq + 1 ; } } void stackClear (Stack s) { if (!s) messcrash("stackClear() - NULL stack"); if (!stackExists(s)) messcrash("stackClear() - non-magic Stack"); memset(s->a->base,0,(mysize_t)(s->a->dim*sizeof(char))) ; s->pos = s->ptr = s->a->base; s->a->max = 0; return; } /* stackClear */ /****************** routines to set text into lines ***********************/ static char *linesText ; static Array lines ; static Array textcopy ; static int kLine, popLine ; /**********/ int uLinesText (char *text, int width) { char *cp,*bp ; int i ; int nlines = 0 ; int length = strlen (text) ; int safe = length + 2*(length/(width > 0 ? width : 1) + 1) ; /* mieg: avoid zero divide */ static int isFirst = TRUE ; if (isFirst) { isFirst = FALSE ; lines = arrayCreate(16,char*) ; textcopy = arrayCreate(128,char) ; } linesText = text ; array(textcopy,safe,char) = 0 ; /* ensures textcopy is long enough */ if (!*text) { nlines = popLine = kLine = 0 ; array(lines,0,char*) = 0 ; return 0 ; } cp = textcopy->base ; nlines = 0 ; for (bp = text ; *bp ; ++bp) { array(lines,nlines++,char*) = cp ; for (i = 0 ; (*cp = *bp) && *cp != '\n' ; ++i, ++cp, ++bp) if (i == width) /* back up to last space */ { while (i--) { --bp ; --cp ; if (*cp == ' ' || *cp == ',' || *cp == ';') goto eol ; } cp += width ; /* no coma or spaces in whole line ! */ bp += width ; break ; } eol: if (!*cp) break ; if (*cp != '\n') ++cp ; *cp++ = 0 ; } kLine = 0 ; /* reset for uNextLine() */ popLine = nlines ; array(lines,nlines,char*) = 0 ; /* 0 terminate */ return nlines ; } char *uNextLine (char *text) { if (text != linesText) messout ("Warning : uNextLine being called with bad context") ; return array(lines,kLine++,char*) ; } char *uPopLine (char *text) { if (text != linesText) messout ("Warning : uPopLine being called with bad context") ; if (popLine) return array(lines,--popLine,char*) ; else return 0; } char **uBrokenLines (char *text, int width) { uLinesText (text,width) ; return (char**)lines->base ; } char *uBrokenText (char *text, int width) { char *cp ; uLinesText (text,width) ; uNextLine (text) ; while ((cp = uNextLine (text))) *(cp-1) = '\n' ; return arrp(textcopy,0,char) ; } /*************************************************************/ /* perfmeters */ int assBounce = 0, assFound = 0, assNotFound = 0, assInserted = 0, assRemoved = 0 ; /* Associator package is for associating pairs of pointers. Assumes that an "in" item is non-zero and non -1. Implemented as a hash table of size 2^m. Originally grabbed from Steve Om's sather code by Richard Durbin. Entirelly rewritten by mieg, using bouncing by relative primes and deletion flagging. User has access to structure member ->n = # of pairs */ #define VSIZE (sizeof(void*)) #define VS5 (VSIZE/5) #define VS7 (VSIZE/7) #define moins_un ((void*) (-1)) #define HASH(_xin) { register long z = VS5, x = (char*)(_xin) - (char*)0 ; \ for (hash = x, x >>= 5 ; z-- ; x >>= 5) hash ^= x ; \ hash &= a->mask ; \ } #define DELTA(_xin) { register long z = VS7, x = (char*)(_xin) - (char*)0 ; \ for (delta = x, x >>= 7 ; z-- ; x >>= 7) delta ^= x ; \ delta = (delta & a->mask) | 0x01 ; \ } /* delta odd is prime relative to 2^m */ /**************** Destruction ****************************/ static void assFinalise(void *cp) { Associator a = (Associator)cp; a->magic = 0 ; if (!finalCleanup) { messfree(a->in) ; messfree(a->out); } } void uAssDestroy (Associator a) { if (assExists(a)) messfree (a) ; /* calls assFinalise */ } /**************** Creation *******************************/ static Associator assDoCreate_dbg (int nbits, STORE_HANDLE handle, const char *hfname, int hlineno) { static int nAss = 0 ; Associator a ; int size = 1 << nbits, /* size must be a power of 2 */ vsize = size * VSIZE ; a = (Associator) handleAlloc_dbg(assFinalise, handle, sizeof (struct AssStruct), hfname, hlineno) ; a->in = (void**) halloc_dbg(vsize, 0, hfname, hlineno) ; a->out = (void**) halloc_dbg(vsize, 0, hfname, hlineno) ; a->magic = ASS_MAGIC ; a->id = ++nAss ; a->n = 0 ; a->i = 0 ; /* start up position for recursive calls */ a->m = nbits ; a->mask = size - 1 ; return a ; } /*******************/ Associator assBigCreate_dbg(int size, const char *hfname, int hlineno) { int n = 2 ; /* make room, be twice as big as needed */ if (size <= 0) uMessSetErrorOrigin(hfname, hlineno), uMessCrash ("assBigCreate called with size = %d <= 0", size) ; --size ; while (size >>= 1) n++ ; /* number of left most bit + 1 */ return assDoCreate_dbg(n, 0, hfname, hlineno) ; } /*******************/ Associator assHandleCreate_dbg(STORE_HANDLE handle, const char *hfname,int hlineno) { return assDoCreate_dbg(5, handle, hfname, hlineno) ; } /*******************/ void assClear (Associator a) { mysize_t sz ; if (!assExists(a)) return ; a->n = 0 ; sz = ( 1 << a->m) * VSIZE ; memset(a->in, 0, sz) ; memset(a->out, 0, sz) ; } /********************/ Associator assReCreate_dbg (Associator a, const char *hfname, int hlineno) { if (!assExists(a)) return assHandleCreate_dbg(0, hfname, hlineno) ; else { assClear (a) ; return a ; } } /********************/ static void assDouble (Associator a) { int oldsize, newsize, nbits ; register int hash, delta ; void **old_in = a->in, **old_out = a->out, **xin, **xout ; int i ; nbits = a->m ; oldsize = 1 << nbits ; newsize = oldsize << 1 ; /* size must be a power of 2 */ a->n = 0 ; a->i = 0 ; /* start up position for recursive calls */ a->m = nbits + 1 ; a->mask = newsize - 1 ; a->in = (void**) messalloc (newsize * VSIZE) ; a->out = (void**) messalloc (newsize * VSIZE) ; for (i = 0, xin = old_in, xout = old_out ; i < oldsize ; i++, xin++, xout++) if (*xin && *xin != moins_un) { HASH(*xin) ; while (TRUE) { if (!a->in[hash]) /* don't need to test moins_un */ { a->in[hash] = *xin ; a->out[hash] = *xout ; ++a->n ; assInserted++ ; break ; } assBounce++ ; DELTA(*xin) ; /* redo each time - cheap overall */ hash = (hash + delta) & a->mask ; } } messfree (old_in) ; messfree (old_out) ; } /************************ Searches ************************************/ BOOL uAssFind (Associator a, void* xin, void** pout) /* if found, updates *pout and returns TRUE, else returns FALSE */ { int hash, delta = 0 ; void* test ; if (!assExists(a)) messcrash ("assFind received corrupted associator") ; if (!xin || xin == moins_un) return FALSE ; HASH(xin) ; while (TRUE) { test = a->in[hash] ; if (test == xin) { if (pout) *pout = a->out[hash] ; assFound++ ; a->i = hash ; return TRUE ; } if (!test) break ; assBounce++ ; if (!delta) DELTA(xin) ; hash = (hash + delta) & a->mask ; } assNotFound++ ; return FALSE ; } /********************/ /* Usage: if(uAssFind()){while (uAssFindNext()) ... } */ BOOL uAssFindNext (Associator a, void* xin, void** pout) /* if found, updates *pout and returns TRUE, else returns FALSE */ { int hash, delta ; void* test ; if (!assExists(a)) messcrash ("assFindNext received corrupted associator") ; if (!xin || xin == moins_un || !a->in[a->i]) return FALSE ; if (a->in[a->i] != xin) messcrash ("Non consecutive call to assFindNext") ; hash = a->i ; DELTA(xin) ; while (TRUE) { test = a->in[hash] ; if (test == xin) { if (pout) *pout = a->out[hash] ; while (TRUE) /* locate on next entry */ { hash = (hash + delta) & a->mask ; test = a->in[hash] ; if (!test || test == xin) break ; assBounce++ ; } a->i = hash ; /* points to next entry or zero */ assFound++ ; return TRUE ; } if (!test) break ; assBounce++ ; hash = (hash + delta) & a->mask ; } assNotFound++ ; return FALSE ; } /************************ Insertions ************************************/ /* if already there returns FALSE, else inserts and returns TRUE */ static BOOL assDoInsert (Associator a, void* xin, void* xout, BOOL noMultiples) { int hash, delta = 0 ; void* test ; if (!assExists(a)) messcrash ("assInsert received corrupted associator") ; if (!xin || xin == moins_un) messcrash ("assInsert received forbidden value xin == 0") ; if (a->n >= (1 << (a->m - 1))) /* reaching floating line */ assDouble (a) ; HASH (xin) ; while (TRUE) { test = a->in[hash] ; if (!test || test == moins_un) /* reuse deleted slots */ { a->in[hash] = xin ; a->out[hash] = xout ; ++a->n ; assInserted++ ; return TRUE ; } if (noMultiples && test == xin) /* already there */ return FALSE ; assBounce++ ; if (!delta) DELTA (xin) ; hash = (hash + delta) & a->mask ; } } /*****************/ /* This one does not allow multiple entries in one key. */ BOOL assInsert (Associator a, void* xin, void* xout) { return assDoInsert (a, xin, xout, TRUE) ; } /*****************/ void assMultipleInsert (Associator a, void* xin, void* xout) /* This one allows multiple entries in one key. */ { assDoInsert (a, xin, xout, FALSE) ; } /************************ Removals ************************************/ /* if found, removes entry and returns TRUE, else returns FALSE */ /* No a->n--, because the entry is blanked but not actually removed */ BOOL assRemove (Associator a, void* xin) { if (assExists(a) && uAssFind (a, xin, 0)) { a->in[a->i] = moins_un ; assRemoved++ ; return TRUE ; } else return FALSE ; } /*******************/ /* if found, removes entry and returns TRUE, else returns FALSE */ /* Requires both xin and xout to match */ BOOL assPairRemove (Associator a, void* xin, void* xout) { if (!assExists(a) || !xin || xin == moins_un) return FALSE ; if (uAssFind (a, xin, 0)) while (uAssFindNext (a, xin, 0)) if (a->out[a->i] == xout) { a->in[a->i] = moins_un ; assRemoved++ ; return TRUE ; } return FALSE ; } /************************ dumpers ********************************/ /* lets you step through all members of the table */ BOOL uAssNext (Associator a, void* *pin, void* *pout) { int size ; void *test ; if (!assExists(a)) messcrash("uAssNext received a non existing associator") ; size = 1 << a->m ; if (!*pin) a->i = -1 ; else if (*pin != a->in[a->i]) { messerror ("Non-consecutive call to assNext()") ; return FALSE ; } while (++a->i < size) { test = a->in[a->i] ; if (test && test != moins_un) /* not empty or deleted */ { *pin = a->in[a->i] ; if (pout) *pout = a->out[a->i] ; return TRUE ; } } return FALSE ; } /*******************/ void assDump (Associator a) { int i ; void **in, **out ; char *cp0 = 0 ; if (!assExists(a)) return ; i = 1 << a->m ; in = a->in - 1 ; out = a->out - 1 ; /* keep stderr here since it is for debugging */ fprintf (stderr,"Associator %lx : %d pairs\n",(unsigned long)a,a->n) ; while (in++, out++, i--) if (*in && *in != moins_un) /* not empty or deleted */ fprintf (stderr,"%lx - %lx\n", (long)((char*)(*in) - cp0),(long)( (char *)(*out) - cp0)) ; } /************************ end of file ********************************/ /**********************************************************************/ acedb-4.9.39+dfsg.01/w1/bump.c0000444000175000017500000001716207435503464015351 0ustar moellermoeller/* File: bump.c * Author: Jean Thierry-Mieg (mieg@mrc-lmb.cam.ac.uk) * Copyright (C) J Thierry-Mieg and R Durbin, 1992 * ------------------------------------------------------------------- * This file is part of the ACEDB genome database package, written by * Richard Durbin (MRC LMB, UK) rd@mrc-lmb.cam.ac.uk, and * Jean Thierry-Mieg (CRBM du CNRS, France) mieg@kaa.cnrs-mop.fr * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * ------------------------------------------------------------------- * This file is part of the ACEDB genome database package, written by * Richard Durbin (MRC LMB, UK) rd@mrc-lmb.cam.ac.uk, and * Jean Thierry-Mieg (CRBM du CNRS, France) mieg@kaa.cnrs-mop.fr * * Description: ** Bumper (Cambridge traditional folklore) * Exported functions: ** bumpCreate, bumpDestroy ** bumpItem, bumpText, bumpTest, bumpAdd ** the BUMP structure is defined in wh/bump.h * HISTORY: * Last edited: Oct 5 15:58 1999 (fw) * Created: Thu Aug 20 10:34:55 1992 (mieg) *------------------------------------------------------------------- */ /* $Id: bump.c,v 1.15 2002/02/22 18:00:20 srk Exp $ */ #include "regular.h" #include "bump.h" #include "bump_.h" /************************************************************/ magic_t BUMP_MAGIC = "BUMP"; #define MINBUMP ((float)(-2000000000.0)) /************* bump package based on gmap text **************/ BUMP bumpCreate (int nCol, int minSpace) { int i ; BUMP bump; bump = (BUMP) messalloc (sizeof (struct BumpStruct)) ; bump->magic = &BUMP_MAGIC ; if (nCol < 1) nCol = 1 ; bump->n = nCol ; bump->bottom = (float*) messalloc (nCol*sizeof (float)) ; for (i = 0 ; i < nCol ; ++i) bump->bottom[i] = MINBUMP ; if (minSpace < 0) minSpace = 0 ; bump->minSpace = minSpace ; bump->sloppy = 0 ; bump->max = 0 ; return bump ; } BUMP bumpReCreate (BUMP bump, int nCol, int minSpace) { int i ; if (!bump) return bumpCreate(nCol, minSpace) ; if (bump->magic != &BUMP_MAGIC) messcrash ("bumpReCreate received corrupt bump->magic"); if (nCol < 1) nCol = 1 ; if (nCol != bump->n) { messfree (bump->bottom) ; bump->bottom = (float*) messalloc (nCol*sizeof (float)) ; bump->n = nCol ; } for (i = 0 ; i < nCol ; ++i) bump->bottom[i] = MINBUMP ; if (minSpace < 0) minSpace = 0 ; bump->minSpace = minSpace ; bump->sloppy = 0 ; bump->max = 0 ; return bump ; } /* bumpReCreate */ void uBumpDestroy (BUMP bump) { if (!bump) return ; if (bump->magic != &BUMP_MAGIC) messcrash ("bumpDestroy received corrupt bump->magic"); messfree (bump->bottom) ; messfree (bump) ; return; } /* bumpDestroy */ int bumpMax (BUMP bump) { if (!bump) return 0 ; if (bump->magic != &BUMP_MAGIC) messcrash ("bumpMax received corrupt bump->magic"); return bump->max ; } /* bumpMax */ float bumpSetSloppy( BUMP bump, float sloppy) { float old ; if (!bump) messcrash ("bumpSetSloppy received NULL bump"); if (bump->magic != &BUMP_MAGIC) messcrash ("bumpSetSloppy received corrupt bump->magic"); old = bump->sloppy; bump->sloppy = sloppy ; return old ; } /* void bumpText(BUMP bump, char *cp, float *x, float *y) { CHECKBUMP ; if (!cp || !*cp) return ; bumpItem(bump, strlen(cp), 1, &xs, &ys) ; } */ void bumpRegister (BUMP bump, int wid, float height, int *px, float *py) { int i = *px , j ; if (!bump) messcrash ("bumpRegister received NULL bump"); if (bump->magic != &BUMP_MAGIC) messcrash ("bumpRegister received corrupt bump->magic"); j = wid < bump->n ? wid : bump->n; if (bump->max < i + j - 1) bump->max = i + j - 1 ; while (j--) /* advance bump */ bump->bottom[i+j] = *py + height ; } /* mhmp 16/05/97 */ void asciiBumpItem (BUMP bump, int wid, float height, int *px, float *py) /* works by resetting x, y */ { int x = *px ; float ynew, y = *py ; if (bump->magic != &BUMP_MAGIC) messcrash ("asciiBumpItem received corrupt bump->magic"); if (bump->xAscii != 0) { if (bump->xAscii + wid + bump->xGapAscii > bump->n) { ynew = y + 1 ; x = 0 ; bump->xAscii = wid ; } else { ynew = y ; x = bump->xAscii + bump->xGapAscii ; bump->xAscii = x + wid ; } } else { if (x + wid > bump->n) { if ((y - bump->yAscii) < 1 && (int) y == (int) bump->yAscii) ynew = y + 1 ; else ynew = y ; x = 0 ; bump->xAscii = wid ; } else { if (y != bump->yAscii && (int) y == (int) bump->yAscii) ynew = y + 1 ; else ynew = y ; } } *px = x ; *py = ynew ; bump->yAscii = ynew ; } BOOL bumpAdd (BUMP bump, int wid, float height, int *px, float *py, BOOL doIt) /* works by resetting x, y */ { int i, j ; int x = *px ; float ynew, y = *py ; if (bump->magic != &BUMP_MAGIC) messcrash ("bumpAdd received corrupt bump->magic"); if (x + wid + bump->minSpace > bump->n) x = bump->n - wid - bump->minSpace ; if (x < 0) x = 0 ; if (wid > bump->n) /* prevent infinite loops */ wid = bump->n ; if (y <= MINBUMP) y = MINBUMP + 1 ; ynew = y ; while (TRUE) { for (i = x, j = wid ; i < bump->n ; ++i) /* always start at x */ { if (bump->bottom[i] > y + bump->sloppy) { j = wid ; ynew = y ; /* this line was missing in the old code */ } else { if (bump->bottom[i] > ynew) ynew = bump->bottom[i] ; if (!--j) /* have found a gap */ break ; } } if (!j) { if (doIt) { for (j = 0 ; j < wid ; j++) /* advance bump */ bump->bottom[i - j] = ynew+height ; if (bump->max < i + 1) bump->max = i + 1 ; } *px = i - wid + 1 ; *py = ynew ; return TRUE ; } y += 1 ; /* try next row down */ if (!doIt && bump->maxDy && y - *py > bump->maxDy) return FALSE ; } } /* abbreviate text, if vertical bump exceeds dy return accepted length */ int bumpText (BUMP bump, char *text, int *px, float *py, float dy, BOOL vertical) { int w, n, x = *px; float y = *py, h, old = bump->maxDy ; if (bump->magic != &BUMP_MAGIC) messcrash ("bumpText received corrupt bump->magic"); if (!text || !*text) return 0 ; n = strlen(text) ; bump->maxDy = dy ; while (TRUE) { x = *px ; y = *py ; /* try always from desired position */ if (vertical) /*like in the genetic map */ { w = n + 1 ; h = 1 ;} else /* like in pmap */ { w = 1 ; h = n + 1 ;} if (bumpAdd (bump, w, h, &x, &y, FALSE)) { /* success */ bump->maxDy = old ; bumpRegister(bump, w, h, &x, &y) ; *px = x ; *py = y ; return n ; } if (n > 7) { n = 7 ; continue ; } if (n > 3) { bump->maxDy = 2 * dy ; n = 3 ; continue ; } if (n > 1) { bump->maxDy = 3 * dy ; n = 1 ; continue ; } bump->maxDy = old ; return 0 ; /* failure */ } } /**************************************************/ /**************************************************/ acedb-4.9.39+dfsg.01/w1/call.c0000444000175000017500000001216507435503464015317 0ustar moellermoeller/* File: call.c * Author: Richard Durbin (rd@sanger.ac.uk) * Copyright (C) J Thierry-Mieg and R Durbin, 1994 * ------------------------------------------------------------------- * This file is part of the ACEDB genome database package, written by * Richard Durbin (MRC LMB, UK) rd@mrc-lmb.cam.ac.uk, and * Jean Thierry-Mieg (CRBM du CNRS, France) mieg@kaa.cnrs-mop.fr * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * ------------------------------------------------------------------- * This file is part of the ACEDB genome database package, written by * Richard Durbin (MRC LMB, UK) rd@mrc-lmb.cam.ac.uk, and * Jean Thierry-Mieg (CRBM du CNRS, France) mieg@kaa.cnrs-mop.fr * * Description: provides hooks to optional code, basically a call by name dispatcher plus wscripts/ interface * Exported functions: * HISTORY: * Last edited: Oct 16 12:59 2001 (edgrif) * * Sept 3, mieg, suppressed all statics, phread safe. * * Mar 3 15:51 1996 (rd) * Created: Mon Oct 3 14:05:37 1994 (rd) *------------------------------------------------------------------- */ /* $Id: call.c,v 1.36 2002/02/22 18:00:20 srk Exp $ */ #include "acedb.h" #include "call.h" #include "mytime.h" #include /* for isprint */ /************************* call by name package *********************/ typedef struct { char *name ; CallFunc func ; } CALL ; static Array calls ; /* array of CALL to store registered routines */ /************************************/ static int callOrder (void *a, void *b) { return strcmp (((CALL*)a)->name, ((CALL*)b)->name) ; } void callRegister (char *name, CallFunc func) { CALL c ; /* getMutex ("callRegister") ; */ if (!calls) calls = arrayCreate (16, CALL) ; c.name = name ; c.func = func ; if (!arrayInsert (calls, &c, callOrder)) messcrash ("Duplicate callRegister with name %s", name) ; /* releaseMutex ("callRegister") ; */ } BOOL callExists (char *name) { CALL c ; int i; /* getMutex ("callExists") ; */ if (calls) { c.name = name ; return arrayFind (calls, &c, &i, callOrder) ; } /* releaseMutex ("callExists") ; */ return FALSE ; } #include /* for va_start */ BOOL call (char *name, ...) { va_list args ; CALL c ; int i ; c.name = name ; /* getMutex ("call") ; */ if (calls && arrayFind (calls, &c, &i, callOrder)) { va_start(args, name) ; (*(arr(calls,i,CALL).func))(args) ; va_end(args) ; /* releaseMutex ("call") ; */ return TRUE ; } /* releaseMutex ("call") ; */ return FALSE ; } /***************** routines to run external programs *******************/ /* ALL calls to system() and popen() should be through these routines ** First, this makes it easier for the Macintosh to handle them. ** Second, by using wscripts as an intermediate one can remove system ** dependency in the name, and even output style, of commands. ** Third, if not running in ACEDB it does not look for wscripts... */ static char *buildCommand (Stack command, char *dir, char *script, char *args) { char *cmd_string = NULL ; /* don't use messprintf() - often used to make args */ command = stackReCreate (command, 128) ; if (dir) { catText (command, "cd ") ; catText (command, dir) ; catText (command, "; ") ; } catText (command, "\""); catText (command, script) ; catText (command, "\""); if (args) { catText (command, " ") ; catText (command, args) ; } cmd_string = stackText (command, 0) ; return cmd_string ; } int callCdScript (char *dir, char *script, char *args) { Stack s = 0 ; int nn = 0 ; if (!script) return -1; nn = system (buildCommand (s, dir, script, args)) ; stackDestroy (s) ; return nn ; } int callScript (char *script, char *args) { return callCdScript (0, script, args) ; } FILE* callCdScriptPipe (char *dir, char *script, char *args) { Stack s = 0 ; char *command; FILE *pipe = 0 ; int peek ; if (!script) return 0; command = buildCommand (s, dir, script, args) ; pipe = popen (command, "r" ) ; if (pipe) { peek = fgetc (pipe) ; /* first char from popen on DEC seems often to be -1 == EOF!!! */ if (isprint(peek)) ungetc (peek, pipe) ; } #ifdef DEBUG printf ("First char on callCdScriptPipe is %c (0x%x)\n", peek, peek) ; #endif stackDestroy (s) ; return pipe ; } FILE* callScriptPipe (char *script, char *args) { return callCdScriptPipe (0, script, args) ; } acedb-4.9.39+dfsg.01/w1/chronoexe.c0000444000175000017500000001511307677665752016413 0ustar moellermoeller/* File: chronoexe.c * Author: Jean Thierry-Mieg (mieg@mrc-lmb.cam.ac.uk) * Copyright (C) J Thierry-Mieg and R Durbin, 1992 *------------------------------------------------------------------- * This file is part of the ACEDB genome database package, written by * Richard Durbin (MRC LMB, UK) rd@mrc-lmb.cam.ac.uk, and * Jean Thierry-Mieg (CRBM du CNRS, France) mieg@kaa.cnrs-mop.fr * * Description: General Timing statistics * This package is self contained since any function * called from here cannot be timed. * If you compile without flag CHRONO all calls to the * chrono package just disappear out of the code. * See chrono.h for how this works. * The basis of this code is the UNIX getrusage() routine, * this is _not_ a POSIX call and may not be available on * all platforms. * * * 2 routines are public : * * chrono, chronoReturn * * * * chrono("procedure") switches the timing to "procedure" * * chronoReturn ends it. * * chrono.h defines chrono = chronoSwitch or void * * and chronoReturn = chronoDoReturn or void * * If you compile without flag CHRONO all calls to the * * chrono package just disappear out of the code. * * Exported functions: see chrono.h * HISTORY: * Last edited: Dec 4 11:36 1998 (fw) * * Oct 13 14:37 1998 (edgrif): Removed ACEDB defines, replaced with * function calls. * * Nov 27 12:36 1995 (mieg) * Created: Mon Jun 15 14:42:32 1990 (mieg) *------------------------------------------------------------------- */ /* $Id: chronoexe.c,v 1.1 2003/06/29 22:44:58 mieg Exp $ */ #include "regular.h" #include "array.h" #include "chrono.h" /* Specify platforms to run chrono on... */ /* Basically, you can't run this on much, I assume this is because it uses getrusage() to get the timings and this is not a POSIX call. */ /* If we are on the correct platform then define the chrono stuff. */ /* */ #define CHRONO #ifdef CHRONO #include "chrono_.h" #include "freeout.h" #include #include #include /* subroutines to return info about system and real time */ typedef struct rusage *Timer_ ; static struct rusage previous[1], current[1] ; static BOOL chronoIsRunning = FALSE ; static int last = 0, level = 0 ; static Stack chronoStack = 0 ; static Array chronoArray = 0 ; /**********************************************/ /* This is not portable at all, we should be using clock ticks to do this, */ /* see a Unix manual.... */ static double MICRO = .000001 ; static double convert (struct timeval *tval) /* conversion to seconds */ { return (double) (tval->tv_sec + MICRO*tval->tv_usec) ; } /******************************************/ static void chronoGo(int i) { Chrono *ch ; getrusage (RUSAGE_SELF,current) ; ch = arrayp (chronoArray, i, Chrono) ; ch->tSys += convert (¤t->ru_stime) - convert (&previous->ru_stime) ; ch->tUser += convert (¤t->ru_utime) - convert (&previous->ru_utime) ; ch = arrayp (chronoArray, 0, Chrono) ; *previous = *current ; } /******************************************/ static int chronoOrder (void *a,void *b) { Chrono *ca = (Chrono *) a, *cb = (Chrono *) b ; /* double x = ca->tUser - cb->tUser ; if (x < 0) return -1 ; else if (x > 0) return 1 ; */ return strcmp(ca->prok, cb->prok) ; } /******************************************/ /*********** Public Routines **************/ /******************************************/ /******************************************/ BOOL chronoStart(void) { Chrono *ch ; chronoArray = arrayReCreate (chronoArray, 64, Chrono) ; ch = arrayp (chronoArray, 0, Chrono) ; ch->prok = "Chrono" ; getrusage (RUSAGE_SELF,previous) ; chronoStack = stackReCreate(chronoStack, 64) ; chronoIsRunning = TRUE ; last = 0 ; return TRUE ; } /******************************************/ void chronoStop(void) { chronoIsRunning = FALSE ; last = 0 ; chronoStack = stackReCreate(chronoStack, 64) ; } /******************************************/ static Array chronoDoReport (void) { Array aa = 0 ; if (chronoArray) { aa = arrayCopy (chronoArray) ; arraySort (aa, chronoOrder) ; } return aa ; } /* chronoDoReport */ /******************************************/ void chronoReport (void) { Chrono *ch ; double tSysTotal = 0, tUserTotal = 0; Array aa = chronoDoReport() ; int i = aa ? arrayMax(aa) : 0 ; ch = arrayp (aa, 0, Chrono) - 1 ; while(ch++, i--) { tSysTotal += ch->tSys ; tUserTotal += ch->tUser ; } freeOutf("// Total time : %.2f s system, %.2f user level = %d\n", tSysTotal, tUserTotal, level) ; freeOutf ("// # of calls System %% User %%\n") ; for (i = 0 ; i < arrayMax(aa) ; i++) { ch = arrayp (aa, i, Chrono) ; freeOutf ("// %22s %6d %8.2f s %5d %% %8.2f s %5d %%\n", ch->prok, ch->call, ch->tSys, (int)(100 * (ch->tSys)/(.001+tSysTotal)) , ch->tUser, (int)( 100 * (ch->tUser)/(.001+tUserTotal))) ; } return ; } /* chronoReport */ /******************************************/ /* aliased to chrono in chrono.h */ void chronoSwitch(char *cp) { int i = 0, n ; Chrono *ch = 0 ; if (!chronoIsRunning) return ; n = arrayMax(chronoArray) ; if (n > 0) for (i = 0, ch = arrayp (chronoArray, 0, Chrono) ; ch->prok != cp && i < n ; ch++, i++) ; if (i == n) { ch = arrayp (chronoArray, n, Chrono) ; ch->prok = cp ; } ch->call ++ ; chronoGo(last) ; level++ ; push(chronoStack, last, int) ; last = i ; } /*****************************************/ /* aliased to chronoReturn in chrono.h */ void chronoDoReturn(void) { if (!chronoIsRunning) return ; chronoGo(last) ; level-- ; last = pop(chronoStack, int) ; } /*****************************************/ /*****************************************/ #else BOOL chronoStart (void) { return FALSE ; } void chronoStop (void) { return ; } void chronoReport (void) { return ; } void chronoSwitch(char *cp) { return ; } void chronoDoReturn(void) { return ; } #endif /* CHRONO */ acedb-4.9.39+dfsg.01/w1/dict.c0000444000175000017500000002577107677675004015346 0ustar moellermoeller/* File: dict.c * Author: Richard Durbin and Jean Thierry-Mieg (rd@sanger.ac.uk) * Copyright (C) J Thierry-Mieg and R Durbin, 1995 * ------------------------------------------------------------------- * Acedb is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * or see the on-line version at http://www.gnu.org/copyleft/gpl.txt * ------------------------------------------------------------------- * This file is part of the ACEDB genome database package, written by * Richard Durbin (MRC LMB, UK) rd@mrc-lmb.cam.ac.uk, and * Jean Thierry-Mieg (CRBM du CNRS, France) mieg@kaa.cnrs-mop.fr * * Description: * Exported functions: * HISTORY: DICT library was rewritten nov 2002 to ensure that the char* returned by dictName are valid untill the whole dict is destroyed. i.e. they are never reallocated even if you keep adding names foreever and dictRemove was added * Last edited: Dec 4 14:50 2002 (mieg) * Created: Tue Jan 17 17:33:44 1995 (rd) *------------------------------------------------------------------- */ /* $Id: dict.c,v 1.19 2003/06/29 23:45:08 mieg Exp $ */ #include "regular.h" /* every thing here is private */ static char *DICT_MAGIC = "dict-magic" ; typedef struct { unsigned curr ; int pos, free, max ; char *base ; } DVOC ; typedef struct { BOOL caseSensitive ; /* default FALSE, public */ int dim ; /* dimension of the hash table, has to be a power of 2 */ int max ; /* 2 to the dict->dim */ int count ; /* number of active names in the dict */ int nVoc ; /* current dVoc */ int newPos ; /* moving index in the hash table */ char *magic ; Array table ; /* hash table */ Array keys ; /* ofsets in the set of vocs */ Array dVocs ; /* array of DVOC */ STORE_HANDLE handle ; } _DICT ; #define DICT _DICT #include "dict.h" #undef DICT /* The names are stored incrementally in large buffers, dVoc->buff, which are never reallocated, so that the pointers returned by dictName remain valid until the dict is destroyed. The key is as usual in acedb a composite 1 byte for the dVoc number 3 bytes for the offsett in dVoc->buff. In reality we divide by 8 the offset since we align the names on 64 bit boundaries. The table is a double hashing hash table, its dimension is a power of 2 so it is prime with the delta hash value which is always odd. In this way the orbit (first hash value modulo delta covers the whole table). The first 0 found during the travle indicates that the name is absent in the hash table. The first negative value indicates a spot than has been freed and can be reused, but does not stop the bouncing search . We retrieve a name by direct dereferencing. We recognize a name by hash search. */ #define DEBUG_MODE #ifndef DEBUG_MODE /* optimised mode */ /* these 2 private complex macros are useful to accelerate the hashing code */ /* whereas the public interface always checks the range of the parameters */ #define dictKey2Name(_dict,_k) ((arrp (_dict->dVocs, ((k >> 24) & 0x000000ff) - 1, DVOC))->base + ((0x00ffffff & (_k)) << 3)) #define dictIndex2Name(_dict_i) (dictKey2Name(_dict,arr(-dict->keys,_i,KEY))) #else /* debugging mode */ static char *dictKey2Name (_DICT *dict, KEY k) { int nVoc = ((k >> 24) & 0x000000ff) - 1 ; int pos = (0x00ffffff & k) << 3 ; DVOC *dVoc ; if (nVoc < 0 || nVoc >= arrayMax (dict->dVocs)) messcrash ("uDictKey2Name bad nVoc = %d", nVoc) ; dVoc = arrp (dict->dVocs, nVoc, DVOC) ; if (pos >= dVoc->curr) messcrash ("uDictKey2Name bad pos = %d >= curr = %d", pos, dVoc->curr) ; return dVoc->base + pos ; } static char *dictIndex2Name (_DICT *dict, int ii) { KEY key ; if (ii < 0 || ii >= arrayMax (dict->keys)) messcrash ("uDictIndex2Name") ; key = arr(dict->keys, ii, KEY) ; return dictKey2Name (dict, key) ; } #endif /* DEBUG_MODE */ /************* standard utility from Jean *************/ #define SIZEOFINT (8 * sizeof (int)) static int dictHash (char *cp, int n, BOOL isDiff) { register int i ; register unsigned int j, x = 0 ; register int rotate = isDiff ? 21 : 13 ; register int leftover = SIZEOFINT - rotate ; while (*cp) x = freeupper (*cp++) ^ (( x >> leftover) | (x << rotate)) ; /* compress down to n bits */ for (j = x, i = n ; i < SIZEOFINT ; i += n) j ^= (x >> i) ; j &= (1 << n) - 1 ; if (isDiff) /* return odd number */ j |= 1 ; return j ; } /* dictHash */ /****************************************************************************/ static void dictReHash (_DICT *dict, int newDim) { int ii ; KEY *kp ; if (newDim <= dict->dim) return ; dict->dim = newDim ; dict->max = 1 << newDim ; /* remake the table */ arrayDestroy (dict->table) ; dict->table = arrayHandleCreate (dict->max, int, dict->handle) ; array (dict->table, dict->max-1, int) = 0 ; /* set arrayMax */ /* reinsert all the names */ for (ii = 1, kp = arrp(dict->keys, ii, KEY) ; ii < arrayMax(dict->keys) ; ii++, kp++) { dictFind (dict, dictKey2Name (dict, *kp), 0) ; /* will fail, but sets dict->newPos */ arr(dict->table, dict->newPos, int) = ii ; } } /* dictReHash */ /****************************************************************************/ static DVOC *dictAddVoc (_DICT *dict, int s) { DVOC *dVoc ; int n1 = 0 ; dVoc = arrayp (dict->dVocs, dict->nVoc, DVOC) ; if (dict->nVoc > 0) n1 = 2 * (dVoc - 1)->max ; if (n1 < 8 * s) n1 = 8 * s ; dVoc->base = halloc (n1, dict->handle) ; /* never realloc */ dVoc->curr = 0 ; dVoc->max = n1 ; dVoc->free = n1 ; dict->nVoc++ ; return dVoc ; } /* dictAddVoc */ void uDictDestroy (_DICT *dict) { if (dict && dict->magic == DICT_MAGIC) { /* we need 2 lines, because otherwise messfree sets (freed) dict->handle=0 */ STORE_HANDLE handle = dict->handle ; messfree (handle) ; } } /****************************************************************************/ _DICT *dictHandleCreate (int size, STORE_HANDLE handle) { STORE_HANDLE h = handleHandleCreate (handle) ; _DICT *dict = (_DICT*) halloc (sizeof (_DICT), h) ; dict->handle = h ; dict->magic = DICT_MAGIC ; dict->caseSensitive = FALSE ; dict->count = 0 ; for (dict->dim = 6, dict->max = 64 ; dict->max < size ; ++dict->dim, dict->max *= 2) ; dict->table = arrayHandleCreate (dict->max, int, dict->handle) ; array (dict->table, dict->max-1, int) = 0 ; /* set arrayMax */ dict->dVocs = arrayHandleCreate (8, DVOC, dict->handle) ; dictAddVoc (dict, 8 * dict->max) ; dict->keys = arrayHandleCreate (dict->dim/4, KEY, dict->handle) ; array (dict->keys, 0, KEY) = 0 ; /* reserved for empty table entry */ return dict ; } /* dictHandleCreate */ _DICT *dictCreate (int size) { return dictHandleCreate (size, 0) ; } /* dictCreate */ _DICT *dictCaseSensitiveHandleCreate (int size, STORE_HANDLE handle) { _DICT *dict = dictHandleCreate (size, handle) ; dict->caseSensitive = TRUE ; return dict ; } /* dictCaseSensitiveHandleCreate */ /****************************************************************************/ BOOL dictFind (_DICT *dict, char *s, int *ip) { register int ii, h, dh = 0 ; int (*mystrcmp)() = dict->caseSensitive ? strcmp : strcasecmp ; if (!dict || !s || !*s) return FALSE ; dict->newPos = 0 ; /* will become first reusable spot */ h = dictHash (s, dict->dim, FALSE) ; while (TRUE) { ii = arr (dict->table, h, KEY) ; if (!ii) /* empty slot, s is unknown */ { if (ip) *ip = ii - 1 ; if (dict->newPos == 0) dict->newPos = h ; return FALSE ; } else if (ii < 0) /* freed stop */ { if (dict->newPos == 0) dict->newPos = h ; continue ; } else if (!mystrcmp (s, dictIndex2Name(dict,ii))) { if (ip) *ip = ii - 1 ; dict->newPos = h ; return TRUE ; } if (!dh) dh = dictHash (s, dict->dim, TRUE) ; h += dh ; if (h >= dict->max) h -= dict->max ; } } /* dictFind */ /****************************************************************************/ BOOL dictRemove (_DICT *dict, char *s) { int ii = 0 ; if (!dict || !s || !dictFind (dict, s, &ii)) /* word unkown */ return FALSE ; ii++ ; arr (dict->keys, ii, KEY) = 0 ; /* will not be rehashed */ arr (dict->table, dict->newPos, int) = -ii ; /* will be reusable */ dict->count-- ; return TRUE ; } /* dictRemove */ /****************************************************************************/ /* always fills ip, returns TRUE if added, FALSE if known */ BOOL dictAdd (_DICT *dict, char *s, int *ip) { int ii = 0, len ; DVOC *dVoc ; if (!dict || !s) return FALSE ; if (dictFind (dict, s, &ii)) /* word already known */ { if (ip) *ip = ii ; return FALSE ; } ii++ ; if (ii < 0) ii = -ii ; /* reuse */ else ii = arrayMax(dict->keys) ; array (dict->table, dict->newPos, int) = ii ; dVoc = arrp (dict->dVocs, dict->nVoc - 1, DVOC) ; len = strlen (s) ; if (len + 1 >= dVoc->free) dVoc = dictAddVoc (dict, len) ; array (dict->keys, ii, KEY) = (0xff000000 & ((dict->nVoc)<<24)) | (0x00ffffff & (dVoc->curr)>>3) ; strcpy (dVoc->base + dVoc->curr, s) ; len++ ; /* count the terminal zero */ while (len%8) len++ ; /* adjust on word boundary */ dVoc->curr += len ; dVoc->free -= len ; dict->count++ ; if (arrayMax(dict->keys) > 0.4 * dict->max) dictReHash (dict, dict->dim+1) ; if (ip) *ip = ii - 1 ; return TRUE ; } /* dictAdd */ /********************** utilities ***********************/ /* dictName returns a pointer that never gets reallocated */ char *dictName (_DICT *dict, int ii) { KEY key ; if (ii < 0 || ii + 1 >= arrayMax(dict->keys)) { messcrash ("Call to dictName() out of bounds: %d not in [0,%d] ", ii, dictMax(dict) - 1) ; return "(Dict error, NULL NAME)" ; } key = arr (dict->keys, ii + 1, KEY) ; return dictKey2Name(dict, key) ; } /* dictName */ int dictCount (_DICT *dict) { return dict->count ; /* number of active names */ } /* dictMax */ int dictMax (_DICT *dict) /* max to be used if looping on all entries */ { return arrayMax(dict->keys) - 1 ; /* 0 == reserved pseudo key */ } /* dictMax */ /******************** end of file **********************/ /****************************************************************************/ /****************************************************************************/ acedb-4.9.39+dfsg.01/w1/filsubs.c0000444000175000017500000007502607766346425016071 0ustar moellermoeller/* File: filsubs.c * Author: Jean Thierry-Mieg (mieg@mrc-lmb.cam.ac.uk) * Copyright (C) J Thierry-Mieg and R Durbin, 1991 * ------------------------------------------------------------------- * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * ------------------------------------------------------------------- * This file is part of the ACEDB genome database package, written by * Richard Durbin (MRC LMB, UK) rd@mrc-lmb.cam.ac.uk, and * Jean Thierry-Mieg (CRBM du CNRS, France) mieg@kaa.cnrs-mop.fr * * Description: * cross platform file system routines * * Exported functions: * HISTORY: * Last edited: Dec 12 11:32 2003 (edgrif) * * Nov 29 11:53 1999 (edgrif): Added new filCopyFile function. * * Apr 13 13:40 1999 (fw): fixed bug in filCheck if spec is "wd" or "ad" * * Dec 8 10:20 1998 (fw): new function filAge to determine time since * last modification of file * * Oct 22 16:17 1998 (edgrif): Replace unsafe strtok with strstr. * * Oct 15 11:47 1998 (fw): include messSysErrorText in some messges * * Sep 30 09:37 1998 (edgrif): Replaced my strdup with acedb strnew. * * Sep 9 14:07 1998 (edgrif): Add filGetFilename routine that will * return the filename given a pathname * (NOT the same as the UNIX basename). * * DON'T KNOW WHO DID THE BELOW..assume Richard Bruskiewich (edgrif) * - fix root path detection for default drives (in WIN32) * * Oct 8 23:34 1996 (rd) * filDirectory() returns a sorted Array of character * strings of the names of files, with specified ending * and spec's, listed in a given directory "dirName"; * If !dirName or directory is inaccessible, * the function returns 0 * * Jun 6 17:58 1996 (rd) * * Mar 24 02:42 1995 (mieg) * * Feb 13 16:11 1993 (rd): allow "" endName, and call getwd if !*dname * * Sep 14 15:57 1992 (mieg): sorted alphabetically * * Sep 4 13:10 1992 (mieg): fixed NULL used improperly when 0 is meant * * Jul 20 09:35 1992 (aochi): Add directory names to query file chooser * * Jan 11 01:59 1992 (mieg): If file has no ending i suppress the point * * Nov 29 19:15 1991 (mieg): If file had no ending, we were losing the last character in dirDraw() * Created: Fri Nov 29 19:15:34 1991 (mieg) * CVS info: $Id: filsubs.c,v 1.80 2003/12/12 14:13:41 edgrif Exp $ *------------------------------------------------------------------- */ #include #include #include #include /* for callScript (to mail stuff) */ #include #include /********************************************************************/ /*****************************************************************************/ /* This function returns the directory part of a given path, */ /* */ /* Given "/some/load/of/directories/filename" returns */ /* returns "/some/load/of/directories" */ /* */ /* The function returns NULL for the following input: */ /* */ /* 1) supplying a NULL ptr as the path */ /* 2) supplying "" as the path */ /* */ /* and returns "." for the following input: */ /* supplying a path that does not contain a "/" */ /* */ /* NOTE, this function is _NOT_ the same as the UNIX dirname command or the */ /* XPG4_UNIX dirname() function which do different things. */ /* */ /* The function makes a copy of the supplied path on which to work, this */ /* copy is thrown away each time the function is called. */ /* */ char *filGetDirname(char *path) { static char *path_copy = NULL ; char *result = NULL, *tmp = NULL ; if (path != NULL) { if (path_copy != NULL) messfree(path_copy) ; path_copy = strnew(path, 0) ; tmp = strrchr(path_copy, SUBDIR_DELIMITER) ; if (tmp) { *tmp = '\0' ; result = path_copy ; } else result = "." ; } return(result) ; } /* filGetDirname */ /*****************************************************************************/ /* This function returns the filename part of a given path, */ /* */ /* Given "/some/load/of/directories/filename" returns "filename" */ /* */ /* The function returns NULL for the following errors: */ /* */ /* 1) supplying a NULL ptr as the path */ /* 2) supplying "" as the path */ /* 3) supplying a path that ends in "/" */ /* */ /* NOTE, this function is _NOT_ the same as the UNIX basename command or the */ /* XPG4_UNIX basename() function which do different things. */ /* */ /* The function makes a copy of the supplied path on which to work, this */ /* copy is thrown away each time the function is called. */ /* */ char *filGetFilename(char *path) { static char *path_copy = NULL ; const char *path_delim = SUBDIR_DELIMITER_STR ; char *result = NULL, *tmp ; if (path != NULL) { if (strcmp((path + strlen(path) - 1), path_delim) != 0) /* Last char = "/" ?? */ { if (path_copy != NULL) messfree(path_copy) ; path_copy = strnew(path, 0) ; tmp = path ; while (tmp != NULL) { result = tmp ; tmp = strstr(tmp, path_delim) ; if (tmp != NULL) tmp++ ; } } } return(result) ; } /* filGetFilename */ /*****************************************************************************/ /* This function returns the base filename part of a given path. */ /* */ /* Given "/some/load/of/directories/filename.something.ext" */ /* returns "filename.something" */ /* */ /* i.e. it lops off the directory bit and the _last_ extension. */ /* */ /* The function returns NULL for the following errors: */ /* */ /* 1) supplying a NULL ptr as the path */ /* 2) supplying "" as the path */ /* 3) supplying a path that ends in "/" */ /* */ /* NOTE, this function is _NOT_ the same as the UNIX basename command or the */ /* XPG4_UNIX basename() function which do different things. */ /* */ /* The function makes a copy of the supplied path on which to work, this */ /* copy is thrown away each time the function is called. */ /* */ char *filGetFilenameBase(char *path) { static char *path_copy = NULL ; const char *path_delim = SUBDIR_DELIMITER_STR ; char *result = NULL, *tmp ; if (path != NULL) { if (strcmp((path + strlen(path) - 1), path_delim) != 0) /* Last char = "/" ?? */ { if (path_copy != NULL) messfree(path_copy) ; path_copy = strnew(path, 0) ; tmp = path ; while (tmp != NULL) { result = tmp ; tmp = strstr(tmp, path_delim) ; if (tmp != NULL) tmp++ ; } tmp = strrchr(result, EXT_DELIMITER) ; if (tmp) *tmp = '\0' ; } } return(result) ; } /*****************************************************************************/ /* This function returns the file-extension part of a given path/filename, */ /* */ /* Given "/some/load/of/directories/filename.ext" returns "ext" */ /* */ /* The function returns NULL for the following errors: */ /* */ /* 1) supplying a NULL ptr as the path */ /* 2) supplying a path with no filename */ /* */ /* The function returns "" for a filename that has no extension */ /* */ /* The function makes a copy of the supplied path on which to work, this */ /* copy is thrown away each time the function is called. */ /* */ char *filGetExtension(char *path) { static char *path_copy = NULL ; char *extension = NULL, *cp ; if (path == NULL) return NULL; if (strlen(path) == 0) return NULL; if (path_copy != NULL) messfree(path_copy) ; path_copy = messalloc ((strlen(path)+1) * sizeof(char)); strcpy (path_copy, path); cp = path_copy + (strlen(path_copy) - 1); while (cp > path_copy && *cp != SUBDIR_DELIMITER && *cp != EXT_DELIMITER) --cp; extension = cp+1; return(extension) ; } /* filGetExtension */ /***************************************************************************/ static BOOL filCheck (char *name, char *spec) /* allow 'd' as second value of spec for a directory */ { char *cp ; BOOL result ; struct stat status ; if (spec[1] == 'd') if (stat (name, &status) == 0 && (!(status.st_mode & S_IFDIR))) /* the pathname isn't a directory, but we asked for that */ return FALSE; switch (*spec) { case 'e': /* file exists. */ if (access (name, F_OK) == 0) { if (spec[1] != 'd') if (stat (name, &status) == 0 && (status.st_mode & S_IFDIR)) /* the pathname exists and is readable, but it is a directory and we didn't ask for that */ return FALSE; return TRUE; } return FALSE; case 'r': if (access (name, R_OK) == 0) { if (spec[1] != 'd') if (stat (name, &status) == 0 && (status.st_mode & S_IFDIR)) /* the pathname exists and is readbale, but it is a directory and we didn't ask for that */ return FALSE; return TRUE; } return FALSE; case 'w': case 'a': if (access (name, W_OK) == 0) /* requires file exists */ { if (spec[1] != 'd') if (stat (name, &status) == 0 && (status.st_mode & S_IFDIR)) /* the pathname exists and is writable, but it is a directory and we didn't ask for that */ return FALSE; return TRUE ; } if (spec[1] == 'd') return FALSE; if (stat (name, &status) == 0) /* write access failed, but file exists, so check failed */ return FALSE; /* for file check, we test whether its directory is writable */ cp = name + strlen (name) ; while (cp > name) if (*--cp == SUBDIR_DELIMITER) break ; if (cp == name) return !(access (".", W_OK)) ; else { *cp = 0 ; result = !(access (name, W_OK)) ; *cp = SUBDIR_DELIMITER ; return result ; } case 'x': return (access (name, X_OK) == 0) ; default: messcrash ("Unknown spec %s passed to filName", spec) ; } return FALSE ; } /************************************************/ static BOOL filCanonPath (Stack s, char *name, char *ending) { #ifdef __CYGWIN__ char posix[PATH_MAX]; /* cygwin_conv doesn't like these (but they're already posix) */ if ((*name) && (strcmp(name, ".") != 0) && (*name != '~')) cygwin_conv_to_full_posix_path(name, posix); else strcpy(posix, name); /* win32 doesn't like : in filenames - replace with . */ for (name = posix; *name; name++) if (*name == ':') *name = '.'; name = posix; #endif if (*name == '/') /* absolute path */ catText(s, name); else if (*name == '~') /* tilde expansion */ { char *name_copy = strnew(name, 0); char *user = name_copy+1; char *user_endp, *path; char *homedir; /* get the username */ user_endp = strstr (name_copy, "/"); if (user_endp) { *user_endp = 0; path = user_endp+1; } else path = 0; if (strlen(user) == 0) user = getLogin(TRUE); homedir = getUserHomeDir (user, 0); messfree(name_copy); if (homedir) { catText(s, homedir); catText(s, "/"); messfree(homedir); } else return FALSE; if (path) catText(s, path); } else /* Add cwd to make absolute path */ { int wdsiz = MAXPATHLEN; char *wd = messalloc(wdsiz); while (!getcwd(wd, wdsiz)) { messfree(wd); wdsiz += MAXPATHLEN; wd = messalloc(wdsiz); } catText(s, wd); if ((*name) && (strcmp(name, ".") != 0)) /* dump empty name or "." */ { catText(s, "/"); catText(s, name); } messfree(wd); } if (ending && *ending) { catText(s, "."); catText(s, ending); } return TRUE; } char *filGetName(char *name, char *ending, char *spec, STORE_HANDLE handle) { Stack s = stackCreate(MAXPATHLEN); char *ret; if (!name) messcrash ("filGetName received a null name") ; if (filCanonPath(s, name, ending) && filCheck(stackText(s, 0), spec)) ret = strnew(stackText(s, 0), handle); else ret = NULL; stackDestroy(s); return ret; } BOOL filCheckName(char *name, char *ending, char *spec) { Stack s = stackCreate(MAXPATHLEN); BOOL ret; if (!name) messcrash ("filCheckName received a null name") ; ret = filCanonPath(s, name, ending) && filCheck(stackText(s, 0), spec); stackDestroy(s); return ret; } char *filGetFullPath(char *dir, STORE_HANDLE handle) { Stack s = stackCreate(MAXPATHLEN); char *ret; if (filCanonPath(s, dir, 0)) ret = strnew(stackText(s, 0), handle); else ret = NULL; stackDestroy(s); return ret; } /* Compatibilty function: Note that: THIS IS NOT THREADSAFE. Continued use of this function will send you blind. */ char *filName (char *name, char *ending, char *spec) { static Stack s = NULL; if (!s) s = stackCreate(MAXPATHLEN); else stackClear(s); if (filCanonPath(s, name, ending) && filCheck(stackText(s, 0), spec)) return stackText(s, 0); else return NULL; } /************************************************************/ BOOL filremove (char *name, char *ending) /* TRUE if file is deleted. -HJC*/ { Stack s = stackCreate(MAXPATHLEN); BOOL ret; filCanonPath(s, name, ending) ; ret = unlink(stackText(s, 0)) ? FALSE : TRUE ; stackDestroy(s); return ret; } /* filremove */ /**************************************************************/ FILE *filopen (char *name, char *ending, char *spec) { Stack s = stackCreate(MAXPATHLEN); FILE *result = 0 ; filCanonPath(s, name, ending); if (!filCheck(stackText(s, 0), spec)) { if (spec[0] == 'r') messerror ("Failed to open for reading: %s (%s)", stackText(s, 0), messSysErrorText()) ; else if (spec[0] == 'w') messerror ("Failed to open for writing: %s (%s)", stackText(s ,0), messSysErrorText()) ; else if (spec[0] == 'a') messerror ("Failed to open for appending: %s (%s)", stackText(s ,0), messSysErrorText()) ; else messcrash ("filopen() received invalid filespec %s", spec ? spec : "(null)"); } else if (!(result = fopen (stackText(s, 0), spec))) messerror ("Failed to open %s (%s)", stackText(s, 0), messSysErrorText()) ; stackDestroy(s); return result ; } /* filopen */ /********************* temporary file stuff *****************/ static Associator tmpFiles = 0 ; FILE *filtmpopen (char **nameptr, char *spec) { return filTmpOpenWithSuffix(nameptr, 0, spec); } FILE *filTmpOpenWithSuffix (char **nameptr, char *suffix, char *spec) { char *nam, *realname; #ifdef __CYGWIN__ char *tmpenv = getenv("TEMP"); char tmppath[PATH_MAX]; if (tmpenv) cygwin_conv_to_full_posix_path(tmpenv, tmppath); else cygwin_conv_to_full_posix_path("c:\\Temp", tmppath); #endif if (!nameptr) messcrash ("filtmpopen requires a non-null nameptr") ; if (!strcmp (spec, "r")) return filopen (*nameptr, 0, spec) ; #if defined(SUN) || defined(SOLARIS) if (!(nam = tempnam ("/var/tmp", "ACEDB"))) #elif defined(__CYGWIN__) if (!(nam = tempnam(tmppath, "ACEDB"))) #else if (!(nam = tempnam ("/tmp", "ACEDB"))) #endif { messerror ("failed to create temporary file (%s)", messSysErrorText()) ; return 0 ; } if (suffix == 0) { realname = strnew(nam, 0); } else { realname = messalloc(strlen(nam)+strlen(suffix)+2); /* . and terminator */ strcpy(realname, nam); strcat(realname, "."); strcat(realname, suffix); } free(nam); if (!tmpFiles) tmpFiles = assCreate () ; assInsert (tmpFiles, realname, realname) ; *nameptr = realname; return filopen (*nameptr, 0, spec) ; } /* filtmpopen */ /************************************************************/ BOOL filtmpremove (char *name) /* delete and free() */ { BOOL result = filremove (name, 0) ; assRemove (tmpFiles, name) ; messfree(name); return result ; } /************************************************************/ void filtmpcleanup (void) { char *name = 0 ; if (tmpFiles) while (assNext (tmpFiles, &name, 0)) { char *name1 = name; filremove (name, 0) ; messfree (name1) ; /* Since messfree zeros it. */ } } /************* filqueryopen() ****************/ static QueryOpenRoutine queryOpenFunc = 0 ; QueryOpenRoutine filQueryOpenRegister (QueryOpenRoutine new) { QueryOpenRoutine old = queryOpenFunc ; queryOpenFunc = new ; return old ; } FILE *filqueryopen (char *dname, char *fname, char *end, char *spec, char *title) { Stack s ; FILE* fil = 0 ; int i ; ACEIN answer_in; /* use registered routine if available */ if (queryOpenFunc) return (*queryOpenFunc)(dname, fname, end, spec, title) ; /* otherwise do here and use messPrompt() */ s = stackCreate(50); if (dname && *dname) { pushText(s, dname) ; catText(s,"/") ; } if (fname) catText(s,fname) ; if (end && *end) { catText(s,".") ; catText(s,end) ; } lao: answer_in = messPrompt("File name please", stackText(s,0), "w", 0); if (!answer_in) { stackDestroy(s) ; return 0 ; } i = stackMark(s) ; pushText(s, aceInPath(answer_in)); aceInDestroy (answer_in); if (spec[0] == 'w' && filCheckName (stackText(s,i), "", "r")) { if (messQuery (messprintf ("Overwrite %s?", stackText(s,i)))) { if ((fil = filopen (stackText(s,i), "", spec))) goto bravo ; else messout ("Sorry, can't open file %s for writing", stackText (s,i)) ; } goto lao ; } else if (!(fil = filopen (stackText(s,i), "", spec))) messout ("Sorry, can't open file %s", stackText(s,i)); bravo: stackDestroy(s) ; return fil ; } /* filqueryopen */ /*********************************************/ Associator mailFile = 0, mailAddress = 0 ; void filclose (FILE *fil) { char *address ; char *filename ; if (!fil || fil == stdin || fil == stdout || fil == stderr || fil == (FILE *)0x1) /* see filquery.c - 0x1 == dummy directory */ return ; fclose (fil) ; if (mailFile && assFind (mailFile, fil, &filename)) { if (assFind (mailAddress, fil, &address)) callScript ("mail", messprintf ("%s < %s", address, filename)) ; else messerror ("Have lost the address for mailfile %s", filename) ; assRemove (mailFile, fil) ; assRemove (mailAddress, fil) ; filtmpremove (filename) ; /* came from filmail() */ } } /* filclose */ /***********************************/ FILE *filmail (char *address) /* requires filclose() */ { char *filename ; FILE *fil ; if (!mailFile) { mailFile = assCreate () ; mailAddress = assCreate () ; } if (!(fil = filtmpopen (&filename, "w"))) { messout ("failed to open temporary mail file %s", filename) ; return 0 ; } assInsert (mailFile, fil, filename) ; assInsert (mailAddress, fil, address) ; return fil ; } /* filmail */ /******************* directory stuff *************************/ static int dirOrder(void *a, void *b) { char *cp1 = *(char **)a, *cp2 = *(char**)b; return strcmp(cp1, cp2) ; } /* dirOrder */ static void filDirFinalise (void *vp) { FilDir fdir = (FilDir)vp; handleDestroy (fdir->handle); return; } /* filDirFinalise */ FilDir filDirHandleCopy (FilDir fd, STORE_HANDLE handle) { int i; FilDir fdir; fdir = (FilDir)halloc(sizeof(struct FilDirStruct), handle); blockSetFinalise (fdir, filDirFinalise); fdir->handle = handleCreate(); fdir->entries = arrayHandleCreate (arrayMax(fd->entries), char*, fdir->handle) ; for (i = 0; i < filDirMax(fd); ++i) { array (fdir->entries, i, char*) = strnew(filDirEntry(fd, i), fdir->handle); } return fdir; } /* filDirCopy */ /* returns a directory listing of strings representing the filename in the given directory according to the spec. "r" will list all files, and "rd" will list all directories. The behavior of the "w" spec is undefined. The directory entries are accessed using char *filDirEntry (FilDir dir, int i); int filDirMax (FilDir dir); The returned FilDir object has to be destroyed using messfree, which reclaims all memory. */ FilDir filDirHandleCreate (char *dirName, char *ending, char *spec, STORE_HANDLE handle) { FilDir fdir ; DIR *dirp ; char *dName, entryPathName[MAXPATHLEN], *leaf ; int dLen, endLen ; MYDIRENT *dent ; if (!dirName || !(dirp = opendir (dirName))) return 0 ; fdir = (FilDir)halloc(sizeof(struct FilDirStruct), handle); blockSetFinalise (fdir, filDirFinalise); fdir->handle = handleCreate(); fdir->entries = arrayHandleCreate (16, char*, fdir->handle) ; if (ending) endLen = strlen (ending) ; else endLen = 0 ; strcpy (entryPathName, dirName) ; strcat (entryPathName, "/") ; leaf = entryPathName + strlen(dirName) + 1 ; while ((dent = readdir (dirp))) { dName = dent->d_name ; dLen = strlen (dName) ; if (endLen && (dLen <= endLen || dName[dLen-endLen-1] != '.' || strcmp (&dName[dLen-endLen],ending))) continue ; strcpy (leaf, dName) ; if (!filCheck (entryPathName, spec)) continue ; if (ending && dName[dLen - endLen - 1] == '.') /* remove ending */ dName[dLen - endLen - 1] = 0 ; /* the memory of these strings is reclaimed by filDirFinalise, if the returned FilDir object is destroyed using messfree() */ array(fdir->entries, arrayMax(fdir->entries), char*) = strnew (dName, fdir->handle); } closedir (dirp) ; /************* reorder ********************/ arraySort(fdir->entries, dirOrder) ; return fdir ; } /* filDirCreate */ /*************************************************************/ /* This function copies a file (surprisingly there is no standard Posix */ /* function to do this). The file is created with read/write permissions */ /* for the user. Note that it is permissible for the new file to exist, in */ /* which case its contents will be OVERWRITTEN. This is to allow the caller */ /* to create a file with a unique name, close it and then supply it as an */ /* argument to this call (e.g. caller may use aceTmpCreate() to create the */ /* file). */ /* */ /* The function returns FALSE for the following errors: */ /* */ /* 1) supplying a NULL ptr or empty string for either file name. */ /* 2) if the file to be copied does not exist/is not readable. */ /* 3) if the file to be created is not writeable. */ /* 4) if the copy fails for some other reason (e.g. read/write failed) */ /* */ /* This code is adapted from ffcopy.c from "POSIX Programmers Guide" */ /* by Donald Levine, publ. by O'Reilly. */ /* */ /* It would be handy to use access() to check whether we can read a file */ /* but this only uses the real UID, not the effective UID. stat() returns */ /* info. about the file mode but we would need to get hold of all sorts of */ /* other information (effective UID, group membership) to use it. */ /* */ BOOL filCopyFile(char *curr_name, char *new_name) { BOOL status = TRUE ; struct stat file_stat ; ssize_t buf_size ; size_t bytes_left ; enum {BUF_MAX_BYTES = 4194304} ; /* Buffer can be up to this size. */ char *buffer = NULL ; int curr_file = -1, new_file = -1 ; /* File names supplied ? */ if (!curr_name || !(*curr_name) || !new_name || !(*new_name)) status = FALSE ; /* Make sure file to be copied exists and can be opened for reading. */ if (status) { if (stat(curr_name, &file_stat) != 0) status = FALSE ; else { bytes_left = buf_size = file_stat.st_size ; if (buf_size > BUF_MAX_BYTES) buf_size = BUF_MAX_BYTES ; if ((curr_file = open(curr_name, O_RDONLY, 0)) == -1) status = FALSE ; } } /* Make sure file to be written can be opened for writing (O_TRUNC means */ /* existing contents of the file will be overwritten). */ if (status) { if ((new_file = open(new_name, O_WRONLY|O_CREAT|O_TRUNC, S_IRUSR|S_IWUSR)) == -1) status = FALSE ; } /* allocate a buffer for the whole file, or the maximum chunk if the file */ /* is bigger. */ if (status) { if((buffer = (char *)messalloc(buf_size)) == NULL) status = FALSE ; } /* Copy the file. */ if (status) { while (bytes_left > 0 && status) { if (read(curr_file, buffer, buf_size) != buf_size) status = FALSE ; if (status) { if (write(new_file, buffer, buf_size) != buf_size) status = FALSE ; } if (status) { bytes_left -= buf_size; if (bytes_left < buf_size) buf_size = bytes_left ; } } } /* Clear up buffer and files. */ if (buffer != NULL) messfree(buffer) ; if (curr_file > -1) { if (close(curr_file) != 0) messcrash("close() of file being copied failed.") ; } if (new_file > -1) { if (close(new_file) != 0) messcrash("close() of file being copied failed.") ; } return status ; } /************************************************************/ /* determines the age of a file, according to its last modification date. returns TRUE if the age could determined and the int-pointers (if non-NULL will be filled with the numbers). returns FALSE if the file doesn't exist, is not readable, or the age could not be determined. */ /************************************************************/ BOOL filAge (char *name, char *end, int *diffYears, int *diffMonths, int *diffDays, int *diffHours, int *diffMins, int *diffSecs) { struct stat status; mytime_t time_now, time_modified; char time_modified_str[25]; char *filName; time_t t; struct tm *ts; /* get the last-modification time of the file, we parse the time into two acedb-style time structs in order to compare them using the timediff functions */ if (!(filName = filGetName(name, end, "r", 0))) return FALSE; if (stat (filName, &status) == -1) { messfree(filName); return FALSE; } messfree(filName); t = status.st_mtime; /* convert the time_t time into a tm-struct time */ ts = localtime(&t); /* get a string with that time in it */ strftime (time_modified_str, 25, "%Y-%m-%d_%H:%M:%S", ts) ; time_now = timeNow(); time_modified = timeParse(time_modified_str); if (diffYears) timeDiffYears (time_modified, time_now, diffYears); if (diffMonths) timeDiffMonths (time_modified, time_now, diffMonths); if (diffDays) timeDiffDays (time_modified, time_now, diffDays); if (diffHours) timeDiffHours (time_modified, time_now, diffHours); if (diffMins) timeDiffMins (time_modified, time_now, diffMins); if (diffSecs) timeDiffSecs (time_modified, time_now, diffSecs); return TRUE; } /* filAge */ /*************** end of file ****************/ acedb-4.9.39+dfsg.01/w1/freeout.c0000444000175000017500000001373710112001151016027 0ustar moellermoeller/* File: freeout.c * Author: Danielle et jean Thierry-Mieg (mieg@mrc-lmba.cam.ac.uk) * Copyright (C) J Thierry-Mieg and R Durbin, 1995 * ------------------------------------------------------------------- * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * ------------------------------------------------------------------- * This file is part of the ACEDB genome database package, written by * Richard Durbin (MRC LMB, UK) rd@mrc-lmba.cam.ac.uk, and * Jean Thierry-Mieg (CRBM du CNRS, France) mieg@frmop11.bitnet * * Description: * Exported functions: see regular.h * HISTORY: * Last edited: Nov 3 13:14 1999 (fw) * * Sep 11 09:26 1998 (edgrif): Add messExit function registering. * * Dec 14 16:47 1995 (mieg) * Created: Thu Dec 7 22:22:33 1995 (mieg) *------------------------------------------------------------------- */ /* $Id: freeout.c,v 1.23 2004/08/22 02:18:17 mieg Exp $ */ #include "freeout.h" #include #include typedef struct outStruct { int magic ; FILE *fil ; Stack s ; int line ; /* line number */ int pos ; /* char number in line */ int byte ; /* total byte length */ int level ; struct outStruct *next ; } OUT ; static int MAGIC = 245393 ; static int outLevel = 0 ; static Array outArray = 0 ; static OUT *outCurr ; static Stack outBuf = 0 ; /* buffer for messages */ #define BUFSIZE 65536 /************************************************/ void freeOutInit (void) { static BOOL isInitialised = FALSE ; if (!isInitialised) { isInitialised = TRUE ; outLevel = 0 ; outCurr = 0 ; outArray = arrayCreate (6, OUT) ; freeOutSetFile (stdout) ; outBuf = stackCreate (BUFSIZE) ; } } /************************************************/ static int freeOutSetFileStack (FILE *fil, Stack s) { int i = 0 ; freeOutInit () ; while (array (outArray, i, OUT).magic) i++ ; outLevel++ ; outCurr = arrayp (outArray, i, OUT) ; if (fil) outCurr->fil = fil ; else if (s) outCurr->s = s ; outCurr->line = outCurr->pos = outCurr->byte = 0 ; outCurr->next = 0 ; outCurr->level = outLevel ; outCurr->magic = MAGIC ; return outLevel ; } int freeOutSetFile (FILE *fil) { return freeOutSetFileStack (fil, 0) ; } int freeOutSetStack (Stack s) { return freeOutSetFileStack (0, s) ; } /************************************************/ void freeOutClose (int level) { int i = arrayMax (outArray) ; OUT *out ; while (i--) { out = arrayp (outArray, i, OUT) ; if (!out->magic) continue ; if (out->magic != MAGIC) messcrash("bad magic in freeOutClose") ; if (out->level >= outLevel) /* close all tees */ { /* do NOT close fil, because freeOutSetFile did not open it */ out->s = 0 ; out->fil = 0 ; outCurr->line = outCurr->pos = outCurr->byte = 0 ; out->next = 0 ; out->magic = 0 ; out->level = 0 ; } else break ; } outLevel-- ; outCurr = arrayp (outArray, i, OUT) ; if (outCurr->level != outLevel) messcrash ("anomaly in freeOutClose") ; } /************************************************/ void freeOut (char *text) { OUT *out = outCurr ; char *cp ; int pos = 0, line = 0, ln ; cp = text ; ln = strlen(text) ; while (*cp) if (*cp++ == '\n') { pos = 0 ; line++ ;} else pos++ ; while (out) { if (out->s) catText(out->s, text) ; if (out->fil) fputs(text, out->fil) ; /* fprintf over interprets % and \ */ out->byte += ln ; if (line) { out->line += line ; out->pos = pos ; } else out->pos += pos ; out = out->next ; } } /*************************************************************/ /* copy a binary structure onto a text stack */ void freeOutBinary (char *data, int size) { OUT *out = outCurr ; if (out->fil) fwrite(data,size,1,out->fil); else if (out->s) { catBinary (out->s,data,size); /* acts like a newline was added */ out->pos = 0; out->line++; } } /*************************************************************/ void freeOutxy (char *text, int x, int y) { static Array buf = 0 ; OUT *out = outCurr ; int i, j, k = 0 ; i = x - out->pos , j = y - out->line ; if (i || j) { buf = arrayReCreate (buf, 100, char) ; k = 0 ; if (j > 0) { while (j--) array (buf, k++, char) = '\n' ; i = x ; } if (i < 0) { array (buf, k++, char) = '\n' ; i = x ; out->line-- ; /* kludge, user should ignore this line feed */ } if (i > 0) { while (i--) array (buf, k++, char) = ' ' ; } array (buf, k++, char) = 0 ; freeOut (arrp(buf, 0, char)) ; } freeOut (text) ; } /************************************************/ void freeOutf (char *format,...) { int len ; char *message ; va_list ap; stackClear (outBuf) ; va_start(ap, format); len = g_printf_string_upper_bound (format, ap) ; va_end (ap) ; stackExtend (outBuf, len + 1) ; message = stackText (outBuf, 0) ; va_start (ap, format); len = vsprintf (message, format, ap) ; va_end (ap) ; freeOut (message) ; } /************************************************/ int freeOutLine (void) { return outCurr->line ; } int freeOutByte (void) { return outCurr->byte ; } int freeOutPos (void) { return outCurr->pos ; } /************************************************/ /************************************************/ acedb-4.9.39+dfsg.01/w1/freesubs.c0000444000175000017500000011542410130455652016213 0ustar moellermoeller/* File: freesubs.c * Author: Richard Durbin (rd@mrc-lmb.cam.ac.uk) * Copyright (C) J Thierry-Mieg and R Durbin, 1991 * ------------------------------------------------------------------- * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * ------------------------------------------------------------------- * This file is part of the ACEDB genome database package, written by * Richard Durbin (MRC LMB, UK) rd@mrc-lmb.cam.ac.uk, and * Jean Thierry-Mieg (CRBM du CNRS, France) mieg@kaa.cnrs-mop.fr * * Description: free format input - record based * Exported functions: lots - see regular.h * HISTORY: * Last edited: Oct 5 09:10 2004 (edgrif) * * Apr 26 10:06 1999 (edgrif): Add code to trap NULL value for freedouble. * * Jan 14 13:31 1999 (fw): increased version umber to 1.1.2 * due to changes in the directory handling interface * (Array)filDirectoryCreate -> (FilDir)filDirHandleCreate * * Dec 3 14:46 1998 (edgrif): Insert version macros for libfree. * freecard ignores "\r" and "\n" under WIN32 * * Sep 30 14:19 1998 (edgrif) * * Nov 27 12:30 1995 (mieg): freecard no longer stips \, freeword does * also i added freeunprotect * Created: Sun Oct 27 18:16:01 1991 (rd) * CVS info: $Id: freesubs.c,v 1.61 2004/10/05 08:30:34 edgrif Exp $ *------------------------------------------------------------------- */ #include #include "regular.h" #include "version.h" #include /* free package version and copyright string. */ /* */ #define FREE_TITLE "Free library" #define FREE_DESC "Sanger Centre Informatics utilities library." #define FREE_VERSION 1 #define FREE_RELEASE 1 #define FREE_UPDATE 2 #define FREE_VERSION_NUMBER UT_MAKE_VERSION_NUMBER(FREE_VERSION, FREE_RELEASE, FREE_UPDATE) UT_COPYRIGHT_STRING(FREE_TITLE, FREE_VERSION, FREE_RELEASE, FREE_UPDATE, FREE_DESC) /* uuugghhh, this has to go... * have a look at session.s:realIsInteractive about how to determine this properly */ BOOL isInteractive = TRUE ; /* can set FALSE, i.e. in tace */ #define MAXSTREAM 80 #define MAXNPAR 80 typedef struct { FILE *fil ; char *text ; char special[24] ; int npar ; int parMark[MAXNPAR] ; int line ; BOOL isPipe ; } STREAM ; static STREAM stream[MAXSTREAM] ; static int streamlevel ; static FILE *currfil ; /* either currfil or currtext is 0 */ static char *currtext ; /* the other is the current source */ static Stack parStack = 0 ; static int maxcard = 1024 ; static unsigned char *card = 0, *word = 0, *cardEnd, *pos ; static Associator filAss = 0 ; #define _losewhite while (*pos == ' '|| *pos == '\t') ++pos #define _stepover(x) (*pos == x && ++pos) #define _FREECHAR (currfil ? getc (currfil) : *currtext++) /************************************/ void freeshutdown (void) { messfree (card) ; messfree (word) ; stackDestroy (parStack) ; assDestroy (filAss) ; } /************************************/ void freeinit (void) { static BOOL isInitialised = FALSE ; if (!isInitialised) { streamlevel = 0 ; currtext = 0 ; stream[streamlevel].fil = currfil = stdin ; stream[streamlevel].text = 0 ; freespecial ("\n\t\\/@%") ; card = (unsigned char *) messalloc (maxcard) ; cardEnd = &card[maxcard-1] ; pos = card ; word = (unsigned char *) messalloc (maxcard) ; filAss = assCreate () ; parStack = stackCreate (128) ; isInitialised = TRUE ; } } /*******************/ /* Sometimes you may need to know if a function below you succeeded in */ /* changing a stream level. */ int freeCurrLevel(void) { return streamlevel ; } /*******************/ static void freeExtend (unsigned char **pin) { /* only happens when getting card */ unsigned char *oldCard = card ; maxcard *= 2 ; card = (unsigned char *) messalloc (maxcard) ; if (oldCard) /* jtm june 22, 1992 */ memcpy (card, oldCard, maxcard/2) ; cardEnd = &card[maxcard-1] ; *pin += (card - oldCard) ; messfree (oldCard) ; messfree (word) ; word = (unsigned char *) messalloc (maxcard) ; } /********************/ static char special[256] ; void freespecial (char* text) { if (!text) messcrash ("freespecial received 0 text") ; if (strlen(text) > 23) messcrash ("freespecial received a string longer than 23") ; if (text != stream[streamlevel].special) strcpy (stream[streamlevel].special, text) ; memset (special, 0, (mysize_t) 256) ; while (*text) special [((int) *text++) & 0xFF] = TRUE ; special[0] = TRUE ; special[(unsigned char)EOF] = TRUE ; /* better have these to ensure streams terminate! */ } /********************/ void freeforcecard (char *string) { int level = freesettext (string, "") ; freespecial ("") ; freecard (level) ; } /********************/ char* freecard (int level) /* returns 0 when streamlevel drops below level */ { unsigned char *in,ch,*cp ; int kpar ; int isecho = FALSE ; /* could reset sometime? */ FILE *fil ; BOOL acceptShell, acceptCommand ; restart : if (level > streamlevel) return 0 ; if (isecho) printf (!currfil ? "From text >" : "From file >") ; in = card - 1 ; acceptCommand = special['@'] ; acceptShell = special['$'] ; while (TRUE) { if (++in >= cardEnd) freeExtend (&in) ; *in = _FREECHAR ; lao: if (special[((int) *in) & 0xFF] && *in != '$' && *in != '@' ) switch (*in) { #if defined(WIN32) case '\r': continue ; /* ignore carriage returns */ #endif case '\n': /* == '\x0a' */ case ';': /* card break for multiple commands on one line */ goto got_line ; case (unsigned char) EOF: case '\0': freeclose(streamlevel) ; goto got_line; case '\t': /* tabs should get rounded to 8 spaces */ if (isecho) /* write it out */ putchar (*in) ; *in++ = ' ' ; while ((in - card) % 8) { if (in >= cardEnd) freeExtend (&in) ; *in++ = ' ' ; } --in ; continue ; case '/': /* // means start of comment */ if ((ch = _FREECHAR) == '/') { while ((ch = _FREECHAR) != '\n' && ch && ch != (unsigned char)EOF) ; *in = ch ; goto lao ; /* mieg, nov 2001, to treat the EOF, this was breaking the server if sent a comment */ } else { if (isecho) putchar (*in) ; if (currfil) /* push back ch */ ungetc (ch, currfil) ; else --currtext ; } break ; case '%': /* possible parameter */ --in ; kpar = 0 ; while (isdigit (ch = _FREECHAR)) kpar = kpar*10 + (ch - '0') ; if (kpar > 0 && kpar <= stream[streamlevel].npar) for (cp = (unsigned char *) stackText (parStack, stream[streamlevel].parMark[kpar-1]) ; *cp ; ++cp) { if (++in >= cardEnd) freeExtend (&in) ; *in = *cp ; if (isecho) putchar (*in) ; } else messout ("Parameter %%%d can not be substituted", kpar) ; if (++in >= cardEnd) freeExtend (&in) ; *in = ch ; goto lao ; /* mieg */ case '\\': /* escapes next character - interprets \n */ *in = _FREECHAR ; if (*in == '\n') /* fold continuation lines */ { if (isInteractive && !streamlevel) printf (" Continuation >") ; while ((ch = _FREECHAR) == ' ' || ch == '\t') ; /* remove whitespace at start of next line */ if (currfil) /* push back ch */ ungetc (ch, currfil) ; else --currtext ; stream[streamlevel].line++ ; --in ; } #if !defined(WIN32) else if (*in == 'n') /* reinterpret \n as a format */ { *in = '\n' ; } #endif else /* keep the \ till freeword is called */ { *(in+1) = *in ; *in = '\\' ; if (++in >= cardEnd) freeExtend (&in) ; } break ; default: messerror ("freesubs got unrecognised special character 0x%x = %c\n", *in, *in) ; } else { if (!isprint(*in) && *in != '\t' && *in != '\n') /* mieg dec 15 94 */ --in ; else if (isecho) /* write it out */ putchar (*in) ; } } /* while TRUE loop */ got_line: stream[streamlevel].line++ ; *in = 0 ; if (isecho) putchar ('\n') ; pos = card ; _losewhite ; if (acceptCommand && _stepover ('@')) /* command file */ { char *name ; if ((name = freeword ()) && (fil = filopen (name, 0, "r"))) freesetfile (fil, (char*) pos) ; goto restart ; } if (acceptShell && _stepover ('$')) /* shell command */ { #if !defined(MACINTOSH) system ((char*)pos) ; #endif goto restart ; } return (char*) card ; } /************************************************/ void freecardback (void) /* goes back one card */ { stream[streamlevel].line-- ; freesettext ((char*) card, "") ; } /************************************************/ /* reads card from fil, has some embedded logic for dealing with * escaped newlines which doesn't use the freespecial() stuff. * I don't know the reason for this and probably it could be added * but this is now legacy code as the aceIn/Out package should be * used instead. */ BOOL freeread (FILE *fil) { unsigned char ch, *in = card ; int *line, chint ; if (!assFind (filAss, fil, &line)) { line = (int*) messalloc (sizeof (int)) ; assInsert (filAss, fil, line) ; } --in ; while (TRUE) { ++in ; if (in >= cardEnd) freeExtend (&in) ; chint = getc(fil) ; if (ferror(fil)) messerror ("chint was bad"); *in = chint ; switch (*in) { case '\n' : ++*line ; case (unsigned char) EOF : goto got_line ; case '/' : /* // means start of comment */ if ((ch = getc (fil)) == '/') { while (getc(fil) != '\n' && !feof(fil)) ; ++*line ; if (in > card) /* // at start of line ignores line */ goto got_line ; else --in ; /* in = 0 unprintable, so backstepped */ } else ungetc (ch,fil) ; break ; case '\\' : /* escape next character, NOTE fall through. */ *in = getc(fil) ; if (*in == '\n') /* continuation */ { ++*line ; while (isspace (*in = getc(fil))) ; /* remove whitespace */ } else if (*in == '"' || *in == '/' || *in == '\\' || *in == 'n') /* escape for freeword, newline */ { *(in+1) = *in ; *in = '\\' ; ++in ; } /* NB fall through - in case next char is nonprinting */ default: if (!isprint (*in) && *in != '\t') /* ignore control chars, e.g. \x0d */ --in ; } } got_line : *in = 0 ; pos = card ; _losewhite ; if (feof(fil)) { assRemove (filAss, fil) ; messfree (line) ; } return *pos || !feof(fil) ; } int freeline (FILE *fil) { int *line ; if (assFind (filAss, fil, &line)) return *line ; else return 0 ; } int freestreamline (int level) { return stream[level].line ; } /********************************************/ static void freenewstream (char *parms) { int kpar ; stream[streamlevel].fil = currfil ; stream[streamlevel].text = currtext ; if (++streamlevel == MAXSTREAM) messcrash ("MAXSTREAM overflow in freenewstream") ; strcpy (stream[streamlevel].special, stream[streamlevel-1].special) ; stream[streamlevel].npar = 0 ; stream[streamlevel].line = 1 ; if (!parms || !*parms) return ; /* can t abuse NULL ! */ pos = (unsigned char *) parms ; /* abuse freeword() to get parms */ for (kpar = 0 ; kpar < MAXNPAR && freeword () ; kpar++) /* read parameters */ { stream[streamlevel].parMark[kpar] = stackMark (parStack) ; pushText (parStack, (char*) word) ; } stream[streamlevel].npar = kpar ; stream[streamlevel].isPipe = FALSE ; pos = card ; /* restore pos to start of blank card */ *card = 0 ; } int freesettext (char *string, char *parms) { freenewstream (parms) ; currfil = 0 ; currtext = string ; return streamlevel ; } int freesetfile (FILE *fil, char *parms) { freenewstream (parms) ; currfil = fil ; currtext = 0 ; return streamlevel ; } int freesetpipe (FILE *fil, char *parms) { freenewstream (parms) ; currfil = fil ; currtext = 0 ; stream[streamlevel].isPipe = TRUE ; return streamlevel ; } void freeclose(int level) { int kpar ; while (streamlevel >= level) { if (currfil && currfil != stdin && currfil != stdout) { if (stream[streamlevel].isPipe) pclose (currfil) ; else filclose (currfil) ; } for (kpar = stream[streamlevel].npar ; kpar-- ;) popText (parStack) ; --streamlevel ; currfil = stream[streamlevel].fil ; currtext = stream[streamlevel].text ; freespecial (stream[streamlevel].special) ; } } /************************************************/ /* freeword(), freewordcut() and freestep() are the only calls that directly move pos forward -- all others act via freeword(). freeback() moves pos back one word. */ char *freeword (void) { unsigned char *cw ; _losewhite ; /* needed in case of intervening freestep() */ if (_stepover ('"')) { for (cw = word ; !_stepover('"') && *pos ; *cw++ = *pos++) if (_stepover('\\')) /* accept next char unless end of line */ if (!*pos) break ; _losewhite ; *cw = 0 ; return (char*) word ; /* always return a word, even if empty */ } /* default: break on space and \t, not on comma */ for (cw = word ; isgraph (*pos) && *pos != '\t' ; *cw++ = *pos++) if (_stepover('\\')) /* accept next char unless end of line */ if (!*pos) break ; _losewhite ; *cw = 0 ; return *word ? (char*) word : 0 ; } /************************************************/ #if defined(WIN32) char *freepath (void) { unsigned char *cw ; _losewhite ; /* needed in case of intervening freestep() */ if (_stepover ('"')) { for (cw = word ; !_stepover('"') && *pos ; *cw++ = *pos++) if (_stepover('\\')) /* accept next char unless end of line */ if (!*pos) break ; _losewhite ; *cw = 0 ; return (char*) word ; /* always return a word, even if empty */ } /* default: break on space, \t or end of line, not on comma also, does not skip over backslashes which are assumed to be MS DOS/Windows path delimiters */ for (cw = word ; ( *pos == '\\' || isgraph (*pos) ) && *pos != '\t' ; *cw++ = *pos++) ; _losewhite ; *cw = 0 ; return *word ? (char*) word : 0 ; } #endif /************************************************/ char *freewordcut (char *cutset, char *cutter) /* Moves along card, looking for a character from cut, which is a 0-terminated char list of separators. Returns everything up to but not including the first match. pos is moved one char beyond the character. *cutter contains the char found, or if end of card is reached, 0. */ { unsigned char *cc,*cw ; for (cw = word ; *pos ; *cw++ = *pos++) for (cc = (unsigned char *) cutset ; *cc ; ++cc) if (*cc == *pos) goto wcut ; wcut: *cutter = *pos ; if (*pos) ++pos ; _losewhite ; *cw = 0 ; return *word ? (char*) word : 0 ; } /************************************************/ void freeback (void) /* goes back one word - inefficient but reliable */ {unsigned char *now = pos ; unsigned char *old = pos ; pos = card ; _losewhite ; while (pos < now) {old = pos ; freeword () ; } pos = old ; } /************************************************/ /* Read a word representing an int from wherever free is pointing to. */ /* */ /* If there is no word OR the word cannot be converted to an int, reset */ /* the free pos, don't set the int param. and return FALSE */ /* If the word is "NULL" set int param to the POSIX "too small" int value */ /* and return TRUE */ /* Otherwise set the int param to the converted int and return TRUE */ /* */ /* Note that valid range of ints is INT_MIN < valid < INT_MAX */ /* otherwise UT_NON_INT doesn't work. */ /* */ BOOL freeint (int *p) {BOOL result = FALSE ; unsigned char *keep ; enum {DECIMAL_BASE = 10} ; char *endptr ; long int bigint ; keep = pos ; if (freeword ()) { /*printf ("freeint got '%s'\n", word) ;*/ if (!strcmp((char *)word, "NULL")) { *p = UT_NON_INT ; result = TRUE ; } else { errno = 0 ; bigint = strtol((char *)word, &endptr, DECIMAL_BASE) ; if ((bigint == 0 && endptr == (char *)word) /* first character wrong */ || (endptr != (char *)(word + strlen((char *)word))) /* some other character wrong */ || (errno == ERANGE) /* number too small/big for long int */ || (bigint <= INT_MIN || bigint >= INT_MAX)) /* number too small/big for int */ { pos = keep ; return FALSE ; } else { *p = (int)bigint ; result = TRUE ; } } } else { pos = keep ; result = FALSE ; } return result ; } /*****************************/ /* Read a word representing a float from wherever free is pointing to. */ /* */ /* If there is no word OR the word cannot be converted to a float, reset */ /* the free pos, don't set the float param. and return FALSE */ /* If the word is "NULL" set float param to the POSIX "too small" float value*/ /* and return TRUE */ /* Otherwise set the float param to the converted float and return TRUE */ /* */ /* Note that valid range of floats is: */ /* -ve -FLT_MAX < valid < -FLT_MIN */ /* +ve FLT_MIN < valid < FLT_MAX */ /* otherwise UT_NON_FLOAT doesn't work as a range check for applications. */ /* */ BOOL freefloat (float *p) { BOOL result = FALSE ; unsigned char *keep ; double bigfloat ; char *endptr ; keep = pos ; if (freeword ()) { if (strcmp ((char*)word, "NULL") == 0) { *p = UT_NON_FLOAT ; /* UT_NON_FLOAT = -FLT_MAX */ result = TRUE ; } else { errno = 0 ; bigfloat = strtod((char *)word, &endptr) ; if ((bigfloat == +0.0 && endptr == (char *)word) /* first character wrong */ || (endptr != (char *)(word + strlen((char *)word))) /* some other character wrong */ || (errno == ERANGE) /* number too small/big for double */ || (bigfloat < 0 && (bigfloat >= -FLT_MIN || bigfloat <= -FLT_MAX)) || (bigfloat > 0 && (bigfloat <= FLT_MIN || bigfloat >= FLT_MAX))) { /* number too small/big for float */ pos = keep ; result = FALSE ; } else { *p = (float)bigfloat ; result = TRUE ; } } } else { pos = keep ; result = FALSE ; } return result ; } /**************************************************/ /* Read a word representing a double from wherever free is pointing to. */ /* */ /* If there is no word OR the word cannot be converted to a double, reset */ /* the free pos, don't set the double param. and return FALSE */ /* Otherwise set the double param to the converted double and return TRUE */ /* */ /* Note that valid range of doubles is: */ /* -ve -DBL_MAX < valid < -DBL_MIN */ /* +ve DBL_MIN < valid < DBL_MAX */ /* otherwise UT_NON_DOUBLE doesn't work as a range check for applications. */ /* */ /* Note that because double is the largest number we can only check to see */ /* if the converted number is equal to this, not >= as in the case of floats.*/ /* */ BOOL freedouble (double *p) { BOOL result = FALSE ; unsigned char *keep ; double bigfloat ; char *endptr ; keep = pos ; if (freeword ()) { if (strcmp ((char*)word, "NULL") == 0) { *p = UT_NON_DOUBLE ; /* UT_NON_DOUBLE = -DBL_MAX */ result = TRUE ; } else { errno = 0 ; bigfloat = strtod((char *)word, &endptr) ; if ((bigfloat == +0.0 && endptr == (char *)word) /* first character wrong */ || (endptr != (char *)(word + strlen((char *)word))) /* some other character wrong */ || (errno == ERANGE) /* number too small/big for double */ || (bigfloat < 0 && (bigfloat == -DBL_MIN || bigfloat == -DBL_MAX)) || (bigfloat > 0 && (bigfloat == DBL_MIN || bigfloat == DBL_MAX))) { /* number too small/big. */ pos = keep ; result = FALSE ; } else { *p = bigfloat ; result = TRUE ; } } } else { pos = keep ; result = FALSE ; } return result ; } /*************************************************/ static int ambiguouskey; BOOL freekey (KEY *kpt, FREEOPT *options) { unsigned char *keep = pos ; if (!freeword()) return FALSE ; if (freekeymatch ((char*) word, kpt, options)) return TRUE; if (ambiguouskey) messout ("Keyword %s is ambiguous",word) ; else if (word[0] != '?') messout ("Keyword %s does not match",word) ; pos = keep ; return FALSE ; } /*****************/ BOOL freekeymatch (char *cp, KEY *kpt, FREEOPT *options) { char *io,*iw ; int nopt = (int)options->key ; KEY key ; ambiguouskey = FALSE; if (!nopt || !cp) return FALSE ; while (TRUE) { iw = cp ; io = (++options)->text ; while (freeupper (*iw++) == freeupper(*io++)) if (!*iw) goto foundit ; if (!--nopt) return FALSE ; } foundit : key = options->key ; if (*io && *io != ' ') /* not a full word match */ while (--nopt) /* check that later options are different */ { io = (++options)->text ; iw = (char*) word ; while (freeupper (*iw++) == freeupper (*io++)) if (!*iw) { ambiguouskey = TRUE; return FALSE ; } } *kpt = key ; return TRUE ; } /***************************************************/ /* Return the text corresponding to the key */ char *freekey2text (KEY k, FREEOPT *o) { int i = o->key ; char *title = o->text ; if (i<0) messcrash("Negative number of options in freekey2text") ; while (o++, i--) if (o->key == k) return (o->text) ; return title ; } /***************************************************/ BOOL freeselect (KEY *kpt, FREEOPT *options) /* like the old freemenu */ { if (isInteractive) printf ("%s > ",options[0].text) ; freecard (0) ; /* just get a card */ if (isInteractive) while (freestep ('?')) /* write out options list */ { int i ; for (i = 1 ; i <= options[0].key ; i++) printf (" %s\n",options[i].text) ; printf ("%s > ",options[0].text) ; freecard (0) ; } return freekey (kpt,options) ; } /* same but returns TRUE, -1, if stremlevel drops below level */ BOOL freelevelselect (int level, KEY *kpt, FREEOPT *options) /* like the old freemenu */ { if (isInteractive) printf ("%s > ",options[0].text) ; if (!freecard (level)) /* try to get another card */ { *kpt = (KEY)(-1) ; return TRUE ; } if (isInteractive) while (freestep ('?')) /* write out options list */ { int i ; for (i = 1 ; i <= options[0].key ; i++) printf (" %s\n",options[i].text) ; printf ("%s > ",options[0].text) ; if (!freecard (level)) /* try to get another card */ { *kpt = (KEY)(-1) ; return TRUE ; } } return freekey (kpt,options) ; } /**************************************/ BOOL freequery (char *query) { if (isInteractive) { int retval, answer = 0 ; printf ("%s (y or n) ",query) ; answer = getchar () ; retval = (answer == 'y' || answer == 'Y') ? TRUE : FALSE ; while (answer != (unsigned char) EOF && answer != -1 && /* mieg: used not to break on EOF in pipes */ answer != '\n') answer = getchar () ; return retval ; } else return TRUE ; } /**********/ BOOL freeprompt (char *prompt, char *dfault, char *fmt) { if (isInteractive) printf("%s ? > ",prompt); freecard (0) ; /* just get a card */ if (freecheck (fmt)) return TRUE ; else { messout ("input mismatch : format '%s' expected, card was\n%s", fmt, card) ; return FALSE ; } } /*************************************/ int freefmtlength (char *fmt) {char *cp ; int length = 0 ; if (isdigit((int)*fmt)) { sscanf (fmt,"%d",&length) ; return length ; } for (cp = fmt ; *cp ; ++cp) switch (*cp) { case 'i' : case 'f' : case 'd' : length += 8 ; break ; case 'w' : length += 32 ; break ; case 't' : length += 80 ; break ; case 'o' : if (*++cp) messcrash ("'o' can not end free format %s",fmt) ; length += 2 ; break ; } if (!length) length = 40 ; return length ; } /****************/ BOOL freecheck (char *fmt) /* checks that whatever is in card fits specified format note that 't' format option changes card by inserting a '"' */ { unsigned char *keep = pos ; union {int i ; float r ; double d ;} target ; char *fp ; unsigned char *start ; int nquote = 1 ; for (fp = fmt ; *fp ; ++fp) switch (*fp) { case 'w' : if (freeword ()) break ; else goto retFALSE ; case 'i' : if (freeint (&target.i)) break ; else goto retFALSE ; case 'f' : if (freefloat (&target.r)) break ; else goto retFALSE ; case 'd' : if (freedouble (&target.d)) break ; else goto retFALSE ; case 't' : /* must insert '"' and escape any remaining '"'s or '\'s */ for (start = pos ; *pos ; ++pos) if (*pos == '"' || *pos == '\\') ++nquote ; *(pos+nquote+1) = '"' ; /* end of line */ for ( ; pos >= start ; --pos) { *(pos + nquote) = *pos ; if (*pos == '"' || *pos == '\\') *(pos + --nquote) = '\\' ; } *start = '"' ; goto retTRUE ; case 'z' : if (freeword ()) goto retFALSE ; else goto retTRUE ; case 'o' : if (!*++fp) messcrash ("'o' can not end free format %s",fmt) ; freestep (*fp) ; break ; case 'b' : break; /* special for graphToggleEditor no check needed il */ default : if (!isdigit((int)*fp) && !isspace((int)*fp)) messerror ("unrecognised char %d = %c in free format %s", *fp, *fp, fmt) ; } retTRUE : pos = keep ; return TRUE ; retFALSE : pos = keep ; return FALSE ; } /************************ little routines ************************/ BOOL freestep (char x) { return (*pos && freeupper (*pos) == x && pos++) ; } void freenext (void) { _losewhite ; } char FREE_UPPER[] = { 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, 16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31, 32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47, 48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63, 64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79, 80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95, 96,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79, 80,81,82,83,84,85,86,87,88,89,90,123,124,125,126,127 } ; char FREE_LOWER[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127 } ; char* freepos (void) /* cheat to give pos onwards */ { return (char*) pos ; } /****************** little arithmetic routines ************************/ /* 1.3 -> 1 ; 1.7 -> 2 * -1.3 -> -1 ; -1.7 -> -2 */ int freeArrondi (float x) { if (x >= 0) return (int) (x + 0.5) ; else return (int) (x - 0.5) ; } /********************************************/ /* returns 1, 2, 5, 10, 20, 50, 100 etc * in absolute value the returned number is smaller than p * 19 -> 10 ; -19 -> -10 */ int freeMainPart (float p) { register int i = 1, sign = 1; if (!p) return 0 ; if (p < 0) { sign = -1 ; p = -p ; } while(i <= p + .00001) i = 10 * i; i /= 10 ; if (2 * i > p) return i * sign; if(5 * i > p) return 2 * i * sign; return 5*i*sign; } /********************************************/ /* returns 1, 2, 5, 10, 20, 50, 100 etc * but the returned number may be a bit bigger than p * 19 -> 20 ; -19 -> -20 */ int freeMainRoundPart (float p) { register int i = 1, sign = 1; if (!p) return 0 ; if (p < 0) {sign = -1 ; p = -p ; } /* RD: ambiguous without spaces on SGI */ while (i < p + .1) i = 10 * i; if (4 * i < 5 * p) return i * sign; i /= 2; if (4 * i < 5 * p) return i * sign; i = (2 * i) / 5; if (4 * i < 5 * p) return i * sign; i = i/2; return i * sign; } /*************************************************************************/ /* returns 1 , 2 , 5 ,10 , 20, 50 ,100 etc */ double freeDoubleMainPart (double p) { register double i = 1, sign = 1; if (!p) return 0.; if(p < 0) {sign = -1; p = -p;} i = (double) exp(log((double)10.0) * (double)(1 + (int)(log10((double)p)))) ; if (4 * i < 5 * p) return i * sign; i /= 2; if (4 * i < 5 * p) return i * sign; i = (2 * i) / 5; if (4 * i < 5 * p) return i*sign; i = i/2; return i*sign; } /*************************************************************************/ /*************************************************************************/ char* freeunprotect (char *text) { static char *buf = 0 ; char *cp, *cp0, *cq ; messfree (buf) ; buf = strnew(text ? text : "", 0) ; /* remove external space and tabs and first quotes */ cp = buf ; while (*cp == ' ' || *cp == '\t') cp++ ; if (*cp == '"') cp++ ; while (*cp == ' ' || *cp == '\t') cp++ ; cq = cp + strlen(cp) - 1 ; while (cq > cp && (*cq == ' ' || *cq == '\t')) *cq-- = 0 ; if (*cq == '"') /* remove one unprotected quote */ { int i = 0 ; char *cr = cq - 1 ; while (cr > cp && *cr == '\\') { i++ ; cr-- ; } if ( i%2 == 0) *cq-- = 0 ; /* discard */ } while (cq > cp && (*cq == ' ' || *cq == '\t')) *cq-- = 0 ; /* gobble the \ */ cp0 = cq = cp-- ; while (*++cp) switch (*cp) { case '\\': if (*(cp+1) == '\\') { cp++ ; *cq++ = '\\' ; break ;} if (*(cp+1) == '\n') { cp ++ ; break ; } /* skip backslash-newline */ if (*(cp+1) == 'n') { cp ++ ; *cq++ = '\n' ; break ; } break ; default: *cq++ = *cp ; } *cq = 0 ; /* terminate the string */ return cp0 ; } char* freeprotect (char* text) /* freeword will read result back as text */ { static Array a = 0 ; char *cp, *cq ; int base ; /* code to make this efficiently reentrant */ if (a && text >= arrp(a,0,char) && text < arrp(a,arrayMax(a),char)) { base = text - arrp(a,0,char) ; array (a, base+3*(1+strlen(text)), char) = 0 ; /* ensure long enough */ text = arrp(a,0,char) + base ; /* may have relocated */ base += 1 + strlen(text) ; } else { a = arrayReCreate (a, 128, char) ; base = 0 ; array (a, 2*(1+strlen(text)), char) = 0 ; /* ensure long enough */ } cq = arrp (a, base, char) ; *cq++ = '"' ; for (cp = text ; *cp ; *cq++ = *cp++) { if (*cp == '\\' || *cp == '"' || /* protect these */ *cp == '/' || *cp == '%' || *cp == ';' || *cp == '\t' || *cp == '\n') *cq++ = '\\' ; if (*cp == '\n') /* -> /n/n (text then real) */ { *cq++ = 'n' ; *cq++ = '\\' ; } } *cq++ = '"' ; *cq = 0 ; return arrp (a, base, char) ; } char* freejavaprotect (char* text) /* freeword will read result back as text */ { static Array a = 0 ; char *cp, *cq ; int base ; /* code to make this efficiently reentrant */ if (a && text >= arrp(a,0,char) && text < arrp(a,arrayMax(a),char)) { base = text - arrp(a,0,char) ; array (a, base+3*(1+strlen(text)), char) = 0 ; /* ensure long enough */ text = arrp(a,0,char) + base ; /* may have relocated */ base += 1 + strlen(text) ; } else { a = arrayReCreate (a, 128, char) ; base = 0 ; array (a, 2*(1+strlen(text)), char) = 0 ; /* ensure long enough */ } cq = arrp (a, base, char) ; cp = text; while (*cp) switch (*cp) { case '\n': *cq++ = '\\'; *cq++ = 'n'; cp++; break; case '\t': *cq++ = '\\'; *cq++ = 't'; cp++; break; case '\\': case '?': *cq++ = '\\' ; /* fall thru */ default: *cq++ = *cp++; } *cq = 0 ; return arrp (a, base, char) ; } /* This routine would be better written as a general routine that takes an */ /* array of chars and their replacement strings and then just does it, this */ /* way it doesn't need to know anything about xml or java or anything.... */ /* */ char* freeXMLprotect (char* text) /* freeword will read result back as text */ { static Array a = 0 ; char *cp, *cq ; int base ; /* ACTUALLY I THINK THIS IS ALL RATHER HORRIBLE, IT JUST MAKES FOR COMPLEX */ /* CODE THAT ISN'T GREAT....WHY NOT JUST RETURN A POINTER TO A STATIC */ /* AND HAVE PEOPLE COPY IT IF NECESSARY...OR ALWAYS RETURN A COPY AND */ /* PEOPLE HAVE TO THROW IT AWAY.... */ /* code to make this efficiently reentrant */ if (a && text >= arrp(a,0,char) && text < arrp(a,arrayMax(a),char)) { base = text - arrp(a,0,char) ; array (a, base+7*(1+strlen(text)), char) = 0 ; /* ensure long enough */ text = arrp(a,0,char) + base ; /* may have relocated */ base += 1 + strlen(text) ; } else { a = arrayReCreate (a, 128, char) ; base = 0 ; array (a, 6*(1+strlen(text)), char) = 0 ; /* ensure long enough */ } cq = arrp (a, base, char) ; cp = text ; while (*cp) switch (*cp) { case '<': strcat (cq, "<") ; cq += 4 ; cp++; break; case '>': strcat (cq, ">") ; cq += 4 ; cp++; break; case '"': strcat (cq, """) ; cq += 6 ; cp++; break; case '\'': strcat (cq, "'") ; cq += 6 ; cp++; break; case '&': strcat (cq, "&") ; cq += 5 ; cp++; break; case '\n': strcat (cq, "&") ; cq += 5 ; cp++; break; default: *cq++ = *cp++; } *cq = 0 ; return arrp (a, base, char) ; } #ifdef ED_G_NEVER_INCLUDE_THIS_CODE /* A generalised "freeXXXprotect()" routine which doesn't need to know about */ /* java, xml etc. etc. */ /* */ /* */ /* Note that freeword() when used on the result will read it as straight text*/ /* */ /* Efficiency will be a problem here, several things could be done: */ /* - copy the translations into a new array which had the lengths of the */ /* protect strings already worked out, this would be faster, we could */ /* do memcpy's then. */ /* - forget this routine and just do the xml stuff with a switch. */ /* */ /* */ char *freeCharProtect(char* text, Array translations) { static Array a = 0 ; char *cp, *cq ; int base ; /* code to make this efficiently reentrant */ /* DOES THIS ACTUALLY WORK FOR ALL CASES ?? I'm not so sure.... */ /* OK, THIS WOULD HAVE TO BE REWRITTEN, THE CALCULATIONS DEPEND ON THE */ /* LENGTHS OF STUFF SUBSTITUED IN.... */ if (a && text >= arrp(a,0,char) && text < arrp(a,arrayMax(a),char)) { base = text - arrp(a,0,char) ; array (a, base+7*(1+strlen(text)), char) = 0 ; /* ensure long enough */ text = arrp(a,0,char) + base ; /* may have relocated */ base += 1 + strlen(text) ; } else { a = arrayReCreate (a, 128, char) ; base = 0 ; array (a, 6*(1+strlen(text)), char) = 0 ; /* ensure long enough */ } cq = arrp (a, base, char) ; cp = text ; while (*cp) { int i ; BOOL found ; for (i = 0, found = FALSE ; i < arrayMax(translations) ; i++) { if (*cp == array(translations, i, ARRAYTYPE).char) { strcat (cq, array(translations, i, ARRAYTYPE).protect) ; cq += strlen(array(translations, i, ARRAYTYPE).protect) ; cp++; found = TRUE ; } } if (!found) *cq++ = *cp++; } *cq = '\0' ; /* string terminator. */ return arrp (a, base, char) ; } #endif /* ED_G_NEVER_INCLUDE_THIS_CODE */ /*******************************************************/ /* mieg: i am putting here the non thread safe timesubs functions */ #include "mytime.h" char *timeShowJava (mytime_t t) { static char ace_time[25] ; return timeShowJava2 (ace_time, t) ; } /*******/ char *timeShow (mytime_t t) { static char ace_time[25] ; return timeShow2 (ace_time, t) ; } /*******/ char *timeDiffShow (mytime_t t1, mytime_t t2) { static char buf[25] ; return timeDiffShow2 (buf, t1, t2) ; } /*******************************************************/ /*********** end of file *****************/ acedb-4.9.39+dfsg.01/w1/getopt.c0000444000175000017500000007621507345370756015722 0ustar moellermoeller/* File: getopt.c * Author: Ed Griffiths (edgrif@sanger.ac.uk) * Copyright (c) J Thierry-Mieg and R Durbin, 2001 *------------------------------------------------------------------- * Acedb is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * or see the on-line version at http://www.gnu.org/copyleft/gpl.txt *------------------------------------------------------------------- * This file is part of the ACEDB genome database package, written by * Richard Durbin (Sanger Centre, UK) rd@sanger.ac.uk, and * Jean Thierry-Mieg (CRBM du CNRS, France) mieg@kaa.crbm.cnrs-mop.fr * * Description: This file is code originally written by GNU people, * I've put our standard header here, but after that the * code was all originally writtne by GNU people. * * Exported functions: See getopt.h * HISTORY: * Last edited: Sep 5 10:34 2001 (edgrif) * Created: Tue Sep 4 13:44:44 2001 (edgrif) * CVS info: $Id: getopt.c,v 1.1 2001/09/05 09:35:42 edgrif Exp $ *------------------------------------------------------------------- */ /* Getopt for GNU. NOTE: getopt is now part of the C library, so if you don't know what "Keep this file name-space clean" means, talk to drepper@gnu.org before changing it! Copyright (C) 1987,88,89,90,91,92,93,94,95,96,98,99,2000,2001 Free Software Foundation, Inc. This file is part of the GNU C Library. The GNU C Library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. The GNU C Library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with the GNU C Library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ /* This tells Alpha OSF/1 not to define a getopt prototype in . Ditto for AIX 3.2 and . */ #ifndef _NO_PROTO # define _NO_PROTO #endif #ifdef HAVE_CONFIG_H # include #endif #if !defined __STDC__ || !__STDC__ /* This is a separate conditional since some stdc systems reject `defined (const)'. */ # ifndef const # define const # endif #endif #include /* Comment out all this code if we are using the GNU C Library, and are not actually compiling the library itself. This code is part of the GNU C Library, but also included in many other GNU distributions. Compiling and linking in this code is a waste when using the GNU C library (especially if it is a shared library). Rather than having every GNU program understand `configure --with-gnu-libc' and omit the object files, it is simpler to just do this in the source for each such file. */ #define GETOPT_INTERFACE_VERSION 2 #if !defined _LIBC && defined __GLIBC__ && __GLIBC__ >= 2 # include # if _GNU_GETOPT_INTERFACE_VERSION == GETOPT_INTERFACE_VERSION # define ELIDE_CODE # endif #endif #ifndef ELIDE_CODE /* This needs to come after some library #include to get __GNU_LIBRARY__ defined. */ #ifdef __GNU_LIBRARY__ /* Don't include stdlib.h for non-GNU C libraries because some of them contain conflicting prototypes for getopt. */ # include # include #endif /* GNU C library. */ #ifdef VMS # include # if HAVE_STRING_H - 0 # include # endif #endif #ifndef _ /* This is for other GNU distributions with internationalized messages. */ # if defined HAVE_LIBINTL_H || defined _LIBC # include # ifndef _ # define _(msgid) gettext (msgid) # endif # else # define _(msgid) (msgid) # endif #endif /* This version of `getopt' appears to the caller like standard Unix `getopt' but it behaves differently for the user, since it allows the user to intersperse the options with the other arguments. As `getopt' works, it permutes the elements of ARGV so that, when it is done, all the options precede everything else. Thus all application programs are extended to handle flexible argument order. Setting the environment variable POSIXLY_CORRECT disables permutation. Then the behavior is completely standard. GNU application programs can use a third alternative mode in which they can distinguish the relative order of options and other arguments. */ #include "getopt.h" /* For communication from `getopt' to the caller. When `getopt' finds an option that takes an argument, the argument value is returned here. Also, when `ordering' is RETURN_IN_ORDER, each non-option ARGV-element is returned here. */ char *optarg; /* Index in ARGV of the next element to be scanned. This is used for communication to and from the caller and for communication between successive calls to `getopt'. On entry to `getopt', zero means this is the first call; initialize. When `getopt' returns -1, this is the index of the first of the non-option elements that the caller should itself scan. Otherwise, `optind' communicates from one call to the next how much of ARGV has been scanned so far. */ /* 1003.2 says this must be 1 before any call. */ int optind = 1; /* Formerly, initialization of getopt depended on optind==0, which causes problems with re-calling getopt as programs generally don't know that. */ int __getopt_initialized; /* The next char to be scanned in the option-element in which the last option character we returned was found. This allows us to pick up the scan where we left off. If this is zero, or a null string, it means resume the scan by advancing to the next ARGV-element. */ static char *nextchar; /* Callers store zero here to inhibit the error message for unrecognized options. */ int opterr = 1; /* Set to an option character which was unrecognized. This must be initialized on some systems to avoid linking in the system's own getopt implementation. */ int optopt = '?'; /* Describe how to deal with options that follow non-option ARGV-elements. If the caller did not specify anything, the default is REQUIRE_ORDER if the environment variable POSIXLY_CORRECT is defined, PERMUTE otherwise. REQUIRE_ORDER means don't recognize them as options; stop option processing when the first non-option is seen. This is what Unix does. This mode of operation is selected by either setting the environment variable POSIXLY_CORRECT, or using `+' as the first character of the list of option characters. PERMUTE is the default. We permute the contents of ARGV as we scan, so that eventually all the non-options are at the end. This allows options to be given in any order, even with programs that were not written to expect this. RETURN_IN_ORDER is an option available to programs that were written to expect options and other ARGV-elements in any order and that care about the ordering of the two. We describe each non-option ARGV-element as if it were the argument of an option with character code 1. Using `-' as the first character of the list of option characters selects this mode of operation. The special argument `--' forces an end of option-scanning regardless of the value of `ordering'. In the case of RETURN_IN_ORDER, only `--' can cause `getopt' to return -1 with `optind' != ARGC. */ static enum { REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER } ordering; /* Value of POSIXLY_CORRECT environment variable. */ static char *posixly_correct; #ifdef __GNU_LIBRARY__ /* We want to avoid inclusion of string.h with non-GNU libraries because there are many ways it can cause trouble. On some systems, it contains special magic macros that don't work in GCC. */ # include # define my_index strchr #else # if HAVE_STRING_H # include # else # include # endif /* Avoid depending on library functions or files whose names are inconsistent. */ #ifndef getenv extern char *getenv (); #endif static char * my_index (str, chr) const char *str; int chr; { while (*str) { if (*str == chr) return (char *) str; str++; } return 0; } /* If using GCC, we can safely declare strlen this way. If not using GCC, it is ok not to declare it. */ #ifdef __GNUC__ /* Note that Motorola Delta 68k R3V7 comes with GCC but not stddef.h. That was relevant to code that was here before. */ # if (!defined __STDC__ || !__STDC__) && !defined strlen /* gcc with -traditional declares the built-in strlen to return int, and has done so at least since version 2.4.5. -- rms. */ extern int strlen (const char *); # endif /* not __STDC__ */ #endif /* __GNUC__ */ #endif /* not __GNU_LIBRARY__ */ /* Handle permutation of arguments. */ /* Describe the part of ARGV that contains non-options that have been skipped. `first_nonopt' is the index in ARGV of the first of them; `last_nonopt' is the index after the last of them. */ static int first_nonopt; static int last_nonopt; #ifdef _LIBC /* Stored original parameters. XXX This is no good solution. We should rather copy the args so that we can compare them later. But we must not use malloc(3). */ extern int __libc_argc; extern char **__libc_argv; /* Bash 2.0 gives us an environment variable containing flags indicating ARGV elements that should not be considered arguments. */ # ifdef USE_NONOPTION_FLAGS /* Defined in getopt_init.c */ extern char *__getopt_nonoption_flags; static int nonoption_flags_max_len; static int nonoption_flags_len; # endif # ifdef USE_NONOPTION_FLAGS # define SWAP_FLAGS(ch1, ch2) \ if (nonoption_flags_len > 0) \ { \ char __tmp = __getopt_nonoption_flags[ch1]; \ __getopt_nonoption_flags[ch1] = __getopt_nonoption_flags[ch2]; \ __getopt_nonoption_flags[ch2] = __tmp; \ } # else # define SWAP_FLAGS(ch1, ch2) # endif #else /* !_LIBC */ # define SWAP_FLAGS(ch1, ch2) #endif /* _LIBC */ /* Exchange two adjacent subsequences of ARGV. One subsequence is elements [first_nonopt,last_nonopt) which contains all the non-options that have been skipped so far. The other is elements [last_nonopt,optind), which contains all the options processed since those non-options were skipped. `first_nonopt' and `last_nonopt' are relocated so that they describe the new indices of the non-options in ARGV after they are moved. */ #if defined __STDC__ && __STDC__ static void exchange (char **); #endif static void exchange (argv) char **argv; { int bottom = first_nonopt; int middle = last_nonopt; int top = optind; char *tem; /* Exchange the shorter segment with the far end of the longer segment. That puts the shorter segment into the right place. It leaves the longer segment in the right place overall, but it consists of two parts that need to be swapped next. */ #if defined _LIBC && defined USE_NONOPTION_FLAGS /* First make sure the handling of the `__getopt_nonoption_flags' string can work normally. Our top argument must be in the range of the string. */ if (nonoption_flags_len > 0 && top >= nonoption_flags_max_len) { /* We must extend the array. The user plays games with us and presents new arguments. */ char *new_str = malloc (top + 1); if (new_str == NULL) nonoption_flags_len = nonoption_flags_max_len = 0; else { memset (__mempcpy (new_str, __getopt_nonoption_flags, nonoption_flags_max_len), '\0', top + 1 - nonoption_flags_max_len); nonoption_flags_max_len = top + 1; __getopt_nonoption_flags = new_str; } } #endif while (top > middle && middle > bottom) { if (top - middle > middle - bottom) { /* Bottom segment is the short one. */ int len = middle - bottom; register int i; /* Swap it with the top part of the top segment. */ for (i = 0; i < len; i++) { tem = argv[bottom + i]; argv[bottom + i] = argv[top - (middle - bottom) + i]; argv[top - (middle - bottom) + i] = tem; SWAP_FLAGS (bottom + i, top - (middle - bottom) + i); } /* Exclude the moved bottom segment from further swapping. */ top -= len; } else { /* Top segment is the short one. */ int len = top - middle; register int i; /* Swap it with the bottom part of the bottom segment. */ for (i = 0; i < len; i++) { tem = argv[bottom + i]; argv[bottom + i] = argv[middle + i]; argv[middle + i] = tem; SWAP_FLAGS (bottom + i, middle + i); } /* Exclude the moved top segment from further swapping. */ bottom += len; } } /* Update records for the slots the non-options now occupy. */ first_nonopt += (optind - last_nonopt); last_nonopt = optind; } /* Initialize the internal data when the first call is made. */ #if defined __STDC__ && __STDC__ static const char *_getopt_initialize (int, char *const *, const char *); #endif static const char * _getopt_initialize (argc, argv, optstring) int argc; char *const *argv; const char *optstring; { /* Start processing options with ARGV-element 1 (since ARGV-element 0 is the program name); the sequence of previously skipped non-option ARGV-elements is empty. */ first_nonopt = last_nonopt = optind; nextchar = NULL; posixly_correct = getenv ("POSIXLY_CORRECT"); /* Determine how to handle the ordering of options and nonoptions. */ if (optstring[0] == '-') { ordering = RETURN_IN_ORDER; ++optstring; } else if (optstring[0] == '+') { ordering = REQUIRE_ORDER; ++optstring; } else if (posixly_correct != NULL) ordering = REQUIRE_ORDER; else ordering = PERMUTE; #if defined _LIBC && defined USE_NONOPTION_FLAGS if (posixly_correct == NULL && argc == __libc_argc && argv == __libc_argv) { if (nonoption_flags_max_len == 0) { if (__getopt_nonoption_flags == NULL || __getopt_nonoption_flags[0] == '\0') nonoption_flags_max_len = -1; else { const char *orig_str = __getopt_nonoption_flags; int len = nonoption_flags_max_len = strlen (orig_str); if (nonoption_flags_max_len < argc) nonoption_flags_max_len = argc; __getopt_nonoption_flags = (char *) malloc (nonoption_flags_max_len); if (__getopt_nonoption_flags == NULL) nonoption_flags_max_len = -1; else memset (__mempcpy (__getopt_nonoption_flags, orig_str, len), '\0', nonoption_flags_max_len - len); } } nonoption_flags_len = nonoption_flags_max_len; } else nonoption_flags_len = 0; #endif return optstring; } /* Scan elements of ARGV (whose length is ARGC) for option characters given in OPTSTRING. If an element of ARGV starts with '-', and is not exactly "-" or "--", then it is an option element. The characters of this element (aside from the initial '-') are option characters. If `getopt' is called repeatedly, it returns successively each of the option characters from each of the option elements. If `getopt' finds another option character, it returns that character, updating `optind' and `nextchar' so that the next call to `getopt' can resume the scan with the following option character or ARGV-element. If there are no more option characters, `getopt' returns -1. Then `optind' is the index in ARGV of the first ARGV-element that is not an option. (The ARGV-elements have been permuted so that those that are not options now come last.) OPTSTRING is a string containing the legitimate option characters. If an option character is seen that is not listed in OPTSTRING, return '?' after printing an error message. If you set `opterr' to zero, the error message is suppressed but we still return '?'. If a char in OPTSTRING is followed by a colon, that means it wants an arg, so the following text in the same ARGV-element, or the text of the following ARGV-element, is returned in `optarg'. Two colons mean an option that wants an optional arg; if there is text in the current ARGV-element, it is returned in `optarg', otherwise `optarg' is set to zero. If OPTSTRING starts with `-' or `+', it requests different methods of handling the non-option ARGV-elements. See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above. Long-named options begin with `--' instead of `-'. Their names may be abbreviated as long as the abbreviation is unique or is an exact match for some defined option. If they have an argument, it follows the option name in the same ARGV-element, separated from the option name by a `=', or else the in next ARGV-element. When `getopt' finds a long-named option, it returns 0 if that option's `flag' field is nonzero, the value of the option's `val' field if the `flag' field is zero. The elements of ARGV aren't really const, because we permute them. But we pretend they're const in the prototype to be compatible with other systems. LONGOPTS is a vector of `struct option' terminated by an element containing a name which is zero. LONGIND returns the index in LONGOPT of the long-named option found. It is only valid when a long-named option has been found by the most recent call. If LONG_ONLY is nonzero, '-' as well as '--' can introduce long-named options. */ int _getopt_internal (argc, argv, optstring, longopts, longind, long_only) int argc; char *const *argv; const char *optstring; const struct option *longopts; int *longind; int long_only; { int print_errors = opterr; if (optstring[0] == ':') print_errors = 0; if (argc < 1) return -1; optarg = NULL; if (optind == 0 || !__getopt_initialized) { if (optind == 0) optind = 1; /* Don't scan ARGV[0], the program name. */ optstring = _getopt_initialize (argc, argv, optstring); __getopt_initialized = 1; } /* Test whether ARGV[optind] points to a non-option argument. Either it does not have option syntax, or there is an environment flag from the shell indicating it is not an option. The later information is only used when the used in the GNU libc. */ #if defined _LIBC && defined USE_NONOPTION_FLAGS # define NONOPTION_P (argv[optind][0] != '-' || argv[optind][1] == '\0' \ || (optind < nonoption_flags_len \ && __getopt_nonoption_flags[optind] == '1')) #else # define NONOPTION_P (argv[optind][0] != '-' || argv[optind][1] == '\0') #endif if (nextchar == NULL || *nextchar == '\0') { /* Advance to the next ARGV-element. */ /* Give FIRST_NONOPT & LAST_NONOPT rational values if OPTIND has been moved back by the user (who may also have changed the arguments). */ if (last_nonopt > optind) last_nonopt = optind; if (first_nonopt > optind) first_nonopt = optind; if (ordering == PERMUTE) { /* If we have just processed some options following some non-options, exchange them so that the options come first. */ if (first_nonopt != last_nonopt && last_nonopt != optind) exchange ((char **) argv); else if (last_nonopt != optind) first_nonopt = optind; /* Skip any additional non-options and extend the range of non-options previously skipped. */ while (optind < argc && NONOPTION_P) optind++; last_nonopt = optind; } /* The special ARGV-element `--' means premature end of options. Skip it like a null option, then exchange with previous non-options as if it were an option, then skip everything else like a non-option. */ if (optind != argc && !strcmp (argv[optind], "--")) { optind++; if (first_nonopt != last_nonopt && last_nonopt != optind) exchange ((char **) argv); else if (first_nonopt == last_nonopt) first_nonopt = optind; last_nonopt = argc; optind = argc; } /* If we have done all the ARGV-elements, stop the scan and back over any non-options that we skipped and permuted. */ if (optind == argc) { /* Set the next-arg-index to point at the non-options that we previously skipped, so the caller will digest them. */ if (first_nonopt != last_nonopt) optind = first_nonopt; return -1; } /* If we have come to a non-option and did not permute it, either stop the scan or describe it to the caller and pass it by. */ if (NONOPTION_P) { if (ordering == REQUIRE_ORDER) return -1; optarg = argv[optind++]; return 1; } /* We have found another option-ARGV-element. Skip the initial punctuation. */ nextchar = (argv[optind] + 1 + (longopts != NULL && argv[optind][1] == '-')); } /* Decode the current option-ARGV-element. */ /* Check whether the ARGV-element is a long option. If long_only and the ARGV-element has the form "-f", where f is a valid short option, don't consider it an abbreviated form of a long option that starts with f. Otherwise there would be no way to give the -f short option. On the other hand, if there's a long option "fubar" and the ARGV-element is "-fu", do consider that an abbreviation of the long option, just like "--fu", and not "-f" with arg "u". This distinction seems to be the most useful approach. */ if (longopts != NULL && (argv[optind][1] == '-' || (long_only && (argv[optind][2] || !my_index (optstring, argv[optind][1]))))) { char *nameend; const struct option *p; const struct option *pfound = NULL; int exact = 0; int ambig = 0; int indfound = -1; int option_index; for (nameend = nextchar; *nameend && *nameend != '='; nameend++) /* Do nothing. */ ; /* Test all long options for either exact match or abbreviated matches. */ for (p = longopts, option_index = 0; p->name; p++, option_index++) if (!strncmp (p->name, nextchar, nameend - nextchar)) { if ((unsigned int) (nameend - nextchar) == (unsigned int) strlen (p->name)) { /* Exact match found. */ pfound = p; indfound = option_index; exact = 1; break; } else if (pfound == NULL) { /* First nonexact match found. */ pfound = p; indfound = option_index; } else if (long_only || pfound->has_arg != p->has_arg || pfound->flag != p->flag || pfound->val != p->val) /* Second or later nonexact match found. */ ambig = 1; } if (ambig && !exact) { if (print_errors) fprintf (stderr, _("%s: option `%s' is ambiguous\n"), argv[0], argv[optind]); nextchar += strlen (nextchar); optind++; optopt = 0; return '?'; } if (pfound != NULL) { option_index = indfound; optind++; if (*nameend) { /* Don't test has_arg with >, because some C compilers don't allow it to be used on enums. */ if (pfound->has_arg) optarg = nameend + 1; else { if (print_errors) { if (argv[optind - 1][1] == '-') /* --option */ fprintf (stderr, _("%s: option `--%s' doesn't allow an argument\n"), argv[0], pfound->name); else /* +option or -option */ fprintf (stderr, _("%s: option `%c%s' doesn't allow an argument\n"), argv[0], argv[optind - 1][0], pfound->name); } nextchar += strlen (nextchar); optopt = pfound->val; return '?'; } } else if (pfound->has_arg == 1) { if (optind < argc) optarg = argv[optind++]; else { if (print_errors) fprintf (stderr, _("%s: option `%s' requires an argument\n"), argv[0], argv[optind - 1]); nextchar += strlen (nextchar); optopt = pfound->val; return optstring[0] == ':' ? ':' : '?'; } } nextchar += strlen (nextchar); if (longind != NULL) *longind = option_index; if (pfound->flag) { *(pfound->flag) = pfound->val; return 0; } return pfound->val; } /* Can't find it as a long option. If this is not getopt_long_only, or the option starts with '--' or is not a valid short option, then it's an error. Otherwise interpret it as a short option. */ if (!long_only || argv[optind][1] == '-' || my_index (optstring, *nextchar) == NULL) { if (print_errors) { if (argv[optind][1] == '-') /* --option */ fprintf (stderr, _("%s: unrecognized option `--%s'\n"), argv[0], nextchar); else /* +option or -option */ fprintf (stderr, _("%s: unrecognized option `%c%s'\n"), argv[0], argv[optind][0], nextchar); } nextchar = (char *) ""; optind++; optopt = 0; return '?'; } } /* Look at and handle the next short option-character. */ { char c = *nextchar++; char *temp = my_index (optstring, c); /* Increment `optind' when we start to process its last character. */ if (*nextchar == '\0') ++optind; if (temp == NULL || c == ':') { if (print_errors) { if (posixly_correct) /* 1003.2 specifies the format of this message. */ fprintf (stderr, _("%s: illegal option -- %c\n"), argv[0], c); else fprintf (stderr, _("%s: invalid option -- %c\n"), argv[0], c); } optopt = c; return '?'; } /* Convenience. Treat POSIX -W foo same as long option --foo */ if (temp[0] == 'W' && temp[1] == ';') { char *nameend; const struct option *p; const struct option *pfound = NULL; int exact = 0; int ambig = 0; int indfound = 0; int option_index; /* This is an option that requires an argument. */ if (*nextchar != '\0') { optarg = nextchar; /* If we end this ARGV-element by taking the rest as an arg, we must advance to the next element now. */ optind++; } else if (optind == argc) { if (print_errors) { /* 1003.2 specifies the format of this message. */ fprintf (stderr, _("%s: option requires an argument -- %c\n"), argv[0], c); } optopt = c; if (optstring[0] == ':') c = ':'; else c = '?'; return c; } else /* We already incremented `optind' once; increment it again when taking next ARGV-elt as argument. */ optarg = argv[optind++]; /* optarg is now the argument, see if it's in the table of longopts. */ for (nextchar = nameend = optarg; *nameend && *nameend != '='; nameend++) /* Do nothing. */ ; /* Test all long options for either exact match or abbreviated matches. */ for (p = longopts, option_index = 0; p->name; p++, option_index++) if (!strncmp (p->name, nextchar, nameend - nextchar)) { if ((unsigned int) (nameend - nextchar) == strlen (p->name)) { /* Exact match found. */ pfound = p; indfound = option_index; exact = 1; break; } else if (pfound == NULL) { /* First nonexact match found. */ pfound = p; indfound = option_index; } else /* Second or later nonexact match found. */ ambig = 1; } if (ambig && !exact) { if (print_errors) fprintf (stderr, _("%s: option `-W %s' is ambiguous\n"), argv[0], argv[optind]); nextchar += strlen (nextchar); optind++; return '?'; } if (pfound != NULL) { option_index = indfound; if (*nameend) { /* Don't test has_arg with >, because some C compilers don't allow it to be used on enums. */ if (pfound->has_arg) optarg = nameend + 1; else { if (print_errors) fprintf (stderr, _("\ %s: option `-W %s' doesn't allow an argument\n"), argv[0], pfound->name); nextchar += strlen (nextchar); return '?'; } } else if (pfound->has_arg == 1) { if (optind < argc) optarg = argv[optind++]; else { if (print_errors) fprintf (stderr, _("%s: option `%s' requires an argument\n"), argv[0], argv[optind - 1]); nextchar += strlen (nextchar); return optstring[0] == ':' ? ':' : '?'; } } nextchar += strlen (nextchar); if (longind != NULL) *longind = option_index; if (pfound->flag) { *(pfound->flag) = pfound->val; return 0; } return pfound->val; } nextchar = NULL; return 'W'; /* Let the application handle it. */ } if (temp[1] == ':') { if (temp[2] == ':') { /* This is an option that accepts an argument optionally. */ if (*nextchar != '\0') { optarg = nextchar; optind++; } else optarg = NULL; nextchar = NULL; } else { /* This is an option that requires an argument. */ if (*nextchar != '\0') { optarg = nextchar; /* If we end this ARGV-element by taking the rest as an arg, we must advance to the next element now. */ optind++; } else if (optind == argc) { if (print_errors) { /* 1003.2 specifies the format of this message. */ fprintf (stderr, _("%s: option requires an argument -- %c\n"), argv[0], c); } optopt = c; if (optstring[0] == ':') c = ':'; else c = '?'; } else /* We already incremented `optind' once; increment it again when taking next ARGV-elt as argument. */ optarg = argv[optind++]; nextchar = NULL; } } return c; } } int getopt (argc, argv, optstring) int argc; char *const *argv; const char *optstring; { return _getopt_internal (argc, argv, optstring, (const struct option *) 0, (int *) 0, 0); } #endif /* Not ELIDE_CODE. */ #ifdef TEST /* Compile with -DTEST to make an executable for use in testing the above definition of `getopt'. */ int main (argc, argv) int argc; char **argv; { int c; int digit_optind = 0; while (1) { int this_option_optind = optind ? optind : 1; c = getopt (argc, argv, "abc:d:0123456789"); if (c == -1) break; switch (c) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': if (digit_optind != 0 && digit_optind != this_option_optind) printf ("digits occur in two different argv-elements.\n"); digit_optind = this_option_optind; printf ("option %c\n", c); break; case 'a': printf ("option a\n"); break; case 'b': printf ("option b\n"); break; case 'c': printf ("option c with value `%s'\n", optarg); break; case '?': break; default: printf ("?? getopt returned character code 0%o ??\n", c); } } if (optind < argc) { printf ("non-option ARGV-elements: "); while (optind < argc) printf ("%s ", argv[optind++]); printf ("\n"); } exit (0); } #endif /* TEST */ acedb-4.9.39+dfsg.01/w1/getopt1.c0000444000175000017500000001410107345370764015764 0ustar moellermoeller/* File: getopt1.c * Author: Ed Griffiths (edgrif@sanger.ac.uk) * Copyright (c) J Thierry-Mieg and R Durbin, 2001 *------------------------------------------------------------------- * Acedb is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * or see the on-line version at http://www.gnu.org/copyleft/gpl.txt *------------------------------------------------------------------- * This file is part of the ACEDB genome database package, written by * Richard Durbin (Sanger Centre, UK) rd@sanger.ac.uk, and * Jean Thierry-Mieg (CRBM du CNRS, France) mieg@kaa.crbm.cnrs-mop.fr * * Description: This file is code originally written by GNU people, * I've put our standard header here, but after that the * code was all originally writtne by GNU people. * * Exported functions: See getopt.h * HISTORY: * Last edited: Sep 5 10:35 2001 (edgrif) * Created: Tue Sep 4 13:46:54 2001 (edgrif) * CVS info: $Id$ *------------------------------------------------------------------- */ /* getopt_long and getopt_long_only entry points for GNU getopt. Copyright (C) 1987,88,89,90,91,92,93,94,96,97,98 Free Software Foundation, Inc. This file is part of the GNU C Library. The GNU C Library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. The GNU C Library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with the GNU C Library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ #ifdef HAVE_CONFIG_H #include #endif #include "getopt.h" #if !defined __STDC__ || !__STDC__ /* This is a separate conditional since some stdc systems reject `defined (const)'. */ #ifndef const #define const #endif #endif #include /* Comment out all this code if we are using the GNU C Library, and are not actually compiling the library itself. This code is part of the GNU C Library, but also included in many other GNU distributions. Compiling and linking in this code is a waste when using the GNU C library (especially if it is a shared library). Rather than having every GNU program understand `configure --with-gnu-libc' and omit the object files, it is simpler to just do this in the source for each such file. */ #define GETOPT_INTERFACE_VERSION 2 #if !defined _LIBC && defined __GLIBC__ && __GLIBC__ >= 2 #include #if _GNU_GETOPT_INTERFACE_VERSION == GETOPT_INTERFACE_VERSION #define ELIDE_CODE #endif #endif #ifndef ELIDE_CODE /* This needs to come after some library #include to get __GNU_LIBRARY__ defined. */ #ifdef __GNU_LIBRARY__ #include #endif #ifndef NULL #define NULL 0 #endif int getopt_long (argc, argv, options, long_options, opt_index) int argc; char *const *argv; const char *options; const struct option *long_options; int *opt_index; { return _getopt_internal (argc, argv, options, long_options, opt_index, 0); } /* Like getopt_long, but '-' as well as '--' can indicate a long option. If an option that starts with '-' (not '--') doesn't match a long option, but does match a short option, it is parsed as a short option instead. */ int getopt_long_only (argc, argv, options, long_options, opt_index) int argc; char *const *argv; const char *options; const struct option *long_options; int *opt_index; { return _getopt_internal (argc, argv, options, long_options, opt_index, 1); } #endif /* Not ELIDE_CODE. */ #ifdef TEST #include int main (argc, argv) int argc; char **argv; { int c; int digit_optind = 0; while (1) { int this_option_optind = optind ? optind : 1; int option_index = 0; static struct option long_options[] = { {"add", 1, 0, 0}, {"append", 0, 0, 0}, {"delete", 1, 0, 0}, {"verbose", 0, 0, 0}, {"create", 0, 0, 0}, {"file", 1, 0, 0}, {0, 0, 0, 0} }; c = getopt_long (argc, argv, "abc:d:0123456789", long_options, &option_index); if (c == -1) break; switch (c) { case 0: printf ("option %s", long_options[option_index].name); if (optarg) printf (" with arg %s", optarg); printf ("\n"); break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': if (digit_optind != 0 && digit_optind != this_option_optind) printf ("digits occur in two different argv-elements.\n"); digit_optind = this_option_optind; printf ("option %c\n", c); break; case 'a': printf ("option a\n"); break; case 'b': printf ("option b\n"); break; case 'c': printf ("option c with value `%s'\n", optarg); break; case 'd': printf ("option d with value `%s'\n", optarg); break; case '?': break; default: printf ("?? getopt returned character code 0%o ??\n", c); } } if (optind < argc) { printf ("non-option ARGV-elements: "); while (optind < argc) printf ("%s ", argv[optind++]); printf ("\n"); } exit (0); } #endif /* TEST */ acedb-4.9.39+dfsg.01/w1/heap.c0000444000175000017500000001344107435503464015317 0ustar moellermoeller/* File: heap.c * Author: Richard Durbin (rd@mrc-lmb.cam.ac.uk) * Copyright (C) J Thierry-Mieg and R Durbin, 1991 * ------------------------------------------------------------------- * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * ------------------------------------------------------------------- * This file is part of the ACEDB genome database package, written by * Richard Durbin (MRC LMB, UK) rd@mrc-lmb.cam.ac.uk, and * Jean Thierry-Mieg (CRBM du CNRS, France) mieg@kaa.cnrs-mop.fr * * Description: supports maximising heaps with a float score. * Exported functions: heapCreate, heapDestroy, heapInsert, heapExtract keySetAlphaHeap * HISTORY: * Last edited: Jul 8 15:05 1998 (il) * * Nov 12 20:12 1991 (mieg): i add here my own keySetAlphaHeap it is probably equivalent to your code, i did not verify, but our 2 files were in w1, although i never saw your file before today, i must have killed it by mistake. * Created: Sat Oct 12 20:02:41 1991 (rd) *------------------------------------------------------------------- */ /* $Id: heap.c,v 1.6 2002/02/22 18:00:20 srk Exp $ */ #include "regular.h" /* Package to manage a heap - keeps the max largest entries inserted. Top of tree (1) is smallest of these. Daughters of each node must be larger. Tree is kept balanced at all times, so daughters of n are implicit 2n and 2n+1. Insert returns 0 if not inserted, else an index in the range [1..max] that the user can use to associate extra data to the item. Extract returns that index for the SMALLEST item in the heap, or 0 if the heap is empty. */ typedef struct heapStruct { float *scores ; int *index ; int max ; int n ; int magic ; } *Heap ; #define HEAP_INTERNAL #include "heap.h" #define HEAPMAGIC 897237 /************************************/ Heap heapCreate (int size) { Heap heap = (Heap) messalloc (sizeof (struct heapStruct)) ; if (size <= 0) messcrash ("heapCreate called with non-positive arg %d", size) ; heap->magic = HEAPMAGIC ; heap->max = size ; heap->n = 0 ; heap->scores = (float*) messalloc (size * sizeof(float)) ; heap->index = (int*) messalloc (size * sizeof(int)) ; return heap ; } /***************/ void heapDestroy (Heap heap) /* mhmp 11.12 .98 */ { if (!heap) return ; if (heap->magic != HEAPMAGIC) messcrash ("heapDestroy received corrupt heap->magic"); heap->magic = 0 ; if (heap->scores && *heap->scores) messfree (heap->scores) ; if (heap->index && *heap->index) messfree (heap->index) ; messfree (heap) ; } /*************************************/ static int filterDown (Heap heap, int n, float score) { /* return final position */ int n2 = n*2 ; while (n2 <= heap->n) { if (n2 < heap->n && heap->scores[n2+1] < heap->scores[n2]) ++n2 ; if (score < heap->scores[n2]) break ; heap->scores[n] = heap->scores[n2] ; heap->index[n] = heap->index[n2] ; n = n2 ; n2 = n*2 ; } heap->scores[n] = score ; return n ; } /**************************************/ static int filterUp (Heap heap, int n, float score) { /* return final position */ int n2 = n/2 ; while (n > 1 && score < heap->scores[n2]) { heap->scores[n] = heap->scores[n2] ; heap->index[n] = heap->index[n2] ; n = n2 ; n2 = n/2 ; } return filterDown (heap, n, score) ; /* must check down other branch */ } /**************************************/ int heapInsert (Heap heap, float score) { int n, ind ; if (!heap || heap->magic != HEAPMAGIC) messcrash ("Bad heap passed to heapInsert") ; if (heap->n < (heap->max - 1)) { heap->scores[++heap->n] = score ; n = filterUp (heap, heap->n, score) ; return (heap->index[n] = heap->n) ; } else if (heap->scores[1] < score) { heap->scores[1] = score ; ind = heap->index[1] ; n = filterDown (heap, 1, score) ; return (heap->index[n] = ind) ; } else return 0 ; } /*************************************/ int heapExtract (Heap heap, float *sp) { int n, ind ; if (!heap || heap->magic != HEAPMAGIC) messcrash ("Bad heap passed to heapExtract") ; if (!heap->n) return 0 ; *sp = heap->scores[1] ; ind = heap->index[1] ; heap->scores[1] = heap->scores[heap->n] ; --heap->n ; n = filterDown (heap, 1, heap->scores[1]) ; heap->index[n] = heap->index[heap->n + 1] ; /* new resting place */ return ind ; } /*****************************************************/ /********** main() for test program ******************/ /****** commented out ******* static float scores[] = { 1, 9, 27, 8, 19, 4, 23, 2, 6, 12, 23, 7} ; void main (void) { float score ; int i ; Heap heap = heapCreate(4) ; for (i = 0 ; i < 12 ; ++i) if (heapInsert (heap, scores[i])) printf ("Inserted %f\n", scores[i]) ; else printf (" failed %f\n", scores[i]) ; printf ("\n") ; while (heapExtract (heap, &score)) printf ("Extracted %f\n", score) ; heapDestroy (heap) ; } ****************************/ /**************************************************************************/ /**************************************************************************/ acedb-4.9.39+dfsg.01/w1/helpsubs.c0000444000175000017500000012744307435503464016237 0ustar moellermoeller/* File: helpsubs.c * Author: Fred Wobus (fw@sanger.ac.uk) * Copyright (C) J Thierry-Mieg and R Durbin, 1998 * ------------------------------------------------------------------- * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * ------------------------------------------------------------------- * This file is part of the ACEDB genome database package, written by * Richard Durbin (MRC LMB, UK) rd@sanger.ac.uk, and * Jean Thierry-Mieg (CRBM du CNRS, France) mieg@kaa.cnrs-mop.fr * * SCCS: %W% %G% * Description: controls the help system, provides HTML parsing * Exported functions: * HISTORY: * Last edited: Nov 23 18:22 1999 (fw) * * Oct 12 12:27 1998 (fw): checkSubject now case-insensitive * * Oct 8 17:23 1998 (fw): removed warning, in case that an open-list tag (e.g.
    was directly followed by a close-list tag (e.g.
). The warning tried to enforce that every type of list only has a certain type of items. * * Oct 8 11:36 1998 (fw): helpSubjectGetFilename takes over logic from readHelpfile to locate the file containing the help for a particular subject * Created: Tue Aug 18 16:11:07 1998 (fw) *------------------------------------------------------------------- */ #include "help_.h" #include "aceio.h" /************************************************************/ static char *makeHtmlIndex (STORE_HANDLE handle); static char *makeHtmlImagePage (char *link, STORE_HANDLE handle); static HtmlNode *parseHtmlText (char *text, STORE_HANDLE handle); static BOOL parseSection (char **cp, HtmlNode **resultnode, STORE_HANDLE handle); /************************************************************/ /************ directory where help files are stored *********/ /* help files are found in this directory and in its * first level subdirectories (not recursivly yet) ************************************************************/ static char *helpDir = NULL; /************************************************************/ /* function to register the helpOnRoutine This can be called at any stage (before the first helpOn, or later on, it will affect the system next time helpOn is called. */ /************************************************************/ static struct helpContextStruct helpContext = { NULL, NULL }; struct helpContextStruct helpOnRegister (struct helpContextStruct context) /* call with func = 0x0 just to check whether anything has been registered yet */ { struct helpContextStruct old = helpContext; helpContext = context; return old; } /* helpOnRegister */ /************************************************************/ /* Sets the helpDir; */ /************************************************************/ char *helpSetDir (char *dirname) { if (!dirname) messcrash("helpSetDir() called with NULL pointer"); if (helpDir) messfree(helpDir); helpDir = filGetName (dirname,0,"rd", 0); return helpDir; } /* helpGetDir */ /************************************************************/ /* return the current helpDirectory or initialise if not previously set */ char *helpGetDir (void) { if (helpDir) return helpDir; else return ""; } /* helpGetDir */ /************************************************************/ /* pop up help on the given subject, depending on the registered display function, that will be textual, in the built-in simple HTML browser or even launch an external browser to display the help document */ /************************************************************/ BOOL helpOn (char *subject) { char *helpFilename; BOOL ok; if (!filCheckName(helpGetDir(), "", "rd")) { messout ("Sorry, No help available ! " "Could not open the HTML help directory " "%s\n" "(%s)", helpGetDir(), messSysErrorText()); return FALSE; } helpFilename = helpSubjectGetFilename(subject); /* may be NULL if file could not be found, the registered helpOnRoutine has to cope with this case and may decide to display an index instead */ if (helpContext.user_func) ok = (*helpContext.user_func)(helpFilename, helpContext.user_pointer); else { ACEOUT fo = aceOutCreateToStdout (0); ok = helpPrint (helpFilename, (void*)fo); /* textual help to stdout as default */ aceOutDestroy (fo); } return ok; } /* helpOn */ /************************************************************/ char *helpSubjectGetFilename (char *subject) /* this function attempts to find the file name corresponding to a particular help-subject. It will attempt to find a matching file according to the current settings of helpDir. the subject '?' will just return ? again. This is a special code within the help system to tell the help display function that the user required some kind of help. Usually the helpOnRegister'd function would display a dynamically created index of the help-directory. this function can be even cleverer by doing keyword searches on and <H1> strings in files that might be relevant of no obvious match is found. */ { static char filename_array[MAXPATHLEN] = ""; char *filename = &filename_array[0]; char *subject_copy; FilDir dirList; if (subject == NULL) return NULL; if (strlen(subject) == 0) return NULL; if (strcmp(subject, "?") == 0) { /* return ? to signal that the calling function needs to display a dynamically created index or show some kind of help. */ /* if the construct page = htmlPageCreate(helpGetFilename(subject_requested)); is used, the resulting page will therefor be a marked up directory listing of helpsubjects */ strcpy (filename, "?"); return filename; } subject_copy = strnew (subject, 0); strcpy (filename, ""); /* intialise, if this is non-empty at the end of the loop, we found a matching helpfile */ while (TRUE) { /* simple attempt to locate file - path/helpDir/subject.html */ sprintf(filename, "%s/%s.html", helpGetDir(), subject_copy); if (filCheckName(filename, 0, "r")) break; /* another attempt to file subject.shtml */ sprintf(filename, "%s/%s.shtml", helpGetDir(), subject_copy); if (filCheckName(filename, 0, "r")) break; /* advanced attempt, try to find a matching file from the list of available ones by scanning the directory contents of the helpdirectory */ if ((dirList = filDirCreate(helpGetDir(), "html", "r")) ) { int i; int matches; char *s; /* first look for an exact case-insensitive match */ strcpy (filename, ""); for (i = 0 ; i < filDirMax(dirList) ; i++) { s = filDirEntry(dirList, i); if (strcasecmp (s, subject_copy) == 0) { sprintf(filename, "%s%s%s.%s", helpGetDir(), SUBDIR_DELIMITER_STR, s, "html"); if (filCheckName(filename, 0, "r")) break; /* exit for-loop */ strcpy (filename, ""); } } if (strlen(filename) > 0) break; /* exit while(true) loop */ /* count the number of filenames starting with the given subject string */ matches = 0; for (i = 0 ; i < filDirMax(dirList) ; i++) { s = filDirEntry(dirList, i); if (strncasecmp (s, subject_copy, strlen(subject_copy)) == 0) { sprintf(filename, "%s%s%s.%s", helpGetDir(), SUBDIR_DELIMITER_STR, s, "html"); ++matches; } } if (matches == 0) { strcpy (filename, ""); /* not found */ } else if (matches == 1) { /* the one exact match (already in filename string) is the complete filename */ if (filCheckName(filename, 0, "r")) break; /* exit while(true) loop */ } else if (matches > 1) { /* construct a filename that we know won't work. But it may be used by the help display function to give a meaningful message to say that this subject is ambiguos. The returned filename is then considered a template, similar to 'ls subject*' so the help-display function may give a list of possible matching subjects. */ sprintf(filename, "%s%s%s", helpGetDir(), SUBDIR_DELIMITER_STR, subject_copy); break; } messfree (dirList); } /* endif dirList */ /* file didn't exist, whichever way we tried so far, so we try to chop off the last bit of the subject name. In case trySubject was "Tree_Clone_Inside", we now go through the look again with "Tree_Clone" and re-try. */ if (strchr (subject_copy, '_')) { int j; j = strlen (subject_copy); while (subject_copy[j--] != '_') ; /* find the last _ char */ subject_copy[j + 1] = '\0'; } else { /* If we run out of trailing components, then we exit * anyway. */ strcpy (filename, ""); break; /* exit while(true)loop */ } } /* end-while(true) */ messfree (subject_copy); if (strcmp(filename, "") != 0) return filename; /* success */ if ((strcasecmp(subject, "index") == 0) || (strcasecmp(subject, "home") == 0) || (strcasecmp(subject, "toc") == 0)) { /* we asked for some kind of index-page but couldn't find it, so we can always try to return the question mark '?' which will ask the calling function to display a dynamically created index of help-subjects. */ strcpy (filename, "?"); return filename; } return NULL; /* failure - no file found */ } /* helpSubjectGetFilename */ /************************************************************/ /* helpPackage utility to find out the filename of a given link reference. Absolute filenames are returned unchanged, but relative filenames are expanded to be the full path of the helpfile. Can be used for html/gif files referred to by the HREF of anchor tags or the SRC or IMG tags */ /* NOTE: the pointer returned is a static copy, which is re-used everytime it is called. If the calling function wants to mess about with the returned string, a copy has to be made. NULL is returned if the resulting file can't be opened. the calling function can inspect the result of messSysErrorText(), the report the resaon for failure */ /************************************************************/ char *helpLinkGetFilename (char *link) { static char link_path_array[MAXPATHLEN] = ""; char *link_path = &link_path_array[0]; if (link[0] == SUBDIR_DELIMITER) /* absolute path (UNIX) */ { strcpy (link_path, link); } else /* relative path */ { BOOL found = FALSE; FilDir dirs; strcpy (link_path, helpGetDir()); strcat (link_path, SUBDIR_DELIMITER_STR); strcat (link_path, link); if (!(filCheckName(link_path, "", "r"))) { int i = 0; dirs = filDirCreate(helpGetDir(), "", "rd"); while (!found && i < filDirMax(dirs)) { strcpy (link_path, helpGetDir()); strcat (link_path, SUBDIR_DELIMITER_STR); strcat (link_path, filDirEntry(dirs, i++)); strcat (link_path, SUBDIR_DELIMITER_STR); strcat (link_path, link); found = filCheckName(link_path, "", "r") ? TRUE : FALSE; } messfree (dirs); } } if (filCheckName(link_path, "", "r")) return link_path; return NULL; } /* helpLinkGetFilename */ /************************************************************/ /****************** ***********************/ /************** private helpPackage functions ***************/ /****************** ***********************/ /************************************************************/ HtmlPage *htmlPageCreate (char *helpFilename, STORE_HANDLE handle) /* complemeted by htmlPageDestroy */ { FILE *fil; HtmlPage *page = 0; if (!helpFilename) /* we could get a NULL filename */ return 0; /* here, which might come from helpSubjectGetFilename() that couldn't find a file matching the subject */ /* create a page with a marked up directory listing */ if (strcmp(helpFilename, "?") == 0) { page = halloc (sizeof(HtmlPage), handle); page->handle = handleHandleCreate(handle); page->htmlText = makeHtmlIndex(page->handle); if (!(page->root = parseHtmlText(page->htmlText, page->handle))) htmlPageDestroy(page); return page; } if (!(filCheckName(helpFilename, "", "r"))) return 0; /* prevent error caused by unsucsessful filopen */ /* create a page inlining the image */ if (strcasecmp (helpFilename + (strlen(helpFilename)-4), ".gif") == 0) { page = halloc (sizeof(HtmlPage), handle); page->handle = handleHandleCreate(handle); page->htmlText = makeHtmlImagePage(helpFilename, page->handle); if (!(page->root = parseHtmlText(page->htmlText, page->handle))) htmlPageDestroy(page); return page; } /* assume HTML page */ if ((fil = filopen(helpFilename, "", "r"))) { page = htmlPageCreateFromFile (fil, handle); filclose (fil); } return page; } /* htmlPageCreate */ /************************************************************/ HtmlPage *htmlPageCreateFromFile (FILE *fil, STORE_HANDLE handle) { HtmlPage *page; int fileSize; if (!fil) return (HtmlPage*)0; /* determine filesize */ rewind (fil); fseek (fil, 0, SEEK_END); fileSize = ftell (fil); rewind (fil); if (fileSize == 0) return (HtmlPage*)0; /* if we have a positive fileSize, we are pretty much guaranteed, that we'll get some HTML text and a parsetree */ page = halloc (sizeof(HtmlPage), handle); page->handle = handleHandleCreate(handle); /* grab the contents of the file */ page->htmlText = halloc ((fileSize + 1) * sizeof(char), page->handle); fread (page->htmlText, sizeof (char), fileSize, fil); page->htmlText[fileSize] = '\0'; /* add string terminator */ /* get parsetree */ page->root = parseHtmlText(page->htmlText, page->handle); return page; } /* htmlPageCreateFromFile */ /************************************************************/ void htmlPageDestroy (HtmlPage *page) /* only to be used if the page wasn't created on a handle */ { if (!page) return; /* clear all memory used during parsing of the page */ handleDestroy (page->handle); /* clear the memory taken up by the structure itself */ messfree (page); return; } /* htmlPageDestroy */ /************************************************************/ void htmlStripSpaces (char *cp) /* utility to get rid of multiple spaces from a string */ /* we use it on node->text, where the text isn't within <PRE> tags */ { char *s ; int i ; /* strip unwanted white spaces from the text */ for (i = 0; i < strlen(cp); ++i) if (isspace ((int)cp[i])) cp[i] = ' ' ; while ((s = strstr (cp, " "))) { s[1] = 0 ; strcat (cp, s+2) ; } if (cp[strlen(cp)-1] == ' ') cp[strlen(cp)-1] = '\0' ; return ; } /* htmlStripSpaces */ /************************************************************/ /****************** ***********************/ /****************** static functions ***********************/ /****************** ***********************/ /************************************************************/ /************************************************************/ /* as the helpviewer supports inlined images, it is easy to display image, even when they're not inlined as in <A HREF=image.gif>click here for image</A>. We just return a container page, that inlines the image */ /************************************************************/ static char *makeHtmlImagePage (char *link, STORE_HANDLE handle) { char *text; int len; len = 0; len = 7+6+strlen(filGetFilename(link))+8+10+strlen(link)+2; text = halloc((len+1)*sizeof(char), handle); sprintf (text, "<TITLE>Image %s" "", filGetFilename(link), link); text[len] = 0; return text; } /* makeHtmlImagePage */ /************************************************************/ /* reads the directory of helpDir and constructs an HTML-page containing a