display.c

Go to the documentation of this file.
00001 /* Copyright (c) 1985 Ceriel J.H. Jacobs */
00002 
00003 # ifndef lint
00004 static char rcsid[] = "$Header: /opt/proj/minix/cvsroot/src/commands/yap/display.c,v 1.1.1.1 2005/04/21 14:55:39 beng Exp $";
00005 # endif
00006 
00007 # define _DISPLAY_
00008 
00009 # include "in_all.h"
00010 # include "display.h"
00011 # include "assert.h"
00012 # include "machine.h"
00013 # include "term.h"
00014 # include "output.h"
00015 # include "options.h"
00016 # include "process.h"
00017 # include "getline.h"
00018 # include "main.h"
00019 
00020 STATIC char * do_line();
00021 
00022 /*
00023  * Fill n lines of the screen, each with "str".
00024  */
00025 
00026 STATIC VOID
00027 fillscr(n,str) char *str; int n; {
00028 
00029         while (n-- > 0) {
00030                 putline(str);
00031         }
00032 }
00033 
00034 /*
00035  * Skip "n" screenlines of line "p", and return what's left of it.
00036  */
00037 
00038 STATIC char *
00039 skiplines(p,n) char *p; int n; {
00040 
00041         while (n-- > 0) {
00042                 p = do_line(p,0);
00043                 scr_info.currentpos--;
00044         }
00045         return p;
00046 }
00047 
00048 /*
00049  * Redraw screen.
00050  * "n" = 1 if it is a real redraw, 0 if one page must be displayed.
00051  * It is also called when yap receives a stop signal.
00052  */
00053 
00054 VOID
00055 redraw(n) int n; {
00056         register struct scr_info *p = &scr_info;
00057         register int i;
00058 
00059         i = pagesize;
00060         if (n && p->currentpos) {
00061                 i = p->currentpos;
00062         }
00063         (VOID) display(p->firstline,p->nf,i,1);
00064 }
00065 
00066 /*
00067  * Compute return value for the routines "display" and "scrollf".
00068  * This return value indicates wether we are at the end of file
00069  * or at the start, or both.
00070  * "s" contains that part of the last line that was not displayed.
00071  */
00072 
00073 STATIC int
00074 compretval(s) char *s; {
00075         register int i;
00076         register struct scr_info *p = &scr_info;
00077 
00078         i = 0;
00079         if (!s || (!*s && !getline(p->lastline+1, 1))) {
00080                 i = EOFILE;
00081         }
00082         if (p->firstline == 1 && !p->nf) {
00083                 i |= START;
00084         }
00085         status = i;
00086         return i;
00087 }
00088 
00089 /*
00090  * Display nlines, starting at line n, not displaying the first
00091  * nd screenlines of n.
00092  * If reallydispl = 0, the actual displaying is not performed,
00093  * only the computing associated with it is done.
00094  */
00095 
00096 int
00097 display(n,nd,nlines,reallydispl)
00098   long n; int nd; register int nlines; int reallydispl; {
00099 
00100         register struct scr_info *s = &scr_info;
00101         register char *p;       /* pointer to line to be displayed */
00102 
00103         if (startcomm)  {       /* No displaying on a command from the
00104                                  * yap command line. In this case, displaying
00105                                  * will be done after executing the command,
00106                                  * by a redraw.
00107                                  */
00108                 reallydispl = 0;
00109         }
00110         if (!n) {
00111                 n = 1L;
00112                 nd = 0;
00113         }
00114         if (reallydispl) {      /* move cursor to starting point */
00115                 if (stupid) {
00116                         putline(currentfile);
00117                         putline(", line ");
00118                         prnum(n);
00119                         nlines--;
00120                 }
00121                 if (cflag) {
00122                         putline("\r\n");
00123                 }
00124                 else {
00125                         home();
00126                         clrscreen();
00127                 }
00128         }
00129         /*
00130          * Now, do computations and display
00131          */
00132         s->currentpos = 0;
00133         s->nf = nd;
00134         s->head = s->tail;
00135         s->tail->cnt = 0;
00136         s->tail->line = n;
00137         p = skiplines(getline(n,1),nd);
00138         while (nlines && p) {
00139                 /*
00140                  * While there is room,
00141                  * and there is something left to display ...
00142                  */
00143                 (s->tail->cnt)++;
00144                 nlines--;
00145                 if (*(p = do_line(p,reallydispl)) == '\0') {
00146                         /*
00147                          * File-line finished, get next one ...
00148                          */
00149                         p = getline(++n,1);
00150                         if (nlines && p) {
00151                                 s->tail = s->tail->next;
00152                                 s->tail->cnt = 0;
00153                                 s->tail->line = n;
00154                         }
00155                 }
00156         }
00157         if (!stupid) {
00158                 s->currentpos += nlines;
00159                 if (reallydispl) {
00160                         fillscr(nlines, "~\r\n");
00161                         fillscr(maxpagesize - s->currentpos, "\r\n");
00162                 }
00163         }
00164         return compretval(p);
00165 }
00166 
00167 /*
00168  * Scroll forwards n lines.
00169  */
00170 
00171 int
00172 scrollf(n,reallydispl) int n; int reallydispl; {
00173 
00174         register struct scr_info *s = &scr_info;
00175         register char *p;
00176         register long ll;
00177         register int i;
00178 
00179         /*
00180          * First, find out how many screenlines of the last line were already
00181          * on the screen, and possibly above it.
00182          */
00183 
00184         if (n <= 0 || (status & EOFILE)) return status;
00185         if (startcomm) reallydispl = 0;
00186         /*
00187          * Find out where to begin displaying
00188          */
00189         i = s->tail->cnt;
00190         if ((ll = s->lastline) == s->firstline) i += s->nf;
00191         p = skiplines(getline(ll, 1), i);
00192         /*
00193          * Now, place the cursor at the first free line
00194          */
00195         if (reallydispl && !stupid) {
00196                 clrbline();
00197                 mgoto(s->currentpos);
00198         }
00199         /*
00200          * Now display lines, keeping track of which lines are on the screen.
00201          */
00202         while (n-- > 0) {       /* There are still rows to be displayed */
00203                 if (!*p) {      /* End of line, get next one */
00204                         if (!(p = getline(++ll, 1))) {
00205                                 /*
00206                                  * No lines left. At end of file
00207                                  */
00208                                 break;
00209                         }
00210                         s->tail = s->tail->next;
00211                         s->tail->cnt = 0;
00212                         s->tail->line = ll;
00213                 }
00214                 if (s->currentpos >= maxpagesize) {
00215                         /*
00216                          * No room, delete first screen-line
00217                          */
00218                         s->currentpos--;
00219                         s->nf++;
00220                         if (--(s->head->cnt) == 0) {
00221                                 /*
00222                                  * The first file-line on the screen is wiped
00223                                  * out completely; update administration
00224                                  * accordingly.
00225                                  */
00226                                 s->nf = 0;
00227                                 s->head = s->head->next;
00228                                 assert(s->head->cnt > 0);
00229                         }
00230                 }
00231                 s->tail->cnt++;
00232                 p = do_line(p, reallydispl);
00233         }
00234         return compretval(p);
00235 }
00236 
00237 /*
00238  * Scroll back n lines
00239  */
00240 
00241 int
00242 scrollb(n, reallydispl) int n, reallydispl; {
00243 
00244         register struct scr_info *s = &scr_info;
00245         register char *p;       /* Holds string to be displayed */
00246         register int i;
00247         register int count;
00248         register long ln;       /* a line number */
00249         register int nodispl;
00250         int cannotscroll;       /* stupid or no insert-line */
00251 
00252         /*
00253          * First, find out where to start
00254          */
00255         if ((count = n) <= 0 || (status & START)) return status;
00256         if (startcomm) reallydispl = 0;
00257         cannotscroll = stupid || (!*AL && !*SR);
00258         ln = s->firstline;
00259         nodispl = s->nf;
00260         while (count) { /* While scrolling back ... */
00261                 if (i = nodispl) {
00262                         /*
00263                          * There were screen-lines of s->firstline that were not
00264                          * displayed.
00265                          * We can use them now, but only "count" of them.
00266                          */
00267                         if (i > count) i = count;
00268                         s->currentpos += i;
00269                         nodispl -= i;
00270                         count -= i;
00271                 }
00272                 else {  /* Get previous line */
00273                         if (ln == 1) break; /* isn't there ... */
00274                         p = getline(--ln, 1);
00275                         /*
00276                          * Make it the first line of the screen and compute
00277                          * how many screenlines it takes. These lines are not
00278                          * displayed, but nodispl is set to this count, so
00279                          * that it will be nonzero next time around
00280                          */
00281                         nodispl = 0;
00282                         do {    /* Find out how many screenlines */
00283                                 nodispl++;
00284                                 p = skiplines(p, 1);
00285                         } while (*p);
00286                 }
00287         }
00288         n -= count;
00289         if ((i = s->currentpos) > maxpagesize) i = maxpagesize;
00290         if (reallydispl && hardcopy) i = n;
00291         /*
00292          * Now that we know where to start, we can use "display" to do the
00293          * rest of the computing for us, and maybe even the displaying ...
00294          */
00295         i = display(ln,
00296                     nodispl,
00297                     i,
00298                     reallydispl && cannotscroll);
00299         if (cannotscroll || !reallydispl) {
00300                 /*
00301                  * Yes, "display" did the displaying, or we did'nt have to
00302                  * display at all.
00303                  * I like it, but the user obviously does not.
00304                  * Let him buy another (smarter) terminal ...
00305                  */
00306                 return i;
00307         }
00308         /*
00309          * Now, all we have to do is the displaying. And we are dealing with
00310          * a smart terminal (it can insert lines or scroll back).
00311          */
00312         home();
00313         /*
00314          * Insert lines all at once
00315          */
00316         for (i = n; i; i--) {
00317                 if (DB && *CE) {
00318                         /*
00319                          * Grumble..., terminal retains lines below, so we have
00320                          * to clear the lines that we push off the screen
00321                          */
00322                         clrbline();
00323                         home();
00324                 }
00325                 if (*SR) {
00326                         scrollreverse();
00327                 }
00328                 else {
00329 # ifdef VT100_PATCH
00330                         insert_line(0);
00331 # else
00332                         insert_line();
00333 # endif
00334                 }
00335         }
00336         p = skiplines(getline(ln = s->firstline, 1), s->nf);
00337         for (i = 0; i < n; i++) {
00338                 p = do_line(p,1);
00339                 s->currentpos--;
00340                 if (!*p) {
00341                         p = getline(++ln, 1);
00342                 }
00343         }
00344         return count;
00345 }
00346 
00347 /*
00348  * Process a line.
00349  * If reallydispl > 0 then display it.
00350  */
00351 
00352 STATIC char *
00353 do_line(str, reallydispl) register char *str; int reallydispl; {
00354 
00355         char buf[1024];
00356         register char *p = buf;
00357         register int pos = COLS;
00358         register int c;
00359         register int c1;
00360         register int do_ul = 0, do_hl = 0;
00361         int lastmode = 0, lasthlmode = 0;
00362         int c2;
00363 
00364         while (*str && pos > 0) {
00365                 if (*str < ' ' && (c1 = match(str,&c2,sppat)) > 0) {
00366                         /*
00367                          * We found a string that matches, and thus must be
00368                          * echoed literally
00369                          */
00370                         if ((pos - c2) <= 0) {
00371                                 /*
00372                                  * It did not fit
00373                                  */
00374                                 break;
00375                         }
00376                         pos -= c2;
00377                         str += c1;
00378                         if (reallydispl) {
00379                                 c = *str;
00380                                 *p = *str = 0;
00381                                 cputline(p = buf);
00382                                 putline(str - c1);
00383                                 *str = c;
00384                         }
00385                         continue;
00386                 }
00387                 c = *str++;
00388                 do_hl = 0;
00389                 if (*str == '\b' && *(str+1) != 0
00390                                         && (c != '_' || *(str+2) == '\b')) {
00391                         while (*str == '\b' && *(str+1) != 0) {
00392                                 str++;
00393                                 c = *str++;
00394                                 do_hl = 1;
00395                         }
00396                 }
00397                 do_ul = 1;
00398                 /*
00399                  * Find underline sequences ...
00400                  */
00401                 if (c == '_' && *str == '\b') {
00402                         str++;
00403                         c = *str++;
00404                 }
00405                 else {
00406                         if (*str == '\b' && *(str+1) == '_') {
00407                                 str += 2;
00408                         }
00409                         else    do_ul = 0;
00410                 }
00411                 if (reallydispl && do_hl != lasthlmode) {
00412                         *p = 0;
00413                         cputline(p = buf);
00414                         if (do_hl) bold();
00415                         else end_bold();
00416                 }
00417                 lasthlmode = do_hl;
00418                 if (reallydispl && do_ul != lastmode) {
00419                         *p = 0;
00420                         cputline(p = buf);
00421                         if (do_ul) underline();
00422                         else end_underline();
00423                 }
00424                 lastmode = do_ul;
00425                 *p++ = c;
00426                 if (c >= ' ' && c < 0177) {
00427                         pos--;
00428                         if (reallydispl && do_ul && *UC && pos > 0) {
00429                                 /*
00430                                  * Underlining apparently is done one
00431                                  * character at a time.
00432                                  */
00433                                 *p = 0;
00434                                 cputline(p = buf);
00435                                 backspace();
00436                                 underchar();
00437                         }
00438                         continue;
00439                 }
00440                 if (c == '\t') {
00441                         p--;
00442                         c1 = 8 - ((COLS - pos) & 07);
00443                         /*
00444                          * Actually, if COLS is a multiple of 8, this can be
00445                          * simplified to
00446                          *     c1 = pos & 07;
00447                          * But of course, we don't know that for sure.
00448                          */
00449                         if (pos - c1 < 0) break;
00450                         pos -= c1;
00451                         if (reallydispl) {
00452                                 if (expandtabs) {
00453                                         /*
00454                                          * Expand tabs. We cannot let the
00455                                          * kernel take care of this
00456                                          * for two reasons:
00457                                          * 1. There can be tabs in cursor
00458                                          *    addressing strings,
00459                                          * 2. We probably do it better.
00460                                          */
00461                                         while (c1-- > 0) {
00462                                                 *p++ = ' ';
00463                                         }
00464                                 }
00465                                 else {
00466                                         *p = 0;
00467                                         cputline(p = buf);
00468                                         givetab();
00469                                 }
00470                         }
00471                         continue;
00472                 }
00473                 /*
00474                  * Now we have a control character, which takes two positions
00475                  */
00476                 if (pos <= 1) {
00477                         p--;
00478                         break;
00479                 }
00480                 pos -= 2;
00481         }
00482         if (reallydispl) {
00483                 *p = 0;
00484                 cputline(buf);
00485                 if (pos > 0 || (pos <= 0 && (!AM || XN))) {
00486                         putline("\r\n");
00487                 }
00488                 /*
00489                  * The next should be here! I.e. it may not be before printing
00490                  * the newline. This has to do with XN. We don't know exactly
00491                  * WHEN the terminal will stop ignoring the newline.
00492                  * I have for example a terminal (Ampex a230) that will
00493                  * continue to ignore the newline after a clear to end of line
00494                  * sequence, but not after an end_underline sequence.
00495                  */
00496                 if (do_ul) {
00497                         end_underline();
00498                 }
00499                 if (do_hl) {
00500                         standend();
00501                 }
00502         }
00503         scr_info.currentpos++;
00504         return str;
00505 }
00506 
00507 /* ARGSUSED */
00508 int
00509 setmark(cnt) long cnt; {        /* Set a mark on the current page */
00510         register struct scr_info *p = &scr_info;
00511 
00512         p->savfirst = p->firstline;
00513         p->savnf = p->nf;
00514 }
00515 
00516 /* ARGSUSED */
00517 int
00518 tomark(cnt) long cnt; {         /* Go to the mark */
00519         register struct scr_info *p = &scr_info;
00520 
00521         (VOID) display(p->savfirst,p->savnf,pagesize,1);
00522 }
00523 
00524 /* ARGSUSED */
00525 int
00526 exgmark(cnt) long cnt; {        /* Exchange mark and current page */
00527         register struct scr_info *p = &scr_info;
00528         register long svfirst;
00529         register int svnf;
00530 
00531         svfirst = p->firstline;
00532         svnf = p->nf;
00533         tomark(0L);
00534         p->savfirst = svfirst;
00535         p->savnf = svnf;
00536 }
00537 
00538 VOID
00539 d_clean() {                     /* Clean up */
00540         register struct scr_info *p = &scr_info;
00541 
00542         p->savnf = 0;
00543         p->savfirst = 0;
00544         p->head = p->tail;
00545         p->head->line = 0;
00546         p->currentpos = 0;
00547 }

Generated on Fri Apr 14 22:57:14 2006 for minix by  doxygen 1.4.6