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

  1. /****************************************************************/
  2. /*                                                              */
  3. /*      MODUL:  text_2.c                                        */
  4. /*                                                              */
  5. /*      FUNKTIONEN:                                             */
  6. /*              - textbeginn (an textbeginn)                    */
  7. /*              - textende (an textende)                        */
  8. /*              - lines_down (anzahl von zeilen runter)         */
  9. /*              - lines_up (anzahl von zeilen hoch)             */
  10. /*              - screen_up (eine fenstergroesse hoch)          */
  11. /*              - screen_down (eine fenstergroesse runter)      */
  12. /*              - half_up (halbe fenstergroesse hoch)           */
  13. /*              - half_down (halbe fenstergroesse runter)       */
  14. /*              - insert (zeichen an akt. position einfuegen)   */
  15. /*              - enter_char (Zeichen an aktuelle Pos. kop.)    */
  16. /*              - koppel_line (Neue Zeile in Text einkoppeln)   */
  17. /*              - new_line (zeile splitten)                     */
  18. /*              - del_line (Zeile loeschen)                     */
  19. /*              - gotox (gehe zu Zeile X)                       */
  20. /*              - indent_line (aktuelle Zeile einruecken)       */
  21. /*              - fastleft (in Zeile ein Zeichen nach links)    */
  22. /*              - fastright (in Zeile ein Zeichen nach rechts)  */
  23. /*              - fastll (Zeilenlaenge der aktuellen Zeile)     */
  24. /*              - fastzeichen (Hole Zeichen aus akt. Zeile)     */
  25. /*              - fastzeile (hole aktuelle Zeile uhne Unterstr.)*/
  26. /*              - put_zeile (Zeile in Datei schreiben)          */
  27. /*              - schreib_file (Schreib File auf Platte)        */
  28. /*              - tab_in_buff (Tab in Puffer einfuegen)         */
  29. /*              - lies_file (Datei einlesen)                    */
  30. /*              - free_text (Text freigeben)                    */
  31. /*              - save_delline (aktuelle zeile sichern)         */
  32. /*              - rest_delline (gespeicherte Zeile einfuegen)   */
  33. /*              - reflow_paragraph (Absatz neu ausrichten)      */
  34. /****************************************************************/
  35.  
  36. #include <io.h>          /* Für den Aufruf von fstat() in */
  37. #include <sys/types.h>   /* der Routine copy_file         */
  38. #include <sys/utime.h>   /* Für den Aufruf von utime()    */
  39. #include "defs.h"
  40.  
  41. extern char backupflag;
  42. extern char clear_buff;
  43. extern marker_typ marker[];
  44.  
  45. /* *** globale Daten und Initialisierung *** */
  46. extern char linebuff [3*MAXLENGTH+1], /* Zeilenpuffer                  */
  47.         bufflag,         /* Flag, ob linebuff belegt ist           */
  48.         *sd_line,        /* Zwischenspeicher fuer geloeschte Zeile */
  49.         space;           /* Globales Leerzeichen                   */
  50. char        *fastzeichen();
  51.  
  52. /****************************************************************
  53. *
  54. * FUNKTION:     textbeginn()    (an textanfang)
  55. * ERGEBNIS:     TRUE,FALSE
  56. * BESCHREIBUNG: - die erste zeile wird zur aktuellen
  57. *****************************************************************/
  58.  
  59. int textbeginn()
  60. {
  61.   check_buff();  /* evtl. Pufferinhalt in Text uebernehmen */
  62.   if(akt_winp->maxline >= 0)    /* nur wenn Datei nicht leer */
  63.   { /* Da dummy vor der ersten Zeile, ist erste Zeile Nachfolger von dummy */
  64.     akt_winp->alinep = akt_winp->dummyp->next;
  65.     akt_winp->textline = 0;
  66.     return(TRUE);
  67.   }
  68.   return(FALSE);
  69. }
  70.  
  71.  
  72. /****************************************************************
  73. *
  74. * FUNKTION:     textende()      (an textende)
  75. * ERGEBNIS:     TRUE
  76. * BESCHREIBUNG: - die letzte zeile wird zur aktuellen
  77. *****************************************************************/
  78.  
  79. int textende()
  80. {
  81.   check_buff(); /* evtl. Pufferinhalt in Text uebernehmen */
  82.   /* dummy steht hinter letzter, also ist letzte Vorgaenger von dummy */
  83.   akt_winp->alinep = akt_winp->dummyp->prev;
  84.   akt_winp->textline = akt_winp->maxline;
  85.   return(TRUE);
  86. }
  87.  
  88.  
  89. /****************************************************************
  90. *
  91. * FUNKTION:     lines_down()    (anzahl von zeilen runter)
  92. *
  93. * PARAMETER:    int anz: anzahl zu ueberspringender zeilen
  94. * ERGEBNIS:     int: anzahl der wirklich uebersprungenen zeilen
  95. * BESCHREIBUNG: - es wird versucht, anz zeilen im text nach unten
  96. *               zu springen.
  97. *****************************************************************/
  98.  
  99. int lines_down(anz)
  100. register int anz;
  101. {
  102.   /* *** interne Daten und Initialisierung *** */
  103.   register int hilf = anz; /* Zwischenspeicher fuer Parameter */
  104.  
  105.   if (anz > 0 && akt_winp->maxline >=0)
  106.   {
  107.     check_buff(); /* evtl. Pufferinhalt in Text uebernehmen */
  108.  
  109.     while(anz-- && (akt_winp->textline < akt_winp->maxline))
  110.     {
  111.       akt_winp->textline++;
  112.       akt_winp->alinep = akt_winp->alinep->next;
  113.     }
  114.     return(hilf-anz-1);
  115.   }
  116.   return (0);
  117. }
  118.  
  119.  
  120. /****************************************************************
  121. *
  122. * FUNKTION:     lines_up()      (anzahl von zeilen hoch)
  123. *
  124. * PARAMETER:    int anz: anzahl zu ueberspringender zeilen
  125. * ERGEBNIS:     int: anzahl der wirklich uebersprungenen zeilen
  126. * BESCHREIBUNG: - es wird versucht, anz zeilen im text nach oben
  127. *               zu springen.
  128. *****************************************************************/
  129.  
  130. int lines_up(anz)
  131. register int anz;
  132. {
  133.   /* *** interne Daten und Initialisierung *** */
  134.   register int hilf = anz; /* Zwischenspeicher fuer Parameter */
  135.  
  136.   if (anz > 0 && akt_winp->maxline >= 0)
  137.   {
  138.     check_buff(); /* evtl. Pufferinhalt in Text uebernehmen */
  139.  
  140.     while(anz-- && akt_winp->textline)
  141.     {
  142.       akt_winp->textline--;
  143.       akt_winp->alinep = akt_winp->alinep->prev;
  144.     }
  145.     return(hilf-anz-1);
  146.   }
  147.   return (0);
  148. }
  149.  
  150.  
  151. /****************************************************************
  152. *
  153. * FUNKTION:     screen_up()     (eine bildschirmseite hoch)
  154. *
  155. * ERGEBNIS:     int: anzahl der wirklich uebersprungenen zeilen
  156. * BESCHREIBUNG: - es wird versucht, eine bildschirmseite im text
  157. *               nach oben zu springen.
  158. *****************************************************************/
  159.  
  160. int screen_up()
  161. {
  162.   return(lines_up(akt_winp->dy));
  163. }
  164.  
  165.  
  166. /****************************************************************
  167. *
  168. * FUNKTION:     screen_down()   (eine bildschirmseite runter)
  169. *
  170. * ERGEBNIS:     int: anzahl der wirklich uebersprungenen zeilen
  171. * BESCHREIBUNG: - es wird versucht, eine bildschirmseite im text
  172. *               nach unten zu springen.
  173. *****************************************************************/
  174.  
  175. int screen_down()
  176. {
  177.   return(lines_down(akt_winp->dy));
  178. }
  179.  
  180. /****************************************************************
  181. *
  182. * FUNKTION:     half_up()       (eine halbe bildschirmseite hoch)
  183. *
  184. * ERGEBNIS:     int: anzahl der wirklich uebersprungenen zeilen
  185. * BESCHREIBUNG: - es wird versucht, eine halbe bildschirmseite
  186. *               im text nach oben zu springen.
  187. *****************************************************************/
  188.  
  189. int half_up()
  190. {
  191.   return(lines_up(akt_winp->dy / 2));
  192. }
  193.  
  194.  
  195. /****************************************************************
  196. *
  197. * FUNKTION:     half_down()     (eine halbe bildschirmseite runter)
  198. *
  199. * ERGEBNIS:     int: anzahl der wirklich uebersprungenen zeilen
  200. * BESCHREIBUNG: - es wird versucht, eine halbe bildschirmseite
  201. *               im text nach unten zu springen.
  202. *****************************************************************/
  203.  
  204. int half_down()
  205. {
  206.   return(lines_down(akt_winp->dy / 2));
  207. }
  208.  
  209. /****************************************************************
  210. *
  211. * FUNKTION:     insert()        (zeichen einfuegen)
  212. *
  213. * PARAMETER:    int n: anzahl einzufuegender zeichen
  214. * ERGEBNIS:     int: Anzahl tatsaechlich eingefuegter Zeichen
  215. * BESCHREIBUNG: - fuer n zeichen wird ab der aktuellen position
  216. *               platz geschaffen
  217. *               - die Anzahl der tatsaechlich eingefuegten
  218. *               Zeichen wird zurueckgegeben
  219. *****************************************************************/
  220.  
  221. int insert(n)
  222. register int n;
  223. {
  224.   /* *** interne Daten und Initialisierung *** */
  225.   register int n2 = 0, /* Anzahl wirklich einzufuegender Positionen */
  226.            old_sc = akt_winp->screencol, /* alte Cursorspalte   */
  227.            old_tc; /* alte Cursorspalte intern                  */
  228.  
  229.   fill_buff(); /* sicherstellen, dass aktuelle Zeile im Puffer ist */
  230.   old_tc = akt_winp->textcol; /* Cursorspalte merken */
  231.   eol(); /* Falls hinter Zeilenend nicht genug Platz fuer n Zeichen, */
  232.   if((n2 = MAXLENGTH - akt_winp->screencol) > n) /* dann weniger einfuegen */
  233.     n2 = n;                      /* Im Unterstreich-Modus pro Zeichen 3 */
  234.   n2 *= 1+2*akt_winp->underflag; /* Bytes einfuegen. */
  235.   akt_winp->textcol = old_tc;    /* Cursorspalte merken */
  236.   akt_winp->screencol = old_sc;
  237.   if(n2)                         /* noch platz da ? */
  238.   {
  239.     akt_winp->changeflag = TRUE;  /* Text als geaendert markieren */
  240.     linebuff[3*MAXLENGTH-n2] = '\0'; /* Neues Ende setzen */
  241.     /* Ab Cursor alles um n2 Postionen nach rects */
  242.     revcpy(&linebuff[akt_winp->textcol+n2],&linebuff[akt_winp->textcol]);
  243.     /* Falls die Anzahl einzufuegender Zeichen groesser als die Laenge
  244.       des zu verschiebenden Textes ist, wird '\0' nicht durch revcpy
  245.       ueberschrieben. Dies muss man dann hier nachholen.               */
  246.     if (n2 > 3*MAXLENGTH-n2-akt_winp->textcol)
  247.       linebuff[3*MAXLENGTH-n2] = ' ';     /* Blockgrenzen in screencol-Mass */
  248.     insdel_blockadapt(n2/(1+2*akt_winp->underflag)); /* anpassen */
  249.   }
  250.   return(n2 / (1 + 2*akt_winp->underflag));
  251. }
  252.  
  253. /****************************************************************
  254. *
  255. * FUNKTION:     enter_char()    (zeichen an aktuelle pos kopieren)
  256. *
  257. * PARAMETER:    char c: einzufuegendes zeichen
  258. *               char *scrolled: Wird auf TRUE gesetzt, wenn
  259. *                               horizontal gescrollt wurde und der
  260. *                               Pointer nicht NULL ist.
  261. *                               Wenn nicht gescrollt wurde, bleibt
  262. *                               es unverändert.
  263. *               int ins_put:    Modus, wie bei der Anzeige verfahren
  264. *                               werden soll: INSERT bedeutet einfügen
  265. *                               PUT bedeutet überschreiben.
  266. *               char linebreak: TRUE: nicht seitlich scrollen, sondern
  267. *                               nur *scrolled entsprechend setzen
  268. * ERGEBNIS:     TRUE/FALSE
  269. * BESCHREIBUNG: - das zeichen c wird an die aktuelle position ko-
  270. *               piert
  271. *               - danach wird check_underl() aufgerufen
  272. *               - das neue Zeichen wird angezeigt und evtl. der
  273. *               Bildschirm gescrollt
  274. *****************************************************************/
  275.  
  276. int enter_char(c, scrolled, ins_put, linebreak)
  277. register char c;
  278. char *scrolled;
  279. int ins_put;
  280. char linebreak;
  281. {
  282.   /* *** interne Daten und Initialisierung *** */
  283.   register int cu_ret = FALSE; /* Rueckgabewert der check_underl()-Funktion */
  284.  
  285.   fill_buff(); /* sicherstellen, dass aktuelle Zeile im Puffer ist */
  286.   if(akt_winp->screencol < MAXLENGTH) /* Nur wenn Cursor nicht hinter */
  287.   {                                   /* Zeilenende steht             */
  288.     akt_winp->changeflag = TRUE; /* Text als geaendert markieren */
  289.     if(akt_winp->underflag) /* Unterstreichung aktiv ? */
  290.     {                       /* Dann vor dem Zeichen _ und  einsetzen */
  291.       linebuff[akt_winp->textcol] = '_';
  292.       linebuff[akt_winp->textcol+1] = '';
  293.       linebuff[akt_winp->textcol+2] = c;
  294.     }
  295.     else
  296.     {
  297.       linebuff[akt_winp->textcol] = c;
  298.       cu_ret = check_underl(); /* pruefen ob Unterstreichung entstanden ist */
  299.     }
  300.     if (akt_winp->screencol-akt_winp->ws_col >= akt_winp->dx-1)
  301.     { /* Testen, ob horizontal gescrollt werden muss */
  302.       /* Wenn ja, dann normal die voreingestellte Weite. Sollte diese */
  303.       /* groesser als die Fensterbreite sein, dann 1/4 Fensterbreite  */
  304.       if (scrolled)
  305.     *scrolled = TRUE;
  306.       if (!linebreak)
  307.       {
  308.     akt_winp->ws_col += EC_SCROLL_WIDTH < akt_winp->dx ?
  309.                 EC_SCROLL_WIDTH : akt_winp->dx / 4 + 1;
  310.     if(akt_winp->ws_col >= MAXLENGTH) /* Zu weit, dann eins zurueck */
  311.       akt_winp->ws_col = MAXLENGTH-1;
  312.     show_win(W_AKT);  /* Fensterinhalt neu anzeigen */
  313.     fill_buff(); /* aktuelle Zeile wieder in Puffer kopieren */
  314.       }
  315.       else  /* letztes Zeichen in alter Zeile anzeigen (wichtig, falls */
  316.         /* Overwrite-Modus aktiv) !                                */
  317.     if (akt_winp->screencol-akt_winp->ws_col == akt_winp->dx-1)
  318.       fastcharout(akt_winp->textline-akt_winp->ws_line,
  319.               akt_winp->screencol-akt_winp->ws_col,
  320.               linebuff+akt_winp->textcol,ins_put);
  321.     }
  322.     else  /* Wenn nicht gescrollt werden musste: */
  323.       if (cu_ret) /*Bei neu entstandener Unterstreichung Zeile neu anzeigen */
  324.     lineout(akt_winp->textline-akt_winp->ws_line);
  325.       else        /* Sonst nur neu eingefuegtes Zeichen */
  326.     fastcharout(akt_winp->textline-akt_winp->ws_line,
  327.             akt_winp->screencol-akt_winp->ws_col,
  328.             linebuff+akt_winp->textcol,ins_put);
  329.     akt_winp->textcol+= 1+2*akt_winp->underflag;
  330.     akt_winp->screencol++; /* Cursorspalte anpassen */
  331.     return(TRUE);
  332.   }
  333.   return(FALSE); /* Cursor stand hinter dem Zeilenende */
  334. }
  335.  
  336. /*****************************************************************************
  337. *
  338. *  Funktion      Neue Zeile in Text einkoppeln (koppel_line)
  339. *  --------
  340. *
  341. *  Parameter    : modus     :
  342. *                   Typ          : int
  343. *                   Wertebereich : ADAPT_COORS,IGNORE_COORS
  344. *                   Bedeutung    : ADAPT_COORS:  Block- und Markerpositionen
  345. *                                  sowie letzte Position werden angepasst
  346. *                                  IGNORE_COORS: ... werden nicht angepasst
  347. *
  348. *  Beschreibung : Fuer eine neue Zeile wird Speicherplatz alloziert.
  349. *                 Anschliessend wird das Element korrekt hinter alinep
  350. *                 eingehaengt. Die neu eingefuegte Zeile wird zur
  351. *                 aktuellen Zeile. Der Cursor wird in der ersten Spalte
  352. *                 plaziert.
  353. *                 Abhaengig vom Modus wird nl_blockadapt aufgerufen
  354. *
  355. *****************************************************************************/
  356.  
  357. void koppel_line(modus)
  358. int modus;
  359. {
  360.   /* *** interne Daten und Initialisierung *** */
  361.   register zeil_typ *zeile = (zeil_typ*) reserve_mem(sizeof(zeil_typ));
  362.        /* zeile zeigt auf neu eingehaengte Zeile */
  363.  
  364.   if(modus == ADAPT_COORS)    /* evtl. Blockkoordinaten anpassen */
  365.     nl_blockadapt();
  366.   zeile->prev = akt_winp->alinep;       /* in Liste einhaengen      */
  367.   zeile->next = akt_winp->alinep->next;
  368.   zeile->next->prev = zeile;
  369.   akt_winp->alinep->next = zeile;
  370.   akt_winp->alinep = zeile;
  371.   akt_winp->alinep->text = NULL;        /* Zeile als leer markieren */
  372.   akt_winp->textcol = akt_winp->screencol = 0; /* Cursor in Spalte 0 */
  373.   akt_winp->maxline++;  /* Zeilenzahl und Cursorzeile haben sich erhoeht */
  374.   akt_winp->textline++;
  375.   akt_winp->changeflag = TRUE; /* Text wurde geaendert */
  376. }
  377.  
  378. /****************************************************************
  379. *
  380. * FUNKTION:     new_line()      (zeile splitten)
  381. *
  382. * ERGEBNIS:       TRUE, FALSE
  383. * BESCHREIBUNG: - die aktuelle zeile wird an der aktuellen po-
  384. *               sition gespalten und der rechte teil in eine
  385. *               neue, der aktuellen zeile nachfolgenden zeile
  386. *               kopiert
  387. *               - diese neue zeile wird dann zur aktuellen zeile,
  388. *               wobei der cursor in die erste spalte gesetzt
  389. *               wird
  390. *               - Wenn durch das Einfuegen der neuen Zeile das
  391. *               Zeilenlimit ueberschritten wuerde, wird keine
  392. *               Zeile eingefuegt und FALSE zurueckgegeben.
  393. *               Sonst ist der RETURN-Wert TRUE.
  394. *               - Der Fensterinhalt des zugehörigen Curses-Fensters
  395. *               wird in der Zeile, in der sich der Cursor vor der Operation
  396. *               befand, angepaßt (Löschen bis zum Zeilenende falls Insert,
  397. *               rechten Rahmen restaurieren). Es wird also erwartet, daß der
  398. *               Fensterinhalt mit der Textstruktur übereinstimmt.
  399. *               - ws_col und ws_line werden _n_i_c_h_t angepaßt.
  400. *
  401. *****************************************************************/
  402.  
  403. int new_line()
  404. {
  405.   /* *** interne Daten und Initialisierung *** */
  406.   register char *zeil_anf, /* Zeiger auf Anfang der neuen Zeile        */
  407.         *ltext;    /* Zeiger auf aktuelle Zeile                */
  408.   int           old_sc = akt_winp->screencol, /* alte Cursorspalte     */
  409.         i,         /* Zähler für Zeichen in Zeile              */
  410.         y;         /* Zeilennummer absolut auf Bildschirm      */
  411.   short int     rc;        /* Zeichen, mit dem Rahmen restauriert wird */
  412.  
  413.   if(akt_winp->maxline < MAX_ANZ_LINES - 1)
  414.   {
  415.     check_buff();                       /* eventuell Puffer in Text zurueck */
  416.     ltext = akt_winp->alinep->text;
  417.     zeil_anf = fastzeichen(akt_winp->screencol);/* Anfang neuer Zeile holen */
  418.     koppel_line(ADAPT_COORS);   /* Eine neue Zeile erzeugen */
  419.     if(zeil_anf != &space)   /* wenn nicht am Zeilenende gesplittet wurde */
  420.     {
  421.       y = akt_winp->textline-akt_winp->ws_line;
  422.       wmove(akt_winp->winp, /* Zur Cursorposition auf Bildschirm */
  423.         y,old_sc-akt_winp->ws_col+1);
  424.       /* Die Cursorposition liegt nun in der Zeile vor der aktuellen Zeile,
  425.      da koppel_line die neue Zeile zur aktuellen macht. */
  426.       wclrtoeol(akt_winp->winp); /* Rest der aktuellen Zeile loeschen */
  427.       if(y == 1)
  428.       rc = REST_ARR_UP | 256*A_STANDOUT;
  429.     else
  430.       if(y == akt_winp->dy)
  431.         rc = REST_ARR_DN | 256*A_STANDOUT;
  432.       else
  433.         rc = REST_CHAR | 256*A_STANDOUT;
  434.       mvwaddch(akt_winp->winp,y,
  435.            akt_winp->dx+1,rc); /* Rechten Rahmen restaurieren */
  436.       akt_winp->alinep->text = save_text(zeil_anf);/* neue zeile abspeichern*/
  437.  
  438.       *zeil_anf = '\0';
  439.       /* Jetzt neue Länge berechnen (es könnten am Ende Spaces stehen) */
  440.       for (i=strlen(ltext)-1; i>=0 && ltext [i] == ' '; i--);
  441.       /* Falls letztes Zeichen der Zeile ein unterstrichenes Space ist, so
  442.      wuerde der Puffer normal ein Zeichen zu frueh abgeschnitten. Diesen
  443.      Fall muss man also hier testen. */
  444.       if (i>0 && ltext[i-1]=='_' && ltext[i]=='')
  445.     ltext[i+2] = '\0';
  446.       else
  447.     ltext[i+1] = '\0'; /* ende alte zeile setzen und neue alte Zeile */
  448.       akt_winp->alinep->prev->text = save_text(ltext);  /* abspeichern */
  449.       free(ltext);                              /* alte zeile freigeben   */
  450.     }
  451.     return (TRUE);                              /* Einfuegen hat geklappt */
  452.   }
  453.   return (FALSE);
  454. }
  455.  
  456. /*****************************************************************************
  457. *
  458. *  Funktion       Zeile loeschen (del_line)
  459. *  --------
  460. *
  461. *  Parameter    : modus     :
  462. *                   Typ          : int
  463. *                   Wertebereich : IGNORE_COORS, ADAPT_COORS
  464. *                   Bedeutung    : IGNORE_COORS: del_line wird von Blockfunktion
  465. *                                  aufgerufen
  466. *                                  ADAPT_COORS: del_line wird nicht von einer
  467. *                                  Blockfunktion aufgerufen
  468. *
  469. *  Ergebnis     :
  470. *                   Typ          : int
  471. *                   Wertebereich : NO_LINE_DEL,LAST_LINE_DEL,OTHER_LINE_DEL
  472. *                   Bedeutung    : NO_LINE_DEL : Konnte keine Zeile loeschen
  473. *                                  OTHER_LINE_DEL : Zeile ungleich letzter
  474. *                                                   geloescht
  475. *                                  LAST_LINE_DEL : Letzte Zeile geloescht
  476. *
  477. *  Beschreibung : Die aktuelle Zeile wird aus der Zeilenliste ausgekoppelt
  478. *                 und der dafuer reservierte Speicherplatz freigegeben.
  479. *                 Wird die letzte Zeile des Textes geloescht, dann wird der
  480. *                 Cursor intern um eine Zeile nach oben bewegt und LAST_LINE_DEL
  481. *                 zurueckgegeben.
  482. *                 Wird die Zeile von einer Blockfunktion, z.B. del_normal
  483. *                 aufgerufen, so wird nicht dl_blockadapt aufgerufen, da
  484. *                 schon die Blockfunktion die Anpassung der Marker und der
  485. *                 letzten Position vornimmt.
  486. *
  487. *****************************************************************************/
  488.  
  489. int del_line(modus)
  490. int modus;
  491. {
  492.   /* *** interne Daten *** */
  493.   register zeil_typ *zeile; /* Zeiger auf nachfolgende Zeile */
  494.  
  495.   if (akt_winp->textline != -1)               /* Dummyzeile nicht loeschen */
  496.   {
  497.     akt_winp->changeflag = TRUE;  /* Text als veraendert markieren */
  498.     if(modus == ADAPT_COORS)      /* evtl. Blockgrenzen anpassen */
  499.       dl_blockadapt();
  500.     bufflag = FALSE;                    /* Pufferinhalt ist egal */
  501.     /* Zeile aus Textliste auskoppeln */
  502.     akt_winp->alinep->next->prev = akt_winp->alinep->prev;
  503.     akt_winp->alinep->prev->next = zeile = akt_winp->alinep->next;
  504.     line_free(akt_winp->alinep->text);  /* Zeile freigeben */
  505.     free (akt_winp->alinep);
  506.     akt_winp->alinep = zeile;
  507.     if (akt_winp->textline == akt_winp->maxline--)   /* unterste Textzeile? */
  508.     {
  509.       if(akt_winp->maxline == -1)                 /* allerletzte Textzeile? */
  510.       {
  511.     akt_winp->textline--;                        /* textline auf -1 */
  512.     akt_winp->screencol = 0;
  513.       }
  514.       else
  515.     up();                                         /* eins hoch */
  516.       return (LAST_LINE_DEL);
  517.     }
  518.     return (OTHER_LINE_DEL);
  519.   }
  520.   return (NO_LINE_DEL);
  521. }
  522.  
  523. /*****************************************************************************
  524. *
  525. *  Funktion       Gehe zu Zeile x (gotox)
  526. *  --------
  527. *
  528. *  Parameter    : zeile     :
  529. *                   Typ          : int
  530. *                   Wertebereich : 1-MAX_ANZ_LINES
  531. *                   Bedeutung    : Zeile, die angesprungen werden soll.
  532. *
  533. *  Beschreibung : Es wird getestet, welcher Weg zur uebergebenen Zeile der
  534. *                 kuerzeste ist : vom Start, vom Ende oder von der aktuellen
  535. *                 Zeile aus. Ueber diesen Weg wird dann alinep des aktuellen
  536. *                 Windows gesetzt. textline wird korrekt angepaßt.
  537. *
  538. *****************************************************************************/
  539.  
  540. void gotox (zeile)
  541. register int zeile;
  542. {
  543.   /* *** interne Daten *** */
  544.   register int dist; /* Entfernung zur gewuenschten Zeile */
  545.  
  546.   if(akt_winp->maxline < 0) /* Text leer, dann raus */
  547.     return;
  548.   if(zeile > akt_winp->maxline) /* Zeilennummer zu gross, dann */
  549.     zeile = akt_winp->maxline;  /* zur letzten Zeile           */
  550.   if(zeile < 0)   /* Wenn Zeilennummer kleiner als 0, dann zur ersten */
  551.     zeile = 0;
  552.  
  553.   dist = akt_winp->textline - zeile; /* Entfernung berechnen */
  554.   check_buff(); /* Puffer in Text falls man in aktueller Zeile bleibt */
  555.   /* Pruefen, ob es guenstig ist, von der aktuellen Postion loszulaufen */
  556.   if (abs(dist) <= zeile && abs(dist) <= akt_winp->maxline-zeile)
  557.     if (dist < 0)              /* Abhaengig vom Vorzeichen von dist */
  558.       lines_down (abs(dist));  /* hoch oder runter gehen */
  559.     else
  560.       lines_up   (abs(dist));
  561.   else /* Es bietet sich an, vom Anfang oder vom Ende loszulaufen */
  562.   {
  563.     akt_winp->alinep = akt_winp->dummyp;
  564.     if (zeile < akt_winp->maxline-zeile) /* besser vom Anfang ? */
  565.     {
  566.       akt_winp->textline = -1;           /* dann vorwaerts */
  567.       lines_down (zeile+1);
  568.     }
  569.     else                                 /* sonst rueckwaerts */
  570.     {
  571.       akt_winp->textline = akt_winp->maxline+1;
  572.       lines_up (akt_winp->maxline-zeile+1);
  573.     }
  574.   }
  575. }
  576.  
  577. /*****************************************************************************
  578. *
  579. *  Funktion       aktuelle  Zeile einruecken (indent_line)
  580. *  --------
  581. *
  582. *  Parameter    : above     :
  583. *                   Typ          : char
  584. *                   Wertebereich : TRUE, FALSE
  585. *                   Bedeutung    : TRUE:  richte nach Zeile oberhalb aus
  586. *                                  FALSE: richte nach Zeile unterhalb aus
  587. *
  588. *  Beschreibung : Die aktuelle Zeile wird so eingerueckt, dass die Zeile
  589. *                 am Anfang soviele Blanks enthaelt wie die darueberliegende.
  590. *                 Unterstrichene Blanks werden dabei nicht als Blank
  591. *                 angesehen. Es wird vorausgesetzt, daß die aktuelle
  592. *                 Cursorposition am Beginn der einzurückenden Zeile liegt.
  593. *                 Nach Auführung der Funktion steht der Cursor in der
  594. *                 Spalte, in der in der darüberliegenden Zeile der Text
  595. *                 beginnt.
  596. *
  597. *****************************************************************************/
  598.  
  599. void indent_line(above)
  600. char above;
  601. {
  602.   /* *** interne Daten und Initialisierung *** */
  603.   register int i,     /* Loopvariable fuer Marker und Blanks */
  604.            anz=0; /* Zaehler fuer Einrueckungsweite */
  605.   int          sc=akt_winp->screencol; /* Zwischenspeicher fuer Cursorspalte */
  606.   char         *txt,  /* Zeiger auf vorangehende Zeile  */
  607.            *txt2; /* Zeiger in neuen Zeilenstring   */
  608.  
  609.   check_buff(); /* sicherstellen, dass Pufferinhalt im Text ist */
  610.   if (txt = above ? akt_winp->alinep->prev->text
  611.           : akt_winp->alinep->next->text)
  612.   { /* Wenn vorhergehende Zeile nicht leer, dann fuehrende Blanks zaehlen */
  613.     while(*txt == ' ' && fastright(&txt,1))
  614.       anz++;    /* Zaehlen, wie weit eingerueckt wird */
  615.  
  616.     swap_int(&akt_winp->screencol,&sc); /* Alte Cursorspalte zur neuen machen */
  617.     insdel_blockadapt(anz); /* Block, lastpos und Marker anpassen */
  618.     swap_int(&akt_winp->screencol,&sc); /* Cursor wieder an neuen Zeilenstart */
  619.  
  620.     if(akt_winp->alinep->text) /* Wenn einzurueckende Zeile nicht leer: */
  621.     { /* Platz für Zeile und einzufuegende Blanks allozieren */
  622.       txt2 = txt = reserve_mem(strlen(akt_winp->alinep->text)
  623.               + akt_winp->screencol+1);
  624.       for(i=0;i<akt_winp->screencol;i++)   /* Blanks eintragen */
  625.     *txt2++ = ' ';
  626.       strcpy(txt2,akt_winp->alinep->text); /* Alte Zeile dranhaengen */
  627.       free(akt_winp->alinep->text);   /* Alte Zeile freigeben */
  628.       akt_winp->alinep->text = txt;
  629.     }
  630.   }
  631. }
  632.  
  633. /*****************************************************************************
  634. *
  635. *  Funktion       in Zeile Anzahl Zeichen nach links (fastleft)
  636. *  --------
  637. *
  638. *  Parameter    : zeile     :
  639. *                   Typ          : char**
  640. *                   Wertebereich : Doppelpointer auf ASCII-Zeichenkette
  641. *                   Bedeutung    : Character, ab dem nach links bewegt werden
  642. *                                  soll. Muss auf einen Character in
  643. *                                  akt_winp->alinep->text zeigen.
  644. *
  645. *  Parameter    : anzahl    :
  646. *                   Typ          : int
  647. *                   Wertebereich : 0-MAXLENGTH
  648. *                   Bedeutung    : Anzahl der Positionen, um die nach links
  649. *                                  gegangen werden soll.
  650. *
  651. *  Ergebnis     :
  652. *                   Typ          : int
  653. *                   Wertebereich : TRUE, FALSE
  654. *                   Bedeutung    : TRUE : konnte anzahl Zeichen nach links
  655. *                                  FALSE: konnte nicht anzahl Zeichen nach
  656. *                                         links
  657. *
  658. *  Beschreibung : Der pointer auf den String (*zeile) wird unter Berueck-
  659. *                 sichtigung von unterstrichenen Zeichen so oft nach links
  660. *                 bewegt, bis die vorgegebene Anzahl erreicht ist oder
  661. *                 man am linken Zeilenrand angekommen ist.
  662. *                 akt_winp->screencol wird angepasst.
  663. *
  664. *****************************************************************************/
  665.  
  666. int fastleft(zeile,anzahl)
  667. register char **zeile;
  668. register int  anzahl;
  669. {
  670.   while (anzahl--)
  671.   {
  672.     if (*zeile > akt_winp->alinep->text)  /* Zeilenanfang ? */
  673.     {
  674.       if (*zeile-2 >= akt_winp->alinep->text    /* Steht man auf einem      */
  675.       && *(*zeile-1)=='' && *(*zeile-2)=='_') /* unterstrichenem Zeichen? */
  676.     *zeile -= 3;   /* Dann 3 nach links, */
  677.       else
  678.     (*zeile)--;    /* sonst nur 1 nach links */
  679.       akt_winp->screencol--;  /* screencol anpassen */
  680.     }
  681.     else
  682.       return (FALSE);   /* Zeilenanfang, also FALSE zurueckgeben */
  683.   }
  684.   return (TRUE); /* Konnte anzahl Zeichen nach rechts, also TRUE zurueck */
  685. }
  686.  
  687. /*****************************************************************************
  688. *
  689. *  Funktion       in Zeile Anzahl Zeichen nach rechts (fastright)
  690. *  --------
  691. *
  692. *  Parameter    : zeile     :
  693. *                   Typ          : char**
  694. *                   Wertebereich : Doppelpointer auf ASCII-Zeichenkette
  695. *                   Bedeutung    : Character, ab dem nach rechts bewegt werden
  696. *                                  soll. Muss auf einen Character in
  697. *                                  akt_winp->alinep->text zeigen.
  698. *
  699. *  Parameter    : anzahl    :
  700. *                   Typ          : int
  701. *                   Wertebereich : 0-MAXLENGTH
  702. *                   Bedeutung    : Anzahl der Positionen, um die nach rechts
  703. *                                  gegangen werden soll.
  704. *
  705. *  Ergebnis     :
  706. *                   Typ          : int
  707. *                   Wertebereich : TRUE, FALSE
  708. *                   Bedeutung    : TRUE : konnte anzahl Zeichen nach rechts
  709. *                                  FALSE: konnte nicht anzahl Zeichen nach
  710. *                                         rechts
  711. *
  712. *  Beschreibung : Der pointer auf den String (*zeile) wird unter Berueck-
  713. *                 sichtigung von unterstrichenen Zeichen so oft nach rechts
  714. *                 bewegt, bis die vorgegebene Anzahl erreicht ist oder
  715. *                 man am rechten Zeilenrand angekommen ist.
  716. *                 akt_winp->screencol wird angepasst.
  717. *
  718. *****************************************************************************/
  719.  
  720. int fastright(zeile,anzahl)
  721. register char **zeile;
  722. register int  anzahl;
  723. {
  724.   while (anzahl--)
  725.   {
  726.     if (*(*zeile+1))  /* Zeilenende ? */
  727.     {
  728.       akt_winp->screencol++; /* screencol anpassen */
  729.       (*zeile)++; /* rechts davon _^H, dann noch 2 Positionen weiter */
  730.       if (**zeile=='_' && *(*zeile+1)=='' && *(*zeile+2))
  731.     *zeile += 2;
  732.     }
  733.     else
  734.       return (FALSE);   /* Zeilenende, also FALSE zurueckgeben */
  735.   }
  736.   return (TRUE); /* Konnte anzahl Zeichen nach rechts, also TRUE zurueck */
  737. }
  738.  
  739. /*****************************************************************************
  740. *
  741. *  Funktion       Zeilenlaenge der aktuellen Zeile berechnen (fastll)
  742. *  --------
  743. *
  744. *  Parameter    : txt       :
  745. *                   Typ          : char*
  746. *                   Wertebereich : Pointer auf ASCII-Zeichenkette
  747. *                   Bedeutung    : String, vom dem Laenge in screencol-Mass
  748. *                                  berechnet werden soll.
  749. *
  750. *  Ergebnis     :
  751. *                   Typ          : int
  752. *                   Wertebereich : 0-MAXLENGTH
  753. *                   Bedeutung    : Laenge der aktuellen Zeile in screencol-Mass
  754. *
  755. *  Beschreibung : Die aktuelle Zeile (akt_winp->alinep->text) wird bis zum
  756. *                 Ende durchgegangen, wobei berechnet wird, welche screencol-
  757. *                 position das Zeilenende hat.
  758. *
  759. *****************************************************************************/
  760.  
  761. int fastll(txt)
  762. register char *txt;
  763. {
  764.   /* *** interne Daten und Initialisierung *** */
  765.   register int sc = 0; /* vorlaeufiger return-Wert */
  766.  
  767.   if (!txt)      /* Zeile leer ? */
  768.     return (0);
  769.   while (*txt)  /* Zeilenende ? */
  770.   {
  771.     sc++;
  772.     if (*txt++ == '_' && *txt=='' && txt[1])
  773.       txt += 2; /* bei unterstrichenem Zeichen insgesamt 3 nach rechts */
  774.   }
  775.   return (sc);   /* Zeilenlaenge in screencol-Mass zurueckgeben */
  776. }
  777.  
  778. /*****************************************************************************
  779. *
  780. *  Funktion       hole zeichen aus aktueller zeile (fastzeichen)
  781. *  --------
  782. *
  783. *  Parameter    : n         :
  784. *                   Typ          : int
  785. *                   Wertebereich : 0 - MAXLENGTH-1
  786. *                   Bedeutung    : index des zu ermittelnden Zeichens
  787. *
  788. *  Ergebnis     :
  789. *                   Typ          : char*
  790. *                   Wertebereich : Pointer auf ASCII-Zeichen
  791. *                   Bedeutung    : Zeichen an Position n (s.u.)
  792. *
  793. *  Beschreibung : Die aktuelle Zeile wird bis zur Position n durchlaufen,
  794. *                 wobei _^Hx als ein Zeichen gewertet wird. Daher ist der
  795. *                 Rueckgabewert auch ein Pointer, da ein unterstrichenes
  796. *                 Zeichen mit dem _ beginnt und aus drei Codes besteht.
  797. *                 Ist die Zeile leer oder wird versucht, vor oder hinter der
  798. *                 Zeile zuzugreifen, wird die Addresse der Variablen
  799. *                 space zurueckgeliefert, die ein Leerzeichen enthaelt.
  800. *
  801. *****************************************************************************/
  802.  
  803. char *fastzeichen(n)
  804. register int n;
  805. {
  806.   /* *** interne Daten *** */
  807.   register int  sc;     /* Zaehler fuer Durchlaufen der Zeile */
  808.   register char *zeile; /* Zeiger auf aktuellen Zeilentext    */
  809.  
  810.   check_buff(); /* sicherstellen, dass Pufferinhalt im Text ist */
  811.  
  812.   /* Wenn Zeile leer ist oder n hinters Zeilenende oder vor den       */
  813.   /* Zeilenanfang zeigt, dann die Adresse des globalsn Blanks zurueck */
  814.   if (!(zeile = akt_winp->alinep->text) || (n > MAXLENGTH) || (n < 0))
  815.     return(&space);
  816.  
  817.   for(sc=0;(sc<n) && *zeile;sc++)  /* Zeile durchlaufen */
  818.     if(*zeile++ == '_' && *zeile == '' && zeile[1])
  819.       zeile+=2;
  820.  
  821.   if(!*zeile)        /* Zeilenende erreicht, dann Adresse des */
  822.     return(&space);  /* globalen Blanks zurueckgeben          */
  823.  
  824.   return(zeile);     /* Sonst das Zeichen, auf dem man steht  */
  825. }
  826.  
  827. /*****************************************************************************
  828. *
  829. *  Funktion       hole aktuelle Zeile uhne Unterstreichung (fastzeile)
  830. *  --------
  831. *
  832. *  Parameter    : p         :
  833. *                   Typ          : zeil_typ*
  834. *                   Wertebereich : Pointer auf Zeilenstruktur
  835. *                   Bedeutung    : Zeigt auf zu zu konvertierende Zeile
  836. *
  837. *  Ergebnis     :
  838. *                   Typ          : char*
  839. *                   Wertebereich : Pointer auf ASCII-Zeichen
  840. *                   Bedeutung    : Zeiger auf konvertierte Zeile
  841. *                                  Achtung: statischer Puffer!!!
  842. *
  843. *  Beschreibung : Die aktuelle Zeile wird nötigenfalls aus dem Puffer in
  844. *                 den Text übernommen. Bemerkung: alinep wird dabei nicht
  845. *                 verändert, so daß Parameter Gültigkeit behält.
  846. *                 Anschließend wird in den lokalen
  847. *                 statischen Puffer eine Kopie der angegebenen Zeile
  848. *                 gezogen, die jedoch keine
  849. *                 Unterstreichung enthält. Ist die aktuelle Zeile leer
  850. *                 (text pointer ist NULL), so wird in die erste Position
  851. *                 des Puffers ein '\0' geschrieben.
  852. *
  853. *****************************************************************************/
  854.  
  855. char *fastzeile(p)
  856. zeil_typ *p;
  857. {
  858.   /* *** interne Daten *** */
  859.   register int  sc;     /* Zaehler fuer Durchlaufen der Zeile */
  860.   register char *zeile; /* Zeiger auf aktuellen Zeilentext    */
  861.   static   char buf [BUFFSIZE]; /* Puffer, in dem Zeile zurückkommt */
  862.  
  863.   check_buff(); /* sicherstellen, dass Pufferinhalt im Text ist */
  864.  
  865.   if (!(zeile = p->text))
  866.     *buf = '\0';
  867.   else
  868.   {
  869.     sc = 0;
  870.     while (*zeile)
  871.     {
  872.       if(*zeile == '_' && zeile [1] == '' && zeile[2])
  873.     zeile+=2;
  874.       buf [sc++] = *zeile++;
  875.     }
  876.     buf [sc] = '\0';  /* String terminieren */
  877.   }
  878.   return(buf);
  879. }
  880.  
  881. /*****************************************************************************
  882. *
  883. *  Funktion       Zeile in Datei schreiben (put_zeile)
  884. *  --------
  885. *
  886. *  Parameter    : line      :
  887. *                   Typ          : char *
  888. *                   Wertebereich : Pointer auf ASCII-Zeichenkette
  889. *                   Bedeutung    : zu schreibende Zeile
  890. *
  891. *                 f         :
  892. *                   Typ          : FILE *
  893. *                   Wertebereich : Dateipointer
  894. *                   Bedeutung    : Datei, in die Zeile geschrieben werden soll
  895. *
  896. *  Beschreibung : Die Zeile wird in die Datei geschrieben. Abhaengig von
  897. *                 akt_winp->tabflag werden Spaces am Anfang - wenn moeglich -
  898. *                 zu Tabs komprimiert.
  899. *
  900. *****************************************************************************/
  901.  
  902. void put_zeile(line,f)
  903. register char *line;
  904. FILE *f;
  905. {
  906.   /* *** interne Daten und Initialisierung *** */
  907.   register int i,            /* Schleifenzaehler fuer Tabschreiben */
  908.            anz_spaces=0; /* Zaehler fuer fuehrende Blanks      */
  909.  
  910.   if(akt_winp->tabflag) /* Wenn Spaces zu Tabs komprimiert werden sollen: */
  911.   {
  912.     while(*line++ == ' ') /* Spaces am Zeilenanfang zaehlen */
  913.       anz_spaces++;
  914.     for(i=anz_spaces/STD_TAB;i>0;i--)  /* Tabs in Datei schreiben */
  915.       fputc('\t',f);
  916.     line -= anz_spaces%STD_TAB + 1;  /* Nichtkomprimierte Spaces schreiben */
  917.   }
  918.   fputs(line,f); /* Rest der Zeile in Datei schreiben */
  919. }
  920.  
  921. /*****************************************************************************
  922. *
  923. *  Funktion       Datei kopieren (copy_file)
  924. *  --------
  925. *
  926. *  Parameter    : n1        :
  927. *                   Typ          : char *
  928. *                   Wertebereich : Pointer auf ASCII-Zeichenkette
  929. *                   Bedeutung    : zu lesendes File
  930. *
  931. *                 n1        :
  932. *                   Typ          : char *
  933. *                   Wertebereich : Pointer auf ASCII-Zeichenkette
  934. *                   Bedeutung    : zu schreibende Datei
  935. *
  936. *  Beschreibung : Die Datei mit dem Namen n1 wird in die Datei mit dem Namen
  937. *                 n2 kopiert. Dabei erhält n2 das Zugriffs- und Modifikations-
  938. *                 datum von n1.
  939. *
  940. *****************************************************************************/
  941.  
  942. void copy_file (n1, n2)
  943. char *n1, *n2;
  944. {
  945.   char buff [MAXLENGTH]; /* Puffer für zu lesende / schreibende Zeile */
  946.   FILE *f1,              /* Pointer für Datei n1 */
  947.        *f2;              /* Pointer für Datei n2 */
  948.   struct stat    n1_buf; /* Information über n1  */
  949.   struct utimbuf n2_buf; /* Information über n2  */
  950.  
  951.   if (f1 = fopen (n1, "r"))
  952.   {
  953.     fstat (fileno(f1), &n1_buf);
  954.     if (f2 = fopen (n2, "w"))
  955.     {
  956.       while (!feof(f1))
  957.       {
  958.     fgets (buff, MAXLENGTH, f1);  /* \n bleibt in buff stehen */
  959.     if (!feof(f1))
  960.       fputs (buff, f2);           /* und wird durch fputs wieder */
  961.       }                               /* geschrieben */
  962.       fclose (f2);
  963.       n2_buf.actime  = n1_buf.st_atime;
  964.       n2_buf.modtime = n1_buf.st_mtime;
  965.       utime (n2, &n2_buf);
  966.     }
  967.     fclose (f1);
  968.   }
  969. }
  970.  
  971. /*****************************************************************************
  972. *
  973. *  Funktion       Schreib File auf Platte (schreib_file)
  974. *  --------
  975. *
  976. *  Ergebnis     :   Typ          : int
  977. *                   Wertebereich : TRUE,FALSE
  978. *                   Bedeutung    : Flag, ob Operation erfolgreich
  979. *
  980. *  Beschreibung : Der im aktuellen Fenster stehende Text wird in die
  981. *                 Datei geschrieben, deren Name in der Window-Struktur
  982. *                 angegeben ist. NULL-Pointer werden in Leerzeilen kon-
  983. *                 vertiert.
  984. *
  985. *****************************************************************************/
  986.  
  987. int schreib_file ()
  988. {
  989.   /* *** interne Daten *** */
  990.   FILE     *f;  /* Pointer fuer Schreibdatei                        */
  991.   zeil_typ *tp; /* Zeiger auf aktuelle Zeile                        */
  992.   int      len; /* Laenge des Filenamens vor Anhaengen von .bak     */
  993.   char     *fn, /* Zeiger auf Dateinamen ohne Pfad                  */
  994.        *sc, /* Zur Suche des Punktes im Filenamen               */
  995.        buff[MAXLENGTH+1]; /* fuer Fehlermeldungen und Filenamen */
  996.  
  997.   if (akt_winp->read_only)
  998.   {
  999.     sprintf(buff,PROMPT_WRTPROT,akt_winp->filename);
  1000.     pe_or(buff);
  1001.     return (FALSE);
  1002.   }
  1003.   check_buff(); /* Pufferinhalt evtl. in Text uebernehmen */
  1004.   sprintf(buff,PROMPT_SAVING,akt_winp->filename);
  1005.   print_stat(buff);
  1006.   if(backupflag && !access(akt_winp->filename,2))   /* write permission? */
  1007.   {                   /* .bak erzeugen */
  1008.     strcpy(buff,akt_winp->filename);
  1009. #ifdef OS2  /* OS/2 verkraftet auch xxx.c.bak !!! */
  1010.     strcat(buff,".bak");
  1011. #else
  1012.     if(sc = strchr(fn=sname(buff),'.')) /* Punkt im Filenamen suchen */
  1013.       len = sc-fn;      /* Falls gefunden, ist Länge die Länge bis zum Punkt */
  1014.     else                /* Sonst ist es die gesamte Länge des Filenamens */
  1015.       len = strlen(fn); /* Kann nicht länger als 8 Zeichen sein. */
  1016.     strcpy(&fn[len],".bak");  /* Filename des .bak-Files erzeugen */
  1017. #endif
  1018.     unlink(buff);     /* falls schon ein .bak gleichen Namens existiert */
  1019.     copy_file(akt_winp->filename, buff);  /* Datei kopieren, um Links auf die
  1020.                  Datei konsistent zu halten (wichtig bei OS/2) */
  1021.   }
  1022.   if (f = fopen (akt_winp->filename,"w"))
  1023.   {
  1024.     for (tp = akt_winp->dummyp->next; tp != akt_winp->dummyp; tp = tp->next)
  1025.     { /* Alle Zeilen durchgehen und in die Datei schreiben */
  1026.       if (tp->text)
  1027.     put_zeile(tp->text,f);
  1028.       putc('\n',f);
  1029.     }
  1030.   }
  1031.   else  /* Fehler beim Oeffnen der Datei */
  1032.   {
  1033.     clear_stat();
  1034.     print_stat(PROMPT_ERRWRITE);
  1035.     pe_or(akt_winp->filename);
  1036.     return(FALSE);
  1037.   }
  1038.   akt_winp->changeflag = FALSE;               /* changeflag zuruecksetzen */
  1039.   fclose(f);
  1040.   chmod(akt_winp->filename,akt_winp->attribs); /* Modus korrekt setzen */
  1041.   clear_stat();
  1042.   return(TRUE);
  1043. }
  1044.  
  1045.  
  1046. /*****************************************************************************
  1047. *
  1048. *  Funktion       Tab in Puffer einfuegen (tab_in_buff)
  1049. *  --------
  1050. *
  1051. *  Parameter    : buff      :
  1052. *                   Typ          : char *
  1053. *                   Wertebereich : Pointer auf char-Puffer
  1054. *                   Bedeutung    : Puffer, in den Tab eingefuegt werden soll
  1055. *
  1056. *                 sc        :
  1057. *                   Typ          : int *
  1058. *                   Wertebereich : Pointer auf Integer
  1059. *                   Bedeutung    : aktuelle Bildschirmposition im Puffer
  1060. *
  1061. *                 count     :
  1062. *                   Typ          : int *
  1063. *                   Wertebereich : Pointer auf Integer
  1064. *                   Bedeutung    : aktuelle Position im Puffer
  1065. *
  1066. *  Beschreibung : Bis zur naechsten Tab-Position werden im Puffer Spaces einge-
  1067. *                 fuegt.
  1068. *
  1069. *****************************************************************************/
  1070.  
  1071. void tab_in_buff(buff,sc,count)
  1072. register char *buff;
  1073. register int *sc,*count;
  1074. {
  1075.   do
  1076.   {
  1077.     buff[(*count)++] = ' ';
  1078.   } while(++*sc % STD_TAB && *sc < MAXLENGTH);
  1079. }
  1080.  
  1081. /*****************************************************************************
  1082. *
  1083. *  Funktion       Datei einlesen (lies_file)
  1084. *  --------
  1085. *
  1086. *  Ergebnis     :   Typ          : int
  1087. *                   Wertebereich : TRUE,FALSE
  1088. *                   Bedeutung    : Flag, ob eine Datei geladen wurde
  1089. *
  1090. *  Beschreibung : In die Fensterstruktur des aktuellen Fensters wird der
  1091. *                 Text aus der Datei, deren Name in filename steht, geladen.
  1092. *                 Evtl. vorkommende Tabs werden expandiert.
  1093. *
  1094. *****************************************************************************/
  1095.  
  1096. int lies_file()
  1097. {
  1098.   /* *** interne Daten *** */
  1099.   FILE        *f;     /* Zeiger fuer Ausgabedatei                       */
  1100.   char        buff[3*MAXLENGTH+2],   /* Eingabepuffer                   */
  1101.           buff2[3*MAXLENGTH+2],  /* Ausgabepuffer                   */
  1102.           nlflag; /* Flag zeigt an ob komplette Zeile gelesen wurde */
  1103.   int         len,    /* Laenge der eingelesenen Zeile                  */
  1104.           in,     /* Index in Eingabepuffer                         */
  1105.           out,    /* Index in Ausgabepuffer                         */
  1106.           sc;     /* Zeilenlaenge in screencol-Mass                 */
  1107.   struct stat f_info; /* Zum Einlesen der Dateiattribute                */
  1108.  
  1109.   /* Dummyelement fuer Textstruktur allozieren */
  1110.   akt_winp->dummyp = (zeil_typ*) reserve_mem (sizeof (zeil_typ));
  1111.   akt_winp->dummyp->prev = akt_winp->dummyp->next = akt_winp->alinep = akt_winp->dummyp;
  1112.   akt_winp->dummyp->text = NULL;
  1113.  
  1114.   /* Cursorposition und andere Variablen initialisieren */
  1115.   akt_winp->textline = akt_winp->maxline = -1;
  1116.   akt_winp->screencol = akt_winp->textcol = 0;
  1117.   akt_winp->attribs = STD_FATTR;
  1118.   akt_winp->read_only = FALSE;
  1119.   akt_winp->changeflag = FALSE;
  1120.  
  1121.   if (!(f = fopen (akt_winp->filename,"r")))
  1122.   {
  1123.     sprintf(buff,PROMPT_ASKNEW,akt_winp->filename);
  1124.     return (ja_nein(buff));
  1125.   }
  1126.   sprintf(buff,PROMPT_LOADING,akt_winp->filename);
  1127.   print_stat(buff);
  1128.   if (access(akt_winp->filename,2))  /* Testen, ob Datei schreibgeschuetzt */
  1129.     akt_winp->read_only = TRUE;      /* und evtl. vermerken */
  1130.   if (!stat(akt_winp->filename,&f_info)) /* Fileattribute bestimmen */
  1131.     akt_winp->attribs = f_info.st_mode & (S_IWRITE | S_IREAD);
  1132.  
  1133.   out = sc = 0;
  1134.   while (fgets(buff,3*MAXLENGTH + 1,f) && akt_winp->maxline < MAX_ANZ_LINES-1)
  1135.   { /* Zeile einlesen, testen ob das ging und ob maximale */
  1136.     /* Zeilenanzahl erreicht ist */
  1137.     if(buff[(len = strlen(buff))-1] == '\n')
  1138.     { /* testen, ob eine komplette Zeile eingelesen wurde */
  1139.       nlflag = TRUE;  /* Wenn ja, nlflag setzen */
  1140.       buff[--len] = '\0'; /* und '\n' streichen */
  1141.     }
  1142.     else /* Wenn keine komplette Zeile eingelesen werden konnte */
  1143.       nlflag = FALSE;
  1144.     in = 0;
  1145.     while(in < len)
  1146.     {
  1147.       if (buff[in] == '_' && buff[in+1] == '' && buff[in+2])
  1148.       { /* Wurde ein unterstrichenes Zeichen gelesen, dann den Unter-  */
  1149.     buff2[out++] = buff[in++];  /* strich und das Backspace ueber- */
  1150.     buff2[out++] = buff[in++];  /* nehmen */
  1151.       }
  1152.       if(buff[in] == '\t')   /* Tab ? */
  1153.     tab_in_buff(buff2,&sc,&out);
  1154.       else   /* kein Tab, dann Zeichen in Puffer uebernehmen */
  1155.       {
  1156.     buff2[out++] = buff[in];
  1157.     sc++;  /* Screencol-Laenge der Zeile erhoehen */
  1158.       }
  1159.       in++;    /* Naechstes Zeichen aus Eingabepuffer */
  1160.       if(sc == MAXLENGTH)       /* Aufbereitete Zeile voll ? */
  1161.       {
  1162.     buff2[out] = '\0'; /* Dann Puffer abschliessen */
  1163.     sc = out = 0;      /* Zeile eintragen und neue Zeile anfangen */
  1164.     koppel_line(IGNORE_COORS); /* Marker und lastpos sind eh korrupt */
  1165.     akt_winp->changeflag = FALSE; /* Falls reserve_mem hängt, soll */
  1166.                       /* Text nicht abgespeichert werden */
  1167.     akt_winp->alinep->text = save_text (buff2);
  1168.       }
  1169.     }
  1170.     if(nlflag && !(!sc && len)) /* volle Zeilen nicht doppelt eintragen */
  1171.     {
  1172.       buff2[out] = '\0';  /* Puffer abschliessen, eintragen und neue */
  1173.       sc = out = 0;       /* Zeile anfangen */
  1174.       koppel_line(IGNORE_COORS);
  1175.       akt_winp->changeflag = FALSE; /* Kommentar s.o. */
  1176.       akt_winp->alinep->text = save_text(buff2);
  1177.     }               /* buff wird durch fgets besetzt. Schlaegt fgets fehl, */
  1178.     buff[0] = '\0'; /* ist buff[0]=='\0', sonst nicht. Bricht Schleife     */
  1179.   }            /* nicht wegen fgets ab, dann war das Zeilenlimit erreicht. */
  1180.  
  1181.   /* Wurde die letzte Zeile nicht mit \n abgeschlossen, dann wurde die     */
  1182.   /* Zeile noch nicht in den Text eingetragen sondern steht noch in buff2. */
  1183.   if(out)
  1184.   {
  1185.     buff2[out] = '\0'; /* Puffer abschliessen und eintragen */
  1186.     koppel_line(IGNORE_COORS);
  1187.     akt_winp->changeflag = FALSE; /* Kommentar s.o. */
  1188.     akt_winp->alinep->text= save_text(buff2);
  1189.   }
  1190.  
  1191.   clear_stat();
  1192.   if (buff[0] && akt_winp->maxline >= MAX_ANZ_LINES - 1)
  1193.     print_err(PROMPT_FILETOLNG);
  1194.   fclose(f);
  1195.   akt_winp->alinep = akt_winp->dummyp->next; /* Erste Zeile zur aktuellen */
  1196.   akt_winp->textline = akt_winp->maxline != -1 ? 0 : -1;    /* machen */
  1197.   return (TRUE); /* Kein Fehler, Fenster kann geoeffnet werden */
  1198. }
  1199.  
  1200. /*****************************************************************************
  1201. *
  1202. *  Funktion       Text freigeben (free_text)
  1203. *  --------
  1204. *
  1205. *  Beschreibung : Der zum aktuellen Fenster gehoerige Text, inklusive
  1206. *                 akt_winp->dummyp, wird freigegeben.
  1207. *
  1208. *****************************************************************************/
  1209.  
  1210. void free_text()
  1211. {
  1212.   /* *** interne Daten *** */
  1213.   register zeil_typ *n; /* Zeiger auf naechste freizugebende Zeile */
  1214.  
  1215.   akt_winp->alinep = akt_winp->dummyp;
  1216.   do
  1217.   {
  1218.     line_free(akt_winp->alinep->text); /* Text freigeben */
  1219.     n = akt_winp->alinep->next;        /* Zeiger auf naechste Zeile merken */
  1220.     free(akt_winp->alinep);            /* Zeilenstruktur freigeben */
  1221.   }while((akt_winp->alinep = n) != akt_winp->dummyp);
  1222. }
  1223.  
  1224. /*****************************************************************************
  1225. *
  1226. *  Funktion       aktuelle Zeile abspeichern (save_delline)
  1227. *  --------
  1228. *
  1229. *  Beschreibung :  Der text-Pointer der alten Zeile wird in sd_line ge-
  1230. *                  speichert und anschliessend auf NULL gesetzt. Diese
  1231. *                  Funktion wird in do_delline() vor del_line aufgerufen.
  1232. *                  Der Speicherbereich, auf den sd_line zeigt, wird vorher
  1233. *                  mittels line_free() freigegeben.
  1234. *
  1235. *****************************************************************************/
  1236.  
  1237. void save_delline()
  1238. {
  1239.   line_free(sd_line); /* Alte gespeicherte geloeschte Zeile verwerfen */
  1240.   check_buff();  /* evtl. Pufferinhalt in den Text uebernehmen */
  1241.   sd_line = akt_winp->alinep->text; /* text sichern */
  1242.   akt_winp->alinep->text = NULL; /* funktioniert, da Zeile sowieso */
  1243. }                                /* geloescht wird */
  1244.  
  1245. /*****************************************************************************
  1246. *
  1247. *  Funktion       Gespeicherte Zeile wiederherstellen (rest_delline)
  1248. *  --------
  1249. *
  1250. *  Beschreibung : Die mit save_delline gespeicherte Zeile wird in den Text
  1251. *                 vor der aktuellen Zeile eingefuegt. Die neue Zeile wird
  1252. *                 zur aktuellen.  Es wird eine Kopie der gespeicherten Zeile
  1253. *                 angelegt, so dass die Zeile ggf. mehrmals eingefuegt werden
  1254. *                 kann.
  1255. *
  1256. *****************************************************************************/
  1257.  
  1258. void rest_delline()
  1259. {
  1260.   int old_sc = akt_winp->screencol; /* Zwischenspeicher Screencol */
  1261.  
  1262.   if(akt_winp->maxline < MAX_ANZ_LINES-1)
  1263.   { /* Noch Platz fuer Wiederherstellung der geloeschten Zeile ? */
  1264.     check_buff();  /* Pufferinhalt evtl. in Text uebernehmen */
  1265.     if(akt_winp->alinep != akt_winp->dummyp)
  1266.     { /* Wenn Datei Zeilen enthaelt, dann eine Zeile hoch */
  1267.       akt_winp->textline--; /* nummer bleibt gleich, da neue z. = alte z. */
  1268.       akt_winp->alinep = akt_winp->alinep->prev;
  1269.     }
  1270.     koppel_line(ADAPT_COORS); /* Neue Zeile einfuegen, Block anpassen */
  1271.     akt_winp->alinep->text = save_text(sd_line); /* mehrmals einfuegen */
  1272.     akt_winp->screencol = old_sc; /* Screencol restaurieren */
  1273.   } /* nur moeglich, wenn sichergestellt ist, dass sd_line gleichbleibt */
  1274. }
  1275.  
  1276. /*****************************************************************************
  1277. *
  1278. *  Funktion       Absatz bündig ausrichten (reflow_paragraph)
  1279. *  --------
  1280. *
  1281. *  Ergebnis     :   Typ          : int
  1282. *                   Wertebereich : TRUE,FALSE
  1283. *                   Bedeutung    : Flag, ob Operation ohne Fehler
  1284. *                                  ausgeführt werden konnte.
  1285. *
  1286. *  Beschreibung : Ab der aktuellen Cursorposition wird jede Zeile
  1287. *                 soweit aufgefüllt, bis sie möglichst knapp an den
  1288. *                 rechten Fensterrand heranreicht. Das wird bis zur
  1289. *                 nächsten leeren Zeile durchgeführt.
  1290. *
  1291. *****************************************************************************/ 
  1292.  
  1293. int reflow_paragraph()
  1294.   int  old_sc,            /* Zwischenspeicher Cursorspalte */
  1295.        new_sc,            /* neue x-Position, läuft mit.   */        
  1296.        new_tl,            /* neue Cursorzeile, läuft mit.  */        
  1297.        x_l,               /* linker Rand für Reflowing     */        
  1298.        x_r,               /* rechter Rand für Reflowing    */
  1299.        fll,               /* merkt das Ergebnis von fastll */
  1300.        i;                 /* Zähler                        */        
  1301.   char finished = FALSE,  /* Flag, ob Textende erreicht    */
  1302.        error = FALSE;     /* Flag, ob während der Reformatierung ein 
  1303.                  Fehler auftrat */                       
  1304.  
  1305.   new_sc = akt_winp->screencol;
  1306.   new_tl = akt_winp->textline;
  1307.   x_r    = akt_winp->dx-1;
  1308.  
  1309.   /* Zuerst müssen die Ränder ermittelt werden. */
  1310.   fill_buff();        /* evtl. Zeile in Puffer kopieren */
  1311.   /* Jetzt suche erstes non-Blank in dieser Zeile, um x_l zu bestimmen */
  1312.   if (!akt_winp->alinep->text)
  1313.      x_l = 0;
  1314.   else
  1315.   {
  1316.      for (i=0; i<3*MAXLENGTH && linebuff[i]==' '; i++) ;
  1317.      if (i == 3*MAXLENGTH)
  1318.     x_l = 0;
  1319.      else
  1320.     x_l = i;
  1321.   }
  1322.  
  1323.   /* Jetzt geht's los: Bis zur nächsten Leerzeile die Zeilen jeweils
  1324.      soweit auffüllen, daß für jede Zeile des Absatzes anschließend die
  1325.      folgende Bedingung gilt (ein Wort ist dabei immer als eine von
  1326.      Whitespaces begrenzte Zeichenfolge ohne Whitespaces zu verstehen):
  1327.     Das erste Wort der nächsten Zeile würde, wenn es an diese
  1328.     Zeile angehängt würde, dazu führen, daß diese Zeile über x_r
  1329.     hinausragt, oder die nächste Zeile ist leer. 
  1330.     Das erste non-Whitespace-Zeichen der Zeile steht
  1331.     in Spalte x_l.
  1332.   */
  1333.   check_buff();       /* Puffer in Text zurückschreiben */
  1334.   while (akt_winp->alinep->text /* Reflow geht bis zur nächsten Leerzeile */
  1335.     && !error && !finished  /* oder Textende erreicht                 */
  1336.     && !clear_buff)         /* oder bis Ctrl-Break gedrückt wird      */
  1337.   {
  1338.     /* Solange joinen, bis aktuelle Zeile zu lang bzw. Absatzende erreicht */
  1339.     old_sc = akt_winp->screencol;
  1340.     while ((fll=fastll (akt_winp->alinep->text)) < x_r
  1341.        && akt_winp->alinep->next->text)
  1342.       do_join();
  1343.     akt_winp->screencol = old_sc;
  1344.  
  1345.     if (fll > x_r)  /* Splitting ist nötig */
  1346.     {
  1347.       /* Jetzt zum rechten Fensterrand positionieren */
  1348.       for (i=(old_sc > x_r ? old_sc - x_r : x_r - old_sc); i>0; i--)
  1349.     if (old_sc > x_r)
  1350.        left();
  1351.     else
  1352.        right();
  1353.  
  1354.       /* Von dort aus das nächste Blank zur linken suchen. */
  1355.       while (akt_zeichen() != ' ' && akt_winp->screencol > 0)
  1356.     left();
  1357.       if (akt_zeichen() != ' ')    /* am linken Rand angekommen, und       */
  1358.       {                            /* am Zeilenanfang kein Blank,          */
  1359.     finished = !down();        /* Dann mit nächster Zeile weitermachen */
  1360.     check_and_scroll_by_one(); /* scrollen, falls nötig                */
  1361.       }
  1362.       else
  1363.       { /* Cursor steht jetzt auf einem Blank, rechts davon beginnt Wort */
  1364.     /* Die Cursorspalte ist <= x_r                                   */
  1365.     right();                     /* auf Wortanfang stellen */
  1366.     old_sc = akt_winp->screencol;
  1367.     if (new_line())              /* klappt Zeileneinfügen? */
  1368.     {
  1369.       check_and_scroll_by_one(); /* scrollen, falls nötig              */
  1370.       if (new_sc >= old_sc)      /* wurde links vom Cursor gesplittet? */
  1371.       {                          /* Dann neue Cursorposition ent-      */
  1372.         new_sc -= old_sc;        /* sprechend anpassen                 */
  1373.         new_tl++;
  1374.       }
  1375.       if (akt_winp->autoindflag) /* Einrückung beim Reflowing erfolgt  */
  1376.       {                          /* gemäß aktuellem Autoindent-Flag    */
  1377.         if (akt_winp->alinep->next->text)
  1378.           indent_line(FALSE);    /* Wenn Zeile unterhalb nicht leer,   */
  1379.         else                     /* dann nach unterere Zeile,          */
  1380.           indent_line(TRUE);     /* sonst nach oberer Zeile einrücken  */
  1381.         if (akt_winp->screencol >= x_r) /* würde zu endlosem Splitting */
  1382.         {                               /* führen. Fehler->Abbruch     */
  1383.           pe_or (PROMPT_ERRINDRFL);
  1384.           error = TRUE;
  1385.         }
  1386.         else
  1387.           if (akt_winp->textline == new_tl)
  1388.         new_sc += akt_winp->screencol; /* Einrückung bei Cursor-    */
  1389.       }                                    /* anpassung berücksichtigen */
  1390.       if (akt_winp->screencol < akt_winp->ws_col)  /* Cursor rechts    */
  1391.         akt_winp->ws_col = akt_winp->screencol;    /* vom linken Rand? */
  1392.     }
  1393.     else  /* new_line schlug fehl */
  1394.     {
  1395.       pe_or (B_SIZE_ERRTEXT);
  1396.       error = TRUE;
  1397.     }
  1398.       }
  1399.     } /* end of if Zeile war zu lang und mußte gesplittet werden */
  1400.     else  /* In dieser Zeile ist jetzt alles OK. Nächste Zeile: */
  1401.     {
  1402.       finished = !down();
  1403.       check_and_scroll_by_one(); /* scrollen, falls nötig              */
  1404.     }
  1405.   } /* end of while nicht leere Zeile (also Absatzende) oder Break */
  1406.  
  1407.   /* Jetzt muß nur noch der Cursor an die richtige Position gesetzt
  1408.      werden. Diese wurde göücklicherweise in new_tl und new_sc
  1409.      mitgeschrieben. */
  1410.   check_buff();
  1411.   gotox (new_tl);
  1412.   akt_winp->screencol = new_sc;
  1413.   if (!adapt_screen (1))  /* Wenn adapt_screen kein show_win gemacht hat, */
  1414.     show_win (W_AKT);     /* muß das an dieser Stelle nachgeholt werden   */
  1415.  
  1416.   return !error;
  1417. }
  1418.