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