# 2.11BSD#431 - /usr/src/local/less/line.c

##### Functions

    back_raw_line     X
    forw_raw_line     X
    pappend           X
    prewind           X

##### Variables

    line              X
    public            X

##### Macros

    LN_BOLDFACE       X
    LN_BO_X           X
    LN_BO_XB          X
    LN_NORMAL         X
    LN_UL_X           X
    LN_UL_XB          X
    LN_UNDERLINE      X
    NEW_COLUMN        X

       1: /*
       2:  * Routines to manipulate the "line buffer".
       3:  * The line buffer holds a line of output as it is being built
       4:  * in preparation for output to the screen.
       5:  * We keep track of the PRINTABLE length of the line as it is being built.
       6:  */
       7:
       8: #include "less.h"
       9:
      10: static char linebuf[1024];  /* Buffer which holds the current output line */
      11: static char *curr;      /* Pointer into linebuf */
      12: static int column;      /* Printable length, accounting for
      13: 				   backspaces, etc. */
      14: /*
      15:  * A ridiculously complex state machine takes care of backspaces
      16:  * when in BS_SPECIAL mode.  The complexity arises from the attempt
      17:  * to deal with all cases, especially involving long lines with underlining,
      18:  * boldfacing or whatever.  There are still some cases which will break it.
      19:  *
      20:  * There are four states:
      21:  *	LN_NORMAL is the normal state (not in underline mode).
      22:  *	LN_UNDERLINE means we are in underline mode.  We expect to get
      23:  *		either a sequence like "_\bX" or "X\b_" to continue
      24:  *		underline mode, or anything else to end underline mode.
      25:  *	LN_BOLDFACE means we are in boldface mode.  We expect to get sequences
      26:  *		like "X\bX\b...X\bX" to continue boldface mode, or anything
      27:  *		else to end boldface mode.
      28:  *	LN_UL_X means we are one character after LN_UNDERLINE
      29:  *		(we have gotten the '_' in "_\bX" or the 'X' in "X\b_").
      30:  *	LN_UL_XB means we are one character after LN_UL_X
      31:  *		(we have gotten the backspace in "_\bX" or "X\b_";
      32:  *		we expect one more ordinary character,
      33:  *		which will put us back in state LN_UNDERLINE).
      34:  *	LN_BO_X means we are one character after LN_BOLDFACE
      35:  *		(we have gotten the 'X' in "X\bX").
      36:  *	LN_BO_XB means we are one character after LN_BO_X
      37:  *		(we have gotten the backspace in "X\bX";
      38:  *		we expect one more 'X' which will put us back
      39:  *		in LN_BOLDFACE).
      40:  */
      41: static int ln_state;        /* Currently in normal/underline/bold/etc mode? */
      42: #define LN_NORMAL   0   /* Not in underline, boldface or whatever mode */
      43: #define LN_UNDERLINE    1   /* In underline, need next char */
      44: #define LN_UL_X     2   /* In underline, got char, need \b */
      45: #define LN_UL_XB    3   /* In underline, got char & \b, need one more */
      46: #define LN_BOLDFACE 4   /* In boldface, need next char */
      47: #define LN_BO_X     5   /* In boldface, got char, need \b */
      48: #define LN_BO_XB    6   /* In boldface, got char & \b, need same char */
      49:
      50: public char *line;      /* Pointer to the current line.
      51: 				   Usually points to linebuf. */
      52:
      53: extern int bs_mode;
      54: extern int tabstop;
      55: extern int bo_width, be_width;
      56: extern int ul_width, ue_width;
      57: extern int sc_width, sc_height;
      58:
      59: /*
      60:  * Rewind the line buffer.
      61:  */
      62:     public void
      63: prewind()
      64: {
      65:     line = curr = linebuf;
      66:     ln_state = LN_NORMAL;
      67:     column = 0;
      68: }
      69:
      70: /*
      71:  * Append a character to the line buffer.
      72:  * Expand tabs into spaces, handle underlining, boldfacing, etc.
      73:  * Returns 0 if ok, 1 if couldn't fit in buffer.
      74:  */
      75:
      76: #define NEW_COLUMN(newcol)  if ((newcol) + ((ln_state)?ue_width:0) > sc_width) \
      77:                     return (1); else column = (newcol)
      78:
      79:     public int
      80: pappend(c)
      81:     int c;
      82: {
      83:     if (c == '\0')
      84:     {
      85:         /*
      86: 		 * Terminate any special modes, if necessary.
      87: 		 * Append a '\0' to the end of the line.
      88: 		 */
      89:         switch (ln_state)
      90:         {
      91:         case LN_UL_X:
      92:             curr[0] = curr[-1];
      93:             curr[-1] = UE_CHAR;
      94:             curr++;
      95:             break;
      96:         case LN_BO_X:
      97:             curr[0] = curr[-1];
      98:             curr[-1] = BE_CHAR;
      99:             curr++;
     100:             break;
     101:         case LN_UL_XB:
     102:         case LN_UNDERLINE:
     103:             *curr++ = UE_CHAR;
     104:             break;
     105:         case LN_BO_XB:
     106:         case LN_BOLDFACE:
     107:             *curr++ = BE_CHAR;
     108:             break;
     109:         }
     110:         ln_state = LN_NORMAL;
     111:         *curr = '\0';
     112:         return (0);
     113:     }
     114:
     115:     if (curr > linebuf + sizeof(linebuf) - 12)
     116:         /*
     117: 		 * Almost out of room in the line buffer.
     118: 		 * Don't take any chances.
     119: 		 * {{ Linebuf is supposed to be big enough that this
     120: 		 *    will never happen, but may need to be made
     121: 		 *    bigger for wide screens or lots of backspaces. }}
     122: 		 */
     123:         return (1);
     124:
     125:     if (bs_mode == BS_SPECIAL)
     126:     {
     127:         /*
     128: 		 * Advance the state machine.
     129: 		 */
     130:         switch (ln_state)
     131:         {
     132:         case LN_NORMAL:
     133:             if (curr <= linebuf + 1 || curr[-1] != '\b')
     134:                 break;
     135:
     136:             if (c == curr[-2])
     137:                 goto enter_boldface;
     138:             if (c == '_' || curr[-2] == '_')
     139:                 goto enter_underline;
     140:             curr -= 2;
     141:             break;
     142:
     143: enter_boldface:
     144:             /*
     145: 			 * We have "X\bX" (including the current char).
     146: 			 * Switch into boldface mode.
     147: 			 */
     148:             if (column + bo_width + be_width + 1 >= sc_width)
     149:                 /*
     150: 				 * Not enough room left on the screen to
     151: 				 * enter and exit boldface mode.
     152: 				 */
     153:                 return (1);
     154:
     155:             if (bo_width > 0 &&
     156:                 curr > linebuf + 2 && curr[-3] == ' ')
     157:             {
     158:                 /*
     159: 				 * Special case for magic cookie terminals:
     160: 				 * if the previous char was a space, replace
     161: 				 * it with the "enter boldface" sequence.
     162: 				 */
     163:                 curr[-3] = BO_CHAR;
     164:                 column += bo_width-1;
     165:             } else
     166:             {
     167:                 curr[-1] = curr[-2];
     168:                 curr[-2] = BO_CHAR;
     169:                 column += bo_width;
     170:                 curr++;
     171:             }
     172:             goto ln_bo_xb_case;
     173:
     174: enter_underline:
     175:             /*
     176: 			 * We have either "_\bX" or "X\b_" (including
     177: 			 * the current char).  Switch into underline mode.
     178: 			 */
     179:             if (column + ul_width + ue_width + 1 >= sc_width)
     180:                 /*
     181: 				 * Not enough room left on the screen to
     182: 				 * enter and exit underline mode.
     183: 				 */
     184:                 return (1);
     185:
     186:             if (ul_width > 0 &&
     187:                 curr > linebuf + 2 && curr[-3] == ' ')
     188:             {
     189:                 /*
     190: 				 * Special case for magic cookie terminals:
     191: 				 * if the previous char was a space, replace
     192: 				 * it with the "enter underline" sequence.
     193: 				 */
     194:                 curr[-3] = UL_CHAR;
     195:                 column += ul_width-1;
     196:             } else
     197:             {
     198:                 curr[-1] = curr[-2];
     199:                 curr[-2] = UL_CHAR;
     200:                 column += ul_width;
     201:                 curr++;
     202:             }
     203:             goto ln_ul_xb_case;
     204:             /*NOTREACHED*/
     205:         case LN_UL_XB:
     206:             /*
     207: 			 * Termination of a sequence "_\bX" or "X\b_".
     208: 			 */
     209:             if (c != '_' && curr[-2] != '_' && c == curr[-2])
     210:             {
     211:                 /*
     212: 				 * We seem to have run on from underlining
     213: 				 * into boldfacing - this is a nasty fix, but
     214: 				 * until this whole routine is rewritten as a
     215: 				 * real DFA, ...  well ...
     216: 				 */
     217:                 curr[0] = curr[-2];
     218:                 curr[-2] = UE_CHAR;
     219:                 curr[-1] = BO_CHAR;
     220:                 curr += 2; /* char & non-existent backspace */
     221:                 ln_state = LN_BO_XB;
     222:                 goto ln_bo_xb_case;
     223:             }
     224: ln_ul_xb_case:
     225:             if (c == '_')
     226:                 c = curr[-2];
     227:             curr -= 2;
     228:             ln_state = LN_UNDERLINE;
     229:             break;
     230:         case LN_BO_XB:
     231:             /*
     232: 			 * Termination of a sequnce "X\bX".
     233: 			 */
     234:             if (c != curr[-2] && (c == '_' || curr[-2] == '_'))
     235:             {
     236:                 /*
     237: 				 * We seem to have run on from
     238: 				 * boldfacing into underlining.
     239: 				 */
     240:                 curr[0] = curr[-2];
     241:                 curr[-2] = BE_CHAR;
     242:                 curr[-1] = UL_CHAR;
     243:                 curr += 2; /* char & non-existent backspace */
     244:                 ln_state = LN_UL_XB;
     245:                 goto ln_ul_xb_case;
     246:             }
     247: ln_bo_xb_case:
     248:             curr -= 2;
     249:             ln_state = LN_BOLDFACE;
     250:             break;
     251:         case LN_UNDERLINE:
     252:             if (column + ue_width + bo_width + 1 + be_width >= sc_width)
     253:                 /*
     254: 				 * We have just barely enough room to
     255: 				 * exit underline mode and handle a possible
     256: 				 * underline/boldface run on mixup.
     257: 				 */
     258:                 return (1);
     259:             ln_state = LN_UL_X;
     260:             break;
     261:         case LN_BOLDFACE:
     262:             if (c == '\b')
     263:             {
     264:                 ln_state = LN_BO_XB;
     265:                 break;
     266:             }
     267:             if (column + be_width + ul_width + 1 + ue_width >= sc_width)
     268:                 /*
     269: 				 * We have just barely enough room to
     270: 				 * exit underline mode and handle a possible
     271: 				 * underline/boldface run on mixup.
     272: 				 */
     273:                 return (1);
     274:             ln_state = LN_BO_X;
     275:             break;
     276:         case LN_UL_X:
     277:             if (c == '\b')
     278:                 ln_state = LN_UL_XB;
     279:             else
     280:             {
     281:                 /*
     282: 				 * Exit underline mode.
     283: 				 * We have to shuffle the chars a bit
     284: 				 * to make this work.
     285: 				 */
     286:                 curr[0] = curr[-1];
     287:                 curr[-1] = UE_CHAR;
     288:                 column += ue_width;
     289:                 if (ue_width > 0 && curr[0] == ' ')
     290:                     /*
     291: 					 * Another special case for magic
     292: 					 * cookie terminals: if the next
     293: 					 * char is a space, replace it
     294: 					 * with the "exit underline" sequence.
     295: 					 */
     296:                     column--;
     297:                 else
     298:                     curr++;
     299:                 ln_state = LN_NORMAL;
     300:             }
     301:             break;
     302:         case LN_BO_X:
     303:             if (c == '\b')
     304:                 ln_state = LN_BO_XB;
     305:             else
     306:             {
     307:                 /*
     308: 				 * Exit boldface mode.
     309: 				 * We have to shuffle the chars a bit
     310: 				 * to make this work.
     311: 				 */
     312:                 curr[0] = curr[-1];
     313:                 curr[-1] = BE_CHAR;
     314:                 column += be_width;
     315:                 if (be_width > 0 && curr[0] == ' ')
     316:                     /*
     317: 					 * Another special case for magic
     318: 					 * cookie terminals: if the next
     319: 					 * char is a space, replace it
     320: 					 * with the "exit boldface" sequence.
     321: 					 */
     322:                     column--;
     323:                 else
     324:                     curr++;
     325:                 ln_state = LN_NORMAL;
     326:             }
     327:             break;
     328:         }
     329:     }
     330:
     331:     if (c == '\t')
     332:     {
     333:         /*
     334: 		 * Expand a tab into spaces.
     335: 		 */
     336:         do
     337:         {
     338:             NEW_COLUMN(column+1);
     339:         } while ((column % tabstop) != 0);
     340:         *curr++ = '\t';
     341:         return (0);
     342:     }
     343:
     344:     if (c == '\b')
     345:     {
     346:         if (bs_mode == BS_CONTROL)
     347:         {
     348:             /*
     349: 			 * Treat backspace as a control char: output "^H".
     350: 			 */
     351:             NEW_COLUMN(column+2);
     352:             *curr++ = ('H' | 0200);
     353:         } else
     354:         {
     355:             /*
     356: 			 * Output a real backspace.
     357: 			 */
     358:             column--;
     359:             *curr++ = '\b';
     360:         }
     361:         return (0);
     362:     }
     363:
     364:     if (control_char(c))
     365:     {
     366:         /*
     367: 		 * Put a "^X" into the buffer.
     368: 		 * The 0200 bit is used to tell put_line() to prefix
     369: 		 * the char with a ^.  We don't actually put the ^
     370: 		 * in the buffer because we sometimes need to move
     371: 		 * chars around, and such movement might separate
     372: 		 * the ^ from its following character.
     373: 		 * {{ This should be redone so that we can use an
     374: 		 *    8 bit (e.g. international) character set. }}
     375: 		 */
     376:         NEW_COLUMN(column+2);
     377:         *curr++ = (carat_char(c) | 0200);
     378:         return (0);
     379:     }
     380:
     381:     /*
     382: 	 * Ordinary character.  Just put it in the buffer.
     383: 	 */
     384:     NEW_COLUMN(column+1);
     385:     *curr++ = c;
     386:     return (0);
     387: }
     388:
     389: /*
     390:  * Analogous to forw_line(), but deals with "raw lines":
     391:  * lines which are not split for screen width.
     392:  * {{ This is supposed to be more efficient than forw_line(). }}
     393:  */
     394:     public POSITION
     395: forw_raw_line(curr_pos)
     396:     POSITION curr_pos;
     397: {
     398:     register char *p;
     399:     register int c;
     400:     POSITION new_pos;
     401:
     402:     if (curr_pos == NULL_POSITION || ch_seek(curr_pos) ||
     403:         (c = ch_forw_get()) == EOF)
     404:         return (NULL_POSITION);
     405:
     406:     p = linebuf;
     407:
     408:     for (;;)
     409:     {
     410:         if (c == '\n' || c == EOF)
     411:         {
     412:             new_pos = ch_tell();
     413:             break;
     414:         }
     415:         if (p >= &linebuf[sizeof(linebuf)-1])
     416:         {
     417:             /*
     418: 			 * Overflowed the input buffer.
     419: 			 * Pretend the line ended here.
     420: 			 * {{ The line buffer is supposed to be big
     421: 			 *    enough that this never happens. }}
     422: 			 */
     423:             new_pos = ch_tell() - 1;
     424:             break;
     425:         }
     426:         *p++ = c;
     427:         c = ch_forw_get();
     428:     }
     429:     *p = '\0';
     430:     line = linebuf;
     431:     return (new_pos);
     432: }
     433:
     434: /*
     435:  * Analogous to back_line(), but deals with "raw lines".
     436:  * {{ This is supposed to be more efficient than back_line(). }}
     437:  */
     438:     public POSITION
     439: back_raw_line(curr_pos)
     440:     POSITION curr_pos;
     441: {
     442:     register char *p;
     443:     register int c;
     444:     POSITION new_pos;
     445:
     446:     if (curr_pos == NULL_POSITION || curr_pos <= (POSITION)0 ||
     447:         ch_seek(curr_pos-1))
     448:         return (NULL_POSITION);
     449:
     450:     p = &linebuf[sizeof(linebuf)];
     451:     *--p = '\0';
     452:
     453:     for (;;)
     454:     {
     455:         c = ch_back_get();
     456:         if (c == '\n')
     457:         {
     458:             /*
     459: 			 * This is the newline ending the previous line.
     460: 			 * We have hit the beginning of the line.
     461: 			 */
     462:             new_pos = ch_tell() + 1;
     463:             break;
     464:         }
     465:         if (c == EOF)
     466:         {
     467:             /*
     468: 			 * We have hit the beginning of the file.
     469: 			 * This must be the first line in the file.
     470: 			 * This must, of course, be the beginning of the line.
     471: 			 */
     472:             new_pos = (POSITION)0;
     473:             break;
     474:         }
     475:         if (p <= linebuf)
     476:         {
     477:             /*
     478: 			 * Overflowed the input buffer.
     479: 			 * Pretend the line ended here.
     480: 			 */
     481:             new_pos = ch_tell() + 1;
     482:             break;
     483:         }
     484:         *--p = c;
     485:     }
     486:     line = p;
     487:     return (new_pos);
     488: }

