English Amiga Board Amiga Lore


Go Back   English Amiga Board > Coders > Coders. Language > Coders. C/C++

 
 
Thread Tools
Old 01 August 2017, 12:34   #1
chocsplease
Registered User

 
Join Date: Dec 2016
Location: london
Posts: 134
Question Problems trying to output text to a simple window

Hello all,

I am trying to output text to a window and have run into a number of issues.

I had assumed that the Amiga would be nice and if I set up a window with drag bars and resize etc gadgets it would take care of text that was larger than the size of the window.

It looks like I was wrong.

I am defining my window thus
Code:
int open_window(int scrnwidth,int scrnheight)
{
    int topleftx=0,toplefty=0;
    int width=200,height=200;
    int tempw=0,temph=0;
/*calculate 1 quarter of screen width*/

    if (mywindow)
        return 0; /*opened already*/

    tempw=scrnwidth/4;

/*calculate 1 5th screen height*/

    temph=scrnheight/5;

    topleftx=tempw;
    toplefty=temph;

    width=scrnwidth-(tempw*2);
    height=scrnheight-(temph*2);

    mywindow = OpenWindowTags(NULL, WA_Left, topleftx, WA_Top, toplefty, WA_Width,width, WA_Height,height,\
        WA_IDCMP,IDCMP_CLOSEWINDOW, WA_Flags, WFLG_SIZEGADGET | WFLG_DRAGBAR | WFLG_DEPTHGADGET | WFLG_CLOSEGADGET | WFLG_ACTIVATE,\
        WA_Title, "Info64", WA_PubScreenName, "WorkBench", TAG_DONE);

    if (mywindow)
    {
        myIText.FrontPen    = myTEXTPEN;
                myIText.BackPen     = myBACKGROUNDPEN;
                myIText.DrawMode    = JAM2;
                myIText.LeftEdge    = MYTEXT_LEFT;
                myIText.TopEdge     = MYTEXT_TOP;
                myIText.ITextFont   = &myTextAttr;
                myIText.IText       = "Hello, World.  ;-)";
                myIText.NextText    = NULL;
        mywindowrastport=mywindow->RPort;
        return 0;
    }
    else
        return 1;
}
You'll see that I am also setting up a structure to output some text in the same function. myIText is a global defined as - struct IntuiText myIText;

Later on in the code I replace my simple hello world text with what I want to display -

Code:
if (mywindow)
    {
        sprintf(buffer,"%s%s       %s%s    %s%s       %s%s       %s%s   %s%s  %s%s     %s%s%s\n",messages[9],tabs_ptr[0],\
            messages[10],tabs_ptr[1],messages[11],tabs_ptr[2],messages[12],\
            tabs_ptr[3],messages[13],tabs_ptr[4],messages[14],tabs_ptr[5],messages[15],\
            tabs_ptr[6],messages[16],tabs_ptr[7],messages[17]);
        myIText.IText = buffer;
        PrintIText(mywindow->RPort,&myIText,10,10);
    }
buffer is simply a char array 500 long.

However this text is larger than the window so I had assumed that the Amiga would only display what it could and keep the rest hidden 'somewhere' for when the window was resized.

Nope doesn't do that.

Instead it dumps out the text and overwrites the right most edge of the window.

I've obviously missed something fundamental here but I am struggling to find out what.

Is there a way of confining text output in the way I have described? I don't really want to attach a console to the window, which is the only way I have discovered so far.

Here's hoping, and as always many many thanks in advance.
chocsplease is offline  
AdSense AdSense  
Old 01 August 2017, 14:32   #2
Cylon
Registered User

 
Join Date: Oct 2014
Location: Europe
Posts: 440
Easy way is to use GimmeZeroZero (GZZ) flags on your window, which results in a different Rastport for the window's borders - the system (Intuition) will handle clipping at the edges, or,
you install your own clipping regions.
Third option:
you determine the pixel width of the text and cut the string accordingly.

Last edited by Cylon; 02 August 2017 at 02:00.
Cylon is offline  
Old 03 August 2017, 16:31   #3
chocsplease
Registered User

 
Join Date: Dec 2016
Location: london
Posts: 134
Quote:
Originally Posted by Cylon View Post
Easy way is to use GimmeZeroZero (GZZ) flags on your window, which results in a different Rastport for the window's borders - the system (Intuition) will handle clipping at the edges, or,
you install your own clipping regions.
Third option:
you determine the pixel width of the text and cut the string accordingly.
Many thanks for the reply - I'll check out the gzz option. I have been working on the 3rd, and wrote a function to count the number of chars I was going to output in preparation. Thing is it doesn't work

This is the code
Code:
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <proto/dos.h>   
#include <proto/exec.h>  



