home *** CD-ROM | disk | FTP | other *** search
/ ARM Club 1 / ARM_CLUB_CD.iso / contents / apps / languages / progs / shell / Sources / c / TextRect < prev    next >
Encoding:
Text File  |  1994-06-25  |  9.0 KB  |  387 lines

  1. #include <string.h>
  2. #include <stdio.h>
  3. #include <stdarg.h>
  4.  
  5. #include "DeskLib:WimpSWIs.h"
  6. #include "DeskLib:Error.h"
  7.  
  8. #include "Shell.Shell.h"
  9. #include "Shell.Extra.h"
  10. #include "Shell.SafeAlloc.h"
  11. #include "Shell.TextRect.h"
  12.  
  13.  
  14.  
  15. #define Shell_TEXT_INCREMENT 4096
  16.     /* Text is stored in a malloc-ed block which is a multiple of this size    */
  17.     /* so as to avoid repeadly realloc-ing                    */
  18.  
  19.  
  20.  
  21. typedef struct    {            /* this is used to record a reference point in some     */
  22.     int line;            /* text. 'offset' is the position in text of the first     */
  23.     int offset;            /* chr of line-number 'line'.                */
  24.     }
  25.     Shell_textref;
  26.  
  27.  
  28. typedef struct    {
  29.     char        *text;            /* The text.                    */
  30.     int        datasize,        /* Length of text *excluding* the '\0'.        */
  31.             maxdatasize;        /* Space currently rserved for text (excl '\0').*/
  32.     int        numlines,        /* The number of lines in the text...        */
  33.             maxlinelen;        /* Used to check whether window is wide enough.    */
  34.     Shell_textref    top, bottom, last;    /* 'top' is for top visible line in the window.    */
  35.     }                    /* 'bottom' is for the last visible line.    */
  36.     Shell_textrectblock;            /* 'last' is for the last line in the text.    */
  37.                         /* 'top' and 'bottom' are updated each time any    */
  38.                         /* part of the text is re-drawn, and are set to    */
  39.                         /* first and last line of the redrawn text.    */
  40.  
  41.  
  42.  
  43.  
  44.  
  45. static int Shell_TextRectFindLineNumber( const Shell_textrectblock *info, int line)
  46.     /* This function returns the position of the first charater of line number 'line'    */
  47.     /* in info->text. It finds which reference point is nearest to line number 'line,     */
  48.     /* then counts forward or backwards, counting line-feeds until is reaches the start of     */
  49.     /* line-number 'line'.                                    */
  50.     /* It all looks a bit long-winded, partly 'cos I've tried to make it run fast.        */
  51.     /* It should really be in assembler for speed, but I don't know nearly enough for that.    */
  52. {
  53.     Shell_textref    nearest;
  54.     int        step;
  55.  
  56. if ( line >= info->numlines) return -1;
  57. if ( line == 0) return 0;
  58.  
  59. /* find reference line that is closest to line */
  60.  
  61. if ( line <= info->top.line)    {
  62.     if ( (line-info->top.line-line) < line-0 )    {
  63.         nearest = info->top;
  64.         step = -1;
  65.         }
  66.     else    {
  67.         nearest.line=0;
  68.         nearest.offset =0;
  69.         step = +1;
  70.         }
  71.     }
  72.  
  73. else if ( line <= info->bottom.line)    {
  74.     if ((info->bottom.line-line) < (line-info->top.line))    {
  75.         nearest = info->bottom;
  76.         step = -1;
  77.         }
  78.     else    {
  79.         nearest = info->top;
  80.         step = +1;
  81.         }
  82.     }
  83.  
  84. else    {
  85.     if ((info->last.line-line) < (line-info->bottom.line))    {
  86.         nearest = info->last;
  87.         step = -1;
  88.         }
  89.     else    {
  90.         nearest = info->bottom;
  91.         step = +1;
  92.         }
  93.     }
  94.  
  95.  
  96. /*    now step along from the reference line, counting LF's until we have reached the line...    */
  97.  
  98. if ( step > 0)    {
  99.     for ( ; nearest.line != line; nearest.offset++)    {
  100.         if ( info->text[nearest.offset]=='\n')    nearest.line++;
  101.         }
  102.     }
  103. else    {
  104.     for ( nearest.offset -= 2; nearest.line != line; nearest.offset--)    {
  105.         if ( info->text[nearest.offset]=='\n')    nearest.line--;
  106.         }
  107.     nearest.offset+=2;
  108.     }
  109.  
  110.  
  111. /*    nearest.offset is position in info->text of the first chr of line-number 'line'.*/
  112. /*    Just check here that this position is not outside the range of the text, to      */
  113. /*    prevent subsequent overwriting of memory.                    */
  114.  
  115. if ( nearest.offset < 0 || nearest.offset > info->datasize)
  116.     Error_ReportFatal( 1, Error_PLACE "Error in Shell_TextRectFindLineNumber");
  117.  
  118. return nearest.offset;
  119. }
  120.  
  121.  
  122.  
  123.  
  124.  
  125.  
  126. static BOOL Shell_TextRectSaver( char *filename, Shell_rectblock *r)
  127. {
  128. FILE    *f;
  129. Shell_textrectblock *textrectblock = (Shell_textrectblock *) r->reference;
  130.  
  131. f = fopen( filename, "w");
  132. if ( !f) return FALSE;
  133.  
  134. fprintf( f, textrectblock->text);
  135. fclose(f);
  136.  
  137. return TRUE;
  138. }
  139.  
  140.  
  141.  
  142.  
  143.  
  144. #define Min( a, b) ( (a) < (b) ) ? (a) : (b)
  145.  
  146. static int Shell_TextRectRAMSaver(
  147.     task_handle    sourcetask,
  148.     Shell_rectblock    *r,
  149.     task_handle    desttask,
  150.     void        *destbuffer,
  151.     unsigned int    buffersize,
  152.     int        progress
  153.     )
  154. {
  155. Shell_textrectblock    *textrectblock = (Shell_textrectblock *) r->reference;
  156. int n;
  157.  
  158. n = Min( textrectblock->datasize - progress, buffersize);
  159.     /* The length of the text in the rect is ...->datasize. This excludes    */
  160.     /* the '\0', which looks a bit funny if included into a text editor    */
  161.  
  162. Wimp_TransferBlock(
  163.     sourcetask,    textrectblock->text + progress,
  164.     desttask,    destbuffer,
  165.     n
  166.     );
  167. return n;
  168. }
  169.  
  170.  
  171.  
  172.  
  173.  
  174.  
  175.  
  176.  
  177.  
  178.  
  179.  
  180.  
  181. static void Shell_TextRectRedrawer(
  182.     Shell_convertpoint    convert,
  183.     wimp_point        rectsize,
  184.     void            *reference,
  185.     const wimp_rect        *redrawrect
  186.     )
  187.  
  188. {    Shell_textrectblock    *info    = reference;
  189.     wimp_rect        rect    = *redrawrect;
  190.     int            n;
  191.     char            *c;
  192.  
  193. Shell_ConvertToSubTextRect2( &rect, rectsize);
  194.  
  195. n = Shell_TextRectFindLineNumber( info, rect.min.y);
  196.  
  197. if ( n!= -1)    {
  198.     c = &info->text[n];
  199.     info->top.line = rect.min.y;    /* Update top reference point.            */
  200.     info->top.offset  = n;        /* This will be useful in subsequent redraws    */
  201.     if ( rect.max.y > info->numlines) rect.max.y = info->numlines;
  202.         {    int    y;
  203.             char    *cc;
  204.         for ( y=rect.min.y, cc=c; y<=rect.max.y; y++, c=cc+1)    {
  205.             /* print line number y. Put a '\0' temporarily at end of line */
  206.             cc = strchr( c, '\n'); if (cc) *cc=0;
  207.             Shell_PrintString(
  208.                 c, 0, rectsize.y - y*Shell_TEXTYSIZE, convert
  209.                 );
  210.             if (cc)    *cc = '\n';
  211.             else    break;
  212.             }
  213.         info->bottom.line = y;
  214.         info->bottom.offset = ( c - info->text);
  215.         }
  216.     }
  217. return;
  218. }
  219.  
  220.  
  221.  
  222.  
  223.  
  224.  
  225.  
  226. Shell_rectblock    *Shell_AddTextRect( Shell_windblock *w, int x, int y, int forecol, int backcol)
  227. {
  228.     Shell_textrectblock    *info = Shell_SafeMalloc( sizeof( Shell_textrectblock));
  229.     Shell_rectblock        *r;
  230.  
  231. info->text        = Shell_SafeMalloc( 1+Shell_TEXT_INCREMENT); info->text[0] = 0;
  232. info->maxdatasize    = Shell_TEXT_INCREMENT;
  233. info->datasize        = 0;
  234. info->maxlinelen    = 0;
  235. info->numlines        = 1;
  236. info->last.line        = 0;
  237. info->top.line        = 0;
  238. info->bottom.line    = 0;
  239. info->last.offset    = 0;
  240. info->top.offset     = 0;
  241. info->bottom.offset    = 0;
  242.  
  243. r = Shell_AddRectangle2(
  244.     w, x, y-Shell_TEXTYSIZE, x+Shell_TEXTXSIZE, y,
  245.     Shell_TextRectRedrawer, info
  246.     );
  247.  
  248. Shell_MakeRectIcon( r, forecol, backcol, "R2");
  249.  
  250. r->saver    = Shell_TextRectSaver;
  251. r->ramsaver    = Shell_TextRectRAMSaver;
  252.  
  253. return r;
  254. }
  255.  
  256.  
  257.  
  258.  
  259.  
  260.  
  261.  
  262. Shell_rectblock    *Shell_defaulttextrectblock    = NULL;    /* Not opened yet.    */
  263.  
  264.  
  265.  
  266.  
  267.  
  268.  
  269. void Shell_TextRectPrint( Shell_rectblock *rect, const char *text)
  270. {    int extraneeded;
  271.     int lastLF, numlines, size;
  272.     Shell_textrectblock *info;
  273.  
  274.  
  275. /*    Check whether the rect is Shell_'s default textrect        */
  276. /*    and open a window + textrect if one isn't opened already    */
  277.  
  278. if ( rect == Shell_defaulttextrect)    rect = Shell_defaulttextrectblock;
  279.     /* Plot to the default text-rect window.    */
  280.  
  281. if ( rect == NULL)    {
  282.     rect = Shell_defaulttextrectblock =
  283.         Shell_AddTextRect(
  284.             Shell_OpenGFXWindow(),
  285.             0,
  286.             0,
  287.             colour_BLACK,
  288.             colour_TRANSPARENT
  289.             );
  290.     }
  291.     /* Have to open a new window, and add a textrect    */
  292.  
  293.  
  294. /* Can now do the actual text-printing...                */
  295. /* This involves adding 'text' to the end of the existing text.        */
  296. /* We have to calculate how many lines are added, whether the         */
  297. /* max-linelength has increased, etc.                    */
  298.  
  299. info = (Shell_textrectblock *) rect->reference;
  300.  
  301. /*    Count number of linefeeds in the new text, also find length, and    */
  302. /*    max line-length. Could do this with str* functions, but this will be    */
  303. /*    quicker as it only loops through the text once.                */
  304.  
  305.     {
  306.     char        *c    = (char *) text;
  307.     int        linelen;
  308.  
  309.     size        =    0;
  310.     numlines    =    0;
  311.  
  312.     lastLF = -(int) ( info->datasize - info->last.offset) - 1;
  313.         /* last.offset is ptr to chr *after* the last '\n', so this makes lastLF    */
  314.         /* be the position of the last '\n'                        */
  315.  
  316.     for ( ; ; c++, size++)    {
  317.         if ( *c == '\n' || ( !*c) )    {
  318.             linelen = (int) ( c-text) - lastLF - 1;
  319.             if ( linelen > info->maxlinelen) info->maxlinelen = linelen;
  320.             if ( *c)    {
  321.                 lastLF = c-text;
  322.                 numlines++;
  323.                 }
  324.             }
  325.         if (!*c) break;
  326.         }
  327.     }
  328.  
  329.  
  330. extraneeded = info->datasize + size - info->maxdatasize;
  331.  
  332. if ( extraneeded > Shell_TEXT_INCREMENT)    {
  333.     info->text = Shell_SafeRealloc( info->text, info->datasize+size+1);
  334.     info->maxdatasize = info->datasize + size;
  335.     }
  336. else if ( extraneeded > 0)    {
  337.     info->text = Shell_SafeRealloc( info->text, info->maxdatasize+Shell_TEXT_INCREMENT+1);
  338.     info->maxdatasize += Shell_TEXT_INCREMENT;
  339.     }
  340.  
  341. strcpy( &info->text[ info->datasize], text);
  342.  
  343. if ( lastLF>=0)    {
  344.     info->last.offset = lastLF + info->datasize+1;    /* datasize is still old value */
  345.                             /* ptr is to the chr AFTER the LF */
  346.     info->last.line += numlines;
  347.     info->numlines  += numlines;
  348.     }
  349.  
  350. info->datasize += size;
  351.  
  352.  
  353.     {
  354.         int    oldrectminy = rect->rect.min.y;
  355.         BOOL    yscrollbottom = Shell_CheckYScrollIsBottom( rect->window);
  356.         wimp_rect    newrect;    /* This is the new rect at the bottom.    */
  357.  
  358.     rect->rect.max.x = rect->rect.min.x + Shell_TEXTXSIZE * info->maxlinelen;
  359.     rect->rect.min.y = rect->rect.max.y - Shell_TEXTYSIZE * info->numlines;
  360.  
  361.     Shell_ResizeIconRect( rect);
  362.  
  363.     newrect = rect->rect;
  364.     newrect.max.y = oldrectminy + Shell_TEXTYSIZE;
  365.  
  366.     /*Shell_CheckWindSizeAndRedraw( rect->window, &rect->icon.workarearect);*/
  367.     Shell_CheckWindSizeAndRedraw( rect->window, &newrect);
  368.  
  369.     if ( yscrollbottom)    Shell_MoveYScrollToBottom( rect->window);
  370.     }
  371. }
  372.  
  373.  
  374.  
  375.  
  376.  
  377. void    Shell_TextRectPrintf( Shell_rectblock *rectblock, const char *fmt, ...)
  378. {    va_list args;
  379. va_start( args, fmt);
  380. vsprintf( Shell_string, fmt, args);
  381. va_end( args);
  382. Shell_TextRectPrint( rectblock, Shell_string);
  383. }
  384.  
  385.  
  386.  
  387.