/* File: texthelp.c * Author: Friedemann Wobus (fw@sanger.ac.uk) * and contributions from Darren Platt (daz@sanger.ac.uk) * ------------------------------------------------------------------- * 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: contains contains the code to display an HTML page as plain text Basic formatting is observed, but images and links are stripped. * Exported functions: ** helpPrint(char *helpFilename); * HISTORY: * Last edited: Nov 4 14:16 1999 (fw) * * Nov 4 14:01 1999 (fw): use ACEOUT for server * * Oct 8 16:01 1998 (fw): removed the declaration of helpOn and help for #define MACINTOSH * * Aug 20 16:10 1998 (rd): removed refernces to old help-system * * Aug 18 17:17 1998 (fw): help-system split into w1/helpsubs.c (helpDir, HTML stuff etc). w1/texthelp.c (non-graphical help for tace) w2/graphhelp.c (graphical help for xace,image etc.) * ---------------------------------------------------------------------- * ---- major rework, these revision don't necessarily * ---- affect code still left in this file * ---------------------------------------------------------------------- * * May 2 01:07 1996 (rd): new implementation of helpMakeIndex() using filDirectory() * * May 2 18:24 1996 (mieg): fall back on oldhelp callMosaic if (http:) use freeout for server jaime's file name rotation remaining problem: help topic in tace should be case-insensitive * * May 1 18:24 1996 (fw): fixed freePage() to avoid mem leaks * * Apr 30 16:18 1996 (fw): fixed #ifdef NON_GRAPHICs for tace * * Apr 30 16:18 1996 (fw): added image dictionary * * Apr 29 12:37 1996 (fw): added handling of
lists * * Apr 25 16:27 1996 (fw): added tag * * Apr 22 17:43 1996 (fw): changed help system to HTML browser * Created: Thu Feb 20 14:49:50 1992 (mieg) *------------------------------------------------------------------- */ /* $Id: texthelp.c,v 1.20 2002/02/22 18:00:21 srk Exp $ */ #ifndef MACINTOSH /********************************************************************/ #include "help_.h" #include "aceio.h" /********************************************************************/ typedef struct TextHelpStruct { ACEOUT fo; float xPos ; int indent ; int WINX ; char buf[10000] ; /* text-buffer for wordwrapping */ BOOL MODE_PREFORMAT ; BOOL MODE_HREF ; BOOL MODE_HEADER ; BOOL FOUND_NOBULLET_IN_LIST_NOINDENT ; int itemNumber ; char *currentLink ; } *TextHelp ; static void htmlPagePrint (TextHelp th, HtmlPage *page) ; static void printTextSection (TextHelp th, HtmlNode *node); /********************************************************************/ /* dumps out help-page without images and markups */ BOOL helpPrint (char *helpFilename, void *user_pointer) /* returns TRUE if a help page could successfully be displayed for the given subject, returns FALSE if no such page found */ { HtmlPage *page ; FilDir dirList; char *cp; int i,n,x; TextHelp th; ACEOUT help_out = (ACEOUT)user_pointer; th = (TextHelp) messalloc (sizeof (struct TextHelpStruct)) ; th->fo = (ACEOUT)user_pointer; if ((page = htmlPageCreate (helpFilename, 0))) { /* found a page */ htmlPagePrint (th, page); htmlPageDestroy (page); messfree (th) ; return TRUE; } if (!helpFilename) aceOutPrint (help_out, "Help subject not found\n"); else aceOutPrint (help_out, "Help subject is ambiguous\n"); aceOutPrint (help_out, "Try:\n help\n"); /* now show a list of possible files */ if(!(dirList = filDirCreate(helpGetDir(), "html", "r")) ) { messerror ("Can't open help directory %s\n" "(%s)", helpGetDir(), messSysErrorText()) ; messfree (th) ; return FALSE ; } for (i = 0, x = 0 ; i < filDirMax(dirList) ; i++) { cp = filDirEntry(dirList, i) ; if (!cp || !*cp || !strlen(cp)) continue ; if (helpFilename) { if (strncasecmp(filGetFilename(helpFilename),cp, strlen(filGetFilename(helpFilename))) != 0) continue; } n = strlen(cp) ; if (n > 5 && !strcmp(".html", cp + n - 5)) *(cp + n - 5) = 0 ; x += n + 1 ; if (x > 50) { x = n + 1 ; aceOutPrint (help_out, "\n") ;} aceOutPrint (help_out, "%s ", cp) ; } aceOutPrint (help_out, "\n") ; messfree (dirList); messfree (th) ; return FALSE; } /* helpPrint */ /************************************************************/ /* counter-part to graphWebBrowser(), which remote-controls netscape using the -remote command line option. Useful for textual applications running in an X11 environment, where x-apps can be called from within the application, but the Xtoolkit (used to drive netscape via X-atoms) shouldn't be linked in, because it is a textual app. */ /************************************************************/ BOOL helpWebBrowser(char *link) { /* currently impossible, because it is hard to find out whether a netscape process is already running. Stupidly enough 'netscape -remote...' doesn't exit with code 1, if it can't connect to an existing process */ return FALSE; } /* helpWebBrowser */ /************************************************************/ /****************** ***********************/ /****************** static functions ***********************/ /****************** ***********************/ /************************************************************/ static void htmlPagePrint (TextHelp th, HtmlPage *page) { /* init screen-position parameters */ th->WINX = 80 ; th->indent = 2 ; th->xPos = th->indent ; /* start recursively printing nodes */ printTextSection (th, page->root) ; return; } /* htmlPagePrint */ /************************************************************/ static void newTextLine (TextHelp th) { int i ; /* if (th->xPos != indent)*/ { aceOutPrint (th->fo, "\n") ; for (i = 0; i < th->indent; ++i) aceOutPrint (th->fo, " ") ; th->xPos = th->indent ; } return; } /* newTextLine */ /************************************************************/ static void blankTextLine (TextHelp th) { int i ; aceOutPrint (th->fo, "\n") ; for (i = 0; i < th->indent; ++i) aceOutPrint (th->fo, " ") ; th->xPos = th->indent ; newTextLine (th) ; return; } /* blankTextLine */ /************************************************************/ static void printTextSection (TextHelp th, HtmlNode *node) /* part specific to the text-help system, which uses freeOut to print arsed HTML as plain text */ { int i, len ; char *cp, *start ; switch (node->type) { case HTML_SECTION: printTextSection (th, node->left) ; if (node->right) printTextSection (th, node->right) ; break ; case HTML_COMMENT: /* do nothing */ break ; case HTML_DOC: case HTML_HEAD: case HTML_BODY: if (node->left) printTextSection (th, node->left) ; break ; case HTML_TITLE: for (i = 0; i < strlen(node->text)+4; ++i) aceOutPrint (th->fo, "*") ; aceOutPrint (th->fo, "\n* %s *\n", node->text) ; for (i = 0; i < strlen(node->text)+4; ++i) aceOutPrint (th->fo, "*") ; blankTextLine(th) ; break ; case HTML_HEADER: { th->MODE_HEADER = TRUE ; th->indent = node->hlevel*2 ; blankTextLine (th) ; /* check, in case some bozo has done a thing like

