Update NEWS for 1.6.22
[pkg-k5-afs_openafs.git] / src / gtx / textobject.c
blobffe004294479355d56c14fc078b87c6c46cc3e9b
1 /*
2 * Copyright 2000, International Business Machines Corporation and others.
3 * All Rights Reserved.
5 * This software has been released under the terms of the IBM Public
6 * License. For details, see the LICENSE file in the top-level source
7 * directory or online at http://www.openafs.org/dl/license10.html
8 */
11 * Description:
12 * Implementation of the gator text object.
13 *------------------------------------------------------------------------*/
14 #include <afsconfig.h>
15 #include <afs/param.h>
18 #include "gtxtextobj.h" /*Interface for this module */
19 #include "gtxwindows.h" /*Gator window interface */
20 #include "gtxcurseswin.h" /*Gator curses window interface */
21 #include "gtxdumbwin.h" /*Gator dumb terminal window interface */
22 #include "gtxX11win.h" /*Gator X11 window interface */
23 #include <stdio.h> /*Standard I/O stuff */
24 #include <errno.h>
25 #include <string.h>
26 #include <stdlib.h>
28 /*Externally-advertised array of text onode operations*/
29 struct onodeops gator_text_ops = {
30 gator_text_destroy,
31 gator_text_display,
32 gator_text_release
35 static char mn[] = "gator_textobject"; /*Module name */
37 #define GATOR_TEXTCB_DO_BOX 0
39 /*------------------------------------------------------------------------
40 * gator_text_create
42 * Description:
43 * Create a gator text object.
45 * Arguments:
46 * struct onode *text_onp : Ptr to the text onode to fill out.
47 * struct onode_createparams *params : Generic ptr to creation
48 * parameters.
50 * Returns:
51 * Zero if successful,
52 * Error value otherwise.
54 * Environment:
55 * The base onode fields have already been set. Text onodes are
56 * empty upon creation.
58 * Side Effects:
59 * Upon successful creation, the onode's o_window field is
60 * replaced with a new window created for the text object,
61 * with the parent window is remembered within the new window
62 * structure. On failure, it remains unchanged.
63 *------------------------------------------------------------------------*/
65 int
66 gator_text_create(struct onode *text_onp, struct onode_createparams *params)
67 { /*gator_text_create */
69 static char rn[] = "gator_text_create"; /*Routine name */
70 struct gator_textobj_params *text_params; /*My specific creation params */
71 struct gator_textobj *text_data; /*Ptr to private data */
72 struct gator_textcb_hdr *newCB; /*Ptr to CB hdr */
74 text_params = (struct gator_textobj_params *)params;
75 if (objects_debug) {
76 fprintf(stderr,
77 "[%s:%s] Private data passed to text object at %p:\n", mn,
78 rn, text_onp);
79 fprintf(stderr, "\tmaxEntries: %d, maxCharsPerEntry: %d\n",
80 text_params->maxEntries, text_params->maxCharsPerEntry);
84 * Allocate the private data area.
86 if (objects_debug)
87 fprintf(stderr,
88 "[%s:%s] Allocating %" AFS_SIZET_FMT " bytes for text object private data region\n",
89 mn, rn, sizeof(struct gator_textobj));
90 text_data = (struct gator_textobj *)malloc(sizeof(struct gator_textobj));
91 if (text_data == (struct gator_textobj *)0) {
92 fprintf(stderr,
93 "[%s:%s] Can't allocate %" AFS_SIZET_FMT " bytes for text object private data region, errno is %d\n",
94 mn, rn, sizeof(struct gator_textobj), errno);
95 return (errno);
99 * Create the text circular buffer for this new object.
101 if (objects_debug)
102 fprintf(stderr, "[%s:%s] Creating circular buffer, %dx%d chars\n", mn,
103 rn, text_params->maxEntries, text_params->maxCharsPerEntry);
104 newCB =
105 gator_textcb_Create(text_params->maxEntries,
106 text_params->maxCharsPerEntry);
107 if (newCB == (struct gator_textcb_hdr *)0) {
108 fprintf(stderr, "[%s:%s] Can't create text object circular buffer\n",
109 mn, rn);
110 free(text_data);
111 return (-1);
115 * Now that we have the private structures allocated, set them up.
117 text_data->llrock = (int *)0;
118 text_data->numLines = text_onp->o_height;
119 text_data->cbHdr = newCB;
120 text_data->firstEntShown = 0;
121 text_data->lastEntShown = 0;
122 if (objects_debug)
123 fprintf(stderr, "[%s:%s] Number of lines in window: %d: ", mn, rn,
124 text_data->numLines);
127 * Attach the text-specific private
128 * data to the generic onode and return the happy news.
130 text_onp->o_data = (int *)text_data;
131 return (0);
133 } /*gator_text_create */
135 /*------------------------------------------------------------------------
136 * gator_text_destroy
138 * Description:
139 * Destroy a gator text object.
141 * Arguments:
142 * struct onode *onp : Ptr to the text onode to delete.
144 * Returns:
145 * 0: Success
146 * Error value otherwise.
148 * Environment:
149 * Nothing interesting.
151 * Side Effects:
152 * As advertised.
153 *------------------------------------------------------------------------*/
156 gator_text_destroy(struct onode *onp)
157 { /*gator_text_destroy */
160 * For now, this is a no-op.
162 return (0);
164 } /*gator_text_destroy */
166 /*------------------------------------------------------------------------
167 * gator_text_display
169 * Description:
170 * Display/redraw a gator text object.
172 * Arguments:
173 * struct onode *onp: Ptr to the text onode to display.
175 * Returns:
176 * 0: Success
177 * Error value otherwise.
179 * Environment:
180 * Nothing interesting.
182 * Side Effects:
183 * As advertised.
184 *------------------------------------------------------------------------*/
187 gator_text_display(struct onode *onp)
188 { /*gator_text_display */
190 static char rn[] = "gator_text_display"; /*Routine name */
191 struct gator_textobj *text_data; /*Ptr to text obj data */
192 struct gator_textcb_hdr *cbHdr; /*Ptr to CB header */
193 struct gwin_strparams strparams; /*String-drawing params */
194 int currLine; /*Current line being updated */
195 int currLinesUsed; /*Num screen lines used */
196 int currIdx; /*Current line index */
197 int currEnt; /*Current entry being drawn */
198 struct gator_textcb_entry *curr_ent; /*Ptr to current entry */
200 if (objects_debug)
201 fprintf(stderr, "[%s:%s] Displaying text object at %p\n", mn, rn,
202 onp);
203 text_data = (struct gator_textobj *)(onp->o_data);
204 cbHdr = text_data->cbHdr;
205 if (objects_debug)
206 fprintf(stderr,
207 "[%s:%s] Displaying text object at %p, object-specific data at %p\n",
208 mn, rn, onp, text_data);
211 * Update each line in the screen buffer with its proper contents.
213 currEnt = text_data->firstEntShown;
214 currLinesUsed = text_data->lastEntShown - currEnt + 1;
215 currIdx =
216 (cbHdr->oldestEntIdx +
217 (currEnt - cbHdr->oldestEnt)) % cbHdr->maxEntriesStored;
218 curr_ent = cbHdr->entry + currIdx;
220 if (objects_debug)
221 fprintf(stderr,
222 "[%s:%s] Drawing %d populated lines, starting with entry %d (index %d) at %p",
223 mn, rn, currLinesUsed, currEnt, currIdx, curr_ent);
225 strparams.x = onp->o_x;
226 strparams.y = onp->o_y;
227 for (currLine = 0; currLine < text_data->numLines; currLine++) {
229 * Draw the current entry.
231 if (currLinesUsed > 0) {
233 * Drawing a populated line. We need to iterate if there are
234 * inversions (I don't feel like doing this now).
236 strparams.s = curr_ent->textp;
237 strparams.highlight = curr_ent->highlight;
238 WOP_DRAWSTRING(onp->o_window, &strparams);
240 currLinesUsed--;
241 currEnt++;
242 currIdx++;
243 if (currIdx >= cbHdr->maxEntriesStored) {
244 currIdx = 0;
245 curr_ent = cbHdr->entry;
246 } else
247 curr_ent++;
248 } else {
250 * Draw a blank line.
252 strparams.s = cbHdr->blankLine;
253 strparams.highlight = 0;
254 WOP_DRAWSTRING(onp->o_window, &strparams);
258 * Adjust the X and Y locations.
260 strparams.x = 0;
261 strparams.y++;
263 } /*Update loop */
266 * Box the window before we leave.
268 #if GATOR_TEXTCB_DO_BOX
269 if (objects_debug)
270 fprintf(stderr, "[%s:%s] Boxing window structure at 0x%x\n", mn, rn,
271 onp->o_window);
272 WOP_BOX(onp->o_window);
273 #endif /* GATOR_TEXTCB_DO_BOX */
276 * For now, this is all we do.
278 return (0);
280 } /*gator_text_display */
282 /*------------------------------------------------------------------------
283 * gator_text_release
285 * Description:
286 * Drop the refcount on a gator text object.
288 * Arguments:
289 * struct onode *onp : Ptr to the onode whose refcount is
290 * to be dropped.
292 * Returns:
293 * 0: Success
294 * Error value otherwise.
296 * Environment:
297 * Nothing interesting.
299 * Side Effects:
300 * As advertised.
301 *------------------------------------------------------------------------*/
304 gator_text_release(struct onode *onp)
305 { /*gator_text_release */
308 * For now, this is a no-op.
310 return (0);
312 } /*gator_text_release */
314 /*------------------------------------------------------------------------
315 * gator_text_Scroll
317 * Description:
318 * Scroll a text object some number of lines.
320 * Arguments:
321 * struct onode *onp : Ptr to the text onode to be scrolled.
322 * int nlines : Number of lines to scroll.
323 * int direction : Scroll up or down?
325 * Returns:
326 * 0: Success,
327 * Error value otherwise.
329 * Environment:
330 * Invariant: the text object's firstEntShown and lastEntShown
331 * are always between oldestEnt and currEnt (inclusive).
333 * Side Effects:
334 * As advertised.
335 *------------------------------------------------------------------------*/
338 gator_text_Scroll(struct onode *onp, int nlines, int direction)
339 { /*gator_text_Scroll */
341 static char rn[] = "gator_text_Scroll"; /*Routine name */
342 struct gator_textobj *text_data; /*Ptr to text obj data */
345 * We move the markers for first & last entries displayed, depending
346 * on what's available to us in the circular buffer. We never leave
347 * the window empty.
349 if (objects_debug)
350 fprintf(stderr, "[%s:%s] Scrolling text object %d lines %s\n",
351 mn, rn, nlines,
352 (direction == GATOR_TEXT_SCROLL_UP) ? "UP" : "DOWN");
354 text_data = (struct gator_textobj *)(onp->o_data);
355 if (direction == GATOR_TEXT_SCROLL_DOWN) {
357 * Move the object's text ``down'' by sliding the window up.
359 text_data->firstEntShown -= nlines;
360 if (text_data->firstEntShown < text_data->cbHdr->oldestEnt)
361 text_data->firstEntShown = text_data->cbHdr->oldestEnt;
363 text_data->lastEntShown -= nlines;
364 if (text_data->lastEntShown < text_data->cbHdr->oldestEnt)
365 text_data->lastEntShown = text_data->cbHdr->oldestEnt;
367 } /*Moving down */
368 else {
370 * Move the object's text ``up'' by sliding the window down.
372 text_data->firstEntShown += nlines;
373 if (text_data->firstEntShown > text_data->cbHdr->currEnt)
374 text_data->firstEntShown = text_data->cbHdr->currEnt;
376 text_data->lastEntShown += nlines;
377 if (text_data->lastEntShown > text_data->cbHdr->currEnt)
378 text_data->lastEntShown = text_data->cbHdr->currEnt;
380 } /*Moving up */
383 * Return the happy news.
385 return (0);
387 } /*gator_text_Scroll */
389 /*------------------------------------------------------------------------
390 * gator_text_Write
392 * Description:
393 * Write the given string to the end of the gator text object.
395 * Arguments:
396 * struct onode *onp : Ptr to the onode whose to which we're
397 * writing.
398 * char *strToWrite : String to write.
399 * int numChars : Number of chars to write.
400 * int highlight : Use highlighting?
401 * int skip : Force a skip to the next line?
403 * Returns:
404 * 0: Success
405 * Error value otherwise.
407 * Environment:
408 * Nothing interesting.
410 * Side Effects:
411 * As advertised.
412 *------------------------------------------------------------------------*/
415 gator_text_Write(struct onode *onp, char *strToWrite, int numChars,
416 int highlight, int skip)
417 { /*gator_text_Write */
419 static char rn[] = "gator_text_Write"; /*Routine name */
420 int code; /*Return value on routines */
421 struct gator_textobj *text_data; /*Ptr to text obj data */
422 struct gator_textcb_hdr *cbHdr; /*Ptr to text CB header */
423 int i; /*Loop variable */
424 int oldCurrEnt; /*CB's old currEnt value */
425 int redisplay; /*Redisplay after write? */
426 int shownDiff; /*Diff between 1st & last lines */
427 int writeDiff; /*Num lines really written */
428 int bumpAmount; /*Amount to bump count */
433 if (objects_debug) {
434 fprintf(stderr,
435 "[%s:%s] Writing %d chars to text object at %p (highlight=%d, skip=%d: '",
436 mn, rn, numChars, onp, highlight, skip);
437 for (i = 0; i < numChars; i++)
438 fprintf(stderr, "%c", strToWrite[i]);
439 fprintf(stderr, "\n");
442 if (numChars == 0)
443 numChars = strlen(strToWrite); /* simplify caller */
444 text_data = (struct gator_textobj *)(onp->o_data);
445 cbHdr = text_data->cbHdr;
446 if (cbHdr == (struct gator_textcb_hdr *)0) {
447 fprintf(stderr, "[%s:%s] Text object missing its circular buffer!\n",
448 mn, rn);
449 return (-1);
452 * If the current CB entry is being displayed, we track the write
453 * visually and redisplay.
455 if ((cbHdr->currEnt <= text_data->lastEntShown)
456 && (cbHdr->currEnt >= text_data->firstEntShown)) {
457 if (objects_debug)
458 fprintf(stderr,
459 "[%s:%s] Current entry is on screen. Tracking this write\n",
460 mn, rn);
461 oldCurrEnt = cbHdr->currEnt;
462 redisplay = 1;
463 } else {
464 if (objects_debug)
465 fprintf(stderr,
466 "[%s:%s] Current entry NOT on screen, not tracking write\n",
467 mn, rn);
468 redisplay = 0;
472 if (redisplay) {
474 * We're tracking the write. Compute the number of screen lines
475 * actually written and adjust our own numbers, then call the
476 * display function.
478 shownDiff = text_data->lastEntShown - text_data->firstEntShown;
479 writeDiff = cbHdr->currEnt - oldCurrEnt;
480 if (objects_debug)
481 fprintf(stderr,
482 "[%s:%s] Preparing to redisplay. Difference in shown lines=%d, difference in written lines=%d\n",
483 mn, rn, shownDiff, writeDiff);
484 if (shownDiff < (text_data->numLines - 1)) {
486 * We weren't showing a full screen of stuff. Bump the last
487 * line shown by the minimum of the number of free lines still
488 * on the screen and the number of new lines actually written.
490 bumpAmount = (text_data->numLines - 1) - shownDiff;
491 if (writeDiff < bumpAmount)
492 bumpAmount = writeDiff;
493 text_data->lastEntShown += bumpAmount;
494 writeDiff -= bumpAmount;
495 if (objects_debug)
496 fprintf(stderr,
497 "[%s:%s] Empty lines appeared on screen, bumping bottom line shown by %d; new writeDiff is %d\n",
498 mn, rn, bumpAmount, writeDiff);
502 * If we have any more lines that were written not taken care
503 * of by the above, we just bump the counters.
505 if (writeDiff > 0) {
506 if (objects_debug)
507 fprintf(stderr,
508 "[%s:%s] Still more lines need to be tracked. Moving first & last shown down by %d\n",
509 mn, rn, writeDiff);
510 text_data->firstEntShown += writeDiff;
511 text_data->lastEntShown += writeDiff;
515 /*Redisplay needed */
517 * Simply call the circular buffer write op.
519 code = gator_textcb_Write(cbHdr, strToWrite, numChars, highlight, skip);
520 if (code) {
521 fprintf(stderr,
522 "[%s:%s] Can't write to text object's circular buffer, errror code is %d\n",
523 mn, rn, code);
524 return (code);
528 * Everything went well. Return the happy news.
530 return (0);
532 } /*gator_text_Write */
534 /*------------------------------------------------------------------------
535 * gator_text_BlankLine
537 * Description:
538 * Write a given number of blank lines to the given text object.
540 * Arguments:
541 * struct onode *onp : Ptr to the onode to which we're writing.
542 * int numBlanks : Number of blank lines to write.
544 * Returns:
545 * 0: Success,
546 * Error value otherwise.
548 * Environment:
549 * Nothing interesting.
551 * Side Effects:
552 * As advertised.
553 *------------------------------------------------------------------------*/
556 gator_text_BlankLine(struct onode *onp, int numBlanks)
557 { /*gator_text_BlankLine */
559 static char rn[] = "gator_text_BlankLine"; /*Routine name */
560 int code; /*Return value on routines */
561 struct gator_textobj *text_data; /*Ptr to text obj data */
564 * We just call the circular buffer routine directly.
566 if (objects_debug)
567 fprintf(stderr,
568 "[%s:%s] Writing %d blank lines to text object at %p\n", mn,
569 rn, numBlanks, onp);
571 text_data = (struct gator_textobj *)(onp->o_data);
572 code = gator_textcb_BlankLine(text_data->cbHdr, numBlanks);
573 if (code) {
574 fprintf(stderr,
575 "[%s:%s] Can't write %d blank lines to text object at %p\n",
576 mn, rn, numBlanks, onp);
577 return (code);
581 * Blank lines written successfully. Adjust what lines are currently
582 * shown. Iff we were tracking the end of the buffer, we have to
583 * follow the blank lines.
585 if (text_data->lastEntShown == text_data->cbHdr->currEnt - numBlanks) {
586 text_data->firstEntShown += numBlanks;
587 text_data->lastEntShown += numBlanks;
591 * Return the happy news.
593 return (0);
595 } /*gator_text_BlankLine */