#### Defined functions

back_raw_line defined in line 438; used 2 times

- in /usr/src/local/less/funcs.h line 70
- in /usr/src/local/less/prim.c line 676

forw_raw_line defined in line 394; used 2 times

- in /usr/src/local/less/funcs.h line 69
- in /usr/src/local/less/prim.c line 669

pappend defined in line 79; used 6 times

- in /usr/src/local/less/funcs.h line 68
- in /usr/src/local/less/input.c line 52, 64, 174, 181, 188

prewind defined in line 62; used 3 times

- in /usr/src/local/less/funcs.h line 67
- in /usr/src/local/less/input.c line 37, 166

#### Defined variables

column defined in line 12; used 20 times

- in line 67, 77, 148, 164-169(2), 179, 195-200(2), 252, 267, 288, 296, 314, 322, 338-339(2), 351, 358, 376, 384

curr defined in line 11; used 64 times

- in line 65, 92-115(12), 133-140(5), 156(2), 163-170(5), 187(2), 194-201(5), 209(2), 217-220(5), 226-227(2), 234(2), 240-248(6), 286-289(4), 298, 312-315(4), 324, 340, 352, 359, 377, 385

line defined in line 50; used 13 times

- in line 65, 430, 486
- in /usr/src/local/less/input.c line 66
- in /usr/src/local/less/output.c line 37-41(3)
- in /usr/src/local/less/prim.c line 128, 137, 181, 695-700(3)

linebuf defined in line 10; used 13 times

- in line 65, 115(2), 133, 156, 187, 406, 415(2), 430, 450(2), 475

ln_state defined in line 41; used 16 times

- in line 66, 76, 89, 110, 130, 221, 228, 244-249(2), 259-264(2), 274-278(2), 299-304(2), 325

public defined in line 79; never used

#### Defined macros

LN_BOLDFACE defined in line 46; used 1 times

- in line 249

LN_BO_X defined in line 47; used 1 times

- in line 274

LN_BO_XB defined in line 48; used 3 times

- in line 221, 264, 304

LN_NORMAL defined in line 42; used 4 times

- in line 66, 110, 299, 325

LN_UL_X defined in line 44; used 1 times

- in line 259

LN_UL_XB defined in line 45; used 2 times

- in line 244, 278

LN_UNDERLINE defined in line 43; used 1 times

- in line 228

NEW_COLUMN defined in line 76; used 4 times

- in line 338, 351, 376, 384

Last modified: 1990-07-10 Generated: 2016-12-26 | Generated by src2html V0.67 page hit count: 897 |