*/ if (node->left) printTextSection (th, node->left) ; aceOutPrint (th->fo, "\n") ; for (i = 0; i < th->xPos; ++i) { if (i < th->indent) aceOutPrint (th->fo, " ") ; else aceOutPrint (th->fo, "*") ; } blankTextLine (th) ; th->MODE_HEADER = FALSE ; } break ; case HTML_LIST: if (node->lstyle == HTML_LIST_BULLET || node->lstyle == HTML_LIST_NUMBER) th->indent += 2 ; else if (node->lstyle == HTML_LIST_NOINDENT) th->indent -= 2 ; newTextLine (th) ; th->itemNumber = 0 ; /* a list might not have a leftnode (a list item) */ if (node->left) printTextSection (th, node->left) ; if (node->lstyle == HTML_LIST_BULLET || node->lstyle == HTML_LIST_NUMBER) th->indent -= 2 ; else if (node->lstyle == HTML_LIST_NOINDENT) th->indent += 2 ; if (node->lstyle == HTML_LIST_NOINDENT && th->FOUND_NOBULLET_IN_LIST_NOINDENT) { th->indent -= 4 ; th->FOUND_NOBULLET_IN_LIST_NOINDENT = FALSE ; } blankTextLine (th) ; break ; case HTML_LISTITEM: ++(th->itemNumber) ; if (node->left) { if (node->lstyle == HTML_LIST_NOINDENT_NOBULLET) { /* if we are in a
list and went to indentation because of a
item, a
item brings back the old indent-level (noindent for
's) */ if (th->FOUND_NOBULLET_IN_LIST_NOINDENT) { th->indent -= 6 ; th->FOUND_NOBULLET_IN_LIST_NOINDENT = FALSE ; newTextLine (th) ; aceOutPrint (th->fo, " ") ; } } else newTextLine (th) ; if (node->lstyle == HTML_LIST_BULLET || node->lstyle == HTML_LIST_NOINDENT) { aceOutPrint (th->fo, "* ") ; th->indent += 2 ; th->xPos = th->indent ; } else if (node->lstyle == HTML_LIST_NUMBER) { aceOutPrint (th->fo, "%d. ", th->itemNumber) ; th->indent += strlen(messprintf ("%d. ", th->itemNumber)) ; th->xPos = th->indent ; } else if (node->lstyle == HTML_LIST_NOBULLET) { /* part of a
noindented list, but a
item becomes indented, but no bullet */ /* if we come across the first NO_BULLET item, in a LIST_NOINDENT, the LIST becomes indented */ if (!th->FOUND_NOBULLET_IN_LIST_NOINDENT) { th->indent += 6 ; th->xPos = th->indent ; aceOutPrint (th->fo, " ") ; fflush (stdout) ; th->FOUND_NOBULLET_IN_LIST_NOINDENT = TRUE ; } } printTextSection (th, node->left) ; } if (node->lstyle == HTML_LIST_BULLET || node->lstyle == HTML_LIST_NOINDENT) { th->indent -= 2 ; } else if (node->lstyle == HTML_LIST_NUMBER) { th->indent -= strlen(messprintf ("%d. ", th->itemNumber)) ; } else if (node->lstyle == HTML_LIST_NOBULLET) { if (!th->FOUND_NOBULLET_IN_LIST_NOINDENT) th->indent -= 6 ; } if (node->right) { printTextSection (th, node->right) ; } break ; case HTML_HREF: if (node->link) { th->MODE_HREF = TRUE ; th->currentLink = node->link ; } /* we have to check for leftnode, in case we have a thing like . The HREF-node doesn't have a TEXT node attached, and it would crash otherwise */ if (node->left)printTextSection (th, node->left) ; if (node->link) { th->MODE_HREF = FALSE ; th->currentLink = 0 ; } break ; case HTML_TEXT: cp = node->text ; if (!th->MODE_PREFORMAT) htmlStripSpaces (node->text) ; /* for th->MODE_PREFORMAT keeps all controls chars */ while (*cp) { len = 0 ; start = cp ; if (!th->MODE_PREFORMAT) { while (*cp && !isspace((int)*cp)) { ++(cp) ; ++len ; } if (*cp) ++cp ; /* skip whitespace */ } else { while (*cp && *cp != '\n') { ++(cp) ; ++len ; } if (*cp) { ++cp ; /* skip RETURN */ ++len ; /* so we copy the RETURN into buf */ } } memset (th->buf, 0, 10000) ; strncpy (th->buf, start, len) ; th->buf[len] = 0 ; /* linewrapping of words/lines longer than WINX */ if (strlen(th->buf) > th->WINX) { cp = start + (int)(th->WINX) ; th->buf[(int)th->WINX] = 0 ; len = (int)th->WINX ; } /* word wrapping if not in preformatting mode */ if (!th->MODE_PREFORMAT) { if (th->xPos != th->indent) /* not at start of line ... */ { th->xPos += 1 ; /* ... one space before the word */ aceOutPrint (th->fo, " ") ; fflush (stdout) ; } if (th->xPos + len > th->WINX) { newTextLine (th) ; } aceOutPrint (th->fo, "%s", th->buf) ; th->xPos += strlen(th->buf) ; /* place th->xPos at the end of word */ } else if (th->MODE_PREFORMAT) { int oldpos, stringpos, screenpos, ii ; i = 0 ; /* replace TABs with appropriate number of spaces */ while (th->buf[i]) { if (th->buf[i] == '\t') { /* oldpos is the position, that this TAB char would go on the screen without TABifying NOTE: xPos is always at least "indent" (to leave a left margin) */ oldpos = (th->xPos - th->indent) + i ; /* screenpos is the position of the TAB char after inserting spaces NOTE: the TAB itself will be overwritten by one space */ screenpos = (((oldpos/8)+1)*8) - 1 ; /* stringpos is where the TAB should go in the string, where it'll turn into a space at that position */ stringpos = screenpos - (th->xPos-th->indent) ; /* shift all text from current position "i" onwards */ for (ii = strlen(th->buf)-1; ii >= i ; --ii) th->buf[ii+(stringpos-i)] = th->buf[ii] ; /* fill gap with spaces and also overwrite TAB with a space */ for (ii = i; ii <= stringpos; ++ii) th->buf[ii] = ' ' ; i = stringpos ; } ++i ; } /* don't use len, it might have changed when inserting spaces */ if (th->buf[strlen(th->buf)-1] == '\n') { th->buf[strlen(th->buf)-1] = 0 ; aceOutPrint (th->fo, "%s", th->buf) ; th->xPos += strlen(th->buf) ; newTextLine (th); /* for the '\n' */ } else { aceOutPrint (th->fo, "%s", th->buf) ; th->xPos += strlen(th->buf) ; } } } break ; case HTML_GIFIMAGE: { aceOutPrint (th->fo, " [IMAGE] ") ; th->xPos += 9 ; } break ; case HTML_NOIMAGE: break ; case HTML_RULER: { newTextLine (th) ; for (i = th->indent; i < th->WINX; ++i) aceOutPrint (th->fo, "-") ; th->xPos = th->WINX ; newTextLine (th) ; } break ; case HTML_PARAGRAPH: blankTextLine (th) ; break ; case HTML_LINEBREAK: newTextLine (th) ; break ; case HTML_BOLD_STYLE: case HTML_STRONG_STYLE: case HTML_ITALIC_STYLE: case HTML_CODE_STYLE: case HTML_UNDERLINED_STYLE: { if (node->left) printTextSection (th, node->left) ; } break ; case HTML_STARTBLOCKQUOTE: newTextLine (th) ; th->indent += 3 ; th->xPos = th->indent ; for (i = 0; i < th->indent; ++i) aceOutPrint (th->fo, " ") ; /* fflush (stdout) ; we deal with freeOutf, not with stdout */ break ; case HTML_ENDBLOCKQUOTE: th->indent -= 3 ; blankTextLine (th) ; break ; case HTML_STARTPREFORMAT: th->MODE_PREFORMAT = TRUE ; newTextLine (th) ; break ; case HTML_ENDPREFORMAT: th->MODE_PREFORMAT = FALSE ; break ; case HTML_UNKNOWN: break; /* compiler happiness */ } return; } /* printTextSection */ /************************************************************/ #endif /* !def MACINTOSH */