long count_chars(char *format, ...) /* variable number of args*/
{
    va_list valist;
    unsigned int i,longcount=0,spcfound=1,nosign=0,ok=0,ii=0,error=0;
    long count=0;
    long long number;
/*    char *format;*/
    char letter1,letter2,letter3;
    char* string;

    va_start(valist,format);

/*    if (num<1)/
    {
        error=-2;
        va_end(valist);
        return error;    
    }*/

    /*format=(char*)va_arg(valist,char);*/ /*get format string*/

    if (strlen(format)==0) /*if dud format string*/
    {
        va_end(valist); /*free memory*/
        return -3;    /*quit*/
    }

    printf("format is %d long\n",strlen(format));

    /*now parse format string, counting normal chars and calulating size of numbers*/

    for (i=0;i<strlen(format);i++)
    {

        printf("i=%d char=%c\n",i,(char)format[i]);

        if (CheckSignal (SIGBREAKF_CTRL_C))
        { 
            printf("*BREAK main loop*\n");
            break;
        }
                    

        letter1=(char)format[i];
        if (letter1 !='%')
        {
            if (letter1==' ')
                spcfound=1;

            if (spcfound==1)    /*normal character ie not in format% <something>*/
                count++;
        }
        else if ((i+1) <(strlen(format)))
        {
            letter2=(char)format[i+1];
            spcfound=0;        /*now we hunt for a space or %*/
    
            if (letter2=='%') /*want to output a percent sign*/
            {
                count++;    /*just add to count*/
                i++;        /*inc place*/
                spcfound=1;    /*now looking for a space*/
            }
            else if (letter2=='u')    /*signifies unsigned so set flag*/
            {
                nosign=1;
                i++;
            }
            
            else if (letter2=='l')    /*long integer so add to longcount*/
            {
                longcount++;
                i++;
            }

            else if ((letter2=='d') ||(letter2=='x'))    /*work out number of chars in dec or hex number*/
            {
                ok=0;
                i++;
                if (nosign)
                {
                    if (longcount==0)
                    {
                        ok=1;
                        number=va_arg(valist,unsigned int);
                    }
                    if (longcount==1)
                    {
                        ok=1;
                        number=va_arg(valist,unsigned long int);
                    }
                    if (longcount==2)
                    {
                        ok=1;
                        number=va_arg(valist,unsigned long long int);
                    }
                    if (longcount>2)
                    {
                        error=-1;    /*formatting error too many l's*/
                        break;
                    }
                
        
                    if (ok)        /* have something in number*/
                    {
                        while (number!=0)
                        {
                            printf("unsigned  number %d\n",number);
                            if (CheckSignal (SIGBREAKF_CTRL_C))
                            { 
                                printf("*BREAK unsigned loop*\n");
                                break;
                            }
    
                            if (letter2=='d')
                                number=number/10;
                            else
                                number=number/16;

                            count++;
                        }
                    }
                    longcount=0;    /*clear count of l's*/
                                
                }
                else     /*signed*/
                {
                    printf("signed longcount=%d\n",longcount);
                    if (longcount==0)
                    {
                        ok=1;
                        printf("int\n");
                        number=va_arg(valist, int);
                    }
                    if (longcount==1)
                    {
                        ok=1;
                        printf("long int\n");

                        number=(long long int)va_arg(valist, long int);
                    }
                    if (longcount==2)
                    {
                        ok=1;
                        printf("long long int\n");

                        number=(long long int)va_arg(valist, long long int);
                    }
                    if (longcount>2)
                    {
                        error=-1;    /*formatting error too many l's*/
                        break;
                    }
                
                    if(ok)
                    {
                        printf("number starts %d\n",number);
                        if (number<0)    /*negetive number so allow for sign*/
                            count++;
                        while (number!=0)
                        {
                            printf("signed number %d\n",number);

                            if (CheckSignal (SIGBREAKF_CTRL_C))
                            { 
                                printf("*BREAK signed loop*\n");
                                break;
                            }
                    
                            if (letter2=='d')
                                number=number/10;
                            else
                                number=number/16;
                            
                            count++;
                        }

                    }
                    longcount=0;    /*clear count of l's*/
                }
            }    /*end of if (letter1=='d')*/
            
            else if(letter2=='s') /*string*/
            {
                string =va_arg(valist,char*);
                count=count+strlen(string);
            }
        }
        else    /* % at end of string - dud format*/
        {
            printf("dud string\n");
            error=-1;
            break;
        }
    }    /* end for*/

    va_end(valist);    /*clear va memory*/

printf("error=%d\n",error);

    if (error!=0)
        return error;

    return count;
}

