Annotation of libwww/LineMode/src/GridText.c, revision 1.11
1.1 timbl 1: /* Character grid hypertext object
2: ** ===============================
3: */
4:
5: /* Implements:
6: */
7: #include "HText.h"
8:
1.11 ! howcome 9: /* HWL 18/7/94: applied patch from agl@glas2.glas.apc.org (Anton Tropashko) */
! 10: #ifdef CYRILLIC
! 11: #include "a_stdio.h"
! 12: #endif
! 13:
1.1 timbl 14: #include <assert.h>
15: #include <ctype.h>
16: #include "HTUtils.h"
17: #include "HTString.h"
18: #include "GridText.h"
19: #include "HTFont.h"
20: #include "HTBrowse.h"
21: #include "HTStream.h"
1.10 timbl 22: #include "GridStyle.h"
1.1 timbl 23:
24:
25: struct _HTStream { /* only know it as object */
26: CONST HTStreamClass * isa;
27: /* ... */
28: };
29:
30: #define MAX_LINE HTScreenWidth /* No point in accumulating more */
31: #ifdef THINK_C
32: #define LOADED_LIMIT 3 /* For now, save last two texts */
33: #else
34: #define LOADED_LIMIT 6 /* For now, save last five texts */
35: #endif
36:
37: /* From main program:
38: */
1.2 timbl 39: extern char * start_reference; /* Template for anchors */
40: extern char * end_reference; /* Template for anchors */
1.1 timbl 41: extern char * end_mark; /* Template for end */
42: extern int HTScreenWidth, /* The screen width */
43: HTScreenHeight; /* The screen height */
44: extern BOOL display_anchors; /* anchor will be shown in text? */
45:
46: #ifdef CURSES
47: #define DISPLAY_LINES (HTScreenHeight)
48: #define TITLE_LINES 0
49: #else
50: #define DISPLAY_LINES (HTScreenHeight - 1) /* Exclude prompt line */
51: #define TITLE_LINES 1
52: #endif
53:
54:
55: /* From default style sheet:
56: */
57: extern HTStyleSheet * styleSheet; /* Default or overridden */
58:
59:
60: /* Exports
61: */
62: PUBLIC HText * HTMainText = 0; /* Equivalent of main window */
63: PUBLIC HTParentAnchor * HTMainAnchor = 0; /* Anchor for HTMainText */
64:
65: typedef struct _line {
66: struct _line *next;
67: struct _line *prev;
68: short unsigned offset; /* Implicit initial spaces */
69: short unsigned size; /* Number of characters */
70: BOOL split_after; /* Can we split after? */
71: BOOL bullet; /* Do we bullet? */
72: char data[1]; /* Space for terminator at least! */
73: } HTLine;
74:
75: #define LINE_SIZE(l) (sizeof(HTLine)+(l)) /* allow for terminator */
76:
77: typedef struct _TextAnchor {
78: struct _TextAnchor * next;
79: int number; /* For user interface */
80: int start; /* Characters */
81: int extent; /* Characters */
82: HTChildAnchor * anchor;
83: } TextAnchor;
84:
85:
86: /* Notes on struct _Htext:
87: ** next_line is valid iff state is false.
88: ** top_of_screen line means the line at the top of the screen
89: ** or just under the title if there is one.
90: */
91: struct _HText {
92: HTParentAnchor * node_anchor;
93: char * title;
94: HTLine * last_line;
95: int lines; /* Number of them */
96: int chars; /* Number of them */
97: TextAnchor * first_anchor; /* Singly linked list */
98: TextAnchor * last_anchor;
99: int last_anchor_number; /* user number */
100: /* For Internal use: */
101: HTStyle * style; /* Current style */
102: int display_on_the_fly; /* Lines left */
1.3 timbl 103: BOOL all_pages; /* Loop on the fly */
1.1 timbl 104: int top_of_screen; /* Line number */
105: HTLine * top_of_screen_line; /* Top */
106: HTLine * next_line; /* Bottom + 1 */
107: int permissible_split; /* in last line */
108: BOOL in_line_1; /* of paragraph */
109: BOOL stale; /* Must refresh */
110:
111: HTStream* target; /* Output stream */
112: HTStreamClass targetClass; /* Output routines */
113: };
114:
115:
116: #define PUTC(c) (*text->targetClass.put_character)(text->target, c)
117: #define PUTS(s) (*text->targetClass.put_string)(text->target, s)
118:
119: /* Boring static variable used for moving cursor across
120: */
121:
122: #define SPACES(n) (&space_string[HTScreenWidth - (n)])
123: /* String containing blank spaces only */
124: PRIVATE char * space_string;
125:
126: PRIVATE HTStyle default_style =
127: { 0, "(Unstyled)", "",
128: (HTFont)0, 1.0, HT_BLACK, 0, 0,
129: 0, 0, 0, HT_LEFT, 1, 0, 0,
130: NO, NO, 0, 0, 0 };
131:
132:
133: PUBLIC void clear_screen NOPARAMS; /* Forward */
134:
135: PRIVATE HTList * loaded_texts; /* A list of all those in memory */
136:
137: /* Creation Method
138: ** ---------------
1.3 timbl 139: **
140: ** Interactive version
141: **
1.1 timbl 142: */
143: PUBLIC HText * HText_new ARGS1(HTParentAnchor *,anchor)
144: {
145: HTLine * line;
146: HText * self = (HText *) malloc(sizeof(*self));
147: if (!self) return self;
148:
149: if (!loaded_texts) loaded_texts = HTList_new();
150: HTList_addObject(loaded_texts, self);
151: if (HTList_count(loaded_texts) >= LOADED_LIMIT) {
152: if (TRACE) fprintf(stderr, "GridText: Freeing off cached doc.\n");
153: HText_free((HText *)HTList_removeFirstObject(loaded_texts));
154: }
155:
156: line = self->last_line = (HTLine *)malloc(LINE_SIZE(MAX_LINE));
157: if (line == NULL) outofmem(__FILE__, "HText_New");
158: line->next = line->prev = line;
159: line->offset = line->size = 0;
160: self->lines = self->chars = 0;
161: self->title = 0;
162: self->first_anchor = self->last_anchor = 0;
163: self->style = &default_style;
164: self->top_of_screen = 0;
165: self->node_anchor = anchor;
166: self->last_anchor_number = 0; /* Numbering of them for references */
167: self->stale = YES;
168:
169: self->target = NULL;
170:
171: HTAnchor_setDocument(anchor, (HyperDoc *)self);
172:
173: clear_screen();
174: HTMainText = self;
175: HTMainAnchor = anchor;
176: self->display_on_the_fly = DISPLAY_LINES;
1.3 timbl 177: self->all_pages = NO; /* One page at a time on the fly */
1.1 timbl 178:
179: if (!space_string) { /* Make a blank line */
180: char *p;
181: space_string = (char *)malloc(HTScreenWidth+1);
182: if (space_string == NULL) outofmem(__FILE__, "HText_New");
183: for (p=space_string; p<space_string+HTScreenWidth; p++)
184: *p = ' '; /* Used for printfs later */
185: space_string[HTScreenWidth] = '\0';
186: }
187:
188: return self;
189: }
190:
191:
192: /* Creation Method 2
193: ** ---------------
194: **
1.4 timbl 195: ** Non-interative OR interactive if stream is NULL
1.1 timbl 196: ** Stream is assumed open and left open.
197: */
198: PUBLIC HText * HText_new2 ARGS2(
199: HTParentAnchor *, anchor,
200: HTStream*, stream)
201:
202: {
1.3 timbl 203: HText * me = HText_new(anchor);
1.1 timbl 204:
205: if (stream) {
1.3 timbl 206: me->target = stream;
207: me->targetClass = *stream->isa; /* copy action procedures */
1.4 timbl 208: me->all_pages = YES; /* Display whole file on the fly */
1.3 timbl 209: }
210: return me;
1.1 timbl 211: }
212:
213:
214: /* Free Entire Text
215: ** ----------------
216: */
217: PUBLIC void HText_free ARGS1(HText *,self)
218: {
219: HTAnchor_setDocument(self->node_anchor, (HyperDoc *)0);
220:
221: while(YES) { /* Free off line array */
222: HTLine * l = self->last_line;
223: l->next->prev = l->prev;
224: l->prev->next = l->next; /* Unlink l */
225: self->last_line = l->prev;
226: free(l);
227: if (l == self->last_line) break; /* empty */
228: };
229:
230: while(self->first_anchor) { /* Free off anchor array */
231: TextAnchor * l = self->first_anchor;
232: self->first_anchor = l->next;
233: free(l);
234: }
235: free(self);
1.8 frystyk 236: if (self == HTMainText) /* Henrik 24/02-94 */
237: HTMainText = NULL;
1.1 timbl 238: }
239:
240:
241: /* Display Methods
242: ** ---------------
243: */
244: /* Clear the screen (on screen-mode systems)
245: ** ----------------
246: */
247: PUBLIC void clear_screen NOARGS
248: {
1.8 frystyk 249:
1.1 timbl 250: if (TRACE) return; /* in trace mode, don't clear trace away */
251: #ifdef CURSES
252: if (w_text != NULL) {
253: wmove(w_text,0,0);
254: wclear(w_text);
255: }
256: #else
257: #ifdef VM
258: #ifdef NEWLIB
259: int newlib_ncmd = 2;
260: char newlib_cmd[2][80];
261:
262: memset(newlib_cmd, ' ', sizeof(newlib_cmd));
263: strncpy(newlib_cmd[0], "clear", 5); /* Clear screen */
264: strncpy(newlib_cmd[1], "quit", 4); /* Leave newlib */
265: newlib(newlib_cmd, &newlib_ncmd); /* Execute command */
266:
267: #else /* not NEWLIB - real VM */
268: system("CLRSCRN"); /* Clear screen */
269: #endif /* not NEWLIB */
270: #else /* Not VM */
271: /* Do nothing */
272: #endif /* Not VM */
273: #endif /* Not CURSES */
274: if (HTMainText) HTMainText->stale = YES;
275: }
276:
277:
278: /* Output a line
279: ** -------------
280: */
281: PRIVATE void display_line ARGS2(HText *,text, HTLine *,line)
282: {
283: #ifdef CURSES
284: int y, x;
285:
286: waddstr(w_text, SPACES(line->offset));
287: waddstr(w_text, line->data);
288: getyx(w_text, y, x);
289: if (y < DISPLAY_LINES-1) {
290: wmove(w_text, ++y, 0);
291: }
292: #else
293: if (!text->target)
1.11 ! howcome 294: {
! 295: #ifdef CYRILLIC
! 296: /* HWL 18/7/94: applied patch from agl@glas2.glas.apc.org (Anton Tropashko) */
! 297: a_print(SPACES(line->offset),H,stdout);
! 298: a_print(line->data,H,stdout);
! 299: fputc('\n',stdout);
! 300: #else
1.1 timbl 301: printf("%s%s\n", SPACES(line->offset), line->data);
1.11 ! howcome 302: #endif
! 303: }
1.1 timbl 304: else {
305: PUTS(SPACES(line->offset));
306: PUTS(line->data);
307: PUTC('\n');
308: }
309: #endif
310:
311: }
312:
313: /* Output the title line
314: ** ---------------------
315: */
316: PRIVATE void display_title ARGS1(HText *,text)
317: {
318: CONST char * title = HTAnchor_title(text->node_anchor);
319: char percent[20], format[20];
320: if (text->lines > (DISPLAY_LINES-1)) {
321: #ifdef NOPE
322: sprintf(percent, " (p%d of %d)",
323: (text->top_of_screen/(DISPLAY_LINES-1)) + 1,
324: (text->lines-1)/(DISPLAY_LINES-1) + 1);
325: sprintf(percent, " (%d%%)",
326: 100*(text->top_of_screen+DISPLAY_LINES-1)/ /* Seen */
327: (text->lines)); /* Total */
328: #else
329: sprintf(percent, " (%d/%d)",
330: text->top_of_screen+DISPLAY_LINES-1, /* Seen */
331: text->lines); /* Total */
332: #endif
333: } else {
334: percent[0] = 0; /* Null string */
335: }
336:
337: sprintf(format, "%%%d.%ds%%s\n", /* Generate format string */
338: (int)(HTScreenWidth-strlen(percent)),
339: (int)(HTScreenWidth-strlen(percent)) );
340: /* if (TRACE) fprintf(stderr, "FORMAT IS `%s'\n", format); */
341: #ifdef CURSES
342: mvwprintw(w_top, 0, 0, format, title, percent);
343: wrefresh(w_top);
344: #else
345: if (!text->target) printf(format, title, percent);
346: else {
347: char * line = (char*)malloc(HTScreenWidth+10);
348: sprintf(line, format, title, percent);
349: PUTS(line);
350: free(line);
351: }
352: #endif
353: }
354:
355:
356: /* Fill the screen with blank after the file
357: ** --------------------------
358: */
359: PRIVATE void fill_screen ARGS2(HText *, text, int,n)
360: {
361: if (n<=0 || n>1000) return; /* Large value means no pagination */
362: if (text->target) return;
363: #ifdef CURSES
364: waddstr(w_text, end_mark);
365: wclrtobot(w_text);
366: wrefresh(w_text);
367: #else
368: #ifndef VIOLA
369: if (!text->target) printf("%s\n", end_mark);
370: else { PUTS(end_mark); PUTC('\n'); }
371: n--;
372:
373: for (; n; n--) {
374: if (!text->target) printf("\n");
375: else PUTC('\n');
376: }
377: #endif
378: #endif /* Not CURSES */
379: }
380:
381:
382: /* Output a page
383: ** -------------
384: */
385: PRIVATE void display_page ARGS2(HText *,text, int,line_number)
386: {
387: HTLine * line = text->last_line->prev;
388: int i;
389: CONST char * title = HTAnchor_title(text->node_anchor);
390: int lines_of_text = title ? (DISPLAY_LINES-TITLE_LINES) : DISPLAY_LINES;
391: int last_screen = text->lines - lines_of_text;
392:
393: /* Constrain the line number to be within the document
394: */
395: if (text->lines <= lines_of_text) line_number = 0;
396: else if (line_number>last_screen) line_number = last_screen;
397: else if (line_number < 0) line_number = 0;
398:
399: for(i=0, line = text->last_line->next; /* Find line */
400: i<line_number && (line!=text->last_line);
401: i++, line=line->next) /* Loop */ assert(line->next != NULL);
402:
403: while((line!=text->last_line) && (line->size==0)) { /* Skip blank lines */
404: assert(line->next != NULL);
405: line = line->next;
406: line_number ++;
407: }
408:
409: /* Can we just scroll to it?
410: */
411: #ifndef VM /* No scrolling */
412: if (!text->stale && (line_number>=text->top_of_screen) &&
413: (line_number < text->top_of_screen + DISPLAY_LINES)) { /* Yes */
414: lines_of_text = line_number - text->top_of_screen;
415: line = text->next_line;
416: text->top_of_screen = line_number;
417: #ifdef CURSES
418: scrollok(w_text, TRUE);
419: for (i = 0; i < lines_of_text; i++) {
420: scroll(w_text);
421: }
422: #endif
423: } else
424: #endif
425: {
426: clear_screen(); /* No */
427: text->top_of_screen = line_number;
428: if (title) display_title(text);
429: }
430:
431: /* Bug: when we scroll to a part slightly futher down a page which previously
432: fitted all on one screen including the [End], the code below will add an
433: extra [End] to the screen, giving a total of two, one underneath the other.
434: */
435:
436: /* print it
437: */
438: if (line) {
439: for(i=0;
440: (i< lines_of_text) && (line != text->last_line); i++) {
441: assert(line != NULL);
442: display_line(text, line);
443: line = line->next;
444: }
445: fill_screen(text, lines_of_text - i);
446: }
447:
448: text->next_line = line; /* Line after screen */
449: text->stale = NO; /* Display is up-to-date */
450: }
451:
452:
453: /* Object Building methods
454: ** -----------------------
455: **
456: ** These are used by a parser to build the text in an object
457: */
458: PUBLIC void HText_beginAppend ARGS1(HText *,text)
459: {
460: text->permissible_split = 0;
461: text->in_line_1 = YES;
462: }
463:
464:
465: /* Add a new line of text
466: ** ----------------------
467: **
468: ** On entry,
469: **
470: ** split is zero for newline function, else number of characters
471: ** before split.
472: ** text->display_on_the_fly
473: ** may be set to indicate direct output of the finished line.
1.3 timbl 474: ** text->all_pages
475: ** if set indicates all pages are to be done on the fly.
1.1 timbl 476: ** On exit,
477: ** A new line has been made, justified according to the
478: ** current style. Text after the split (if split nonzero)
479: ** is taken over onto the next line.
480: **
481: ** If display_on_the_fly is set, then it is decremented and
482: ** the finished line is displayed.
483: */
484: #define new_line(text) split_line(text, 0)
485:
486: PRIVATE void split_line ARGS2(HText *,text, int,split)
487: {
488: HTStyle * style = text->style;
489: int spare;
490: int indent = text->in_line_1 ? text->style->indent1st
491: : text->style->leftIndent;
1.7 frystyk 492:
1.1 timbl 493: /* Make new line
494: */
495: HTLine * previous = text->last_line;
496: HTLine * line = (HTLine *) malloc(LINE_SIZE(MAX_LINE));
497:
498: if (line == NULL) outofmem(__FILE__, "split_line");
499: text->lines++;
500:
501: previous->next->prev = line;
502: line->prev = previous;
503: line->next = previous->next;
504: previous->next = line;
505: text->last_line = line;
506: line->size = 0;
507: line->offset = 0;
508:
509: /* Split at required point
510: */
511: if (split) { /* Delete space at "split" splitting line */
512: char * p;
513: previous->data[previous->size] = 0;
514: for (p = &previous->data[split]; *p; p++)
515: if (*p != ' ') break;
516: strcpy(line->data, p);
517: line->size = strlen(line->data);
518: previous->size = split;
519: }
520:
521: /* Economise on space.
522: ** Not on the RS6000 due to a chaotic bug in realloc argument passing.
523: ** Same problem with Ultrix (4.2) : realloc() is not declared properly.
524: */
525: #ifndef AIX
526: #ifndef ultrix
527: while ((previous->size > 0) &&
528: (previous->data[previous->size-1] == ' ')) /* Strip trailers */
529: previous->size--;
1.7 frystyk 530:
1.1 timbl 531: previous = (HTLine *) realloc (previous, LINE_SIZE(previous->size));
532: if (previous == NULL) outofmem(__FILE__, "split_line");
533: #endif /* ultrix */
534: #endif /* AIX */
535:
536: previous->prev->next = previous; /* Link in new line */
537: previous->next->prev = previous; /* Could be same node of course */
538:
539: /* Terminate finished line for printing
540: */
541: previous->data[previous->size] = 0;
1.7 frystyk 542:
1.1 timbl 543: /* Align left, right or center
544: */
545:
546: spare = HTScreenWidth -
547: style->rightIndent + style->leftIndent -
548: previous->size; /* @@ first line indent */
549:
550: switch (style->alignment) {
551: case HT_CENTER :
552: previous->offset = previous->offset + indent + spare/2;
553: break;
554: case HT_RIGHT :
555: previous->offset = previous->offset + indent + spare;
556: break;
557: case HT_LEFT :
558: case HT_JUSTIFY : /* Not implemented */
559: default:
560: previous->offset = previous->offset + indent;
561: break;
562: } /* switch */
563:
564: text->chars = text->chars + previous->size + 1; /* 1 for the line */
565: text->in_line_1 = NO; /* unless caller sets it otherwise */
566:
567: /* If displaying as we go, output it:
568: */
569: if (text->display_on_the_fly) {
570: if (text->display_on_the_fly == DISPLAY_LINES) { /* First line */
571: if (previous->size == 0) {
572: text->top_of_screen++; /* Scroll white space off top */
573: return;
574: }
575: if (HTAnchor_title(text->node_anchor)) { /* Title exists */
576: display_title(text);
577: text->display_on_the_fly--;
578: }
579: }
580: display_line(text, previous);
581: text->display_on_the_fly--;
1.3 timbl 582:
583: /* Loop to top of next page? */
584: if (!text->display_on_the_fly && text->all_pages) {
585: PUTS("\f\n"); /* Form feed on its own line a la rfc1111 */
586: text->display_on_the_fly = DISPLAY_LINES;
587: }
1.1 timbl 588: }
589: } /* split_line */
590:
591:
592: /* Allow vertical blank space
593: ** --------------------------
594: */
595: PRIVATE void blank_lines ARGS2(HText *,text, int,newlines)
596: {
597: if (text->last_line->size == 0) { /* No text on current line */
598: HTLine * line = text->last_line->prev;
599: while ((line!=text->last_line) && (line->size == 0)) {
600: if (newlines==0) break;
601: newlines--; /* Don't bother: already blank */
602: line = line->prev;
603: }
604: } else {
605: newlines++; /* Need also to finish this line */
606: }
607:
608: for(;newlines;newlines--) {
609: new_line(text);
610: }
611: text->in_line_1 = YES;
612: }
613:
614:
615: /* New paragraph in current style
616: ** ------------------------------
617: ** See also: setStyle.
618: */
619:
620: PUBLIC void HText_appendParagraph ARGS1(HText *,text)
621: {
622: int after = text->style->spaceAfter;
623: int before = text->style->spaceBefore;
624: blank_lines(text, after>before ? after : before);
625: }
626:
627:
628: /* Set Style
629: ** ---------
630: **
631: ** Does not filter unnecessary style changes.
632: */
633: PUBLIC void HText_setStyle ARGS2(HText *,text, HTStyle *,style)
634: {
635: int after, before;
636:
637: if (!style) return; /* Safety */
638: after = text->style->spaceAfter;
639: before = style->spaceBefore;
640: if (TRACE) fprintf(stderr, "HTML: Change to style %s\n", style->name);
641:
642: blank_lines (text, after>before ? after : before);
643:
644: text->style = style;
645: }
646:
647:
648: /* Append a character to the text object
649: ** -------------------------------------
650: */
651: PUBLIC void HText_appendCharacter ARGS2(HText *,text, char,ch)
652: {
653: HTLine * line = text->last_line;
654: HTStyle * style = text->style;
655: int indent = text->in_line_1 ? style->indent1st : style->leftIndent;
656:
657: /* New Line
658: */
659: if (ch == '\n') {
660: new_line(text);
661: text->in_line_1 = YES; /* First line of new paragraph */
662: return;
663: }
664:
665: /* Tabs
666: */
667:
668: if (ch == '\t') {
669: HTTabStop * tab;
670: int target; /* Where to tab to */
671: int here = line->size + line->offset +indent;
672: if (style->tabs) { /* Use tab table */
673: for (tab = style->tabs;
674: tab->position <= here;
675: tab++)
676: if (!tab->position) {
677: new_line(text);
678: return;
679: }
680: target = tab->position;
681: } else if (text->in_line_1) { /* Use 2nd indent */
682: if (here >= style->leftIndent) {
683: new_line(text); /* wrap */
684: return;
685: } else {
686: target = style->leftIndent;
687: }
688: } else { /* Default tabs align with left indent mod 8 */
689: #ifdef DEFAULT_TABS_8
690: target = ((line->offset + line->size + 8) & (-8))
691: + style->leftIndent;
692: #else
693: new_line(text);
694: return;
695: #endif
696: }
697: if (target > HTScreenWidth - style->rightIndent) {
698: new_line(text);
699: return;
700: } else {
701: text->permissible_split = line->size; /* Can split here */
702: if (line->size == 0) line->offset = line->offset + target - here;
703: else for(; here<target; here++) {
704: line->data[line->size++] = ' '; /* Put character into line */
705: }
706: return;
707: }
708: /*NOTREACHED*/
709: } /* if tab */
710:
711:
712: if (ch==' ') {
713: text->permissible_split = line->size; /* Can split here */
714: }
715:
716: /* Check for end of line
717: */
718: if (indent + line->offset + line->size + style->rightIndent
719: >= HTScreenWidth) {
720: if (style->wordWrap) {
1.7 frystyk 721: if(text->permissible_split > line->size) /* HENRIK 21/02-94 */
722: text->permissible_split = line->size;
1.1 timbl 723: split_line(text, text->permissible_split);
724: if (ch==' ') return; /* Ignore space causing split */
725: } else new_line(text);
726: }
727:
728: /* Insert normal characters
729: */
730: if (ch == HT_NON_BREAK_SPACE) {
731: ch = ' ';
732: }
733: {
734: HTLine * line = text->last_line; /* May have changed */
735: HTFont font = style->font;
736: line->data[line->size++] = /* Put character into line */
737: font & HT_CAPITALS ? TOUPPER(ch) : ch;
738: if (font & HT_DOUBLE) /* Do again if doubled */
739: HText_appendCharacter(text, HT_NON_BREAK_SPACE);
740: /* NOT a permissible split */
741: }
742: }
743:
744: /* Anchor handling
745: ** ---------------
746: */
747: /* Start an anchor field
748: */
749: PUBLIC void HText_beginAnchor ARGS2(HText *,text, HTChildAnchor *,anc)
750: {
751: TextAnchor * a = (TextAnchor *) malloc(sizeof(*a));
1.2 timbl 752: char marker[100];
1.1 timbl 753:
754: if (a == NULL) outofmem(__FILE__, "HText_beginAnchor");
755: a->start = text->chars + text->last_line->size;
756: a->extent = 0;
757: if (text->last_anchor) {
758: text->last_anchor->next = a;
759: } else {
760: text->first_anchor = a;
761: }
762: a->next = 0;
763: a->anchor = anc;
764: text->last_anchor = a;
765:
766: if (HTAnchor_followMainLink((HTAnchor*)anc)) {
767: a->number = ++(text->last_anchor_number);
768: } else {
769: a->number = 0;
770: }
1.2 timbl 771:
772: if (start_reference && a->number && display_anchors) {
773: /* If it goes somewhere */
774: sprintf(marker, start_reference, a->number);
775: HText_appendText(text, marker);
776: }
1.1 timbl 777: }
778:
779:
780: PUBLIC void HText_endAnchor ARGS1(HText *,text)
781: {
782: TextAnchor * a = text->last_anchor;
783: char marker[100];
784: if (a->number && display_anchors) { /* If it goes somewhere */
1.2 timbl 785: sprintf(marker, end_reference, a->number);
1.1 timbl 786: HText_appendText(text, marker);
787: }
788: a->extent = text->chars + text->last_line->size - a->start;
789: }
790:
791:
1.5 timbl 792: /* IMAGES
793: */
794: PUBLIC void HText_appendImage ARGS5(
795: HText *, text,
796: HTChildAnchor *, anc,
797: CONST char *, alt,
1.9 frystyk 798: CONST char *, alignment,
1.5 timbl 799: BOOL, isMap)
800: {
1.9 frystyk 801: HText_appendText(text, alt? alt : "[IMAGE]");
1.5 timbl 802: }
803:
1.1 timbl 804: PUBLIC void HText_appendText ARGS2(HText *,text, CONST char *,str)
805: {
806: CONST char * p;
807: for(p=str; *p; p++) {
808: HText_appendCharacter(text, *p);
809: }
810: }
811:
812:
813: PUBLIC void HText_endAppend ARGS1(HText *,text)
814: {
815: new_line(text);
816:
817: if (text->display_on_the_fly) { /* Not finished? */
818: fill_screen(text, text->display_on_the_fly); /* Finish it */
819: text->display_on_the_fly = 0;
820: text->next_line = text->last_line; /* Bug fix after EvA 920117 */
821: text->stale = NO;
822: }
823: }
824:
825:
826:
827: /* Dump diagnostics to stderr
828: */
829: PUBLIC void HText_dump ARGS1(HText *,text)
830: {
831: fprintf(stderr, "HText: Dump called\n");
832: }
833:
834:
835: /* Return the anchor associated with this node
836: */
837: PUBLIC HTParentAnchor * HText_nodeAnchor ARGS1(HText *,text)
838: {
839: return text->node_anchor;
840: }
841:
842: /* GridText specials
843: ** =================
844: */
845: /* Return the anchor with index N
846: **
847: ** The index corresponds to the number we print in the anchor.
848: */
849: PUBLIC HTChildAnchor * HText_childNumber ARGS2(HText *,text, int,number)
850: {
851: TextAnchor * a;
852: for (a = text->first_anchor; a; a = a->next) {
853: if (a->number == number) return a->anchor;
854: }
855: return (HTChildAnchor *)0; /* Fail */
856: }
857:
858: PUBLIC void HText_setStale ARGS1(HText *,text)
859: {
860: text->stale = YES;
861: }
862:
863: PUBLIC void HText_refresh ARGS1(HText *,text)
864: {
865: if (text->stale) display_page(text, text->top_of_screen);
866: }
867:
868: PUBLIC int HText_sourceAnchors ARGS1(HText *,text)
869: {
870: return text->last_anchor_number;
871: }
872:
873: PUBLIC BOOL HText_canScrollUp ARGS1(HText *,text)
874: {
875: return text->top_of_screen != 0;
876: }
877:
878: PUBLIC BOOL HText_canScrollDown ARGS1(HText *,text)
879: {
880: char * title = text->title;
881: return (text->top_of_screen + DISPLAY_LINES - (title? TITLE_LINES:0) ) <
882: text->lines;
883: }
884:
885: /* Scroll actions
886: */
887: PUBLIC void HText_scrollTop ARGS1(HText *,text)
888: {
889: display_page(text, 0);
890: }
891:
892: PUBLIC void HText_scrollDown ARGS1(HText *,text)
893: {
894: display_page(text, text->top_of_screen + DISPLAY_LINES -1);
895: }
896:
897: PUBLIC void HText_scrollUp ARGS1(HText *,text)
898: {
899: display_page(text, text->top_of_screen - DISPLAY_LINES +1);
900: }
901:
902: PUBLIC void HText_scrollBottom ARGS1(HText *,text)
903: {
904: display_page(text, text->lines - DISPLAY_LINES +1);
905: }
906:
907:
908: /* Browsing functions
909: ** ==================
910: */
911:
912: /* Bring to front and highlight it
913: */
914:
915: PRIVATE int line_for_char ARGS2(HText *,text, int,char_num)
916: {
917: int line_number =0;
918: int characters = 0;
919: HTLine * line = text->last_line->next;
920: for(;;) {
921: if (line == text->last_line) return 0; /* Invalid */
922: characters = characters + line->size + 1;
923: if (characters > char_num) return line_number;
924: line_number ++;
925: line = line->next;
926: }
927: }
928:
929: PUBLIC BOOL HText_select ARGS1(HText *,text)
930: {
931: /* if (text != HTMainText) { Do it anyway to refresh */
932: {
933: HTMainText = text;
934: HTMainAnchor = text->node_anchor;
935: display_page(text, text->top_of_screen);
936: }
937: return YES;
938: }
939:
940: PUBLIC BOOL HText_selectAnchor ARGS2(HText *,text, HTChildAnchor *,anchor)
941: {
942: TextAnchor * a;
943:
944: /* This is done later, hence HText_select is unused in GridText.c
945: Should it be the contrary ? @@@
946: if (text != HTMainText) {
947: HText_select(text);
948: }
949: */
950:
951: for(a=text->first_anchor; a; a=a->next) {
952: if (a->anchor == anchor) break;
953: }
954: if (!a) {
955: if (TRACE) fprintf(stderr, "HText: No such anchor in this text!\n");
956: return NO;
957: }
958:
959: if (text != HTMainText) { /* Comment out by ??? */
960: HTMainText = text; /* Put back in by tbl 921208 */
961: HTMainAnchor = text->node_anchor;
962: }
963:
964: {
965: int l = line_for_char(text, a->start);
966: if (TRACE) fprintf(stderr,
967: "HText: Selecting anchor [%d] at character %d, line %d\n",
968: a->number, a->start, l);
969:
970: if ( !text->stale &&
971: (l >= text->top_of_screen) &&
972: ( l < text->top_of_screen + DISPLAY_LINES-1))
973: return YES;
974:
975: display_page(text, l - (DISPLAY_LINES/3)); /* Scroll to it */
976: }
977:
978: return YES;
979: }
980:
981:
982: /* Editing functions - NOT IMPLEMENTED
983: ** =================
984: **
985: ** These are called from the application. There are many more functions
986: ** not included here from the orginal text object.
987: */
988:
989: /* Style handling:
990: */
991: /* Apply this style to the selection
992: */
993: PUBLIC void HText_applyStyle ARGS2(HText *, me, HTStyle *,style)
994: {
995:
996: }
997:
998:
999: /* Update all text with changed style.
1000: */
1001: PUBLIC void HText_updateStyle ARGS2(HText *, me, HTStyle *,style)
1002: {
1003:
1004: }
1005:
1006:
1007: /* Return style of selection
1008: */
1009: PUBLIC HTStyle * HText_selectionStyle ARGS2(
1010: HText *,me,
1011: HTStyleSheet *,sheet)
1012: {
1013: return 0;
1014: }
1015:
1016:
1017: /* Paste in styled text
1018: */
1019: PUBLIC void HText_replaceSel ARGS3(
1020: HText *,me,
1021: CONST char *,aString,
1022: HTStyle *,aStyle)
1023: {
1024: }
1025:
1026:
1027: /* Apply this style to the selection and all similarly formatted text
1028: ** (style recovery only)
1029: */
1030: PUBLIC void HTextApplyToSimilar ARGS2(HText *,me, HTStyle *,style)
1031: {
1032:
1033: }
1034:
1035:
1036: /* Select the first unstyled run.
1037: ** (style recovery only)
1038: */
1039: PUBLIC void HTextSelectUnstyled ARGS2(HText *,me, HTStyleSheet *,sheet)
1040: {
1041:
1042: }
1043:
1044:
1045: /* Anchor handling:
1046: */
1047: PUBLIC void HText_unlinkSelection ARGS1(HText *,me)
1048: {
1049:
1050: }
1051:
1052: PUBLIC HTAnchor * HText_referenceSelected ARGS1(HText *,me)
1053: {
1054: return 0;
1055: }
1056:
1057:
1058: #ifdef CURSES
1059: PUBLIC int HText_getTopOfScreen ARGS1(HText *,text)
1060: {
1061: return text->top_of_screen;
1062: }
1063:
1064: PUBLIC int HText_getLines ARGS1(HText *,text)
1065: {
1066: return text->lines;
1067: }
1068: #endif
1069: PUBLIC HTAnchor * HText_linkSelTo ARGS2(HText *,me, HTAnchor *,anchor)
1070: {
1071: return 0;
1072: }
1073:
1074:
Webmaster