Annotation of 43BSDReno/contrib/emacs-18.55/src/term.c, revision 1.1.1.1

1.1       root        1: /* terminal control module for terminals described by TERMCAP
                      2:    Copyright (C) 1985, 1986, 1987 Free Software Foundation, Inc.
                      3: 
                      4: This file is part of GNU Emacs.
                      5: 
                      6: GNU Emacs is distributed in the hope that it will be useful,
                      7: but WITHOUT ANY WARRANTY.  No author or distributor
                      8: accepts responsibility to anyone for the consequences of using it
                      9: or for whether it serves any particular purpose or works at all,
                     10: unless he says so in writing.  Refer to the GNU Emacs General Public
                     11: License for full details.
                     12: 
                     13: Everyone is granted permission to copy, modify and redistribute
                     14: GNU Emacs, but only under the conditions described in the
                     15: GNU Emacs General Public License.   A copy of this license is
                     16: supposed to have been given to you along with GNU Emacs so you
                     17: can know your rights and responsibilities.  It should be in a
                     18: file named COPYING.  Among other things, the copyright notice
                     19: and this notice must be preserved on all copies.  */
                     20: 
                     21: 
                     22: #include <stdio.h>
                     23: #include <ctype.h>
                     24: #include "config.h"
                     25: #include "termhooks.h"
                     26: #include "termchar.h"
                     27: #include "termopts.h"
                     28: #include "cm.h"
                     29: 
                     30: #define max(a, b) ((a) > (b) ? (a) : (b))
                     31: #define min(a, b) ((a) < (b) ? (a) : (b))
                     32: 
                     33: #define OUTPUT(a) tputs (a, screen_height - curY, cmputc)
                     34: #define OUTPUT1(a) tputs (a, 1, cmputc)
                     35: #define OUTPUTL(a, lines) tputs (a, lines, cmputc)
                     36: #define OUTPUT_IF(a) { if (a) tputs (a, screen_height - curY, cmputc); }
                     37: #define OUTPUT1_IF(a) { if (a) tputs (a, 1, cmputc); }
                     38: 
                     39: /* Terminal charateristics that higher levels want to look at.
                     40:    These are all extern'd in termchar.h */
                     41: 
                     42: int screen_width;              /* Number of usable columns */
                     43: int screen_height;             /* Number of lines */
                     44: int must_write_spaces;         /* Nonzero means spaces in the text
                     45:                                   must actually be output; can't just skip
                     46:                                   over some columns to leave them blank.  */
                     47: int min_padding_speed;         /* Speed below which no padding necessary */
                     48: 
                     49: int line_ins_del_ok;           /* Terminal can insert and delete lines */
                     50: int char_ins_del_ok;           /* Terminal can insert and delete chars */
                     51: int scroll_region_ok;          /* Terminal supports setting the scroll window */
                     52: int memory_below_screen;       /* Terminal remembers lines scrolled off bottom */
                     53: int fast_clear_end_of_line;    /* Terminal has a `ce' string */
                     54: 
                     55: int dont_calculate_costs;      /* Nonzero means don't bother computing */
                     56:                                /* various cost tables; we won't use them.  */
                     57: 
                     58: /* Nonzero means no need to redraw the entire screen on resuming
                     59:    a suspended Emacs.  This is useful on terminals with multiple pages,
                     60:    where one page is used for Emacs and another for all else. */
                     61: int no_redraw_on_reenter;
                     62: 
                     63: /* DCICcost[n] is cost of inserting N characters.
                     64:    DCICcost[-n] is cost of deleting N characters. */
                     65: 
                     66: #define DCICcost (&DC_ICcost[MScreenWidth])
                     67: int DC_ICcost[1 + 2 * MScreenWidth];
                     68: 
                     69: 
                     70: /* Hook functions that you can set to snap out the functions in this file.
                     71:    These are all extern'd in termhooks.h  */
                     72: 
                     73: int (*topos_hook) ();
                     74: int (*raw_topos_hook) ();
                     75: 
                     76: int (*clear_to_end_hook) ();
                     77: int (*clear_screen_hook) ();
                     78: int (*clear_end_of_line_hook) ();
                     79: 
                     80: int (*ins_del_lines_hook) ();
                     81: 
                     82: int (*change_line_highlight_hook) ();
                     83: int (*reassert_line_highlight_hook) ();
                     84: 
                     85: int (*insert_chars_hook) ();
                     86: int (*write_chars_hook) ();
                     87: int (*delete_chars_hook) ();
                     88: 
                     89: int (*ring_bell_hook) ();
                     90: 
                     91: int (*reset_terminal_modes_hook) ();
                     92: int (*set_terminal_modes_hook) ();
                     93: int (*update_begin_hook) ();
                     94: int (*update_end_hook) ();
                     95: int (*set_terminal_window_hook) ();
                     96: 
                     97: int (*read_socket_hook) ();
                     98: int (*fix_screen_hook) ();
                     99: 
                    100: /* Strings, numbers and flags taken from the termcap entry.  */
                    101: 
                    102: char *TS_ins_line;             /* termcap "al" */
                    103: char *TS_ins_multi_lines;      /* "AL" (one parameter, # lines to insert) */
                    104: char *TS_bell;                 /* "bl" */
                    105: char *TS_clr_to_bottom;                /* "cd" */
                    106: char *TS_clr_line;             /* "ce", clear to end of line */
                    107: char *TS_clr_screen;           /* "cl" */
                    108: char *TS_set_scroll_region;    /* "cs" (2 params, first line and last line) */
                    109: char *TS_set_scroll_region_1;   /* "cS" (4 params: total lines,
                    110:                                   lines above scroll region, lines below it,
                    111:                                   total lines again) */
                    112: char *TS_del_char;             /* "dc" */
                    113: char *TS_del_multi_chars;      /* "DC" (one parameter, # chars to delete) */
                    114: char *TS_del_line;             /* "dl" */
                    115: char *TS_del_multi_lines;      /* "DL" (one parameter, # lines to delete) */
                    116: char *TS_delete_mode;          /* "dm", enter character-delete mode */
                    117: char *TS_end_delete_mode;      /* "ed", leave character-delete mode */
                    118: char *TS_end_insert_mode;      /* "ei", leave character-insert mode */
                    119: char *TS_ins_char;             /* "ic" */
                    120: char *TS_ins_multi_chars;      /* "IC" (one parameter, # chars to insert) */
                    121: char *TS_insert_mode;          /* "im", enter character-insert mode */
                    122: char *TS_pad_inserted_char;    /* "ip".  Just padding, no commands.  */
                    123: char *TS_end_keypad_mode;      /* "ke" */
                    124: char *TS_keypad_mode;          /* "ks" */
                    125: char *TS_pad_char;             /* "pc", char to use as padding */
                    126: char *TS_repeat;               /* "rp" (2 params, # times to repeat
                    127:                                   and character to be repeated) */
                    128: char *TS_end_standout_mode;    /* "se" */
                    129: char *TS_fwd_scroll;           /* "sf" */
                    130: char *TS_standout_mode;                /* "so" */
                    131: char *TS_rev_scroll;           /* "sr" */
                    132: char *TS_end_termcap_modes;    /* "te" */
                    133: char *TS_termcap_modes;                /* "ti" */
                    134: char *TS_visible_bell;         /* "vb" */
                    135: char *TS_end_visual_mode;      /* "ve" */
                    136: char *TS_visual_mode;          /* "vi" */
                    137: char *TS_set_window;           /* "wi" (4 params, start and end of window,
                    138:                                   each as vpos and hpos) */
                    139: 
                    140: int TF_hazeltine;      /* termcap hz flag. */
                    141: int TF_insmode_motion; /* termcap mi flag: can move while in insert mode. */
                    142: int TF_standout_motion;        /* termcap mi flag: can move while in standout mode. */
                    143: int TF_underscore;     /* termcap ul flag: _ underlines if overstruck on
                    144:                           nonblank position.  Must clear before writing _.  */
                    145: int TF_teleray;                /* termcap xt flag: many weird consequences.  For t1061. */
                    146: 
                    147: int TF_xs;             /* Nonzero for "xs".  If set together with
                    148:                           TN_standout_width == 0, it means don't bother
                    149:                           to write any end-standout cookies.  */
                    150: 
                    151: int TN_standout_width; /* termcap sg number: width occupied by standout markers */
                    152: 
                    153: static int RPov;       /* # chars to start a TS_repeat */
                    154: 
                    155: static int delete_in_insert_mode;      /* delete mode == insert mode */
                    156: 
                    157: static int se_is_so;   /* 1 if same string both enters and leaves standout mode */
                    158: 
                    159: /* internal state */
                    160: 
                    161: /* Number of chars of space used for standout marker at beginning of line,
                    162:    or'd with 0100.  Zero if no standout marker at all.  */
                    163: /* used iff TN_standout_width >= 0. */
                    164: char chars_wasted[MScreenLength];
                    165: 
                    166: /* nonzero means supposed to write text in standout mode.  */
                    167: int standout_requested;
                    168: 
                    169: int insert_mode;                       /* Nonzero when in insert mode.  */
                    170: int standout_mode;                     /* Nonzero when in standout mode.  */
                    171: 
                    172: /* Size of window specified by higher levels.
                    173:    This is the number of lines, starting from top of screen,
                    174:    to participate in ins/del line operations.
                    175:    Effectively it excludes the bottom
                    176:       screen_height - specified_window_size
                    177:    lines from those operations.  */
                    178: 
                    179: int specified_window;
                    180: 
                    181: char *tparam ();
                    182: 
                    183: ring_bell ()
                    184: {
                    185:   if (ring_bell_hook)
                    186:     {
                    187:       (*ring_bell_hook) ();
                    188:       return;
                    189:     }
                    190:   OUTPUT (TS_visible_bell && visible_bell ? TS_visible_bell : TS_bell);
                    191: }
                    192: 
                    193: set_terminal_modes ()
                    194: {
                    195:   if (set_terminal_modes_hook)
                    196:     {
                    197:       (*set_terminal_modes_hook) ();
                    198:       return;
                    199:     }
                    200:   OUTPUT_IF (TS_termcap_modes);
                    201:   OUTPUT_IF (TS_visual_mode);
                    202:   OUTPUT_IF (TS_keypad_mode);
                    203:   losecursor ();
                    204: }
                    205: 
                    206: reset_terminal_modes ()
                    207: {
                    208:   if (reset_terminal_modes_hook)
                    209:     {
                    210:       (*reset_terminal_modes_hook) ();
                    211:       return;
                    212:     }
                    213:   if (TN_standout_width < 0)
                    214:     turn_off_highlight ();
                    215:   turn_off_insert ();
                    216:   OUTPUT_IF (TS_end_keypad_mode);
                    217:   OUTPUT_IF (TS_end_visual_mode);
                    218:   OUTPUT_IF (TS_end_termcap_modes);
                    219: }
                    220: 
                    221: update_begin ()
                    222: {
                    223:   if (update_begin_hook)
                    224:     (*update_begin_hook) ();
                    225: }
                    226: 
                    227: update_end ()
                    228: {
                    229:   if (update_end_hook)
                    230:     {
                    231:       (*update_end_hook) ();
                    232:       return;
                    233:     }
                    234:   turn_off_insert ();
                    235:   background_highlight ();
                    236:   standout_requested = 0;
                    237: }
                    238: 
                    239: set_terminal_window (size)
                    240:      int size;
                    241: {
                    242:   if (set_terminal_window_hook)
                    243:     {
                    244:       (*set_terminal_window_hook) (size);
                    245:       return;
                    246:     }
                    247:   specified_window = size ? size : screen_height;
                    248:   if (!scroll_region_ok)
                    249:     return;
                    250:   set_scroll_region (0, specified_window);
                    251: }
                    252: 
                    253: set_scroll_region (start, stop)
                    254:      int start, stop;
                    255: {
                    256:   char *buf;
                    257:   if (TS_set_scroll_region)
                    258:     {
                    259:       buf = tparam (TS_set_scroll_region, 0, 0, start, stop - 1);
                    260:     }
                    261:   else if (TS_set_scroll_region_1)
                    262:     {
                    263:       buf = tparam (TS_set_scroll_region_1, 0, 0,
                    264:                    screen_height, start, screen_height - stop, screen_height);
                    265:     }
                    266:   else
                    267:     {
                    268:       buf = tparam (TS_set_window, 0, 0, start, 0, stop, screen_width);
                    269:     }
                    270:   OUTPUT (buf);
                    271:   free (buf);
                    272:   losecursor ();
                    273: }
                    274: 
                    275: turn_on_insert ()
                    276: {
                    277:   if (!insert_mode)
                    278:     OUTPUT (TS_insert_mode);
                    279:   insert_mode = 1;
                    280: }
                    281: 
                    282: turn_off_insert ()
                    283: {
                    284:   if (insert_mode)
                    285:     OUTPUT (TS_end_insert_mode);
                    286:   insert_mode = 0;
                    287: }
                    288: 
                    289: /* Handle highlighting when TN_standout_width (termcap sg) is not specified.
                    290:    In these terminals, output is affected by the value of standout
                    291:    mode when the output is written.
                    292: 
                    293:    These functions are called on all terminals, but do nothing
                    294:    on terminals whose standout mode does not work that way.  */
                    295: 
                    296: turn_off_highlight ()
                    297: {
                    298:   if (TN_standout_width < 0)
                    299:     {
                    300:       if (standout_mode)
                    301:        OUTPUT_IF (TS_end_standout_mode);
                    302:       standout_mode = 0;
                    303:     }
                    304: }
                    305: 
                    306: turn_on_highlight ()
                    307: {
                    308:   if (TN_standout_width < 0)
                    309:     {
                    310:       if (!standout_mode)
                    311:        OUTPUT_IF (TS_standout_mode);
                    312:       standout_mode = 1;
                    313:     }
                    314: }
                    315: 
                    316: /* Set standout mode to the state it should be in for
                    317:    empty space inside windows.  What this is,
                    318:    depends on the user option inverse-video.  */
                    319: 
                    320: background_highlight ()
                    321: {
                    322:   if (TN_standout_width >= 0)
                    323:     return;
                    324:   if (inverse_video)
                    325:     turn_on_highlight ();
                    326:   else
                    327:     turn_off_highlight ();
                    328: }
                    329: 
                    330: /* Set standout mode to the mode specified for the text to be output.  */
                    331: 
                    332: static
                    333: highlight_if_desired ()
                    334: {
                    335:   if (TN_standout_width >= 0)
                    336:     return;
                    337:   if (!inverse_video == !standout_requested)
                    338:     turn_off_highlight ();
                    339:   else
                    340:     turn_on_highlight ();
                    341: }
                    342: 
                    343: /* Handle standout mode for terminals in which TN_standout_width >= 0.
                    344:    On these terminals, standout is controlled by markers that
                    345:    live inside the screen memory.  TN_standout_width is the width
                    346:    that the marker occupies in memory.  Standout runs from the marker
                    347:    to the end of the line on some terminals, or to the next
                    348:    turn-off-standout marker (TS_end_standout_mode) string
                    349:    on other terminals.  */
                    350: 
                    351: /* Write a standout marker or end-standout marker at the front of the line
                    352:    at vertical position vpos.  */
                    353: 
                    354: write_standout_marker (flag, vpos)
                    355:      int flag, vpos;
                    356: {
                    357:   if (flag || (TS_end_standout_mode && !TF_teleray && !se_is_so
                    358:               && !(TF_xs && TN_standout_width == 0)))
                    359:     {
                    360:       cmgoto (vpos, 0);
                    361:       cmplus (TN_standout_width);
                    362:       OUTPUT (flag ? TS_standout_mode : TS_end_standout_mode);
                    363:       chars_wasted[curY] = TN_standout_width | 0100;
                    364:     }
                    365: }
                    366: 
                    367: /* External interface to control of standout mode.
                    368:    Call this when about to modify line at position VPOS
                    369:    and not change whether it is highlighted.  */
                    370: 
                    371: reassert_line_highlight (highlight, vpos)
                    372:      int highlight;
                    373:      int vpos;
                    374: {
                    375:   if (reassert_line_highlight_hook)
                    376:     {
                    377:       (*reassert_line_highlight_hook) (highlight, vpos);
                    378:       return;
                    379:     }
                    380:   if (TN_standout_width < 0)
                    381:     /* Handle terminals where standout takes affect at output time */
                    382:     standout_requested = highlight;
                    383:   else if (chars_wasted[vpos] == 0)
                    384:     /* For terminals with standout markers, write one on this line
                    385:        if there isn't one already.  */
                    386:     write_standout_marker (highlight, vpos);
                    387: }
                    388: 
                    389: /* Call this when about to modify line at position VPOS
                    390:    and change whether it is highlighted.  */
                    391: 
                    392: change_line_highlight (new_highlight, vpos, first_unused_hpos)
                    393:      int new_highlight, vpos, first_unused_hpos;
                    394: {
                    395:   standout_requested = new_highlight;
                    396:   if (change_line_highlight_hook)
                    397:     {
                    398:       (*change_line_highlight_hook) (new_highlight, vpos, first_unused_hpos);
                    399:       return;
                    400:     }
                    401: 
                    402:   topos (vpos, 0);
                    403: 
                    404:   if (TN_standout_width < 0)
                    405:     background_highlight ();
                    406:   /* If line starts with a marker, delete the marker */
                    407:   else if (TS_clr_line && chars_wasted[curY])
                    408:     {
                    409:       turn_off_insert ();
                    410:       /* On Teleray, make sure to erase the SO marker.  */
                    411:       if (TF_teleray)
                    412:        {
                    413:          cmgoto (curY - 1, screen_width - 4);
                    414:          OUTPUT ("\033S");
                    415:          curY++;               /* ESC S moves to next line where the TS_standout_mode was */
                    416:          curX = 0;
                    417:        }
                    418:       else
                    419:        cmgoto (curY, 0);       /* reposition to kill standout marker */
                    420:     }
                    421:   clear_end_of_line_raw (first_unused_hpos);
                    422:   reassert_line_highlight (new_highlight, curY);
                    423: }
                    424: 
                    425: /* Move to absolute position, specified origin 0 */
                    426: 
                    427: topos (row, col)
                    428: {
                    429:   col += chars_wasted[row] & 077;
                    430:   if (topos_hook)
                    431:     {
                    432:       (*topos_hook) (row, col);
                    433:       return;
                    434:     }
                    435:   if (curY == row && curX == col)
                    436:     return;
                    437:   if (!TF_standout_motion)
                    438:     background_highlight ();
                    439:   if (!TF_insmode_motion)
                    440:     turn_off_insert ();
                    441:   cmgoto (row, col);
                    442: }
                    443: 
                    444: /* Similar but don't take any account of the wasted characters.  */
                    445: 
                    446: raw_topos (row, col)
                    447: {
                    448:   if (raw_topos_hook)
                    449:     {
                    450:       (*raw_topos_hook) (row, col);
                    451:       return;
                    452:     }
                    453:   if (curY == row && curX == col)
                    454:     return;
                    455:   if (!TF_standout_motion)
                    456:     background_highlight ();
                    457:   if (!TF_insmode_motion)
                    458:     turn_off_insert ();
                    459:   cmgoto (row, col);
                    460: }
                    461: 
                    462: /* Erase operations */
                    463: 
                    464: /* clear from cursor to end of screen */
                    465: clear_to_end ()
                    466: {
                    467:   register int i;
                    468: 
                    469:   if (clear_to_end_hook)
                    470:     {
                    471:       (*clear_to_end_hook) ();
                    472:       return;
                    473:     }
                    474:   if (TS_clr_to_bottom)
                    475:     {
                    476:       background_highlight ();
                    477:       OUTPUT (TS_clr_to_bottom);
                    478:       bzero (chars_wasted + curY, screen_height - curY);
                    479:     }
                    480:   else
                    481:     {
                    482:       for (i = curY; i < screen_height; i++)
                    483:        {
                    484:          topos (i, 0);
                    485:          clear_end_of_line_raw (screen_width);
                    486:        }
                    487:     }
                    488: }
                    489: 
                    490: /* Clear entire screen */
                    491: 
                    492: clear_screen ()
                    493: {
                    494:   if (clear_screen_hook)
                    495:     {
                    496:       (*clear_screen_hook) ();
                    497:       return;
                    498:     }
                    499:   if (TS_clr_screen)
                    500:     {
                    501:       background_highlight ();
                    502:       OUTPUT (TS_clr_screen);
                    503:       bzero (chars_wasted, screen_height);
                    504:       cmat (0, 0);
                    505:     }
                    506:   else
                    507:     {
                    508:       topos (0, 0);
                    509:       clear_to_end ();
                    510:     }
                    511: }
                    512: 
                    513: /* Clear to end of line, but do not clear any standout marker.
                    514:    Assumes that the cursor is positioned at a character of real text,
                    515:    which implies it cannot be before a standout marker
                    516:    unless the marker has zero width.
                    517: 
                    518:    Note that the cursor may be moved.  */
                    519: 
                    520: clear_end_of_line (first_unused_hpos)
                    521:      int first_unused_hpos;
                    522: {
                    523:   if (TN_standout_width == 0 && curX == 0 && chars_wasted[curY] != 0)
                    524:     write_chars (" ", 1);
                    525:   clear_end_of_line_raw (first_unused_hpos);
                    526: }
                    527: 
                    528: /* Clear from cursor to end of line.
                    529:    Assume that the line is already clear starting at column first_unused_hpos.
                    530:    If the cursor is at a standout marker, erase the marker.
                    531: 
                    532:    Note that the cursor may be moved, on terminals lacking a `ce' string.  */
                    533: 
                    534: clear_end_of_line_raw (first_unused_hpos)
                    535:      int first_unused_hpos;
                    536: {
                    537:   register int i;
                    538:   first_unused_hpos += chars_wasted[curY] & 077;
                    539:   if (clear_end_of_line_hook)
                    540:     {
                    541:       (*clear_end_of_line_hook) (first_unused_hpos);
                    542:       return;
                    543:     }
                    544:   if (curX >= first_unused_hpos)
                    545:     return;
                    546:   /* Notice if we are erasing a magic cookie */
                    547:   if (curX == 0)
                    548:     chars_wasted[curY] = 0;
                    549:   background_highlight ();
                    550:   if (TS_clr_line)
                    551:     {
                    552:       OUTPUT1 (TS_clr_line);
                    553:     }
                    554:   else
                    555:     {                  /* have to do it the hard way */
                    556:       turn_off_insert ();
                    557:       for (i = curX; i < first_unused_hpos; i++)
                    558:        {
                    559:          if (termscript)
                    560:            fputc (' ', termscript);
                    561:          putchar (' ');
                    562:        }
                    563:       cmplus (first_unused_hpos - curX);
                    564:     }
                    565: }
                    566: 
                    567: write_chars (start, len)
                    568:      register char *start;
                    569:      int len;
                    570: {
                    571:   register char *p;
                    572:   register int n;
                    573:   register char *buf;
                    574:   register int c;
                    575:   char *first_check;
                    576: 
                    577:   if (write_chars_hook)
                    578:     {
                    579:       (*write_chars_hook) (start, len);
                    580:       return;
                    581:     }
                    582:   highlight_if_desired ();
                    583:   turn_off_insert ();
                    584: 
                    585:   /* Don't dare write in last column of bottom line, if AutoWrap,
                    586:      since that would scroll the whole screen on some terminals.  */
                    587: 
                    588:   if (AutoWrap && curY + 1 == screen_height
                    589:       && curX + len - (chars_wasted[curY] & 077) == screen_width)
                    590:     len --;
                    591: 
                    592:   cmplus (len);
                    593: 
                    594:   first_check = start;
                    595: 
                    596:   if (RPov > len && !TF_underscore && !TF_hazeltine)
                    597:     {
                    598:       fwrite (start, 1, len, stdout);
                    599:       if (ferror (stdout))
                    600:        clearerr (stdout);
                    601:       if (termscript)
                    602:        fwrite (start, 1, len, termscript);
                    603:     }
                    604:   else
                    605:     while (--len >= 0)
                    606:       {
                    607:        if (RPov + 1 < len && start >= first_check && *start == start[1])
                    608:          {
                    609:            p = start + 2;
                    610: 
                    611:            /* Now, len is number of chars left starting at p */
                    612:            while (*p++ == *start);
                    613:            --p;
                    614:            /* n is number of identical chars in this run */
                    615:            n = p - start;
                    616:            if (n > RPov)
                    617:              {
                    618:                buf = tparam (TS_repeat, 0, 0, *start, n);
                    619:                tputs (buf, n, cmputc);
                    620:                free (buf);
                    621:                start = p;
                    622:                len -= n - 1;
                    623:                continue;
                    624:              }
                    625:            else
                    626:              /* If all N identical chars are too few,
                    627:                 don't even consider the last N-1, the last N-2,...  */
                    628:              first_check = p;
                    629:          }
                    630:        c = *start++;
                    631:        if (c == '_' && TF_underscore)
                    632:          {
                    633:            if (termscript)
                    634:              fputc (' ', termscript);
                    635:            putchar (' ');
                    636:            OUTPUT (Left);
                    637:          }
                    638:        if (TF_hazeltine && c == '~')
                    639:          c = '`';
                    640:        if (termscript)
                    641:          fputc (c, termscript);
                    642:        putchar (c);
                    643:       }
                    644: }
                    645: 
                    646: /* If start is zero, insert blanks instead of a string at start */
                    647: 
                    648: insert_chars (start, len)
                    649:      register char *start;
                    650:      int len;
                    651: {
                    652:   register char *buf;
                    653:   register int c;
                    654: 
                    655:   if (insert_chars_hook)
                    656:     {
                    657:       (*insert_chars_hook) (start, len);
                    658:       return;
                    659:     }
                    660:   highlight_if_desired ();
                    661: 
                    662:   if (TS_ins_multi_chars)
                    663:     {
                    664:       buf = tparam (TS_ins_multi_chars, 0, 0, len);
                    665:       OUTPUT1 (buf);
                    666:       free (buf);
                    667:       if (start)
                    668:        write_chars (start, len);
                    669:       return;
                    670:     }
                    671: 
                    672:   turn_on_insert ();
                    673:   cmplus (len);
                    674: 
                    675:   if (!TF_underscore && !TF_hazeltine && start
                    676:       && TS_pad_inserted_char == 0 && TS_ins_char == 0)
                    677:     {
                    678:       fwrite (start, 1, len, stdout);
                    679:       if (termscript)
                    680:        fwrite (start, 1, len, termscript);
                    681:     }
                    682:   else
                    683:     while (--len >= 0)
                    684:       {
                    685:        OUTPUT1_IF (TS_ins_char);
                    686:        if (!start)
                    687:          c = ' ';
                    688:        else
                    689:          {
                    690:            c = *start++;
                    691:            if (TF_hazeltine && c == '~')
                    692:              c = '`';
                    693:          }
                    694:        if (termscript)
                    695:          fputc (c, termscript);
                    696:        putchar (c);
                    697:        OUTPUT1_IF (TS_pad_inserted_char);
                    698:     }
                    699: }
                    700: 
                    701: delete_chars (n)
                    702:      register int n;
                    703: {
                    704:   char *buf;
                    705:   register int i;
                    706: 
                    707:   if (delete_chars_hook)
                    708:     {
                    709:       (*delete_chars_hook) (n);
                    710:       return;
                    711:     }
                    712: 
                    713:   if (delete_in_insert_mode)
                    714:     {
                    715:       turn_on_insert ();
                    716:     }
                    717:   else
                    718:     {
                    719:       turn_off_insert ();
                    720:       OUTPUT_IF (TS_delete_mode);
                    721:     }
                    722: 
                    723:   if (TS_del_multi_chars)
                    724:     {
                    725:       buf = tparam (TS_del_multi_chars, 0, 0, n);
                    726:       OUTPUT1 (buf);
                    727:       free (buf);
                    728:     }
                    729:   else
                    730:     for (i = 0; i < n; i++)
                    731:       OUTPUT1 (TS_del_char);
                    732:   if (!delete_in_insert_mode)
                    733:     OUTPUT_IF (TS_end_delete_mode);
                    734: }
                    735: 
                    736: /* Insert N lines at vpos VPOS.  If N is negative, delete -N lines.  */
                    737: 
                    738: ins_del_lines (vpos, n)
                    739:      int vpos, n;
                    740: {
                    741:   char *multi = n > 0 ? TS_ins_multi_lines : TS_del_multi_lines;
                    742:   char *single = n > 0 ? TS_ins_line : TS_del_line;
                    743:   char *scroll = n > 0 ? TS_rev_scroll : TS_fwd_scroll;
                    744: 
                    745:   register int i = n > 0 ? n : -n;
                    746:   register char *buf;
                    747:   char copybuf[MScreenWidth];
                    748: 
                    749:   if (ins_del_lines_hook)
                    750:     {
                    751:       (*ins_del_lines_hook) (vpos, n);
                    752:       return;
                    753:     }
                    754: 
                    755:   /* If the lines below the insertion are being pushed
                    756:      into the end of the window, this is the same as clearing;
                    757:      and we know the lines are already clear, since the matching
                    758:      deletion has already been done.  So can ignore this.  */
                    759:   /* If the lines below the deletion are blank lines coming
                    760:      out of the end of the window, don't bother,
                    761:      as there will be a matching inslines later that will flush them. */
                    762:   if (scroll_region_ok && vpos + i >= specified_window)
                    763:     return;
                    764:   if (!memory_below_screen && vpos + i >= screen_height)
                    765:     return;
                    766: 
                    767:   if (multi)
                    768:     {
                    769:       raw_topos (vpos, 0);
                    770:       background_highlight ();
                    771:       buf = tparam (multi, 0, 0, i);
                    772:       OUTPUT (buf);
                    773:       free (buf);
                    774:     }
                    775:   else if (single)
                    776:     {
                    777:       raw_topos (vpos, 0);
                    778:       background_highlight ();
                    779:       while (--i >= 0)
                    780:        OUTPUT (single);
                    781:       if (TF_teleray)
                    782:        curX = 0;
                    783:     }
                    784:   else
                    785:     {
                    786:       set_scroll_region (vpos, specified_window);
                    787:       if (n < 0)
                    788:        raw_topos (specified_window - 1, 0);
                    789:       else
                    790:        raw_topos (vpos, 0);
                    791:       background_highlight ();
                    792:       while (--i >= 0)
                    793:        OUTPUTL (scroll, specified_window - vpos);
                    794:       set_scroll_region (0, specified_window);
                    795:     }
                    796: 
                    797:   if (TN_standout_width >= 0)
                    798:     {
                    799:       if (n < 0)
                    800:        {
                    801:          bcopy (&chars_wasted[curY - n], &chars_wasted[curY], screen_height - curY + n);
                    802:          bzero (&chars_wasted[screen_height + n], - n);
                    803:        }
                    804:       else
                    805:        {
                    806:          bcopy (&chars_wasted[curY], &copybuf[curY], screen_height - curY - n);
                    807:          bcopy (&copybuf[curY], &chars_wasted[curY + n], screen_height - curY - n);
                    808:          bzero (&chars_wasted[curY], n);
                    809:        }
                    810:     }
                    811:   if (!scroll_region_ok && memory_below_screen && n < 0)
                    812:     {
                    813:       topos (screen_height + n, 0);
                    814:       clear_to_end ();
                    815:     }
                    816: }
                    817: 
                    818: extern int cost;               /* In cm.c */
                    819: extern evalcost ();
                    820: 
                    821: /* Compute cost of sending "str", in characters,
                    822:    not counting any line-dependent padding.  */
                    823: string_cost (str)
                    824:      char *str;
                    825: {
                    826:   cost = 0;
                    827:   if (str)
                    828:     tputs (str, 0, evalcost);
                    829:   return cost;
                    830: }
                    831: 
                    832: /* Compute cost of sending "str", in characters,
                    833:    counting any line-dependent padding at one line.  */
                    834: string_cost_one_line (str)
                    835:      char *str;
                    836: {
                    837:   cost = 0;
                    838:   if (str)
                    839:     tputs (str, 1, evalcost);
                    840:   return cost;
                    841: }
                    842: 
                    843: /* Compute per line amount of line-dependent padding,
                    844:    in tenths of characters.  */
                    845: per_line_cost (str)
                    846:      register char *str;
                    847: {
                    848:   cost = 0;
                    849:   if (str)
                    850:     tputs (str, 0, evalcost);
                    851:   cost = - cost;
                    852:   if (str)
                    853:     tputs (str, 10, evalcost);
                    854:   return cost;
                    855: }
                    856: 
                    857: /* ARGSUSED */
                    858: calculate_ins_del_char_costs ()
                    859: {
                    860:   int ins_startup_cost, del_startup_cost;
                    861:   int ins_cost_per_char, del_cost_per_char;
                    862:   register int i;
                    863:   register int *p;
                    864: 
                    865:   if (TS_ins_multi_chars)
                    866:     {
                    867:       ins_cost_per_char = 0;
                    868:       ins_startup_cost = string_cost_one_line (TS_ins_multi_chars);
                    869:     }
                    870:   else if (TS_ins_char || TS_pad_inserted_char
                    871:           || (TS_insert_mode && TS_end_insert_mode))
                    872:     {
                    873:       ins_startup_cost = (30 * (string_cost (TS_insert_mode) + string_cost (TS_end_insert_mode))) / 100;
                    874:       ins_cost_per_char = (string_cost_one_line (TS_ins_char)
                    875:                           + string_cost_one_line (TS_pad_inserted_char));
                    876:     }
                    877:   else
                    878:     {
                    879:       ins_startup_cost = 9999;
                    880:       ins_cost_per_char = 0;
                    881:     }
                    882: 
                    883:   if (TS_del_multi_chars)
                    884:     {
                    885:       del_cost_per_char = 0;
                    886:       del_startup_cost = string_cost_one_line (TS_del_multi_chars);
                    887:     }
                    888:   else if (TS_del_char)
                    889:     {
                    890:       del_startup_cost = (string_cost (TS_delete_mode)
                    891:                          + string_cost (TS_end_delete_mode));
                    892:       if (delete_in_insert_mode)
                    893:        del_startup_cost /= 2;
                    894:       del_cost_per_char = string_cost_one_line (TS_del_char);
                    895:     }
                    896:   else
                    897:     {
                    898:       del_startup_cost = 9999;
                    899:       del_cost_per_char = 0;
                    900:     }
                    901: 
                    902:   /* Delete costs are at negative offsets */
                    903:   p = &DCICcost[0];
                    904:   for (i = screen_width; --i >= 0;)
                    905:     *--p = (del_startup_cost += del_cost_per_char);
                    906: 
                    907:   /* Doing nothing is free */
                    908:   p = &DCICcost[0];
                    909:   *p++ = 0;
                    910: 
                    911:   /* Insert costs are at positive offsets */
                    912:   for (i = screen_width; --i >= 0;)
                    913:     *p++ = (ins_startup_cost += ins_cost_per_char);
                    914: }
                    915: 
                    916: calculate_costs ()
                    917: {
                    918:   register char *s
                    919:     = TS_set_scroll_region ? TS_set_scroll_region : TS_set_scroll_region_1;
                    920: 
                    921:   if (dont_calculate_costs)
                    922:     return;
                    923: 
                    924:   if (s && (!TS_ins_line && !TS_del_line))
                    925:     CalcIDCosts (TS_rev_scroll, TS_ins_multi_lines,
                    926:                 TS_fwd_scroll, TS_del_multi_lines,
                    927:                 s, s);
                    928:   else
                    929:     CalcIDCosts (TS_ins_line, TS_ins_multi_lines,
                    930:                 TS_del_line, TS_del_multi_lines,
                    931:                 0, 0);
                    932: 
                    933:   calculate_ins_del_char_costs ();
                    934: 
                    935:   /* Don't use TS_repeat if its padding is worse than sending the chars */
                    936:   if (TS_repeat && per_line_cost (TS_repeat) * baud_rate < 9000)
                    937:     RPov = string_cost (TS_repeat);
                    938:   else
                    939:     RPov = MScreenWidth;
                    940: 
                    941:   cmcostinit ();               /* set up cursor motion costs */
                    942: }
                    943: 
                    944: term_init (terminal_type)
                    945:      char *terminal_type;
                    946: {
                    947:   char *combuf;
                    948:   char *fill;
                    949:   char tbuf[2044];
                    950:   register char *p;
                    951:   int status;
                    952: 
                    953:   extern char *tgetstr ();
                    954: 
                    955:   Wcm_clear ();
                    956:   dont_calculate_costs = 0;
                    957: 
                    958:   status = tgetent (tbuf, terminal_type);
                    959:   if (status < 0)
                    960:     fatal ("Cannot open termcap database file.\n");
                    961:   if (status == 0)
                    962:     fatal ("Terminal type %s is not defined.\n", terminal_type);
                    963: 
                    964: #ifdef TERMINFO
                    965:   combuf = (char *) malloc (2044);
                    966: #else
                    967:   combuf = (char *) malloc (strlen (tbuf));
                    968: #endif /* not TERMINFO */
                    969:   if (combuf == 0)
                    970:     abort ();
                    971:   fill = combuf;
                    972: 
                    973:   TS_ins_line = tgetstr ("al", &fill);
                    974:   TS_ins_multi_lines = tgetstr ("AL", &fill);
                    975:   TS_bell = tgetstr ("bl", &fill);
                    976:   TS_clr_to_bottom = tgetstr ("cd", &fill);
                    977:   TS_clr_line = tgetstr ("ce", &fill);
                    978:   TS_clr_screen = tgetstr ("cl", &fill);
                    979:   ColPosition = tgetstr ("ch", &fill);
                    980:   AbsPosition = tgetstr ("cm", &fill);
                    981:   CR = tgetstr ("cr", &fill);
                    982:   TS_set_scroll_region = tgetstr ("cs", &fill);
                    983:   TS_set_scroll_region_1 = tgetstr ("cS", &fill);
                    984:   RowPosition = tgetstr ("cv", &fill);
                    985:   TS_del_char = tgetstr ("dc", &fill);
                    986:   TS_del_multi_chars = tgetstr ("DC", &fill);
                    987:   TS_del_line = tgetstr ("dl", &fill);
                    988:   TS_del_multi_lines = tgetstr ("DL", &fill);
                    989:   TS_delete_mode = tgetstr ("dm", &fill);
                    990:   TS_end_delete_mode = tgetstr ("ed", &fill);
                    991:   TS_end_insert_mode = tgetstr ("ei", &fill);
                    992:   Home = tgetstr ("ho", &fill);
                    993:   TS_ins_char = tgetstr ("ic", &fill);
                    994:   TS_ins_multi_chars = tgetstr ("IC", &fill);
                    995:   TS_insert_mode = tgetstr ("im", &fill);
                    996:   TS_pad_inserted_char = tgetstr ("ip", &fill);
                    997:   TS_end_keypad_mode = tgetstr ("ke", &fill);
                    998:   TS_keypad_mode = tgetstr ("ks", &fill);
                    999:   LastLine = tgetstr ("ll", &fill);
                   1000:   Right = tgetstr ("nd", &fill);
                   1001:   Down = tgetstr ("do", &fill);
                   1002:   if (!Down)
                   1003:     Down = tgetstr ("nl", &fill); /* Obsolete name for "do" */
                   1004: #ifdef VMS
                   1005:   /* VMS puts a carriage return before each linefeed,
                   1006:      so it is not safe to use linefeeds.  */
                   1007:   if (Down && Down[0] == '\n' && Down[1] == '\0')
                   1008:     Down = 0;
                   1009: #endif /* VMS */
                   1010:   if (tgetflag ("bs"))
                   1011:     Left = "\b";                 /* can't possibly be longer! */
                   1012:   else                           /* (Actually, "bs" is obsolete...) */
                   1013:     Left = tgetstr ("le", &fill);
                   1014:   if (!Left)
                   1015:     Left = tgetstr ("bc", &fill); /* Obsolete name for "le" */
                   1016:   TS_pad_char = tgetstr ("pc", &fill);
                   1017:   TS_repeat = tgetstr ("rp", &fill);
                   1018:   TS_end_standout_mode = tgetstr ("se", &fill);
                   1019:   TS_fwd_scroll = tgetstr ("sf", &fill);
                   1020:   TS_standout_mode = tgetstr ("so", &fill);
                   1021:   TS_rev_scroll = tgetstr ("sr", &fill);
                   1022:   Wcm.cm_tab = tgetstr ("ta", &fill);
                   1023:   TS_end_termcap_modes = tgetstr ("te", &fill);
                   1024:   TS_termcap_modes = tgetstr ("ti", &fill);
                   1025:   Up = tgetstr ("up", &fill);
                   1026:   TS_visible_bell = tgetstr ("vb", &fill);
                   1027:   TS_end_visual_mode = tgetstr ("ve", &fill);
                   1028:   TS_visual_mode = tgetstr ("vs", &fill);
                   1029:   TS_set_window = tgetstr ("wi", &fill);
                   1030: 
                   1031:   AutoWrap = tgetflag ("am");
                   1032:   memory_below_screen = tgetflag ("db");
                   1033:   TF_hazeltine = tgetflag ("hz");
                   1034:   must_write_spaces = tgetflag ("in");
                   1035:   MetaFlag = tgetflag ("km") || tgetflag ("MT");
                   1036:   TF_insmode_motion = tgetflag ("mi");
                   1037:   TF_standout_motion = tgetflag ("ms");
                   1038:   TF_underscore = tgetflag ("ul");
                   1039:   MagicWrap = tgetflag ("xn");
                   1040:   TF_xs = tgetflag ("xs");
                   1041:   TF_teleray = tgetflag ("xt");
                   1042: 
                   1043:   /* Get screen size from system, or else from termcap.  */
                   1044:   get_screen_size (&screen_width, &screen_height);
                   1045:   if (screen_width <= 0)
                   1046:     screen_width = tgetnum ("co");
                   1047:   if (screen_height <= 0)
                   1048:     screen_height = tgetnum ("li");
                   1049: 
                   1050:   min_padding_speed = tgetnum ("pb");
                   1051:   TN_standout_width = tgetnum ("sg");
                   1052:   TabWidth = tgetnum ("tw");
                   1053: 
                   1054: #ifdef VMS
                   1055:   /* These capabilities commonly use ^J.
                   1056:      I don't know why, but sending them on VMS does not work;
                   1057:      it causes following spaces to be lost, sometimes.
                   1058:      For now, the simplest fix is to avoid using these capabilities ever.  */
                   1059:   if (Down && Down[0] == '\n')
                   1060:     Down = 0;
                   1061: #endif /* VMS */
                   1062: 
                   1063:   if (!TS_bell)
                   1064:     TS_bell = "\07";
                   1065: 
                   1066:   if (!TS_fwd_scroll)
                   1067:     TS_fwd_scroll = Down;
                   1068: 
                   1069:   PC = TS_pad_char ? *TS_pad_char : 0;
                   1070: 
                   1071:   if (TabWidth < 0)
                   1072:     TabWidth = 8;
                   1073:   
                   1074: /* Turned off since /etc/termcap seems to have :ta= for most terminals
                   1075:    and newer termcap doc does not seem to say there is a default.
                   1076:   if (!Wcm.cm_tab)
                   1077:     Wcm.cm_tab = "\t";
                   1078: */
                   1079: 
                   1080:   if (TS_standout_mode == 0)
                   1081:     {
                   1082:       TN_standout_width = tgetnum ("ug");
                   1083:       TS_end_standout_mode = tgetstr ("ue", &fill);
                   1084:       TS_standout_mode = tgetstr ("us", &fill);
                   1085:     }
                   1086: 
                   1087:   if (TF_teleray)
                   1088:     {
                   1089:       Wcm.cm_tab = 0;
                   1090:       /* Teleray: most programs want a space in front of TS_standout_mode,
                   1091:           but Emacs can do without it (and give one extra column).  */
                   1092:       TS_standout_mode = "\033RD";
                   1093:       TN_standout_width = 1;
                   1094:       /* But that means we cannot rely on ^M to go to column zero! */
                   1095:       CR = 0;
                   1096:       /* LF can't be trusted either -- can alter hpos */
                   1097:       /* if move at column 0 thru a line with TS_standout_mode */
                   1098:       Down = 0;
                   1099:     }
                   1100: 
                   1101:   /* Special handling for certain terminal types known to need it */
                   1102: 
                   1103:   if (!strcmp (terminal_type, "supdup"))
                   1104:     {
                   1105:       memory_below_screen = 1;
                   1106:       Wcm.cm_losewrap = 1;
                   1107:     }
                   1108:   if (!strncmp (terminal_type, "c10", 3)
                   1109:       || !strcmp (terminal_type, "perq"))
                   1110:     {
                   1111:       /* Supply a makeshift :wi string.
                   1112:         This string is not valid in general since it works only
                   1113:         for windows starting at the upper left corner;
                   1114:         but that is all Emacs uses.
                   1115: 
                   1116:         This string works only if the screen is using
                   1117:         the top of the video memory, because addressing is memory-relative.
                   1118:         So first check the :ti string to see if that is true.
                   1119: 
                   1120:         It would be simpler if the :wi string could go in the termcap
                   1121:         entry, but it can't because it is not fully valid.
                   1122:         If it were in the termcap entry, it would confuse other programs.  */
                   1123:       if (!TS_set_window)
                   1124:        {
                   1125:          p = TS_termcap_modes;
                   1126:          while (*p && strcmp (p, "\033v  "))
                   1127:            p++;
                   1128:          if (*p)
                   1129:            TS_set_window = "\033v%C %C %C %C ";
                   1130:        }
                   1131:       /* Termcap entry often fails to have :in: flag */
                   1132:       must_write_spaces = 1;
                   1133:       /* :ti string typically fails to have \E^G! in it */
                   1134:       /* This limits scope of insert-char to one line.  */
                   1135:       strcpy (fill, TS_termcap_modes);
                   1136:       strcat (fill, "\033\007!");
                   1137:       TS_termcap_modes = fill;
                   1138:       fill += strlen (fill) + 1;
                   1139:       p = combuf;
                   1140:       /* Change all %+ parameters to %C, to handle
                   1141:         values above 96 correctly for the C100.  */
                   1142:       while (p != fill)
                   1143:        {
                   1144:          if (p[0] == '%' && p[1] == '+')
                   1145:            p[1] = 'C';
                   1146:          p++;
                   1147:        }
                   1148:     }
                   1149: 
                   1150:   screen_height = min (screen_height, MScreenLength);
                   1151:   screen_width = min (screen_width, MScreenWidth);
                   1152: 
                   1153:   ScreenRows = screen_height;
                   1154:   ScreenCols = screen_width;
                   1155:   specified_window = screen_height;
                   1156: 
                   1157:   if (Wcm_init ())     /* can't do cursor motion */
                   1158: #ifdef VMS
                   1159:     fatal ("Terminal type \"%s\" is not powerful enough to run Emacs.\n\
                   1160: It lacks the ability to position the cursor.\n\
                   1161: If that is not the actual type of terminal you have, use either the\n\
                   1162: DCL command `SET TERMINAL/DEVICE= ...' for DEC-compatible terminals,\n\
                   1163: or `define EMACS_TERM \"terminal type\"' for non-DEC terminals.\n",
                   1164:            terminal_type);
                   1165: #else
                   1166:     fatal ("Terminal type \"%s\" is not powerful enough to run Emacs.\n\
                   1167: It lacks the ability to position the cursor.\n\
                   1168: If that is not the actual type of terminal you have,\n\
                   1169: use the C-shell command `setenv TERM ...' to specify the correct type.\n\
                   1170: It may be necessary to do `unsetenv TERMCAP' as well.\n",
                   1171:           terminal_type);
                   1172: #endif
                   1173: 
                   1174:   delete_in_insert_mode
                   1175:     = TS_delete_mode && TS_insert_mode
                   1176:       && !strcmp (TS_delete_mode, TS_insert_mode);
                   1177: 
                   1178:   se_is_so = TS_standout_mode && TS_end_standout_mode
                   1179:     && !strcmp (TS_standout_mode, TS_end_standout_mode);
                   1180: 
                   1181:   /* Remove width of standout marker from usable width of line */
                   1182:   if (TN_standout_width > 0)
                   1183:     screen_width -= TN_standout_width;
                   1184: 
                   1185:   UseTabs = tabs_safe_p () && TabWidth == 8;
                   1186: 
                   1187:   scroll_region_ok = TS_set_window || TS_set_scroll_region
                   1188:     || TS_set_scroll_region_1;
                   1189: 
                   1190:   line_ins_del_ok = (((TS_ins_line || TS_ins_multi_lines)
                   1191:                      && (TS_del_line || TS_del_multi_lines))
                   1192:                     || (scroll_region_ok
                   1193:                         && TS_fwd_scroll
                   1194:                         && TS_rev_scroll));
                   1195: 
                   1196:   char_ins_del_ok = ((TS_ins_char || TS_insert_mode ||
                   1197:                      TS_pad_inserted_char || TS_ins_multi_chars)
                   1198:                     && (TS_del_char || TS_del_multi_chars));
                   1199: 
                   1200:   fast_clear_end_of_line = TS_clr_line != 0;
                   1201: 
                   1202:   init_baud_rate ();
                   1203:   if (read_socket_hook)                /* Baudrate is somewhat */
                   1204:                                /* meaningless in this case */
                   1205:     baud_rate = 9600;
                   1206: 
                   1207:   calculate_costs ();
                   1208: }
                   1209: 
                   1210: /* VARARGS 1 */
                   1211: fatal (str, arg1, arg2)
                   1212: {
                   1213:   fprintf (stderr, "emacs: ");
                   1214:   fprintf (stderr, str, arg1, arg2);
                   1215:   fflush (stderr);
                   1216:   exit (1);
                   1217: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.