int main()
{
    int num1=-500;
    unsigned int num2 =45;
    long int num3 = -5087654;
    unsigned long int num4 = 3637363783;
    long long int num5= -82344826482342;
    unsigned long long int num6 =88268966344;

    long result=0;

    result=count_chars("This is a test %d",num1);

    printf("The number of chars is %d\n",result);
return 0;
}
What I am trying to do is parse a format string like "this is a number %d" in the 1st argument have the actual number, or numbers in subsequent arguments and spit out the total number of characters.

However the line -

number=va_arg(valist, int);

is always setting number to -1. I have tried casting as - number=(long long int)va_arg(valist, int); but this also returns -1.

I'm using this page - https://en.wikibooks.org/wiki/C%2B%2...nctions/va_arg

for my inspiration, but this is C++ and appears to be defining the vars used to pull the arguments out on the fly (eg -
int d = va_arg( argptr, int ); )

Once
again I am stuck. What really baffles me is the loop -

Code:
while (number!=0)                         
{ 
       printf("signed number %d\n",number);                              
       if (CheckSignal (SIGBREAKF_CTRL_C))                             
       {                                  
              printf("*BREAK signed loop*\n");                                 
             break;                             
       }                                                  
       if (letter2=='d')                                 
             number=number/10;                             
       else                                 
             number=number/16;                                                          
       count++;                         
}
Actually works and loops 3 times for the number -500. Even though number is printf-ing as -1 and changing the %d to %ld in my printfs has no effect it still spits out -1.

Can anyone see where I am going wrong?
chocsplease is offline  
Old 03 August 2017, 17:10   #4
alkis
Registered User

 
Join Date: Dec 2010
Location: Athens/Greece
Age: 46
Posts: 343
what exactly are you trying to do?

sprintf should return the 'number of chars' that went into the buffer. If it didn't/doesn't, you can always return strlen(buffer)
alkis is offline  
Old 03 August 2017, 19:06   #5
Cylon
Registered User

 
Join Date: Oct 2014
Location: Europe
Posts: 440
No no, just use TextLength() and if the returned amount of pixels is to high then eat a few chars from the end.
Cylon is offline  
Old 03 August 2017, 20:04   #6
alkis
Registered User

 
Join Date: Dec 2010
Location: Athens/Greece
Age: 46
Posts: 343
Let me try again, what does the function count_chars() supposed to do?
It returns a long. What is the long supposed to represent?
alkis is offline  
Old 08 August 2017, 12:09   #7
chocsplease
Registered User

 
Join Date: Dec 2016
Location: london
Posts: 134
Many thanks for the replies, I'll look into TextLength.

Quote:
Originally Posted by alkis View Post
Let me try again, what does the function count_chars() supposed to do?
It returns a long. What is the long supposed to represent?
count_chars takes a format string, similar to that used in printf and counts all the characters plus any from numbers and additional strings.

If you give it "Test number %d test string %s",number,string it will count the chars in the text (25) and then work out the number of digits in number and then add the length of string to the result before returning the result.

So if number is 50 and string is "Hello" the total would be 32.

There is some very simple format checking and the function will return a negative number if it has hit a problem.

I think I've stumbled on what's going wrong - its to do with the way my version of gcc handles long longs , or rather does not.

64 bit maths is implemented (you can add, subtract etc long longs) as are shifts (<< and >>) and boolean ops ( x &y and x | y work). But printf breaks if you give it a long long. printf ("%lld",number) just returns %lld and printf("%ld",number) returns -1 if the number is a long long. I can cast the number to a long and then printf works.

The other issue is that va_arg() can't handle long longs so I have had to break these into two longs and shift the high bytes after they have been retrieved by va_arg().

I did think about just using sprintf, but this requires a buffer and I do not know the maximum size the resulting string is going to be.
chocsplease is offline  
Old 08 August 2017, 15:45   #8
mark_k
Registered User
 
Join Date: Aug 2004
Location:
Posts: 2,414
How about using fprintf() instead of sprintf()?

It's kind of a hack, but can you open NIL: then call fprintf() outputting to NIL: to discard the output since you're just interested in the return value?
mark_k is offline  
Old 12 August 2017, 13:09   #9
chocsplease
Registered User

 
Join Date: Dec 2016
Location: london
Posts: 134
Quote:
Originally Posted by mark_k View Post
How about using fprintf() instead of sprintf()?

It's kind of a hack, but can you open NIL: then call fprintf() outputting to NIL: to discard the output since you're just interested in the return value?
Many thanks for the suggestion, it may be a hack(ish) but it works. the only problem I have is that the resulting executable is 7.7K for something that is tiny. So I tried to 'Amigaise' it - this is my code.

Code:
#include <proto/dos.h>
#include <proto/exec.h>
#include <ctype.h>
int main()
{
    BPTR *fh;
    long result;
    int number =57;
    fh = Open("NIL:", MODE_NEWFILE);
    if (fh) /*if file opened*/
    {
        result=VFPrintf(fh,"This is a test %ld",(long)number);
        Close(fh);
    }

    Printf("the result is %ld\n",result);
}
I have a problem
  • I am getting a warning on the VFPrintf line (Initialisation makes integer for a pointer without a cast)
