1/****************************************************************/
2/* file logscr.inc
3
4ARIBAS interpreter for Arithmetic
5Copyright (C) 1996 O.Forster
6
7This program is free software; you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
9the Free Software Foundation; either version 2 of the License, or
10(at your option) any later version.
11
12This program is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with this program; if not, write to the Free Software
19Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20
21Address of the author
22
23    Otto Forster
24    Math. Institut der LMU
25    Theresienstr. 39
26    D-80333 Muenchen, Germany
27
28Email   forster@mathematik.uni-muenchen.de
29*/
30/****************************************************************/
31
32/*
33** logscr.inc
34** logical screen
35**
36** date of last change
37** 1995-03-22: Bremse in L_strappend
38** 1998-01-03: cosmetic changes
39** 1998-05-31: #define-s for Win32GUI
40** 2002-02-16: L_text2blatt, L_insidecomment
41*/
42
43#if defined(UNiXorGCC) || defined(Win32GUI)
44#define LINELEN     162
45#define BUFLINES    200
46#else
47#define LINELEN     82
48#define BUFLINES    50
49#endif
50
51
52typedef char zeile[LINELEN];
53
54#define LOCAL static
55LOCAL  zeile *Blatt = NULL;
56
57/*
58** Zeilen-Nummern beginnen bei 0
59** Die einzelnen Zeilen haben in Position 0 die Zeilenlaenge
60** Die Strings werden durch ein Null-Byte abgeschlossen
61** Es gilt also stets fuer ptr = Blatt[n], dass ptr[ptr[0]+1] = 0
62*/
63
64LOCAL int L_iniscr  _((zeile *Buf, char *prompt));
65LOCAL int L_insert  _((int n));
66LOCAL void L_strappend  _((int n, int i, char *str));
67LOCAL int L_len     _((int n));
68LOCAL int L_pagelen _((void));
69LOCAL int L_efflen  _((void));
70LOCAL int L_efffirst    _((void));
71LOCAL int L_indent  _((int n));
72LOCAL int L_trimlen _((int n));
73LOCAL int L_compress    _((void));
74LOCAL int L_expand  _((byte *buf));
75LOCAL char *L_linerest  _((int n, int k));
76LOCAL char *L_line  _((int n));
77
78PRIVATE void L_nulline  _((int n));
79PRIVATE void L_linecpy  _((char *z1, char *z2));
80
81PRIVATE int L_makebstream(int lineno);
82PRIVATE int L_bnextch(void);
83PRIVATE int L_bpeekch(void);
84PRIVATE int L_bskiptoeol(void);
85PRIVATE int L_bskiptoeostr(void);
86PRIVATE int L_bstream(int mode);
87LOCAL int L_insidecomment(int lineno);
88
89#ifdef genWinGUI
90LOCAL int L_text2blatt(char *buf);
91#endif
92
93#ifdef PAGEINPUT
94LOCAL void L_clreol _((int n, int i));
95LOCAL void L_delete _((int n));
96LOCAL int L_spaceins    _((int n, int i, int anz, int bound));
97LOCAL int L_charins _((int n, int i, int ch, int bound));
98LOCAL int L_chardel _((int n, int i));
99LOCAL int L_charndel    _((int n, int i, int anz));
100LOCAL int L_nextgroup   _((int n, int k));
101LOCAL int L_prevgroup   _((int n, int k));
102LOCAL int L_nextword    _((int n, int k));
103LOCAL int L_merge   _((int n, int bound));
104LOCAL int L_retbreak    _((int n, int k));
105#endif
106
107LOCAL int Col0;        /* in der 0-ten Zeile nach Prompt */
108PRIVATE int Actlen = 0;
109/*--------------------------------------------------------------------*/
110LOCAL int L_iniscr(Buf,prompt)
111zeile *Buf;
112char *prompt;
113{
114    int n;
115    int ch;
116    char *ptr;
117
118    Blatt = Buf;
119    Actlen = 1;
120    ptr = Blatt[0];
121    n = 0;
122    while((ch = *prompt++)) {
123        n++;
124        ptr[n] = ch;
125    }
126    ptr[n+1] = 0;
127    ptr[0] = n;
128    Col0 = n+1;
129    for(n=1; n<BUFLINES; n++)
130        L_nulline(n);
131    return(Col0);
132}
133/*-------------------------------------------------------------------*/
134PRIVATE void L_nulline(n)
135int n;
136{
137    char *ptr;
138
139    ptr = Blatt[n];
140    *ptr++ = 0;
141    *ptr = 0;
142}
143/*-------------------------------------------------------------------*/
144/*
145** Fuegt in Blatt eine neue leere n-te Zeile ein;
146** alle folgenden Zeilen werden um eins nach unten verschoben
147** Es wird vorausgesetzt, dass n <= Actlen < BUFLINES
148*/
149LOCAL int L_insert(n)
150int n;
151{
152    int i;
153
154    if(Actlen >= BUFLINES)
155        return(0);
156    for(i=Actlen; i>n; i--)
157        L_linecpy(Blatt[i],Blatt[i-1]);
158    L_nulline(n);
159    Actlen++;
160    return(1);
161}
162/*-------------------------------------------------------------------*/
163PRIVATE void L_linecpy(z1,z2)
164char *z1, *z2;
165{
166    *z1++ = *z2++;
167    strcpy(z1,z2);
168}
169/*-------------------------------------------------------------------*/
170/*
171** Schreibt in Zeile n ab Position i den String str;
172** Es wird vorausgesetzt, dass n < Actlen und 1 <= i < LINELEN-1
173** Falls str zu lang ist, wird abgeschnitten
174*/
175LOCAL void L_strappend(n,i,str)
176int n,i;
177char *str;
178{
179    char *ptr, *ptr0;
180
181    ptr0 = Blatt[n];
182    ptr = ptr0 + i;
183    while((*ptr++ = *str++) && (i < LINELEN-1))
184        i++;
185    ptr0[i] = 0;
186    ptr0[0] = i - 1;
187}
188/*-------------------------------------------------------------------*/
189/*
190** Laenge der n-ten Zeile
191*/
192LOCAL int L_len(n)
193int n;
194{
195    return(Blatt[n][0]);
196}
197/*-------------------------------------------------------------------*/
198LOCAL int L_pagelen()
199{
200    return(Actlen);
201}
202/*-------------------------------------------------------------------*/
203/*
204** effektive Laenge; leere Zeilen am Ende zaehlen nicht
205*/
206LOCAL int L_efflen()
207{
208    int n;
209
210    n = Actlen;
211    while(n > 1 && Blatt[n-1][0] == 0)
212        n--;
213    return(n);
214}
215/*-------------------------------------------------------------------*/
216/*
217** effektive erste Zeile
218*/
219LOCAL int L_efffirst()
220{
221    int i;
222
223    if(Blatt[0][0] > Col0)
224        return(0);
225    for(i=1; i<Actlen; i++) {
226        if(Blatt[i][0] != 0)
227            return(i);
228    }
229    return(0);
230}
231/*-------------------------------------------------------------------*/
232/*
233** Anzahl der Spaces am Anfang von Zeile n
234*/
235LOCAL int L_indent(n)
236int n;
237{
238    char *ptr;
239    int k;
240
241    if(n >= Actlen)
242        return(0);
243    ptr = Blatt[n];
244    k = (n > 0 ? 1 : Col0);
245    while(ptr[k] == ' ')
246        k++;
247    return(k-1);
248}
249/*-------------------------------------------------------------------*/
250/*
251** Laenge der Zeile n ohne Leerzeichen am Ende
252*/
253LOCAL int L_trimlen(n)
254int n;
255{
256    int k, k0;
257    char *ptr;
258
259    if(n >= Actlen)
260        return(0);
261    ptr = Blatt[n];
262    k = ptr[0];
263    k0 = (n > 0 ? 1 : Col0);
264    while(k >= k0 && ptr[k] == ' ')
265        k--;
266    return(k);
267}
268/*-------------------------------------------------------------------*/
269/*
270** Komprimiert den Text in Blatt durch Ersetzen von Leerzeichen
271** am Anfang der Zeile durch verallgemeinerte TAB's.
272** Der entstehende String wird in den Puffer Blatt geschrieben.
273** Rueckgabewert: Laenge des entstehenden Strings
274*/
275LOCAL int L_compress()
276{
277    char *ptr1, *str;
278    int i, k, len, n;
279
280    n = L_efflen();
281    ptr1 = Blatt[0];
282    for(i=0; i<n; i++) {
283        k = L_indent(i);
284        len = L_trimlen(i) - k;
285        str = L_linerest(i,k+1);
286        if(k < TABESC-1) {
287            *ptr1++ = k+1;
288        }
289        else {
290            *ptr1++ = TABESC;
291            *ptr1++ = k;
292        }
293        while(--len >= 0)
294            *ptr1++ = *str++;
295    }
296    *ptr1 = 0;
297    return(ptr1 - Blatt[0]);
298}
299/*-------------------------------------------------------------------*/
300/*
301** Umkehrung von L_compress
302** Der komprimierte String steht in buf; das Ergebnis in Blatt
303** Rueckgabewert: Laenge in Zeilen;
304*/
305LOCAL int L_expand(buf)
306byte *buf;
307{
308    int i, k, n;
309    int ch;
310    char *ptr;
311
312    for(n=0, ch=*buf++; ch && n<BUFLINES; n++) {
313        if(ch < TABESC)
314            k = ch - 1;
315        else
316            k = *buf++;
317        ptr = Blatt[n];
318        i = (n > 0 ? 1 : Col0);
319        while(i <= k)
320            ptr[i++] = ' ';
321        while((ch = *buf++) > TABESC)
322            ptr[i++] = ch;
323        ptr[i] = 0;
324        ptr[0] = i-1;
325    }
326    Actlen = n;
327    return(n);
328}
329/*-------------------------------------------------------------------*/
330LOCAL char *L_linerest(n,k)
331int n, k;
332{
333    char *ptr;
334
335    ptr = Blatt[n];
336    if(k > ptr[0])
337        k = ptr[0] + 1;
338    return(ptr + k);
339}
340/*-------------------------------------------------------------------*/
341LOCAL char *L_line(n)
342int n;
343{
344    char *ptr;
345
346    ptr = Blatt[n];
347    return(ptr + 1);
348}
349/*-------------------------------------------------------------------*/
350#ifdef genWinGUI
351/*-------------------------------------------------------------------*/
352/*
353** copies text from buffer buf to Blatt
354** return value: actual length of Blatt
355**               or -1 if text is too long
356*/
357LOCAL int L_text2blatt(buf)
358char *buf;
359{
360    int i, n;
361    int ch;
362    char *ptr;
363
364    for(n=0, ch=*buf++; ch && n<BUFLINES; n++) {
365        ptr = Blatt[n];
366        i = (n > 0 ? 1 : Col0);
367        while(ch && ch != '\n' && i<LINELEN-2) {
368            ptr[i++] = ch;
369            ch = *buf++;
370        }
371        while(ch == '\n' || ch == '\r') {
372            ch = *buf++;
373        }
374        ptr[i] = 0;
375        ptr[0] = i-1;
376    }
377    Actlen = n;
378    if(ch)
379        return(-1);
380    else
381        return(n);
382}
383/*-------------------------------------------------------------------*/
384#endif
385/*-------------------------------------------------------------------*/
386/*
387** Tests whether line with number lineno in Blatt
388** is inside a comment
389*/
390LOCAL int L_insidecomment(lineno)
391int lineno;
392{
393    int insidecomm = 0;
394    int ch;
395
396    if(L_makebstream(lineno) < 0)
397        return(-1);
398    ch = 'A';
399    while(ch != EOF) {
400        ch = L_bnextch();
401        switch(ch) {
402        case '#':
403            if(insidecomm)
404                break;
405            L_bskiptoeol();
406            if(L_bpeekch() == EOF)
407                return(1);
408            else
409                insidecomm = 0;
410            break;
411        case '(':
412            if(insidecomm)
413                break;
414            ch = L_bnextch();
415            if(ch == '*')
416                insidecomm = 1;
417            break;
418        case '*':
419            if(!insidecomm)
420                break;
421            ch = L_bpeekch();
422            if(ch == ')') {
423                insidecomm = 0;
424                L_bnextch();
425            }
426            break;
427        case '"':
428            if(!insidecomm)
429                L_bskiptoeostr();
430            break;
431        default:
432            break;
433        }
434    }
435    return(insidecomm);
436}
437/*-------------------------------------------------------------------*/
438PRIVATE int L_makebstream(lineno)
439int lineno;
440{
441    return(L_bstream(lineno));
442}
443/*-------------------------------------------------------------------*/
444PRIVATE int L_bnextch()
445{
446    return L_bstream(-1);
447}
448/*-------------------------------------------------------------------*/
449PRIVATE int L_bpeekch()
450{
451    return L_bstream(-2);
452}
453/*-------------------------------------------------------------------*/
454PRIVATE int L_bskiptoeol()
455{
456    return L_bstream(-3);
457}
458/*-------------------------------------------------------------------*/
459PRIVATE int L_bskiptoeostr()
460{
461    return L_bstream(-4);
462}
463/*-------------------------------------------------------------------*/
464PRIVATE int L_bstream(mode)
465int mode;
466{
467    static int curline = 0;
468    static int curlen = 0;
469    static int lastline = 0;
470    static int col = 0;
471    int ch;
472
473    if(mode >= 0) {     /* makebstream */
474        if(Blatt == NULL)
475            return(-1);
476        lastline = mode;
477        if(lastline >= BUFLINES)
478            lastline = BUFLINES-1;
479        curline = 0;
480        curlen = Blatt[curline][0];
481        col = 1;
482        return(lastline);
483    }
484  nochmal:
485    switch(mode) {
486    case -1:    /* bnextch */
487        if(curline > lastline)
488            return(EOF);
489        else if(col > curlen) {
490            curline++;
491            col = 1;
492            if(curline <= lastline)
493                curlen = Blatt[curline][0];
494            else
495                curlen = 0;
496            return(EOL);
497        }
498        else {
499            ch = Blatt[curline][col];
500            col++;
501            return(ch);
502        }
503        break;
504    case -2:    /* bpeekch */
505        if(curline > lastline)
506            return(EOF);
507        else if(col > curlen)
508            return(EOL);
509        else
510            return Blatt[curline][col];
511        break;
512    case -3:    /* skiptoeol */
513        curline++;
514        col = 1;
515        if(curline <= lastline)
516            curlen = Blatt[curline][0];
517        else
518            curlen = 0;
519        return(EOL);
520        break;
521    case -4:    /* skip to end of string */
522        if(col > curlen || curline > lastline) {
523            mode = -1;
524            goto nochmal;
525        }
526        while(col <= curlen) {
527            ch = Blatt[curline][col];
528            col++;
529            if(ch == '"')
530                break;
531        }
532        break;
533    default:
534        break;
535    }
536    return(-1);
537}
538/*-------------------------------------------------------------------*/
539/*-------------------------------------------------------------------*/
540#ifdef PAGEINPUT
541/*-------------------------------------------------------------------*/
542LOCAL void L_clreol(n,i)
543int n, i;
544{
545    char *ptr;
546
547    ptr = Blatt[n];
548    ptr[i] = 0;
549    ptr[0] = i - 1;
550}
551/*-------------------------------------------------------------------*/
552/*
553** Loescht in Blatt die n-te Zeile;
554** alle folgenden Zeilen werden um eins nach oben verschoben
555*/
556LOCAL void L_delete(n)
557int n;
558{
559    int i;
560
561    if(n >= Actlen)
562        return;
563    for(i=n+1; i<Actlen; i++)
564        L_linecpy(Blatt[i-1],Blatt[i]);
565    Actlen--;
566    L_nulline(Actlen);
567}
568/*-------------------------------------------------------------------*/
569/*
570** Fuegt in Zeile n ab Position i insgesamt n Spaces ein, falls
571** dadurch Zeilenlaenge nicht groesser als bound wird.
572** Sonst (oder falls  i > Zeilenlaenge), keine Aktion, Rueckgabewert 0
573** Andernfalls Rueckgabewert anz
574*/
575LOCAL int L_spaceins(n,i,anz,bound)
576int n,i,anz,bound;
577{
578    char *ptr;
579    int k, len;
580
581    ptr = Blatt[n];
582    len = ptr[0];
583    if(n >= Actlen || i > len || len+anz > bound)
584        return(0);
585    ptr[0] = len + anz;
586    for(k=len+1; k>=i; k--)
587        ptr[k+anz] = ptr[k];
588    for(k=0; k<anz; k++)
589        ptr[i+k] = ' ';
590    return(anz);
591}
592/*-------------------------------------------------------------------*/
593/*
594** Fuegt in Zeile n an der Stelle i den Buchstaben ch ein, falls
595** dadurch die Zeile nicht laenger als bound wird.
596** Falls bound ueberschritten wuerde, keine Aktion und Rueckgabewert 0.
597** Sonst: Rueckgebewert neue Zeilenlaenge.
598** Falls i > Zeilenlaenge+1, werden vor ch Leerzeichen eingefuellt
599*/
600LOCAL int L_charins(n,i,ch,bound)
601int n,i,ch,bound;
602{
603    char *ptr;
604    int k, len;
605
606    ptr = Blatt[n];
607    len = ptr[0];
608    if(len >= bound)
609        return(0);
610    if(i <= len) {
611        len++;
612        for(k=len; k>=i; k--)
613            ptr[k+1] = ptr[k];
614        ptr[i] = ch;
615    }
616    else {
617        for(k=len+1; k<i; k++)
618            ptr[k] = ' ';
619        ptr[i] = ch;
620        ptr[i+1] = 0;
621        len = i;
622    }
623    ptr[0] = len;
624    return(len);
625}
626/*-------------------------------------------------------------------*/
627/*
628** Loescht in Zeile n den i-ten Buchstaben und zieht alle
629** folgenden um eins nach vorne
630*/
631LOCAL int L_chardel(n,i)
632int n,i;
633{
634    return(L_charndel(n,i,1));
635}
636/*-------------------------------------------------------------------*/
637/*
638** Loescht in Zeile n ab Position i insgesamt anz Buchstaben
639** und zieht die folgenden um anz nach vorne
640** Es wird vorausgesetzt, dass i >= anz ist
641** Falls i > Zeilenlaenge, werden entsprechend weniger
642** Buchstaben gestrichen.
643** Rueckgabewert: Anzahl der tatsaechlich entfernten Zeichen
644*/
645LOCAL int L_charndel(n,i,anz)
646{
647    char *ptr;
648    int k, len;
649
650    ptr = Blatt[n];
651    len = ptr[0];
652    if(i > len)
653        return(0);
654    else if(i >= len - anz + 1) {
655        ptr[i] = 0;
656        ptr[0] = i - 1;
657        return(len - i + 1);
658    }
659    else {
660        ptr[0] = len - anz;
661        for(k=i; k<=len+1-anz; k++)
662            ptr[k] = ptr[k+anz];
663        return(anz);
664    }
665}
666/*-------------------------------------------------------------------*/
667/*
668** Fuer Cursor-Bewegung mit CTRL-Pfeilrechts:
669** Gibt Position der naechsten Gruppe von Zeichen ohne Spaces
670*/
671LOCAL int L_nextgroup(n,k)
672int n,k;
673{
674    char *ptr;
675    int ch;
676
677    if(n >= Actlen)
678        return(k);
679    ptr = Blatt[n];
680    if(k > ptr[0])
681        return(k);
682    while((ch = ptr[k]) && ch != ' ')
683        k++;
684    while((ch = ptr[k]) && ch == ' ')
685        k++;
686    return(k);
687}
688/*-------------------------------------------------------------------*/
689/*
690** Fuer Cursor-Bewegung mit CTRL-Pfeillinks:
691** Gibt Anfang der vorherigen Gruppe von Zeichen ohne Spaces
692*/
693LOCAL int L_prevgroup(n,k)
694int n,k;
695{
696    char *ptr;
697    int len;
698    int k0;
699
700    if(n >= Actlen)
701        return(k);
702    k0 = (n > 0 ? Col0 : 1);
703
704    ptr = Blatt[n];
705    len = ptr[0];
706    if(len == 0)
707        return(1);
708    else if(k > len)
709        k = len;
710    else if(k > k0)
711        k--;
712    while(k > k0 && ptr[k] == ' ')
713        k--;
714    while(k > k0 && ptr[k-1] != ' ')
715        k--;
716    return(k);
717}
718/*-------------------------------------------------------------------*/
719/*
720** gibt Postion des Anfangs des naechsten Wortes fuer das
721** Kommando Wort loeschen.
722** Es wird bis zu dieser Position ausschliesslich geloescht
723**
724*/
725LOCAL int L_nextword(n,k)
726int n,k;
727{
728    char *ptr;
729    int ch;
730
731    if(n >= Actlen)
732        return(k);
733    ptr = Blatt[n];
734    if(k > ptr[0])
735        return(k);
736    ch = ptr[k];
737    if(isdigalfa(ch)) {
738        k++;
739        while((ch = ptr[k]) && isdigalfa(ch))
740            k++;
741    }
742    else if(ch != ' ') {
743        k++;
744        while((ch = ptr[k]) && ch != ' ' && !isdigalfa(ch))
745            k++;
746    }
747    else {
748        k++;
749        while(ptr[k] == ' ')
750            k++;
751    }
752    return(k);
753}
754/*-------------------------------------------------------------------*/
755/*
756** Die Zeile n wird mit der Zeile n+1 zusammengefuegt und der
757** Rest des Blattes nach oben gezogen.
758** Voraussetzung ist, dass die Summe der Zeilenlaengen
759** <= bound ist. In diesem Fall ist der Rueckgabewert die
760** Position des Anfangs der angehaengten Zeile in Zeile n.
761** Falls die Summe der Zeilenlaengen > bound ist, wird
762** das Blatt unveraendert gelassen und 0 zurueckgegeben.
763** Ausserdem wird vorausgesetzt, dass die Zeile n+1 existiert;
764** andernfalls keine Aktion und Rueckgabewert 0.
765*/
766LOCAL int L_merge(n, bound)
767int n, bound;
768{
769    int k;
770    char *str;
771
772    if(n >= L_pagelen() - 1)
773        return(0);
774    k = L_len(n);
775    if(k + L_len(n+1) > bound)
776        return(0);
777    else {
778        str = L_linerest(n+1,1);
779        L_strappend(n,k+1,str);
780        L_delete(n+1);
781        return(k+1);
782    }
783}
784/*-------------------------------------------------------------------*/
785/*
786** Fuehrt einen Umbruch (wie bei Betaetigung der Return-Taste)
787** von Zeile n ab Position k in eine neuzuschaffende naechste
788** Zeile durch.
789** Falls Blatt zu lang wuerde, wird keine Aktion durchgefuehrt
790** und 0 zurueckgegeben; sonst Rueckgabewert 1.
791*/
792LOCAL int L_retbreak(n,k)
793int n,k;
794{
795    char *str;
796    int len;
797
798    len = L_pagelen();
799    if(len >= BUFLINES || n >= len)
800        return(0);
801    L_insert(n+1);
802    if(k <= L_len(n)) {
803        str = L_linerest(n,k);
804        L_strappend(n+1,1,str);
805        L_clreol(n,k);
806    }
807    return(1);
808}
809/*-------------------------------------------------------------------*/
810#endif /* PAGEINPUT */
811#undef LOCAL
812/*********************************************************************/
813