/* @(#)tydoc.c 17.1.1.1 (ES0-DMD) 01/25/02 17:48:08 */ /*=========================================================================== Copyright (C) 1995 European Southern Observatory (ESO) This program 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., 675 Massachusetss Ave, Cambridge, MA 02139, USA. Corresponding concerning ESO-MIDAS should be addressed as follows: Internet e-mail: midas@eso.org Postal address: European Southern Observatory Data Management Division Karl-Schwarzschild-Strasse 2 D 85748 Garching bei Muenchen GERMANY ===========================================================================*/ /*++++++++++++++ .IDENTIFICATION tydoc.c .LANGUAGE C .AUTHOR ESO-IPG, Garching .ENVIRONMENT TermWindows .KEYWORDS TeX .VERSION 1.0 28-Nov-1990 .COMMENTS This module includes the various functions to deal with Documents, i.e. a set of Windows. \begin{TeX} \end{TeX} ---------------*/ #define DEBUG 0 /* For debugging only */ #define PM_LEVEL LEVEL_TX #include /* TermWindow Definitions */ #include /* String Utilities */ /* Returned DOC numbers are in range [DOC_OFFSET, DOC_OFFSET + DOC+MAX [ */ #define DOC_OFFSET 900 #define DOC_MAX 20 typedef struct { char *name; /* Not used right now */ WINDOW *win; /* Associated Window */ int flags; #define DOC_READY 1 int alp, /* Allocated Pages */ edp; /* Edited Pages */ int nap; /* Number of Bytes/page */ ACHAR **pages;/* Array of Pages */ int pageno; /* Current Page Number */ short lines, /* How many lines/page */ lineno; /* Which line is on Window Top */ } DOC; static DOC *document[DOC_MAX] = { (DOC *)0 }; static int TheDoc = 0; /* Current Document */ /*======================================================================== * Internal Housekeeping Routines *========================================================================*/ static DOC *Object(id) /*++++++++++++++++ .PURPOSE Convert number into Object Pointer .RETURNS Address of Corresponding object / NULL -----------------*/ int id; /* IN: Object number returned by ty_open */ { DOC *pd; if ( (id < DOC_OFFSET) || (id >= DOC_OFFSET + DOC_MAX)) { ERR_ED_I("Bad Document #", id); return ((DOC *)0); } pd = document[id - DOC_OFFSET]; if (!pd) ERR_ED_I("Document does not exist, #", id); return(pd); } static int new(name, w) /*++++++++++++++++ .PURPOSE Create a new DOC folder .RETURNS Number of Created Object / 0 if Fails .REMARKS -----------------*/ char *name; /* IN: Associated name */ WINDOW *w; /* IN: Associated window*/ { int i; DOC *pd; /* Find an emtpy slot */ for (i=0; document[i] && (i < DOC_MAX); i++) ; if (i >= DOC_MAX) { ERR_ED_I("Too many opened documents: ", i); return(0); } /* Allocate & Initialize */ document[i] = pd = MEM_GET(DOC, 1); pd->name = strsave(name); pd->win = w; pd->flags = 0; pd->alp = 0; pd->edp = 0; pd->nap = w->dim[0] * w->dim[1]; pd->pages = (ACHAR **)0; pd->pageno= -1; pd->lines = w->dim[0]; pd->lineno= 0; return(i + DOC_OFFSET); } static int kill(id) /*++++++++++++++++ .PURPOSE Kill (close) a document .RETURNS OK / NOK -----------------*/ int id; /* IN: Object to kill */ { DOC *pd; int i; if_not (pd = Object(id)) return(NOK); /* Remove allocated memory */ for (i = pd->edp; --i >= 0; ) MEM_FREE(pd->pages[i]); MEM_FREE(pd->name); MEM_FREE(pd->pages); MEM_FREE(pd); document[id-DOC_OFFSET] = (DOC *)0; TheDoc = 0; return(OK); } static int save_page(pd) /*++++++++++++++++ .PURPOSE Insert the edited window as a new page .RETURNS OK / NOK -----------------*/ DOC *pd; /* MOD: Document Concerned */ { int cursor; ACHAR *page; cursor = (pd->win)->pos; /* Save */ CursorHome(pd->win); if (pd->edp >= pd->alp) { /* Must expand array of Pages */ pd->alp += 16; pd->pages = MEM_EXP(ACHAR *, pd->pages, pd->alp); } page = MEM_GET(ACHAR, pd->nap); SaveWindowText(pd->win, page, pd->nap); pd->pages[(pd->edp)++] = page; (pd->win)->pos = cursor; /* Restore */ return(OK); } static int init(win, str) /*++++++++++++++++ .PURPOSE Initialisation of a display function .RETURNS Document number (0 if fails). TheDoc is also initialized. .METHOD Check for non-clased documents. Initialize a new one if necessary. -----------------*/ WINDOW *win; /* IN: Window to echo the processed text */ char *str; /* IN: NULL for Continuation */ { DOC *pd; int id; if (str) { /* Create a New Document */ if_not(id = new("<>", win)) return(0); if (TheDoc) { /* Check Current Document properly closed */ pd = Object(TheDoc); if_not (pd->flags & DOC_READY) { WARNING("Non-closed document exists!"); pd->flags |= DOC_READY; } } TheDoc = id; } /* Check there is something to edit */ pd = Object(TheDoc); if (pd->flags & DOC_READY) { /* Nothing more... */ WARNING("Document already complete..."); return(0); } return(TheDoc); } static int next_page(pd) /*++++++++++++++++ .PURPOSE Display on Window the next page .RETURNS OK / NOK (Document already at bottom) -----------------*/ DOC *pd; /* MOD: Document Concerned */ { if (pd->pageno < pd->edp) { pd->lineno = 0; /* Page adjusted on Window */ pd->pageno += 1; /* New page to show */ CursorHome(pd->win); WriteAchars(pd->win, pd->pages[pd->pageno], pd->nap); return(OK); } else return(NOK); } /*======================================================================== * Public Routines *========================================================================*/ int ty_display(win, str, len, option) /*+++ .PURPOSE Display a text on a Document .RETURNS --- Document number (positive number) --- NOK Error occured. .REMARKS ---*/ WINDOW *win; /* IN: Window to echo the processed text */ char *str; /* IN: text to display, or NULL (continuation )*/ int len; /* IN: Length of text */ int option; /* IN: Option 1 to edit the complete document */ { int echo_state, status; DOC *pd; ENTER("+ty_display"); if_not(init(win, str)) EXIT(NOK); pd = Object(TheDoc); /* Deactivate Window to display the Current Page */ echo_state = DeactiveWindow(pd->win); status = tx_display(pd->win, str, len, 1); /* Display with clear_page */ save_page(pd); if (option) while (status == NOK) { /* Edit ALL pages */ status = tx_display(pd->win, (char *)0, 0, 1); save_page(pd); } if (status != NOK) pd->flags |= DOC_READY; /* Edit Next Page if any */ next_page(pd); if (echo_state) ActiveWindow(pd->win); EXIT(TheDoc); } /*========================================================================*/ int ty_mdisplay(win, str, nstr, option) /*+++ .PURPOSE Display a text on the window made of several pieces of text. The pieces are provided by the array of strings str made of (2*nstr) pointers, specifying nstr times (start, end). (a pointer to the end of a string is the byte just following the last byte of the string, i.e. the address of the null character for a standard string) .RETURNS --- Document number (positive number) --- NOK Error occured. .REMARKS ---*/ WINDOW *win; /* IN: Window to echo the processed text */ char **str; /* IN: Array of strings to display, \ as n* (start, end) */ int nstr; /* IN: Number of strings */ int option; /* IN: Option 1 to edit the complete document */ { int echo_state, status; DOC *pd; ENTER("+ty_mdisplay"); if_not(init(win, (char *)str)) EXIT(NOK); pd = Object(TheDoc); /* Deactivate Window to display the Current Page */ echo_state = DeactiveWindow(pd->win); status = tx_mdisplay(pd->win, str, nstr, 1); /* Display with clear_page */ save_page(pd); if (option && (status == NOK)) /* Edit the rest of the Doc */ ty_display(win, (char *)0, 0, 1); if (status != NOK) pd->flags |= DOC_READY; /* Edit Next Page if any */ next_page(pd); if (echo_state) ActiveWindow(pd->win); EXIT(TheDoc); } /*========================================================================*/ int ty_fdisplay(win, fid, len, option) /*+++ .PURPOSE Display a file extract on the window. .RETURNS --- Document number (positive number) --- NOK Error occured. .REMARKS ---*/ WINDOW *win; /* IN: Window to echo the processed text */ int fid; /* IN: File number (opened by fi_open) */ int len; /* IN: Maximal number of bytes to read */ int option; /* IN: Option 1 to edit the complete document */ { int echo_state, status; DOC *pd; ENTER("+ty_fdisplay"); init(win, ""); /* Non-null char pointer */ pd = Object(TheDoc); /* Deactivate Window to display the Current Page */ echo_state = DeactiveWindow(pd->win); status = tx_fdisplay(pd->win, fid, len, 1); /* Display with clear_page */ save_page(pd); if (option && (status == NOK)) /* Edit the rest of the Doc */ ty_display(win, (char *)0, 0, 1); if (status != NOK) pd->flags |= DOC_READY; /* Edit Next Page if any */ next_page(pd); if (echo_state) ActiveWindow(pd->win); EXIT(TheDoc); } /*========================================================================*/ int ty_file(win, fname, option) /*+++ .PURPOSE Display a complete file extract on the window. .RETURNS --- Document number (positive number) --- NOK Error occured. .REMARKS ---*/ WINDOW *win; /* IN: Window to echo the processed text */ char *fname; /* IN: File name */ int option; /* IN: Option 1 to edit the complete document */ { int echo_state, status; DOC *pd; ENTER("ty_file"); init(win, fname); /* Initialize the Document */ pd = Object(TheDoc); /* Deactivate Window to display the Current Page */ echo_state = DeactiveWindow(pd->win); status = tx_file(pd->win, fname, 1); /* Display with clear_page */ save_page(pd); if (option && (status == NOK)) /* Edit the rest of the Doc */ ty_display(win, (char *)0, 0, 1); if (status != NOK) pd->flags |= DOC_READY; /* Edit Next Page if any */ next_page(pd); if (echo_state) ActiveWindow(pd->win); EXIT(TheDoc); } /*========================================================================*/ int ty_close(id) /*+++ .PURPOSE Close a Document .RETURNS OK / NOK .REMARKS ---*/ int id; /* IN: Document to Close */ { int status; ENTER("ty_close"); if (id) kill(id); else status = NOK; EXIT(status); } /*========================================================================*/ int ty_pseek(id, times, mode) /*+++ .PURPOSE Move in the document by PAGE units .RETURNS Current position / -1 for Errors .REMARKS Just SET the position; use ty_show to display the current contents. The position specified is adjusted if it's outside the document limits. ---*/ int id; /* IN: Document concerned */ int times; /* IN: Number of Pages to move */ int mode; /* IN: Mode as 0(Absolute) / 1 (Relative) / 2 (EOF) */ { DOC *pd; int echo_state, pageno;; ENTER("+ty_pseek"); if_not (pd = Object(id)) EXIT(-1); echo_state = tw_st(pd->win, Echo, 0); /* Don't write on Window */ /* Compute ABSOLUTE page number according to mode */ switch(mode) { case 1: pageno = times + pd->pageno; break; case 2: if_not (pd->flags & DOC_READY) ty_display(pd->win, (char *)0, 0, 1); pageno = times + pd->edp; break; default: pageno = times; break; } if (pageno < 0) pageno = 0; /* If new edition has to be done, do it. */ while (pageno >= pd->edp) { if (pd->flags & DOC_READY) break; ty_display(pd->win, (char *)0, 0, 0); /* Display Next Page */ } if (pageno >= pd->edp) pageno = pd->edp - 1; pd->lineno = 0, pd->pageno = pageno; tw_st(pd->win, Echo, echo_state); EXIT(pageno); } /*========================================================================*/ int ty_lseek(id, times, mode) /*+++ .PURPOSE Move in the document by LINE units .RETURNS Current position / -1 for Errors .REMARKS Just SET the position; use ty_show to display the current contents. ---*/ int id; /* IN: Document concerned */ int times; /* IN: Number of Lines to Move */ int mode; /* IN: Mode as 0(Absolute) / 1 (Relative) / 2 (EOF) */ { DOC *pd; int echo_state, i, lineno, pageno;; ENTER("+ty_lseek"); if_not (pd = Object(id)) EXIT(-1); echo_state = tw_st(pd->win, Echo, 0); /* Don't write on Window */ lineno = pd->lineno; pageno = pd->pageno; /* Transform to Absolute seek */ switch(mode) { case 2: /* From EOF */ ty_pseek(id, 0, 2); lineno = pd->edp * pd->lines + times; break; case 1: /* Relative */ if (times == 0) goto DONE; /* Just inquire */ lineno = pageno * pd->lines + lineno + times; break; default: lineno = times; break; } if (lineno < 0) lineno = 0; i = lineno/pd->lines; /* Move First by Page */ pageno = ty_pseek(id, i, 0); /* Load Page */ if (pageno == i) { /* Another page required ? */ lineno %= pd->lines; if (lineno) { ++i; if (ty_pseek(id, i, 0) != i) lineno = 0; } } else lineno = 0; DONE: pd->pageno = pageno; pd->lineno = lineno; tw_st(pd->win, Echo, echo_state); i = pageno * pd->lines + lineno; EXIT(i); } /*========================================================================*/ int ty_end(id) /*+++ .PURPOSE Check if Document is at its end .RETURNS 0 (not at End) / 1 (at End) ---*/ int id; /* IN: Document concerned */ { DOC *pd; int at_end; ENTER("+ty_end"); at_end = 0; if(pd = Object(id)) { if_not(pd->flags & DOC_READY) ; else at_end = (pd->pageno >= (pd->edp - 1)); } EXIT(at_end); } /*========================================================================*/ int ty_show(id) /*+++ .PURPOSE Display on Window the Document at current Position .RETURNS OK / NOK ---*/ int id; /* IN: Document concerned */ { DOC *pd; int cursor, echo_state, len1, len; ENTER("ty_show"); if_not (pd = Object(id)) EXIT(NOK); echo_state = tw_st(pd->win, Echo, 0); /* Don't write on Window */ cursor = (pd->win)->pos; /* Save */ CursorHome(pd->win); len = pd->lineno * (pd->win)->dim[1]; len1= pd->nap - len; WriteAchars(pd->win, pd->pages[pd->pageno] + len, len1); if (len) { (pd->win)->pos = len1; WriteAchars(pd->win, pd->pages[pd->pageno + 1], len); } (pd->win)->pos = cursor; /* Restore */ TouchWindow(pd->win); EXIT(OK); } /*========================================================================*/ int ty_more(id, key) /*+++ .PURPOSE Execute the Unix "more-like" function. .RETURNS OK / NOK (bad key) / EOF (Ask to Exit). Actions may be: \begin{TeX} \begin{itemize} \item {\em Control--}{\tt B} : upwards full-screen \item {\em Control--}{\tt U} : upwards half-screen \item {\em Control--}{\tt D} : downwards half-screen \item {\em Control--}{\tt F} or {\em Space bar}: downwards full-screen \item {\em Return} : downwards one line \item {\tt Q}: Quit \item {\tt R}: Refresh \end{itemize} \end{TeX} .REMARKS Document shown only if Window is active... ---*/ int id; /* IN: Document concerned */ int key; /* IN: Key specifying the action */ { DOC *pd; int before, after, status, hpage; ENTER("ty_more"); if_not (pd = Object(id)) EXIT(-1); hpage = pd->lines / 2; status = OK; before = ty_lseek(id, 0, 1); /* Current Position */ switch(key) { case 'q': case 'Q': case EOF: status = EOF; break; case '$': case 'G': after = ty_pseek(id, 0, 2); break; /* Bottom */ case 'B': case '%': case 'g': case CNTRL('T'): after = ty_pseek(id, 0, 0); break; case 'b': case CNTRL('B'): after = ty_lseek(id, -pd->lines, 1); break; case 'u': case CNTRL('U'): after = ty_lseek(id, -hpage, 1); break; case 'y': case CNTRL('Y'): case '-': after = ty_lseek(id, -1, 1); break; case '\r': case '\n': case 'e': case CNTRL('E'): case '+': case 0: case '.': after = ty_lseek(id, 1, 1); break; case 'd': case CNTRL('D'): after = ty_lseek(id, hpage, 1); break; case ' ': case CNTRL('F'): case 'f': case 'F': /* Scroll Down */ after = ty_lseek(id, pd->lines, 1); break; case 'R': case 'r': case CNTRL('L'): case CNTRL('R'): RefreshScreen(); EXIT(OK); case 'p': case 'P': /* Current Page */ after = ty_pseek(id, 0, 1); break; default: status = NOK; Bell(); break; } if (status == OK) { if (before == after) status = NOK; else ty_show(id); } EXIT(status); }