The executable is 2.2 k and it works, but I've had problems finding info on VFPrintf so suspect I've got the args wrong, can someone point out where?


Many thanks.

Last edited by chocsplease; 12 August 2017 at 13:17.
chocsplease is offline  
Old 12 August 2017, 19:12   #10
a/b
Registered User

 
Join Date: Jun 2016
Location: europe
Posts: 54
You generally don't use v-printf style functions with individual arguments, you use them with a variable length argument list. Something like:
Code:
int some_function(int first, const char* format, ...)  // variable number of arguments
{
va_list list;
va_start(list,format); // format is the last non-variable argument
vfprintf(stdout,format,list);
va_end(list);
}
You should use fprintf instead.
a/b is offline  
Old 13 August 2017, 14:33   #11
mark_k
Registered User
 
Join Date: Aug 2004
Location:
Posts: 2,414
Quote:
Originally Posted by chocsplease View Post
Many thanks for the suggestion, it may be a hack(ish) but it works. the only problem I have is that the resulting executable is 7.7K for something that is tiny. So I tried to 'Amigaise' it - this is my code.
...
I have a problem
  • I am getting a warning on the VFPrintf line (Initialisation makes integer for a pointer without a cast)
The executable is 2.2 k and it works, but I've had problems finding info on VFPrintf so suspect I've got the args wrong, can someone point out where?
I think you're almost there. Check the VFPrintf autodoc.

VFPrintf takes a fixed number of arguments (3). The third argument is a pointer to an array of formatting values. That's unlike the C fprintf() function which takes a variable number of arguments. However as mentioned in the autodoc you can use FPrintf which does take a variable number of arguments. You'll need to link your program with amiga.lib if you don't already. So do something like
Code:
result=FPrintf(fh,"This is a test %ld",(long)number);

Another alternative, which is cleaner in a sense because you don't need to open a file, would be to use the Exec function RawDoFmt(). With that, you could pass &result for the 4th argument (PutChData). Your PutChProc function would look like this:
Code:
PutChProc:  addq.l #1,(A3)
            rts
mark_k is offline  
Old 13 August 2017, 14:48   #12
mark_k
Registered User
 
Join Date: Aug 2004
Location:
Posts: 2,414
No guarantee this is correct. In fact it probably isn't...
Code:
long result = 0;
long PutChProc = 0x52934E75;   /* 68000 opcodes for addq.l #1,(A3) then rts */
RawDoFmt("This is a test %ld", &number, &PutChProc, &result);

Last edited by mark_k; 13 August 2017 at 14:56.
mark_k is offline  
Old 13 August 2017, 15:05   #13
mark_k
Registered User
 
Join Date: Aug 2004
Location:
Posts: 2,414
Another idea... If you wanted to write portable code, it looks like using snprintf() could be neater than fprintf() with NIL: (and of course NIL: is Amiga-specific).
Code:
char dummy = 0;
result = snprintf(&dummy, 1, "This is a test %ld", number);
mark_k is offline  
Old 13 August 2017, 15:46   #14
chocsplease
Registered User

 
Join Date: Dec 2016
Location: london
Posts: 134
Many thanks for the replies.

I wanted to try and keep the executable small, and using fprintf (with fopen, fclose etc) gave one that was over 10k. The Amiga version I posted gave 2.9k however I had completely missed the existence of FPrintf which is exactly what I need.

I tried using VFPrintf with va_start etc, but for some reason it would only output the basic text, 0 for any number and nothing at all for strings. No idea why.

I'm writing for the Amiga so thankfully portability is not an issue.

Many thanks once again.
chocsplease is offline  
AdSense AdSense  
 


Currently Active Users Viewing This Thread: 1 (0 members and 1 guests)
 
Thread Tools

Similar Threads
Thread Thread Starter Forum Replies Last Post
Trying the get bold, italic and coloured text out to the shell window. chocsplease Coders. C/C++ 16 22 June 2017 14:58
Simple and ugly text wrapping routine rockersuke Coders. AMOS 7 21 November 2014 22:31
How can I do I/O redirection to a simple console window? Leffmann Coders. System 5 26 October 2014 23:42
Searching for a simple Text Editor Morbane request.Apps 2 01 January 2012 01:05
Standard output window Rixa support.Apps 5 17 January 2008 23:36

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT +2. The time now is 03:48.


Powered by vBulletin® Version 3.8.8 Beta 1
Copyright ©2000 - 2017, vBulletin Solutions, Inc.
Page generated in 0.29187 seconds with 14 queries