DEVEL15-openafs-string-header-cleanup-20071030
[openafs.git] / src / gtx / textobject.c
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  * 
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  */
9
10 /*
11  * Description:
12  *      Implementation of the gator text object.
13  *------------------------------------------------------------------------*/
14 #define IGNORE_STDS_H
15 #include <afsconfig.h>
16 #include <afs/param.h>
17
18 RCSID
19     ("$Header$");
20
21 #include "gtxtextobj.h"         /*Interface for this module */
22 #include "gtxwindows.h"         /*Gator window interface */
23 #include "gtxcurseswin.h"       /*Gator curses window interface */
24 #include "gtxdumbwin.h"         /*Gator dumb terminal window interface */
25 #include "gtxX11win.h"          /*Gator X11 window interface */
26 #include <stdio.h>              /*Standard I/O stuff */
27 #include <errno.h>
28 #include <string.h>
29 #include <stdlib.h>
30
31 /*Externally-advertised array of text onode operations*/
32 struct onodeops gator_text_ops = {
33     gator_text_destroy,
34     gator_text_display,
35     gator_text_release
36 };
37
38 static char mn[] = "gator_textobject";  /*Module name */
39
40 #define GATOR_TEXTCB_DO_BOX     0
41
42 /*------------------------------------------------------------------------
43  * gator_text_create
44  *
45  * Description:
46  *      Create a gator text object.
47  *
48  * Arguments:
49  *      struct onode *text_onp : Ptr to the text onode to fill out.
50  *      struct onode_createparams *params : Generic ptr to creation
51  *          parameters.
52  *
53  * Returns:
54  *      Zero if successful,
55  *      Error value otherwise.
56  *
57  * Environment:
58  *      The base onode fields have already been set.  Text onodes are
59  *      empty upon creation.
60  *
61  * Side Effects:
62  *      Upon successful creation, the onode's o_window field is
63  *      replaced with a new window created for the text object,
64  *      with the parent window is remembered within the new window
65  *      structure.  On failure, it remains unchanged.
66  *------------------------------------------------------------------------*/
67
68 int
69 gator_text_create(text_onp, params)
70      struct onode *text_onp;
71      struct onode_createparams *params;
72
73 {                               /*gator_text_create */
74
75     static char rn[] = "gator_text_create";     /*Routine name */
76     struct gator_textobj_params *text_params;   /*My specific creation params */
77     struct gator_textobj *text_data;    /*Ptr to private data */
78     struct gator_textcb_hdr *newCB;     /*Ptr to CB hdr */
79
80     text_params = (struct gator_textobj_params *)params;
81     if (objects_debug) {
82         fprintf(stderr,
83                 "[%s:%s] Private data passed to text object at 0x%x:\n", mn,
84                 rn, text_onp);
85         fprintf(stderr, "\tmaxEntries: %d, maxCharsPerEntry: %d\n",
86                 text_params->maxEntries, text_params->maxCharsPerEntry);
87     }
88
89     /*
90      * Allocate the private data area.
91      */
92     if (objects_debug)
93         fprintf(stderr,
94                 "[%s:%s] Allocating %d bytes for text object private data region\n",
95                 mn, rn, sizeof(struct gator_textobj));
96     text_data = (struct gator_textobj *)malloc(sizeof(struct gator_textobj));
97     if (text_data == (struct gator_textobj *)0) {
98         fprintf(stderr,
99                 "[%s:%s] Can't allocate %d bytes for text object private data region, errno is %d\n",
100                 mn, rn, sizeof(struct gator_textobj), errno);
101         return (errno);
102     }
103
104     /*
105      * Create the text circular buffer for this new object.
106      */
107     if (objects_debug)
108         fprintf(stderr, "[%s:%s] Creating circular buffer, %dx%d chars\n", mn,
109                 rn, text_params->maxEntries, text_params->maxCharsPerEntry);
110     newCB =
111         gator_textcb_Create(text_params->maxEntries,
112                             text_params->maxCharsPerEntry);
113     if (newCB == (struct gator_textcb_hdr *)0) {
114         fprintf(stderr, "[%s:%s] Can't create text object circular buffer\n",
115                 mn, rn);
116         free(text_data);
117         return (-1);
118     }
119
120     /*
121      * Now that we have the private structures allocated, set them up.
122      */
123     text_data->llrock = (int *)0;
124     text_data->numLines = text_onp->o_height;
125     text_data->cbHdr = newCB;
126     text_data->firstEntShown = 0;
127     text_data->lastEntShown = 0;
128     if (objects_debug)
129         fprintf(stderr, "[%s:%s] Number of lines in window: %d: ", mn, rn,
130                 text_data->numLines);
131
132     /*
133      * Attach the text-specific private
134      * data to the generic onode and return the happy news.
135      */
136     text_onp->o_data = (int *)text_data;
137     return (0);
138
139 }                               /*gator_text_create */
140
141 /*------------------------------------------------------------------------
142  * gator_text_destroy
143  *
144  * Description:
145  *      Destroy a gator text object.
146  *
147  * Arguments:
148  *      struct onode *onp : Ptr to the text onode to delete.
149  *
150  * Returns:
151  *      0: Success
152  *      Error value otherwise.
153  *
154  * Environment:
155  *      Nothing interesting.
156  *
157  * Side Effects:
158  *      As advertised.
159  *------------------------------------------------------------------------*/
160
161 int
162 gator_text_destroy(onp)
163      struct onode *onp;
164
165 {                               /*gator_text_destroy */
166
167     /*
168      * For now, this is a no-op.
169      */
170     return (0);
171
172 }                               /*gator_text_destroy */
173
174 /*------------------------------------------------------------------------
175  * gator_text_display
176  *
177  * Description:
178  *      Display/redraw a gator text object.
179  *
180  * Arguments:
181  *      struct onode *onp: Ptr to the text onode to display.
182  *
183  * Returns:
184  *      0: Success
185  *      Error value otherwise.
186  *
187  * Environment:
188  *      Nothing interesting.
189  *
190  * Side Effects:
191  *      As advertised.
192  *------------------------------------------------------------------------*/
193
194 int
195 gator_text_display(onp)
196      struct onode *onp;
197
198 {                               /*gator_text_display */
199
200     static char rn[] = "gator_text_display";    /*Routine name */
201     struct gator_textobj *text_data;    /*Ptr to text obj data */
202     struct gator_textcb_hdr *cbHdr;     /*Ptr to CB header */
203     struct gwin_strparams strparams;    /*String-drawing params */
204     int currLine;               /*Current line being updated */
205     int currLinesUsed;          /*Num screen lines used */
206     int currIdx;                /*Current line index */
207     int currEnt;                /*Current entry being drawn */
208     struct gator_textcb_entry *curr_ent;        /*Ptr to current entry */
209
210     if (objects_debug)
211         fprintf(stderr, "[%s:%s] Displaying text object at 0x%x\n", mn, rn,
212                 onp);
213     text_data = (struct gator_textobj *)(onp->o_data);
214     cbHdr = text_data->cbHdr;
215     if (objects_debug)
216         fprintf(stderr,
217                 "[%s:%s] Displaying text object at 0x%x, object-specific data at 0x%x\n",
218                 mn, rn, onp, text_data);
219
220     /*
221      * Update each line in the screen buffer with its proper contents.
222      */
223     currEnt = text_data->firstEntShown;
224     currLinesUsed = text_data->lastEntShown - currEnt + 1;
225     currIdx =
226         (cbHdr->oldestEntIdx +
227          (currEnt - cbHdr->oldestEnt)) % cbHdr->maxEntriesStored;
228     curr_ent = cbHdr->entry + currIdx;
229
230     if (objects_debug)
231         fprintf(stderr,
232                 "[%s:%s] Drawing %d populated lines, starting with entry %d (index %d) at 0x%x\n",
233                 mn, rn, currLinesUsed, currEnt, currIdx, curr_ent);
234
235     strparams.x = onp->o_x;
236     strparams.y = onp->o_y;
237     for (currLine = 0; currLine < text_data->numLines; currLine++) {
238         /*
239          * Draw the current entry.
240          */
241         if (currLinesUsed > 0) {
242             /*
243              * Drawing a populated line.  We need to iterate if there are
244              * inversions (I don't feel like doing this now).
245              */
246             strparams.s = curr_ent->textp;
247             strparams.highlight = curr_ent->highlight;
248             WOP_DRAWSTRING(onp->o_window, &strparams);
249
250             currLinesUsed--;
251             currEnt++;
252             currIdx++;
253             if (currIdx >= cbHdr->maxEntriesStored) {
254                 currIdx = 0;
255                 curr_ent = cbHdr->entry;
256             } else
257                 curr_ent++;
258         } else {
259             /*
260              * Draw a blank line.
261              */
262             strparams.s = cbHdr->blankLine;
263             strparams.highlight = 0;
264             WOP_DRAWSTRING(onp->o_window, &strparams);
265         }
266
267         /*
268          * Adjust the X and Y locations.
269          */
270         strparams.x = 0;
271         strparams.y++;
272
273     }                           /*Update loop */
274
275     /*
276      * Box the window before we leave.
277      */
278 #if GATOR_TEXTCB_DO_BOX
279     if (objects_debug)
280         fprintf(stderr, "[%s:%s] Boxing window structure at 0x%x\n", mn, rn,
281                 onp->o_window);
282     WOP_BOX(onp->o_window);
283 #endif /* GATOR_TEXTCB_DO_BOX */
284
285     /*
286      * For now, this is all we do.
287      */
288     return (0);
289
290 }                               /*gator_text_display */
291
292 /*------------------------------------------------------------------------
293  * gator_text_release
294  *
295  * Description:
296  *      Drop the refcount on a gator text object.
297  *
298  * Arguments:
299  *      struct onode *onp : Ptr to the onode whose refcount is
300  *                                   to be dropped.
301  *
302  * Returns:
303  *      0: Success
304  *      Error value otherwise.
305  *
306  * Environment:
307  *      Nothing interesting.
308  *
309  * Side Effects:
310  *      As advertised.
311  *------------------------------------------------------------------------*/
312
313 int
314 gator_text_release(onp)
315      struct onode *onp;
316
317 {                               /*gator_text_release */
318
319     /*
320      * For now, this is a no-op.
321      */
322     return (0);
323
324 }                               /*gator_text_release */
325
326 /*------------------------------------------------------------------------
327  * gator_text_Scroll
328  *
329  * Description:
330  *      Scroll a text object some number of lines.
331  *
332  * Arguments:
333  *      struct onode *onp : Ptr to the text onode to be scrolled.
334  *      int nlines        : Number of lines to scroll.
335  *      int direction     : Scroll up or down?
336  *
337  * Returns:
338  *      0: Success,
339  *      Error value otherwise.
340  *
341  * Environment:
342  *      Invariant: the text object's firstEntShown and lastEntShown
343  *              are always between oldestEnt and currEnt (inclusive).
344  *
345  * Side Effects:
346  *      As advertised.
347  *------------------------------------------------------------------------*/
348
349 int
350 gator_text_Scroll(onp, nlines, direction)
351      struct onode *onp;
352      int nlines;
353      int direction;
354
355 {                               /*gator_text_Scroll */
356
357     static char rn[] = "gator_text_Scroll";     /*Routine name */
358     struct gator_textobj *text_data;    /*Ptr to text obj data */
359
360     /*
361      * We move the markers for first & last entries displayed, depending
362      * on what's available to us in the circular buffer.  We never leave
363      * the window empty.
364      */
365     if (objects_debug)
366         fprintf(stderr, "[%s:%s] Scrolling text object at 0x%x %d lines %s\n",
367                 mn, rn, nlines,
368                 (direction == GATOR_TEXT_SCROLL_UP) ? "UP" : "DOWN");
369
370     text_data = (struct gator_textobj *)(onp->o_data);
371     if (direction == GATOR_TEXT_SCROLL_DOWN) {
372         /*
373          * Move the object's text ``down'' by sliding the window up.
374          */
375         text_data->firstEntShown -= nlines;
376         if (text_data->firstEntShown < text_data->cbHdr->oldestEnt)
377             text_data->firstEntShown = text_data->cbHdr->oldestEnt;
378
379         text_data->lastEntShown -= nlines;
380         if (text_data->lastEntShown < text_data->cbHdr->oldestEnt)
381             text_data->lastEntShown = text_data->cbHdr->oldestEnt;
382
383     } /*Moving down */
384     else {
385         /*
386          * Move the object's text ``up'' by sliding the window down.
387          */
388         text_data->firstEntShown += nlines;
389         if (text_data->firstEntShown > text_data->cbHdr->currEnt)
390             text_data->firstEntShown = text_data->cbHdr->currEnt;
391
392         text_data->lastEntShown += nlines;
393         if (text_data->lastEntShown > text_data->cbHdr->currEnt)
394             text_data->lastEntShown = text_data->cbHdr->currEnt;
395
396     }                           /*Moving up */
397
398     /*
399      * Return the happy news.
400      */
401     return (0);
402
403 }                               /*gator_text_Scroll */
404
405 /*------------------------------------------------------------------------
406  * gator_text_Write
407  *
408  * Description:
409  *      Write the given string to the end of the gator text object.
410  *
411  * Arguments:
412  *      struct onode *onp : Ptr to the onode whose to which we're
413  *                              writing.
414  *      char *strToWrite  : String to write.
415  *      int numChars      : Number of chars to write.
416  *      int highlight     : Use highlighting?
417  *      int skip          : Force a skip to the next line?
418  *
419  * Returns:
420  *      0: Success
421  *      Error value otherwise.
422  *
423  * Environment:
424  *      Nothing interesting.
425  *
426  * Side Effects:
427  *      As advertised.
428  *------------------------------------------------------------------------*/
429
430 int
431 gator_text_Write(onp, strToWrite, numChars, highlight, skip)
432      struct onode *onp;
433      char *strToWrite;
434      int numChars;
435      int highlight;
436      int skip;
437
438 {                               /*gator_text_Write */
439
440     static char rn[] = "gator_text_Write";      /*Routine name */
441     register int code;          /*Return value on routines */
442     struct gator_textobj *text_data;    /*Ptr to text obj data */
443     struct gator_textcb_hdr *cbHdr;     /*Ptr to text CB header */
444     int i;                      /*Loop variable */
445     int oldCurrEnt;             /*CB's old currEnt value */
446     int redisplay;              /*Redisplay after write? */
447     int shownDiff;              /*Diff between 1st & last lines */
448     int writeDiff;              /*Num lines really written */
449     int bumpAmount;             /*Amount to bump count */
450
451     /*
452      * 
453      */
454     if (objects_debug) {
455         fprintf(stderr,
456                 "[%s:%s] Writing %d chars to text object at 0x%x (highlight=%d, skip=%d: '",
457                 rn, numChars, onp, highlight, skip);
458         for (i = 0; i < numChars; i++)
459             fprintf(stderr, "%c", strToWrite + i);
460         fprintf(stderr, "\n");
461     }
462
463     if (numChars == 0)
464         numChars = strlen(strToWrite);  /* simplify caller */
465     text_data = (struct gator_textobj *)(onp->o_data);
466     cbHdr = text_data->cbHdr;
467     if (cbHdr == (struct gator_textcb_hdr *)0) {
468         fprintf(stderr, "[%s:%s] Text object missing its circular buffer!\n",
469                 mn, rn);
470         return (-1);
471     }
472     /*
473      * If the current CB entry is being displayed, we track the write
474      * visually and redisplay.
475      */
476     if ((cbHdr->currEnt <= text_data->lastEntShown)
477         && (cbHdr->currEnt >= text_data->firstEntShown)) {
478         if (objects_debug)
479             fprintf(stderr,
480                     "[%s:%s] Current entry is on screen.  Tracking this write\n",
481                     mn, rn);
482         oldCurrEnt = cbHdr->currEnt;
483         redisplay = 1;
484     } else {
485         if (objects_debug)
486             fprintf(stderr,
487                     "[%s:%s] Current entry NOT on screen, not tracking write\n",
488                     mn, rn);
489         redisplay = 0;
490     }
491
492
493     if (redisplay) {
494         /*
495          * We're tracking the write.  Compute the number of screen lines
496          * actually written and adjust our own numbers, then call the
497          * display function.
498          */
499         shownDiff = text_data->lastEntShown - text_data->firstEntShown;
500         writeDiff = cbHdr->currEnt - oldCurrEnt;
501         if (objects_debug)
502             fprintf(stderr,
503                     "[%s:%s] Preparing to redisplay.  Difference in shown lines=%d, difference in written lines=%d\n",
504                     mn, rn, shownDiff, writeDiff);
505         if (shownDiff < (text_data->numLines - 1)) {
506             /*
507              * We weren't showing a full screen of stuff.  Bump the last
508              * line shown by the minimum of the number of free lines still
509              * on the screen and the number of new lines actually written.
510              */
511             bumpAmount = (text_data->numLines - 1) - shownDiff;
512             if (writeDiff < bumpAmount)
513                 bumpAmount = writeDiff;
514             text_data->lastEntShown += bumpAmount;
515             writeDiff -= bumpAmount;
516             if (objects_debug)
517                 fprintf(stderr,
518                         "[%s:%s] Empty lines appeared on screen, bumping bottom line shown by %d; new writeDiff is %d\n",
519                         mn, rn, bumpAmount, writeDiff);
520         }
521
522         /*
523          * If we have any more lines that were written not taken care
524          * of by the above, we just bump the counters.
525          */
526         if (writeDiff > 0) {
527             if (objects_debug)
528                 fprintf(stderr,
529                         "[%s:%s] Still more lines need to be tracked.  Moving first & last shown down by %d\n",
530                         mn, rn, writeDiff);
531             text_data->firstEntShown += writeDiff;
532             text_data->lastEntShown += writeDiff;
533         }
534     }
535
536     /*Redisplay needed */
537     /*
538      * Simply call the circular buffer write op.
539      */
540     code = gator_textcb_Write(cbHdr, strToWrite, numChars, highlight, skip);
541     if (code) {
542         fprintf(stderr,
543                 "[%s:%s] Can't write to text object's circular buffer, errror code is %d\n",
544                 mn, rn, code);
545         return (code);
546     }
547
548     /*
549      * Everything went well.  Return the happy news.
550      */
551     return (0);
552
553 }                               /*gator_text_Write */
554
555 /*------------------------------------------------------------------------
556  * gator_text_BlankLine
557  *
558  * Description:
559  *      Write a given number of blank lines to the given text object.
560  *
561  * Arguments:
562  *      struct onode *onp : Ptr to the onode to which we're writing.
563  *      int numBlanks     : Number of blank lines to write.
564  *
565  * Returns:
566  *      0: Success,
567  *      Error value otherwise.
568  *
569  * Environment:
570  *      Nothing interesting.
571  *
572  * Side Effects:
573  *      As advertised.
574  *------------------------------------------------------------------------*/
575
576 int
577 gator_text_BlankLine(onp, numBlanks)
578      struct onode *onp;
579      int numBlanks;
580
581 {                               /*gator_text_BlankLine */
582
583     static char rn[] = "gator_text_BlankLine";  /*Routine name */
584     register int code;          /*Return value on routines */
585     struct gator_textobj *text_data;    /*Ptr to text obj data */
586
587     /*
588      * We just call the circular buffer routine directly.
589      */
590     if (objects_debug)
591         fprintf(stderr,
592                 "[%s:%s] Writing %d blank lines to text object at 0x%x\n", mn,
593                 rn, numBlanks, onp);
594
595     text_data = (struct gator_textobj *)(onp->o_data);
596     code = gator_textcb_BlankLine(text_data->cbHdr, numBlanks);
597     if (code) {
598         fprintf(stderr,
599                 "[%s:%s] Can't write %d blank lines to text object at 0x%x\n",
600                 mn, rn, numBlanks, onp);
601         return (code);
602     }
603
604     /*
605      * Blank lines written successfully.  Adjust what lines are currently
606      * shown.  Iff we were tracking the end of the buffer, we have to
607      * follow the blank lines.
608      */
609     if (text_data->lastEntShown == text_data->cbHdr->currEnt - numBlanks) {
610         text_data->firstEntShown += numBlanks;
611         text_data->lastEntShown += numBlanks;
612     }
613
614     /*
615      * Return the happy news.
616      */
617     return (0);
618
619 }                               /*gator_text_BlankLine */