home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 5 Edit / 05-Edit.zip / ehp14cs.zip / block_1.c < prev    next >
C/C++ Source or Header  |  1995-05-10  |  48KB  |  1,040 lines

  1. /****************************************************************/
  2. /*                                                              */
  3. /*      MODUL:  block_1.c                                       */
  4. /*                                                              */
  5. /*      FUNKTIONEN:                                             */
  6. /*              - tst_overlap (Ueberlappt Block mit Fenster ?)  */
  7. /*              - in_block (Test ob Zeichen im Block)           */
  8. /*              - dup_block (Block duplizieren)                 */
  9. /*              - shrink_line (Teil aus Zeile loeschen)         */
  10. /*              - adjust_pair (Koordinaten anpassen)            */
  11. /*              - adapt_pos (Cursorposition anpassen)           */
  12. /*              - del_rechteck (rechteckigen Block loeschen)    */
  13. /*              - del_normal (normalen Block loeschen)          */
  14. /*              - save_part (Zeilenteil kopieren)               */
  15. /*              - save_rechteck (rechteckigen Block speichern)  */
  16. /*              - save_normal (normalen Block speichern)        */
  17. /*              - ins_normal (normalen Block in Text einfuegen) */
  18. /*              - ins_rechteck (rechteckigen Block einfuegen)   */
  19. /*              - indent_block (Block ein-/ausruecken)          */
  20. /****************************************************************/
  21.  
  22. #include "defs.h"
  23.  
  24. extern char *getenv(),*mktemp(),space,*reserve_mem(),*fastzeichen();
  25. extern marker_typ marker[];
  26.  
  27. /*****************************************************************************
  28. *
  29. *  Funktion       Test, ob Block sich mit Fenster ueberlappt (tst_overlap)
  30. *  --------
  31. *
  32. *  Ergebnis     :
  33. *                   Typ          : int
  34. *                   Wertebereich : TRUE,FALSE
  35. *                   Bedeutung    : TRUE: Teil des Blockes ist in Fenster
  36. *                                        sichtbar
  37. *                                  FALSE: Block nicht sichtbar
  38. *
  39. *  Beschreibung :  Die Blockkoordinaten werden mit den Koordinaten
  40. *                  des aktuellen Fensters verglichen. Ueberlappen sich die
  41. *                  Bloecke, so wird TRUE, sonst FALSE zurueckgegeben.
  42. *
  43. ******************************************************************************/
  44.  
  45. int tst_overlap()
  46. {
  47.   /* *** interne Daten und Initialisierung *** */
  48.   register int xa = akt_winp->block.s_col,  /* Blockkoordinaten */
  49.            xe = akt_winp->block.e_col,
  50.            ya = akt_winp->block.s_line,
  51.            ye = akt_winp->block.e_line;
  52.  
  53.   if(!(ya<akt_winp->ws_line && ye<akt_winp->ws_line /* Block nicht ueber */
  54.   || ya>=akt_winp->ws_line+akt_winp->dy    /* und nicht unter Ausschnitt */
  55.   && ye>=akt_winp->ws_line+akt_winp->dy))
  56.     if(akt_winp->block.typ == BT_RECHTECK)
  57.     { /* Bei Rechteck koennen noch die Spalten geprueft werden */
  58.       if(!(xa<akt_winp->ws_col && xe<akt_winp->ws_col      /* nicht links     */
  59.       || xa>=akt_winp->ws_col+akt_winp->dx /* und nicht rechts vom Ausschnitt */
  60.       && xe>=akt_winp->ws_col+akt_winp->dx))
  61.     return(TRUE);                      /* also innerhalb */
  62.     }
  63.     else              /* normaler Block, kein Spaltentest  */
  64.       return(TRUE);   /* kein genauer Test, aber gut genug */
  65.   return(FALSE);
  66. }
  67.  
  68. /*****************************************************************************
  69. *
  70. *  Funktion       Test, ob Zeichen im Block (in_block)
  71. *  --------
  72. *
  73. *  Parameter    : y         :
  74. *                   Typ          : int
  75. *                   Wertebereich : 0-MAX_ANZ_LINES
  76. *                   Bedeutung    : Zeile, in der Zeichen steht.
  77. *
  78. *               : x         :
  79. *                   Typ          : int
  80. *                   Wertebereich : 0-MAXLENGTH
  81. *                   Bedeutung    : Spalte, in der Zeichen steht
  82. *
  83. *  Ergebnis     :
  84. *                   Typ          : int
  85. *                   Wertebereich : 0 - B_IN_BLOCK | B_FIRST_LINE | B_LAST_LINE |
  86. *                                  B_BEFORE | B_AFTER | B_LINE | B_FIRST_CHAR |
  87. *                                  B_RIGHT
  88. *                   Bedeutung    : B_IN_BLOCK: Zeichen befindet sich im Block
  89. *                                  B_FIRST_LINE: Zeichen befindet sich in
  90. *                                    der ersten Zeile des Blocks
  91. *                                  B_LAST_LINE: Zeichen befindet sich in der
  92. *                                    letzten Zeile des Blocks
  93. *                                  B_BEFORE: Zeichen steht vor dem Block
  94. *                                  B_AFTER: Zeichen steht hinter dem Block
  95. *                                  B_LINE: Zeichen steht in einer Blockzeile
  96. *                                  B_FIRST_CHAR: Zeichen ist erstes Zeichen
  97. *                                    des Blocks
  98. *                                  B_RIGHT: Zeichen steht in Blockzeile, jedoch
  99. *                                    rechts vom Block.
  100. *
  101. *  Beschreibung : Die Funktion berechnet das Verhaeltnis der uebergebenen
  102. *                 Position relativ zum Block. Dazu werden im Rueckgabewert
  103. *                 bestimmte Bits mit bestimmten Bedeutungen gesetzt bzw.
  104. *                 geloescht. Das geschieht, indem fuer jedes Bit die damit
  105. *                 verbundene Bedingung ausgewertet und das Ergebnis mit dem
  106. *                 Bitwert multipliziert wird. Das Ergebnis wird zum Rueck-
  107. *                 gabewert hinzugeODERt.
  108. *
  109. *****************************************************************************/
  110.  
  111. int in_block(y,x)
  112. register int y,x;
  113. {
  114.   /* *** interne Daten und Initialisierung *** */
  115.   register block_typ *akt_bl = &akt_winp->block; /* aktueller Block */
  116.   register int       ret=0;                      /* Rueckgabewert   */
  117.  
  118.   if(!block_defined())  /* Wenn kein Block markiert ist, dann */
  119.     return(0);          /* 0 zurueckgeben */
  120.  
  121.   ret |= B_FIRST_LINE * (y == akt_bl->s_line);
  122.   ret |= B_LAST_LINE  * (y == akt_bl->e_line);
  123.   ret |= B_BEFORE     * (y <  akt_bl->s_line || (y == akt_bl->s_line && x < akt_bl->s_col));
  124.   ret |= B_AFTER      * (y >  akt_bl->e_line || (y == akt_bl->e_line && x >= akt_bl->e_col));
  125.   ret |= B_LINE       * (y >= akt_bl->s_line &&  y <= akt_bl->e_line);
  126.   ret |= B_FIRST_CHAR * (y == akt_bl->s_line &&  x == akt_bl->s_col);
  127.  
  128.   if(akt_bl->typ == BT_RECHTECK)
  129.   {
  130.     ret |= B_RIGHT * ((ret & B_LINE) && x >= akt_bl->e_col);
  131.     ret |= B_IN_BLOCK * ((ret & B_LINE)
  132.        && x >= akt_bl->s_col && x < akt_bl->e_col);
  133.   }
  134.   else
  135.   {
  136.     ret |= B_RIGHT * ((ret & B_LAST_LINE) && x >= akt_bl->e_col);
  137.     ret |= B_IN_BLOCK * ((y == akt_bl->s_line && x >= akt_bl->s_col
  138.        && (y != akt_bl->e_line || x < akt_bl->e_col))
  139.        || (y > akt_bl->s_line && y < akt_bl->e_line)
  140.        || (y == akt_bl->e_line && x < akt_bl->e_col && (y != akt_bl->s_line
  141.        || x >= akt_bl->s_col)));
  142.   }
  143.   return(ret);
  144. }
  145.  
  146. /*****************************************************************************
  147. *
  148. *  Funktion       Block duplizieren (dup_block)
  149. *  --------
  150. *
  151. *  Parameter    : old_bl    :
  152. *                   Typ          : block_typ *
  153. *                   Wertebereich : Pointer auf block_typ
  154. *                   Bedeutung    : zu kopierender Block
  155. *
  156. *  Ergebnis     :
  157. *                   Typ          : block_typ *
  158. *                   Wertebereich : Pointer auf block_typ
  159. *                   Bedeutung    : Kopie des Blocks
  160. *
  161. *  Beschreibung : Die Funktion kopiert den uebegebenen Block und gibt einen
  162. *                 Pointer auf die Kopie zurueck
  163. *
  164. *****************************************************************************/
  165.  
  166. block_typ *dup_block(old_bl)
  167. block_typ *old_bl;
  168. {
  169.   /* *** interne Daten und Initialisierung *** */
  170.   /* new_bl zeigt auf die Struktur des neuen Blockes */
  171.   block_typ          *new_bl = (block_typ*) reserve_mem(sizeof(block_typ));
  172.   register bzeil_typ *nz,  /* Aktuelle Zeile im neuen Block */
  173.              *az;  /* Aktuelle Zeile im alten Block */
  174.  
  175.   memcpy(new_bl,old_bl,sizeof(block_typ));   /* Blockstruktur duplizieren */
  176.   /* Falls Block mindestens eine Zeile hat, Platz dafuer reservieren */
  177.   if (az = old_bl->bstart)
  178.     new_bl->bstart = nz = (bzeil_typ*) reserve_mem(sizeof(bzeil_typ));
  179.   else
  180.     new_bl->bstart = NULL;
  181.   while (az)  /* Alle Blockzeilen in Zeilenliste des neuen Blocks sichern */
  182.   {
  183.     nz->text = save_text(az->text);
  184.     if (az->next)
  185.       nz->next = (bzeil_typ*) reserve_mem(sizeof(bzeil_typ));
  186.     else
  187.       nz->next = NULL;
  188.     nz = nz->next;
  189.     az = az->next;
  190.   }
  191.   return (new_bl);
  192. }
  193.  
  194. /*****************************************************************************
  195. *
  196. *  Funktion       Teil aus Zeile loeschen (shrink_line)
  197. *  --------
  198. *
  199. *  Parameter    : anf       :
  200. *                   Typ          : int
  201. *                   Wertebereich : 0 - MAXLENGTH-1
  202. *                   Bedeutung    : Anfangsspalte
  203. *
  204. *                 ende      :
  205. *                   Typ          : int
  206. *                   Wertebereich : anf - MAXLENGTH-1
  207. *                   Bedeutung    : Erstes nicht mehr zu loeschendes Zeichen
  208. *
  209. *  Beschreibung : Die Funktion loescht in der aktuellen Zeile den Bereich von
  210. *                 anf bis ende (soweit moeglich).  Besteht die Zeile danach
  211. *                 nur noch aus Spaces, so wird die Textpointer freigegeben
  212. *                 ud durch NULL ersetzt (gemaess Konvention).
  213. *
  214. *****************************************************************************/
  215.  
  216. void shrink_line(anf,ende)
  217. int anf,ende;
  218. {
  219.   /* *** interne Daten *** */
  220.   int  len;    /* Laenge des verbleibenden Strings */
  221.   char *anfp,  /* Pointer auf erstes nicht zu uebernehmendes Zeichen */
  222.        *endep; /* Pointer auf letztes nicht zu uebernehmendes Zeichen */
  223.  
  224.   /* Wenn Zeichen wegfallen (anf!=ende), dann wird anfp der Zeiger */
  225.   /* auf das entsprechende Zeichen zugewiesen. Liegt anfp hinter   */
  226.   /* dem Zeilenende (anfp==&space), geschieht nichts.              */
  227.   if(anf != ende && (anfp = fastzeichen(anf)) != &space)
  228.   {
  229.     /* Sonst wird der Zeiger auf das zu ende gehoerende Zeichen ermittelt.    */
  230.     if((endep = fastzeichen(ende)) == &space) /* Liegt ende hinte Zeilenende, */
  231.       *anfp = '\0';              /* so wird der String einfach abgeschnitten. */
  232.     else                         /* Sonst wird der hintere zu uebernehmende   */
  233.       fwdcpy(anfp,endep);        /* Teil direkt an den vorderen kopieret.     */
  234.  
  235.     /* Hat die Zeile eine Laenge ungleich 0 und besteht sie nicht nur aus */
  236.     /* Blanks, dann wird dafuer der noetige Speicher alloziert.           */
  237.     if(akt_winp->alinep->text 
  238.     && (len=strlen(akt_winp->alinep->text)) && strspn(akt_winp->alinep->text," ") != len)
  239.     {
  240.       if(!(akt_winp->alinep->text = realloc(akt_winp->alinep->text,len+1)))
  241.     no_mem_err();            /* Kein Speicher, Fehlermeldung ausgeben */
  242.     }
  243.     else                   /* Zeile leer oder nur Blanks, Zeile freigeben */
  244.     {
  245.       line_free(akt_winp->alinep->text);
  246.       akt_winp->alinep->text = NULL;
  247.     }
  248.   }
  249. }
  250.  
  251. /*****************************************************************************
  252. *
  253. *  Funktion       Koordinaten anpassen (adjust_pair)
  254. *  --------
  255. *
  256. *  Parameter    : y         :
  257. *                   Typ          : int *
  258. *                   Wertebereich : Pointer auf Integer-Variable
  259. *                   Bedeutung    : anzupassende Zeilennummer
  260. *
  261. *                 x         :
  262. *                   Typ          : int *
  263. *                   Wertebereich : Pointer auf Integer-Variable
  264. *                   Bedeutung    : anzupassende Spaltennummer
  265. *
  266. *                 modus     :
  267. *                   Typ          : int
  268. *                   Wertebereich : AP_INSERT, AP_DELETE
  269. *                   Bedeutung    : AP_INSERT: Block wurde eingefuegt
  270. *                                  AP_DELETE: Block soll geloescht werden
  271. *
  272. *  Beschreibung : Falls sich durch ein Loeschen des Blockes (modus == AP_DELETE)
  273. *                 die uebergebenen Koordinaten veraendern wuerden, so
  274. *                 werden diese entsprechend angepasst.
  275. *                 Haben sich durch das Einfuegen des Blockes (modus == AP_INSERT)
  276. *                 die uebergebenen Koordinaten veraendert, so werden diese
  277. *                 entsprechend angepasst.
  278. *
  279. *****************************************************************************/
  280.  
  281. void adjust_pair(y,x,modus)
  282. int *y,*x,modus;
  283. {
  284.   /* *** interne Daten und Initialisierung *** */
  285.   int       ib = in_block(*y,*x);   /* Position relativ zum Block */
  286.   block_typ *bl = &akt_winp->block; /* Zeiger auf aktuellen Block */
  287.  
  288.   if(bl->typ == BT_NORMAL)    /* Normaler Block ? */
  289.   {
  290.     if(ib & B_IN_BLOCK)      /* Position jetzt innerhalb des Blocks ? */
  291.       if(modus == AP_DELETE) /* wird Block geloescht ? */
  292.       {
  293.     *y = bl->s_line; /* falls Koordinaten im Block, an Blockanfang setzen */
  294.     *x = bl->s_col;
  295.       }
  296.       else                   /* Block wird eingefuegt */
  297.       {
  298.     *y += bl->e_line - bl->s_line; /* neue Position ist um Blockhoehe nach */
  299.     if(ib & B_FIRST_LINE)          /* unten gerutscht.Falls Koor in erster */
  300.       *x += bl->e_col - bl->s_col; /* Blockzeile war, auch Spaltenposition */
  301.       }                                /* anpassen */
  302.     else                     /* Position war nicht innerhalb des Blocks */
  303.       if(ib & B_AFTER)       /* Falls dahinter, dann */
  304.     if(modus == AP_DELETE) /* beim Loeschen Blockhoehe subtrahieren */
  305.     { /* wenn letzte und erste Zeile zusammen zu lang, dann wird noetige */
  306.       *y -= bl->e_line - bl->s_line; /* anpassung in del_normal gemacht */
  307.       if(ib & B_LAST_LINE) /* Wenn Position in der letzten Zeile hinter */
  308.         if(ib & B_RIGHT)   /* dem Block liegt, dann X anpassen:         */
  309.           *x += bl->s_col - bl->e_col;
  310.         else               /* Wenn in letzter Zeile im Block, dann X    */
  311.           *x = bl->s_col;  /* auf Blockstart X setzen                   */
  312.     }
  313.     else                 /* Beim Einfuegen Blockhoehe auf Y addieren */
  314.       *y += bl->e_line - bl->s_line;
  315.   }
  316.   else           /* rechteckiger Block, y-Koordinaten werden nicht veraendert */
  317.     if(ib & B_LINE)           /* Befindet sich Position in einer Blockzeile ? */
  318.       if(modus == AP_DELETE)         /* Beim Loeschen falls rechts vom Block, */
  319.       {                              /* Blockbreite von x-Koordinate abzie-   */
  320.     if(ib & B_RIGHT)             /* hen.                                  */
  321.       *x -= bl->e_col-bl->s_col;
  322.     else                         /* Falls innerhalb des Block, x-Koordina-*/
  323.       if(ib & B_IN_BLOCK)        /* te auf Blockanfang X setzen           */
  324.         *x = bl->s_col;
  325.       }
  326.       else                           /* Soll der Block eingefuegt werden und  */
  327.     if(*x >= bl->s_col)          /* die Position liegt rechts der Start-  */
  328.       *x += bl->e_col - bl->s_col; /* spalte, dann Breite zu X addieren   */
  329. }
  330.  
  331. /*****************************************************************************
  332. *
  333. *  Funktion       Positionen anpassen (adapt_pos)
  334. *  --------
  335. *
  336. *  Parameter    : modus     :
  337. *                   Typ          : int
  338. *                   Wertebereich : AP_INSERT, AP_DELETE
  339. *                   Bedeutung    : AP_INSERT: Block wurde eingefuegt
  340. *                                  AP_DELETE: Block soll geloescht werden
  341. *
  342. *  Beschreibung : Entsprechend dem Modus werden Cursorposition, Marker und
  343. *                 letzte Position mit der Funktion adjust_pair angepasst.
  344. *
  345. *****************************************************************************/
  346.  
  347. void adapt_pos(modus)
  348. int modus;
  349. {
  350.   /* *** Interne Daten und Initialisierung *** */
  351.   int i = akt_winp->textline; /* Zwischenspeicher fuer akt. Zeilennummer */
  352.  
  353.   /* Zuerst Cursorposition: */
  354.   adjust_pair(&i,&akt_winp->screencol,modus); /* nicht &textline, damit */
  355.   gotox(i);              /* textline und alinep nicht desynchronisieren */
  356.   for(i=0;i<ANZ_MARKER;i++)  /* Alle Markerpositionen fuer aktuelles    */
  357.     if(akt_winp->wini == marker[i].window)          /* Fenster anpassen */
  358.       adjust_pair(&marker[i].line,&marker[i].col,modus);
  359.   /* Letzte Position anpassen: */
  360.   adjust_pair(&akt_winp->lastline,&akt_winp->lastcol,modus);
  361. }
  362.  
  363. /*****************************************************************************
  364. *
  365. *  Funktion       rechteckigen Block loeschen (del_rechteck)
  366. *  --------
  367. *
  368. *  Beschreibung : Der aktuelle Block wird aus der Textstruktur entfernt und
  369. *                 evtl. die Cursorpositon angepasst.
  370. *
  371. *****************************************************************************/
  372.  
  373. void del_rechteck()
  374. {
  375.   /* *** Interne Daten und Initialisierung */
  376.   zeil_typ  *old_line; /* Zwischenspeicher fuer Zeiger auf aktuelle Zeile */
  377.   int       old_num,   /* Zwischenspeicher fuer aktuelle Zeilennummer     */
  378.         count;     /* Zähler für gelöschte Zeilen                     */
  379.   block_typ *bl = &akt_winp->block; /* Zeiger auf aktuellen Block         */
  380.  
  381.   adapt_pos(AP_DELETE);   /* Cursor, Marker und letzte Position anpassen */
  382.   old_num = akt_winp->textline;   /* Cursorposition erst jetzt speichern */
  383.   old_line = akt_winp->alinep;
  384.  
  385.   /* Aus allen Blockzeilen den zum Block gehoerenden Teil loeschen
  386.      Beachte: count ist nötig, da das Kriterium textline<=bl_eline
  387.           nicht ausreicht, wenn Block sich bis in letzte Zeile
  388.           erstreckt. */
  389.   count = bl->e_line - bl->s_line;
  390.   for(gotox(bl->s_line); count-- >= 0; down())
  391.     shrink_line(bl->s_col,bl->e_col);
  392.   akt_winp->changeflag = TRUE;  /* Text als geaendert markieren */
  393.   akt_winp->alinep = old_line;  /* Alte Cursorposition wieder   */
  394.   akt_winp->textline = old_num; /* herstellen                   */
  395. }
  396.  
  397. /*****************************************************************************
  398. *
  399. *  Funktion       normalen Block loeschen (del_normal)
  400. *  --------
  401. *
  402. *  Beschreibung : Der aktuelle normale Block wird aus der Textstruktur
  403. *                 entfernt und evtl. die Cursorpositon angepasst.
  404. *
  405. *****************************************************************************/
  406.  
  407. void del_normal()
  408. {
  409.   /* *** interne Daten und Initialisierung *** */
  410.   int                anz_del, /* Anzahl zu loeschender Zeilen   */
  411.              len,     /* Laenge der neuen ersten Zeile  */
  412.              old_num, /* Aktuelle Zeilennummer          */
  413.              old_sc,  /* Zwischenspeicher Cursorspalte  */
  414.              fll;     /* Laenge der uebriggebliebenen   */
  415.                   /* ersten Blockzeile              */
  416.   register block_typ *bl = &akt_winp->block; /* aktueller Block */
  417.   char               *ez_anf; /* Zeiger auf Blockanfang         */
  418.  
  419.   adapt_pos(AP_DELETE); /* Cursor, Marker und letzte Position anpassen */
  420.   old_num = akt_winp->textline; /* Zeilennummer merken und zum Block- */
  421.   gotox(bl->s_line);            /* start gehen */
  422.   if(!bl->laenge)               /* Block innerhalb einer Zeile */
  423.     shrink_line(bl->s_col,bl->e_col); /* Blockteil der Zeile loeschen */
  424.   else
  425.   {                          /* Block geht ueber mehrere Zeilen */
  426.     anz_del = bl->laenge-1;  /* letzte Zeile nicht vollstaendig loeschen */
  427.     if(bl->s_col)            /* erste Zeile teilweise loeschen */
  428.     {
  429.       /* Zeiger auf erstes Blockzeichen berechnen und testen, ob es hinter */
  430.       /* dem Zeilenende liegt (== &space)                                  */
  431.       if ((ez_anf = fastzeichen(bl->s_col)) != &space)
  432.       {
  433.     *ez_anf = '\0';  /* Zeile am Blockanfang abschneiden */
  434.     /* Wenn neue Laenge der Zeile == 0 oder Zeile nur noch aus Blanks */
  435.     /* besteht, dann Zeile freigeben. Sonst Platz neu allozieren      */
  436.     if(akt_winp->alinep->text
  437.     && (len=strlen(akt_winp->alinep->text))
  438.     && strspn(akt_winp->alinep->text," ") != len)
  439.     {
  440.       if(!(akt_winp->alinep->text = realloc(akt_winp->alinep->text,len + 1)))
  441.         no_mem_err(); /* Kein Speicherplatz, Fehlermeldung, Abbruch */
  442.     }
  443.     else
  444.     {
  445.       line_free(akt_winp->alinep->text);
  446.       akt_winp->alinep->text = NULL;
  447.     }
  448.       }
  449.       down();  /* In 2. Blockzeile gehen */
  450.     }
  451.     else            /* Wenn Block am Anfang einer Zeile beginnt, */
  452.       anz_del++;    /* dann erste Zeile auch loeschen            */
  453.     for(;anz_del;anz_del--)
  454.       del_line(IGNORE_COORS);   /* blockkoors werden nicht veraendert */
  455.     shrink_line(0,bl->e_col);   /* Blockteil der letzten Zeile loeschen */
  456.     if(bl->s_col)               /* Wenn Block nicht am Anfang einer Zeile */
  457.     {                           /* anfaengt, muss man die Zeilentruemmer */
  458.       up();                     /* zusammenfuegen.                      */
  459.       if(join(IGNORE_COORS)==J_TOOLONG) /* Klappte Join nicht ? */
  460.       { /* Dann ans Zeilenende stellen und Anpassung wie bei newline   */
  461.     /* vornehmen, da adapt_pos alles um eine Zeile zuviel anpasste */
  462.     if(akt_winp->screencol > (fll=fastll(akt_winp->alinep->text))
  463.     && akt_winp->textline == old_num) /* Wenn Cursor in letzter Block- */
  464.       /* zeile hinter dem Block stand, dann Cursorspalte anpassen */
  465.       akt_winp->screencol -= fll;
  466.     old_num++; /* Alte Cursorzeile sowieso anpassen */
  467.     old_sc = akt_winp->screencol; /* Cursorspalte merken */
  468.     akt_winp->screencol = fll;
  469.     nl_blockadapt();              /* Anpassungen vornehmen */
  470.     akt_winp->screencol = old_sc; /* Cursorspalte restaurieren */
  471.       }
  472.     }
  473.   }
  474.   akt_winp->changeflag = TRUE;  /* Text als geaendert markieren */
  475.   gotox(old_num);               /* Alte Zeile aufsuchen         */
  476. }
  477.  
  478. /*****************************************************************************
  479. *
  480. *  Funktion       Zeilenteil kopieren (save_part)
  481. *  --------
  482. *
  483. *  Parameter    : z         :
  484. *                   Typ          : bzeil_typ *
  485. *                   Wertebereich : Pointer auf Blockzeile
  486. *                   Bedeutung    : aktuelle Blockzeile
  487. *
  488. *               : anf       :
  489. *                   Typ          : int
  490. *                   Wertebereich : 0-MAXLENGTH
  491. *                   Bedeutung    : erstes zu kopierendes Zeichen
  492. *
  493. *               : ende      :
  494. *                   Typ          : int
  495. *                   Wertebereich : 0-MAXLENGTH
  496. *                   Bedeutung    : erstes nicht mehr zu kopierendes Zeichen
  497. *
  498. *  Beschreibung : Eine neue Blockzeile wird erzeugt und mit der aktuellen
  499. *                 verknuepft. In die neue Zeile wird der entsprechende Zeilen-
  500. *                 ausschnitt gespeichert (soweit moeglich). Ist der Ausschnitt
  501. *                 leer, so wird ein NULL-Pointer im text-Element eingetragen.
  502. *
  503. *****************************************************************************/
  504.  
  505. bzeil_typ *save_part(z,anf,ende)
  506. register bzeil_typ *z;
  507. int anf,ende;
  508. {
  509.   char *anfp,               /* Zeiger auf erstes zu uebernehmendes Zeichen  */
  510.        *endep,              /* Zeiger auf letztes zu uebernehmendes Zeichen */
  511.        buff[3*MAXLENGTH+1]; /* Puffer fuer zu kopierenden Teil              */
  512.  
  513.   /* Ein neues Element in der Blockstruktur eintragen */
  514.   z = z->next = (bzeil_typ*) reserve_mem(sizeof(bzeil_typ));
  515.   z->next = NULL;
  516.  
  517.   /* Pointer auf erstes zu uebernehmendes Zeichen ermitteln und testen, ob */
  518.   /* es hinter dem Ende der aktuellen Zeile liegt.                         */
  519.   if ((anfp = fastzeichen(anf)) == &space)
  520.     z->text = NULL;     /* Liegt es dahinter, keinen Speicher reservieren */
  521.   else    /* Sonst Ende ermitteln, testen, ob es hinter Zeilenende liegt. */
  522.   {
  523.     if ((endep = fastzeichen(ende)) == &space)              /* Dahinter ? */
  524.       z->text = save_text(anfp);        /* dann alles ab anfp uebernehmen */
  525.     else               /* Sonst zu uebernehmenden Teil in Puffer kopieren */
  526.     {
  527.       strncpy(buff,anfp,endep-anfp);
  528.       buff[endep-anfp] = '\0';   /* Pufferende markieren */
  529.       z->text = save_text(buff); /* Puffer in Blocktext uebernehmen */
  530.     }
  531.   }
  532.   return (z);
  533. }
  534.  
  535. /*****************************************************************************
  536. *
  537. *  Funktion       rechteckigen Block abspeichern (save_rechteck)
  538. *  --------
  539. *
  540. *  Ergebnis     :
  541. *                   Typ          : bzeil_typ*
  542. *                   Wertebereich : Pointer auf bzeil_typ
  543. *                   Bedeutung    : Anfang der verketteten Liste der
  544. *                                  Blockzeilen
  545. *
  546. *  Beschreibung : Der markierte rechteckige Block wird in einer verketteten
  547. *                 Liste, deren Anfang zurueckgegeben wird, abgespeichert.
  548. *                 Das laenge-Element von akt_winp->block wird auf die Zeilen-
  549. *                 anzahl gesetzt.
  550. *
  551. *****************************************************************************/
  552.  
  553. bzeil_typ *save_rechteck()
  554. {
  555.   /* *** interne Daten und Initialisietung *** */
  556.   /* z zeigt auf aktuelle Blockzeile */
  557.   bzeil_typ *z = (bzeil_typ*) reserve_mem(sizeof(bzeil_typ)),
  558.         *anf;         /* Zeiger auf leeres Dummy-Element   */
  559.   int       i,            /* Anzahl noch zu kopierender Zeilen */
  560.         old_tl = akt_winp->textline; /* Alte Zeilennummer  */
  561.   zeil_typ *old_ap = akt_winp->alinep;   /* Alter Zeilenzeiger */
  562.  
  563.   i = akt_winp->block.laenge = akt_winp->block.e_line - akt_winp->block.s_line;
  564.   (anf=z)->next = NULL;       /* Erstes Element ist leeres Element, wird wieder geloescht */
  565.  
  566.   /* Aus jeder zum Block gehoerigen Zeile wird der entsprechende Teil */
  567.   /* ausgeschnitten und in die Blockstruktur kopiert.                 */
  568.   for (gotox(akt_winp->block.s_line); i>=0; i--,down())
  569.     z = save_part(z,akt_winp->block.s_col,akt_winp->block.e_col);
  570.   z = anf->next;
  571.   free (anf);   /* zuviel alloziertes Element wieder freigeben */
  572.   akt_winp->alinep = old_ap;   /* Cursorposition restaurieren  */
  573.   akt_winp->textline = old_tl;
  574.   return (z);
  575. }
  576.  
  577. /*****************************************************************************
  578. *
  579. *  Funktion       normalen Block abspeichern (save_normal)
  580. *  --------
  581. *
  582. *  Ergebnis     :
  583. *                   Typ          : bzeil_typ*
  584. *                   Wertebereich : Pointer auf bzeil_typ
  585. *                   Bedeutung    : Anfang der verketteten Liste der
  586. *                                  Blockzeilen
  587. *
  588. *  Beschreibung : Der markierte normale Block wird in einer verketteten
  589. *                 Liste, deren Anfang zurueckgegeben wird, abgespeichert.
  590. *                 Das laenge-Element von akt_winp->block wird auf die Zeilen-
  591. *                 anzahl gesetzt.
  592. *
  593. *****************************************************************************/
  594.  
  595. bzeil_typ *save_normal()
  596. {
  597.   /* *** interne Daten und Initialisierung *** */
  598.   /* z zeigt auf die aktuelle Zeile in der Blocktextliste */
  599.   register bzeil_typ *z = (bzeil_typ*) reserve_mem(sizeof(bzeil_typ)),
  600.              *anf = z;   /* Erste Zeile in Blocktextliste */
  601.   char               *ez_anf;    /* Erstes Zeichen der Blocks     */
  602.   int                old_tl = akt_winp->textline; /* Alte Zeilennummer  */
  603.   zeil_typ           *old_ap = akt_winp->alinep;  /* Alter Zeilenzeiger */
  604.   block_typ          *bl = &akt_winp->block;      /* aktueller Block    */
  605.  
  606.   bl->laenge = bl->e_line-bl->s_line; /* Anzahl der Blockzeilen berechnen */
  607.   z->next = NULL; /* Erstes Element ist leeres Element, wird wieder geloescht */
  608.   gotox(bl->s_line);  /* Zum Blockanfang gehen */
  609.   if(bl->e_line == bl->s_line)  /* Block innerhalb einer Zeile */
  610.     /* Dann neue Zeile anlegen und entsprechenden Teil rauskopieren */
  611.     z = save_part(z,bl->s_col,bl->e_col);
  612.   else
  613.   {                 /* Wenn der Block ueber mehrere Zeilen geht, */
  614.     if(bl->s_col)   /* und der Block nicht in Spalte 0 anfaengt, */
  615.     {               /* dann eine neue Zeile anlegen.             */
  616.       z->next = (bzeil_typ*) reserve_mem(sizeof(bzeil_typ));
  617.       z = z->next;
  618.       z->next = NULL;
  619.       if ((ez_anf = fastzeichen(bl->s_col)) != &space)
  620.     z->text = save_text(ez_anf); /* Falls Blockanfang nicht hinter */
  621.       else /* Zeilenende, dann Blockteil der Zeile abspeichern, sonst  */
  622.     z->text = NULL;                   /* Zeile als leer markieren. */
  623.       down();  /* Zur naechsten blockzeile gehen */
  624.     }
  625.     while(akt_winp->textline < bl->e_line)  /* Alle komplett zum Block */
  626.     {                      /* gehoerigen Zeilen an die Liste anhaengen */
  627.       z->next = (bzeil_typ*) reserve_mem(sizeof(bzeil_typ));
  628.       z = z->next;
  629.       z->next = NULL;
  630.       z->text = save_text(akt_winp->alinep->text);
  631.       down();
  632.     }
  633.     z = save_part(z,0,bl->e_col); /* Blockteil der letzten Blockzeile */
  634.   }                               /* in Liste eintragen               */
  635.   z = anf->next;
  636.   free (anf);   /* zuviel alloziertes Element wieder freigeben */
  637.   akt_winp->alinep = old_ap;   /* Cursorposition restaurieren */
  638.   akt_winp->textline = old_tl;
  639.   return (z);
  640. }
  641.  
  642. /*****************************************************************************
  643. *
  644. *  Funktion       abgespeicherten norm. Block in Text einfuegen (ins_normal)
  645. *  --------
  646. *
  647. *  Parameter    : bl       :
  648. *                   Typ          : block_typ *
  649. *                   Wertebereich : Pointer auf block_typ
  650. *                   Bedeutung    : Einzufuegender Block
  651. *
  652. *  Ergebnis     :
  653. *                   Typ          : int
  654. *                   Wertebereich : TRUE,FALSE
  655. *                   Bedeutung    : TRUE = Einfuegen war moeglich
  656. *                                  FALSE = Einfuegen war nicht moeglich
  657. *
  658. *  Beschreibung : Der in der mit bl->bstart beginnenden Liste abgespeicherte
  659. *                 Block wird an der aktuellen Position eingefuegt, wenn dazu
  660. *                 genuegend Platz ist. Der eingefuegte Block wird
  661. *                 anschliessend zum aktuellen. Die Koordinaten werden gesetzt.
  662. *                 Bei bl muß laenge und bstart korrekt besetzt sein. Die
  663. *                 Koordinaten sind belanglos.
  664. *                 Die in den Text eingefuegten Textpointer der Blockzeilen
  665. *                 werden in der Blockstruktur auf NULL gesetzt, damit sie
  666. *                 nicht von block_free freigegeben werden.
  667. *
  668. *****************************************************************************/
  669.  
  670. int ins_normal(bl)
  671. block_typ *bl;
  672. {
  673.   /* *** interne Daten und Initialisierung *** */
  674.   bzeil_typ     *akt_zeile = bl->bstart;      /* Aktuelle Blockzeile    */
  675.   register int  fll, /* aktuelle Zeilenlaenge                           */
  676.         i,   /* Zaehler zum Auffuellen einer Zeile mit Blanks   */
  677.         pos, /* Startspalte des Blocks in der ersten Zeile      */
  678.         old_tl = akt_winp->textline,  /* Alte Zeilennummer      */
  679.         old_sc = akt_winp->screencol; /* Alte Spaltennummer     */
  680.   int           line_len,     /* Neue Laenge der ersten Blockzeile      */
  681.         bline_len,    /* Laenge der Blockzeile                  */
  682.         tmp_sline,    /* Zwischenspeicher fuer echten Block-    */
  683.         tmp_scol,     /* start (Zeile / Spalte)                 */
  684.         tmp_eline,    /* Zwischenspeicher fuer echtes Block-    */
  685.         tmp_ecol;     /* ende (Zeile / Spalte)                  */
  686.   char          *fzsc,        /* Zeiger auf erstes Blockzeichen         */
  687.         *rest = NULL, /* Zeiger auf Rest der Zeile, in die      */
  688.                   /* Block eingefuegt wird, nach Splitten   */
  689.         buff[3*MAXLENGTH+1]; /* Puffer fuer Zusammenfuegen der  */
  690.                      /* ersten und letzten Blockzeile   */
  691.  
  692.   if (!akt_zeile || bl->laenge<0)       /* Falls Block leer, fertig */
  693.     return (TRUE);
  694.   if (bl->laenge + akt_winp->maxline + 2 >= MAX_ANZ_LINES) /* Noch Platz ? */
  695.     return (FALSE); /* eee evtl. werden 2 Zeilen verschenkt */
  696.   check_buff(); /* Evtl. noch im Puffer enthaltene Daten in Text aufnehmen */
  697.   akt_winp->changeflag = TRUE;  /* irgendetwas muss eingefuegt werden */
  698.  
  699.   if(akt_winp->maxline <= -1)   /* Falls Text leer, eine Zeile erzeugen */
  700.     koppel_line(IGNORE_COORS);
  701.  
  702.   bline_len = fastll(akt_zeile->text);  /* Laenge der aktuellen Zeile und */
  703.   fll = fastll(akt_winp->alinep->text); /* der ersten Blockzeile merken   */
  704.  
  705.   /* Die Laenge der neuen Zeile ergibt sich aus der Summe von Cursorspalte */
  706.   /* und Laenge der ersten Blockzeile.                                     */
  707.   line_len = akt_winp->screencol + bline_len;
  708.  
  709.   bl->s_line = tmp_sline = akt_winp->textline; /* Blockkoordinaten setzen  */
  710.   bl->s_col  = tmp_scol  = akt_winp->screencol;
  711.   if (akt_winp->alinep->text)           /* Text in aktueller Zeile? */
  712.   {
  713.     /* Position relativ zum Zeilenanfang ermitteln, ab der 1. Blockzeile     */
  714.     /* eingefuegt werden soll. Steht man hinter dem Zeilenende, dann wird    */
  715.     /* direkt hinter dem Zeilenende mit der Einfuegung begonnen, sonst er-   */
  716.     /* gibt sich die Position aus der Differenz des Zeigers auf das aktuelle */
  717.     /* Zeichen und dem Zeiger auf den Zeilenanfang.                          */
  718.  
  719.     if((fzsc = fastzeichen(akt_winp->screencol)) == &space)
  720.       pos = strlen(akt_winp->alinep->text);
  721.     else
  722.       pos = fzsc - akt_winp->alinep->text;
  723.     strncpy(buff,akt_winp->alinep->text,pos);   /* Teil der Zeile vor Block  */
  724.                         /* in Puffer kopieren        */
  725.     if(fll > akt_winp->screencol)          /* Blockeinfuegen splittet Zeile, */
  726.       rest = save_text(akt_winp->alinep->text+pos); /* Rest entsteht, falls  */
  727.     else                            /* Cursor nicht hinter Zeilenende stand. */
  728.       rest = NULL;
  729.   }
  730.   else           /* aktuelle Zeile leer: */
  731.   {              /* pos wird zwar auch auf 0 gesetzt, wenn Cursor nicht am    */
  732.     pos = 0;     /* Zeilenanfang steht, wird jedoch durch Einfuegen der Spaces*/
  733.     rest = NULL; /* bis zur Cursorposition wieder korrekt angepasst. (s.u.)   */
  734.     buff[0]='\0';/* Kein Rest bei leerer Zeile, Puffer leer markieren         */
  735.   }
  736.   if (line_len <= MAXLENGTH) /* wird Zeile durch Anfuegen der */
  737.   {                          /* 1. Blockzeile zu lang ?       */
  738.     for (i = fll;i<akt_winp->screencol;i++)
  739.       buff[pos++] = ' '; /* evtl. bis Cursorposition mit Spaces auffuellen   */
  740.     if (akt_zeile->text)                /* ueberhaupt Text in 1. Blockzeile? */
  741.       strcpy(&buff[pos],akt_zeile->text); /* 1. Blockzeile an Teil der aktu- */
  742.     else                                 /* ellen Zeile im Puffer anhaengen. */
  743.       buff[pos]='\0'; /* kein Text in 1. Blockz., aktuelle Zeile ist zu Ende */
  744.     akt_zeile = akt_zeile->next;        /* Zur 2. Blockzeile */
  745.   }
  746.   else               /* Zeile wuerde zu lang werden, daher 1. Blockzeile in  */
  747.   {                  /* eigener Zeile einfuegen. Neuer Block faengt daher    */
  748.     tmp_sline++;     /* eine Zeile spaeter an                                */
  749.     tmp_scol = 0;
  750.   }
  751.   line_free(akt_winp->alinep->text);        /* Aktuelle Zeile durch neue   */
  752.   akt_winp->alinep->text = save_text(buff); /* Zeile ersetzen.             */
  753.  
  754.   /* Alle restlichen Blockzeilen werden in die Textstruktur eingefuegt */
  755.   while (akt_zeile)
  756.   {
  757.     koppel_line(IGNORE_COORS);                /* damit die uebernommene Zeile*/
  758.     akt_winp->alinep->text = akt_zeile->text; /* nicht von block_free freige-*/
  759.     akt_zeile->text = NULL;                   /* geben wird, text auf NULL.  */
  760.     akt_zeile = akt_zeile->next;
  761.   }
  762.   bl->e_line = tmp_eline = akt_winp->textline; /* Blockendkoordinaten setzen  */
  763.   bl->e_col = tmp_ecol = fastll(akt_winp->alinep->text);
  764.  
  765.   /* Wenn durch das Splitten der ersten Zeile ein Rest entstanden ist, dann */
  766.   /* wird versucht, den Rest an die letzte Blockzeile anzuhaengen. Wuerde   */
  767.   /* die Zeile dadurch zu lang, wird der Rest in eine eigene Zeile geschrie-*/
  768.   /* ben.                                                                   */
  769.   if(rest)
  770.     if (bl->e_col + (fll = fastll(rest)) <= MAXLENGTH) /* nicht zu lang ?   */
  771.       if (akt_winp->alinep->text)
  772.       {
  773.     strcpy(buff,akt_winp->alinep->text); /* beide Teile in buff zusam-  */
  774.     strcat(buff,rest);                   /* menkopieren.                */
  775.     free(rest);                          /* Rest freigeben              */
  776.     free(akt_winp->alinep->text);        /* Neu entstandene Zeile in    */
  777.     akt_winp->alinep->text = save_text(buff); /* Textstruktur eintragen */
  778.       }
  779.       else                                   /* War die aktuelle Zeile leer,*/
  780.     akt_winp->alinep->text = rest;       /* dann einfach Rest eintragen */
  781.     else                                     /* Zeile waere zu lang geworden*/
  782.     {
  783.       koppel_line(IGNORE_COORS);             /* Neue Zeile erzeugen         */
  784.       akt_winp->alinep->text = rest;         /* Rest separat abspeichern    */
  785.       bl->e_line++;    /* Fuer adapt_pos Blockende temporaer "manipulieren" */
  786.       bl->e_col = 0;
  787.     }
  788.  
  789.   /* Eingefügten Block zum aktuellen machen, damit adapt_pos mit den */
  790.   /* richtigen Koordinaten rechnet.                                  */
  791.   memcpy(&akt_winp->block,bl,sizeof(block_typ));
  792.   adapt_pos(AP_INSERT);          /* Marker etc. anpassen */
  793.   bl->s_line = tmp_sline;        /* Echte Blockstart- und Endkoordinaten */
  794.   bl->s_col  = tmp_scol;         /* restaurieren */
  795.   bl->e_line = tmp_eline;
  796.   bl->e_col  = tmp_ecol;
  797.   /* Jetzt angepaßte Werte in den aktuellen Block übernehmen */
  798.   memcpy(&akt_winp->block,bl,sizeof(block_typ));
  799.   gotox (old_tl);                /* Cursorposition restaurieren */
  800.   akt_winp->screencol = old_sc;  /* Cursorspalte bleibt gleich */
  801.   check_underl();   /* evtl. wegen Unterstr. screencol und textcol anpassen */
  802.   return (TRUE);
  803. }
  804.  
  805. /*****************************************************************************
  806. *
  807. *  Funktion    abgespeicherten recht. Block in Text einfuegen (ins_rechteck)
  808. *  --------
  809. *
  810. *  Parameter    : bl       :
  811. *                   Typ          : block_typ *
  812. *                   Wertebereich : Pointer auf block_typ
  813. *                   Bedeutung    : Einzufuegender Block
  814. *
  815. *  Ergebnis     :
  816. *                   Typ          : int
  817. *                   Wertebereich : TRUE,FALSE
  818. *                   Bedeutung    : TRUE = Einfuegen war moeglich
  819. *                                  FALSE = Einfuegen war nicht moeglich
  820. *
  821. *  Beschreibung : Der in der mit bl->bstart beginnenden Liste abgespeicherte
  822. *                 Block wird an der aktuellen Position eingefuegt, wenn dazu
  823. *                 genuegend Platz ist. Der eingefuegte Block wird
  824. *                 anschliessend zum aktuellen.
  825. *                 bl->s_col, bl->e_col, bl->laenge und bl->bstart müssen
  826. *                 korrekt gesetzt sein. Die Position des eingefügten Blocks
  827. *                 wird in bl->?_{col|line} eingetragen.
  828. *
  829. *****************************************************************************/
  830.  
  831. int ins_rechteck(bl)
  832. register block_typ *bl;
  833. {
  834.   /* *** interne Daten und Initialisierung *** */
  835.   register bzeil_typ *akt_zeile = bl->bstart;      /* Aktueller Block    */
  836.   register int       i,        /* Zaehler zum Auffuellen mit Blanks      */
  837.              diff;     /* Anzahl einzufuegender Zeilen           */
  838.   int                line_len, /* Laenge einer Textzeile                 */
  839.              old_tl = akt_winp->textline,  /* alte Zeilennummer  */
  840.              old_sc = akt_winp->screencol; /* alte Spaltennummer */
  841.   zeil_typ           *old_ap = akt_winp->alinep;   /* alter Zeilenzeiger */
  842.   register char      *tp,      /* Index fuer Textpuffer (buff)           */
  843.              *fzsc;    /* Zeiger auf Zeichen, wo eingefuegt wird */
  844.   char               buff[3*MAXLENGTH+1]; /* Puffer zum Zusammenfuegen   */
  845.                       /* der Zeilenbruchstuecke      */
  846.  
  847.   if (!akt_zeile || bl->laenge<0)          /* Falls Block leer, fertig */
  848.     return (TRUE);
  849.   check_buff();      /* Evtl. Pufferinhalt in Textstruktur uebernehmen */
  850.   if(akt_winp->maxline <= -1)  /* Falls Text leer, eine Zeile erzeugen */
  851.     koppel_line(IGNORE_COORS);
  852.  
  853.   /* Es werden alle Zeilen, in die Blockteile eingefuegt werden, darauf */
  854.   /* untersucht, ob durch die Einfuegung die maximale Zeilenlaenge      */
  855.   /* ueberschritten wuerde. Stellt man bei der Zeilenlaengenberechnung  */
  856.   /* fest, dass der Block hinter dem Zeilenende eingefuegt werden soll, */
  857.   /* dann wird als Zeilenlaenge die Cursorposition verwendet.           */
  858.   do
  859.   {
  860.     if((line_len = fastll(akt_winp->alinep->text)) < akt_winp->screencol)
  861.       line_len = akt_winp->screencol;
  862.     if (line_len + bl->e_col - bl->s_col > MAXLENGTH)
  863.       return (FALSE);
  864.   }while ((akt_zeile = akt_zeile->next) && down());
  865.  
  866.   /* Falls zu viele Zeilen eingefuegt werden muessten, FALSE zurueckgeben. */
  867.   if ((diff=old_tl+bl->laenge-akt_winp->textline) + akt_winp->maxline
  868.   >= MAX_ANZ_LINES)
  869.     return (FALSE);
  870.   akt_winp->changeflag = TRUE; /* Text als geaendert markieren */
  871.   while (diff--)
  872.     koppel_line(IGNORE_COORS); /* Falls Text zu kurz, fehlende Zeilen anhaengen */
  873.   akt_winp->textline = old_tl;                /* Cursorposition restaurieren */
  874.   akt_winp->alinep = old_ap;
  875.   akt_winp->screencol = old_sc; /* auch screencol, da von koppel_line geloescht */
  876.  
  877.   bl->e_col += akt_winp->screencol - bl->s_col; /* Blockkoordinaten eintragen */
  878.   bl->s_col  = akt_winp->screencol;
  879.   bl->e_line = bl->s_line = akt_winp->textline;
  880.  
  881.   /* Jetzt Pufferzeilen in Textzeilen hineinkopieren */
  882.   akt_zeile = bl->bstart;
  883.   do
  884.   {
  885.     if ((fzsc = fastzeichen(akt_winp->screencol)) == &space)
  886.     { /* Falls nach Zeilenende angehaengt werden muss */
  887.       if(akt_winp->alinep->text)
  888.       {
  889.     strcpy (buff,akt_winp->alinep->text); /* Ganze Zeile in Puffer kopieren */
  890.     tp = buff+strlen(buff);               /* tp hinter Ende setzen */
  891.       }
  892.       else
  893.     tp = buff;       /* Falls Zeile leer, nichts kopieren */
  894.       for (i=fastll(akt_winp->alinep->text);i<akt_winp->screencol;i++)
  895.     *tp++ = ' ';    /* Puffer mit Spaces bis zum Blockanfang auffuellen */
  896.       *tp = '\0';       /* Puffer mit '\0' abschliessen */
  897.     }
  898.     else /* Falls nicht ans Zeilenende anhaengen, ersten Teil der Zeile kopieren */
  899.     {
  900.       strncpy(buff,akt_winp->alinep->text,fzsc-akt_winp->alinep->text);
  901.       buff[fzsc-akt_winp->alinep->text] = '\0';
  902.       tp = buff+(fzsc-akt_winp->alinep->text);
  903.     }
  904.     if (akt_zeile->text)            /* Steht etwas in der Pufferzeile */
  905.     {
  906.       strcat(buff,akt_zeile->text); /* Ja, dann an Puffer anhaengen */
  907.       tp += strlen(akt_zeile->text);
  908.     }
  909.     for (i=fastll(buff);i<bl->e_col;i++) /* Evtl. Puffer bis e_col mit Spaces */
  910.       *tp++ = ' ';                    /* auffuellen, falls Blockzeile zu kurz */
  911.     *tp = '\0';
  912.     if (fzsc != &space) /* Falls in aktueller Zeile noch Rest, diesen anhaengen */
  913.       strcat (buff,fzsc);
  914.     line_free(akt_winp->alinep->text);        /* alte Zeile freigeben */
  915.     akt_winp->alinep->text = save_text(buff); /* neue Zeile abspeichern */
  916.     down();                                   /* naechste Zeile */
  917.     bl->e_line++;
  918.   }while (akt_zeile=akt_zeile->next); /* Bis letzte Zeile des Blocks eingefuegt */
  919.   bl->e_line--;                       /* e_line ist immer letzte Blockzeile    */
  920.  
  921.   /* Eingefügten Block zum aktuellen machen, damit adapt_pos mit den */
  922.   /* richtigen Koordinaten rechnet.                                  */
  923.   memcpy(&akt_winp->block,bl,sizeof(block_typ));
  924.   adapt_pos(AP_INSERT);               /* Marker etc. anpassen                  */
  925.   akt_winp->textline = old_tl;        /* Cursorposition restaurieren           */
  926.   akt_winp->alinep = old_ap; /* Anschliessend testen, ob aktuelles Zeichen     */
  927.   check_underl();  /* unterstrichen ist und evtl. screencol u. textcol anpassen*/
  928.   return (TRUE);
  929. }
  930.  
  931. /*****************************************************************************
  932. *
  933. *  Funktion       aktuellen Block ein/ausruecken (indent_block)
  934. *  --------
  935. *
  936. *  Parameter    :
  937. *                   Typ          : int
  938. *                   Wertebereich : -MAXLENGTH - MAXLENGTH
  939. *                   Bedeutung    : Anzahl der Spalten, um die eingerueckt
  940. *                                  werden soll
  941. *
  942. *  Ergebnis     :
  943. *                   Typ          : int
  944. *                   Wertebereich : TRUE,FALSE
  945. *                   Bedeutung    : TRUE = Einruecken war moeglich
  946. *                                  FALSE = Einruecken war nicht moeglich
  947. *
  948. *  Beschreibung : Der aktuelle Block wird um weite Spalten nach rechts ein-
  949. *                 gerueckt. Ist weite negativ wird der Block daher nach links
  950. *                 verschoben.  Wuerde durch das Einruecken eine Zeile zu lang,
  951. *                 wird nicht eingerueckt.
  952. *
  953. *****************************************************************************/
  954.  
  955. int indent_block(weite)
  956. register int weite;
  957. {
  958.   /* *** interne Daten und Initialisierung *** */
  959.   int          i,      /* Schleifenzaehler zur Erzeugung des Leerstring */
  960.            /* ib gibt die Position des Cursors relativ zum Block an */
  961.            ib=in_block(akt_winp->textline,akt_winp->screencol);
  962.   register int ie_line = akt_winp->block.e_line,  /* Letzte Blockzeile  */
  963.            old_sc = akt_winp->screencol; /* Alte Cursorspalte       */
  964.   register int old_tl = akt_winp->textline;  /* Alte Cursorzeile        */
  965.   zeil_typ     *old_ap = akt_winp->alinep;   /* Alter Zeilenzeiger      */
  966.   char         leer[MAXLENGTH+1],            /* Puffer fuer Leerstring  */
  967.            buff[3*MAXLENGTH+1],          /* Puffer zum Zusammenfue- */
  968.                          /* von Leerstring und Zeile*/
  969.            *hilf; /* Zeiger in Textzeile bei Einruecken nach links  */
  970.  
  971.   if(!akt_winp->block.e_col)
  972.     ie_line--;             /* falls Blockende am Zeilenanfang, letzte Zeile */
  973.   gotox(akt_winp->block.s_line); /* nicht mit einruecken! */
  974.   if (weite > 0)
  975.   {    /* Wenn Blockzeilen nach rechts verschoben werden, */
  976.     do /* testen, ob Zeile durch Einruecken nach rechts zu lang wuerde */
  977.     {
  978.       if (fastll(akt_winp->alinep->text) + weite > MAXLENGTH)
  979.       {
  980.     akt_winp->alinep = old_ap;    /* Wenn ja, Cursor restaurieren, */
  981.     akt_winp->textline = old_tl;  /* Fehlermeldung ausgeben und    */
  982.     pe_or(PROMPT_INDNTLONG);
  983.     return (FALSE);               /* Funktion verlassen            */
  984.       }
  985.     } while (akt_winp->textline < ie_line && down());
  986.  
  987.     for (i=weite-1;i>=0;i--)
  988.       leer[i] = ' ';    /* String mit Spaces erzeugen, der vor die Zeile */
  989.     leer[weite] = '\0'; /* kopiert wird.                                 */
  990.     gotox(akt_winp->block.s_line);
  991.   }
  992.  
  993.   do
  994.   {
  995.     if (akt_winp->alinep->text)
  996.       if (weite > 0) /* bei Einruecken nach rechts String mit Spaces vor */
  997.       {              /* aktuelle Zeile kopieren                          */
  998.     strcpy(buff,leer);
  999.     strcat(buff,akt_winp->alinep->text);
  1000.     free(akt_winp->alinep->text);
  1001.     akt_winp->alinep->text = save_text(buff);
  1002.       }
  1003.       else
  1004.       { /* bei Einruecken nach links die ersten <weite> Zeichen verwerfen */
  1005.     if ((hilf=fastzeichen(-1 * weite)) == &space)
  1006.       hilf = NULL;
  1007.     else
  1008.       hilf = save_text(hilf);
  1009.     free(akt_winp->alinep->text);
  1010.     akt_winp->alinep->text = hilf;
  1011.       }
  1012.   } while (akt_winp->textline < ie_line && down());
  1013.  
  1014.   akt_winp->alinep = old_ap;    /* Cursorposition restaurieren */
  1015.   akt_winp->textline = old_tl;
  1016.   akt_winp->screencol = old_sc;
  1017.   akt_winp->changeflag = TRUE;
  1018.  
  1019.   if (ib & B_LINE) /* Falls Cursor in Blockzeile steht, X-Position anpassen */
  1020.   {
  1021.     if (weite > 0 && akt_winp->screencol < MAXLENGTH-weite)
  1022.       akt_winp->screencol += weite;
  1023.     else
  1024.       if (weite < 0 && akt_winp->screencol >= -1 * weite)
  1025.     akt_winp->screencol += weite;
  1026.   }
  1027.  
  1028.   if((akt_winp->block.s_col += weite) < 0)  /* Blockkoordinaten X anpassen */
  1029.     akt_winp->block.s_col = 0;
  1030.   if (akt_winp->block.e_col) /* Ende nicht ändern, wenn am Zeilenanfang */
  1031.     if((akt_winp->block.e_col += weite) < 0)
  1032.       akt_winp->block.e_col = 0;
  1033.   if(akt_winp->screencol < akt_winp->ws_col) /* Evtl. Fensterinhalt anpassen */
  1034.     akt_winp->ws_col = akt_winp->screencol;
  1035.   else
  1036.     if(akt_winp->screencol >= akt_winp->ws_col + akt_winp->dx)
  1037.       akt_winp->ws_col = akt_winp->screencol - akt_winp->dx + 1;
  1038.   return (TRUE);
  1039. }
  1040.