Why do I need to call `clear` after `initscr` with ncurses? - ncurses

I have solved this problem in the sense I have code that does what I want, but I don't understand why it is necessary to do what I do, and I cannot see this behaviour documented, so I wonder if someone could explain why?
I am actually "porting" ncurses to Forth. More correctly I am writing some RISC-V assembly that lightly wraps around the C library calls to give Forth users an interface to ncurses.
This is what the code looks like in Forth:
: hello S" Hello, World!" ;
: goodbye S" Goodbye, World! " ;
: garish 1 color_red color_yellow init_pair ;
: cool 2 color_cyan color_black init_pair ;
: doit initscr clear start_color garish cool 1 color_pair attron 10 10 movew hello drop printw refresh getch 1 color_pair attroff ;
: endit 2 color_pair attron 30 30 movew goodbye drop printw refresh getch 2 color_pair attroff endwin ;
doit
endit
For those who don't know Forth this defines a few words then calls the doit and endit words to actually execute the program. But this isn't a question about Forth but about why I need to call clear (which is simply a wrapper around a call to the ncurses clear call) after I call initscr (again just a simple wrapper around a call to the ncurses function).
The assembly is shown below. 'CODEEND' and 'CODEHEADER' are macros that generate Forth function headings and 'TAILMOD' generates the return to the loop code - but the key point is you can see these are very light wrappers around the C calls:
CODEEND INITSCR, 0x01
#(--)
call initscr
la t0, STDSCR #store stdscr
sd a0, 0(t0)
TAILMOD t1
CODEHEADER CLEAR, INITSCR, 0x01
#( -- )
call clear
TAILMOD t1
If I don't call clear, then on every subsequent call of the doit endit pair I just see the previous output - i.e. initscr has not cleared the screen without this explicit call to clear.
Am I right in thinking that initscr should normally clear the screen on every invocation (at the next call of refresh)?
Is it just a function of my terminal type (this is a tty over ssh in this case) that I have to call clear or is there something else at work here?
Adding Just to be totally clear, I know the documentation says a call to refresh is required to clear the screen and I have done that but it doesn't work - that is implicit in the code I've posted where there is an explicit refresh but I am adding this to make it obvious to people who maybe don't grok Forth. (Originally where the clear is there was a refresh but it does not clear the screen on subsequent calls.)

Per manpage:
initscr also causes the first call to refresh(3x) to clear the screen.
You won't see any change on the screen until that refresh. Some functions (such as getch) do a refresh as a side-effect.

Related

Rexx Pull is not working with clrscrn after Displaying ispf Panel

Currently i am writing a rexx program in which i need to mask password input. I use this code to get my panel displayed:
address ispexec"libdef ispplib dataset id('my.pds')
address ispexec 'display panel(member)'
This works perfectly, and returns the password to a variable, in which i perform various checks on.
After that i continue on in my rexx program. the next function that occurs, is taking in input from the user by using Rexx's 'say' 'pull' method. This is where the weird error occurs.
I have to check user input again, if its invalid it loops back to the 'pull'. However, upon returning to the 'pull' instead of allowing the user to input data, the program gets the bottom of data symbol '***'. This then of course causes an infinite loop and the user then can't put in data.
I believe the cause is displaying the panel, then using clrscrn. Cause i can take out clrscrn and it works fine but data truncates on other pages. Or i can sacrifice masking the user password by NOT displaying the ispf panel and it works. But together it fails.
I was wondering what is happening and the potential fix.
Rexx Code i use to replicate the error after displaying the panel:
do while chk <> 'N'
clrscrn
do i = 1 to 5
say '-test'
end
pull chk
end
Result one with user input of ' '
-test
-test
-test
-test
-test
' ' <---- User inputs space, invalid entry, has to be 'N'
*** <-- for some reason hits bottom of data
Then it loops back with a result of:
-test
-test
-test
-test
-test
*** <---- automatically hits bottom of data
To reiterate, if i take out the clrscrn, bottom of data never occurs. but error too many times, data truncates to another page.
Put clrscrn back in, don't display an ispf panel. Code works flawlessly, bottom of data never occurs.
Panel code:
)PANEL
)ATTR
~ TYPE(INPUT) INTENS(NON) Pad(_)
! TYPE(TEXT) COLOR(RED) SKIP(ON)
)BODY WINDOW(80,24)
! CREATE YOUR PIN NUM
!--------------------------------------------
!
! ENTER YOUR PIN:~INP !
! CONFIRM PIN...:~INPT!
!
! MUST BE 4-DIGITS
)END
Another panel I also call before similiar situations:
)PANEL
)ATTR
~ TYPE(INPUT) INTENS(NON) Pad(_)
! TYPE(TEXT) COLOR(RED) SKIP(ON)
)BODY
! VERIFY YOUR IDENTITY
!--------------------------------------------
!
! ENTER YOUR PIN: ~Z !
)INIT
&ZEDSMSG = ''
&ZEDLMSG = ''
.ZVARS = '( INP )'
.ATTR(INP) = '&ATTRPIN'
)PROC
&RESP = .RESP
)END
The 3 asterisks indicate you have gone from full screen mode to line mode. The REXX say statement is line mode. You probably have a terminal using an alternate screen size (mod5, 62 x 160, etc). TSO VTAM will force the *** to protect against issues in changing between primary and alternate screen size. Use the following ISPF service instead of CLRSCRN
address ISPEXEC "CONTROL DISPLAY LINE START(1)"
This will put you in line mode and clear the screen. Your REXX routine works for me when I use the CONTROL DISPLAY LINE. This also tells ISPF that line mode has been entered which could also avoid screen corruption errors using CLRSCRN.

I am new to AS400 and i want to know how can i give input at the run time in rpgle?

I want to convert temperature from Fahrenheit to Celsius. At run time it should ask the temperature in Fahrenheit and then show the the equivalent temperature in celsius.
Unlike other languages, RPG is built specifically for business programs. Thus it has no built in console IO like C or Java. Instead user interaction is traditionally via an object called a device file which mimics database IO. However, there is one op code that can be used to access the external message queue and can send a message and receive a reply. This op code is DSPLY. It is quite limited, you can only display a 52 character message, but will work for this purpose. A real solution where you want user IO would involve a display file. But to get something like what you are asking for in a way similar to other languages, you could write the following:
ctl-opt Option(*SrcStmt : *NoDebugIo: *NoUnref)
DftActGrp(*No) ActGrp(*New)
Main(temprature);
dcl-proc temprature;
dcl-s degreesC Char(15) Inz('');
dcl-s degreesF Char(15) Inz('');
dsply 'Enter temprature in degrees F' '*EXT' degreesF;
degreesC = %char(
(%dec(degreesF:15:0) - 32) * 5 / 9
);
dsply ('Temprature in degrees C is: ' + degreesC);
return;
end-proc;
The first dsply has three parameters, the message, the message queue, and a variable for the reply (which must be a character variable). The second dsply just has the message which can be an expression if it is enclosed in parenthesis. There is no reply, and it sends to the *EXT message queue by default for interactive jobs.
NOTE: DSPLY is really useful only for testing and debug, and has only limited utility for that. A program that will face users would use a display file or some other way to interact with the user such as through a browser using the CGIDEV2 library.
A good start is to look at the RPG Manual then start researching DDS. There is TONS of documentation out there. Just search for "iseries" then your topic.

Fortran error check on formatted read

In my code I am attempting to read in output files that may or may not have a formatted integer in the first line of the file. To aid backwards compatibility I am attempting to be able to read in both examples as shown below.
head -n 3 infile_new
22
8
98677.966601475651 -35846.869655806520 3523978.2959464169
or
head -n 3 infile_old
8
98677.966601475651 -35846.869655806520 3523978.2959464169
101205.49395364164 -36765.047712555031 3614241.1159234559
The format of the top line of infile_new is '(i5)' and so I can accommodate this in my code with a standard read statement of
read(iunit, '(I5)' ) n
This works fine, but if I attempt to read in infile_old using this, I as expected get an error. I have attempted to get around this by using the following
read(iunit, '(I5)' , iostat=ios, err=110) n
110 if(ios == 0) then
print*, 'error in file, setting n'
naBuffer = na
!rewind(iunit) #not sure whether to rewind or close/open to reset file position
close(iunit)
open (iunit, file=fname, status='unknown')
else
print*, "Something very wrong in particle_inout"
end if
The problem here is that when reading in either the old or new file the code ends up in the error loop. I've not been able to find much documentation on using the read statement in this way, but cannot determine what is going wrong.
My one theory was my use of ios==0 in the if statement, but figured since I shouldn't have an error when reading the new file it shouldn't matter. It would be great to know if anyone knows a way to catch such errors.
From what you've shown us, after the code executes the read statement it executes the statement labelled 110. Then, if there wasn't an error and iostat==0 the true branch of the if construct is executed.
So, if there is an error in the read the code jumps to that statement, if there isn't it walks to the same statement. The code doesn't magically know to not execute the code starting at label 110 if there isn't an error in the read statement. Personally I've never used both iostat and err in the same read statement and here I think it's tripping you up.
Try changing the read statement to
read(iunit, '(I5)' , iostat=ios) n
You'd then need to re-work your if construct a bit, since iostat==0 is not an error condition.
Incidentally, to read a line which is known to contain only one integer I wouldn't use an explicit format, I'd just use
read(iunit, * , iostat=ios) n
and let the run-time worry about how big the integer is and where to find it.

fopen crashes only when running from release executable

I make several calls to a function that reads data from an input file. Everything works fine in debug mode, but when I try to run the executable from release mode, the line with fopen crashes the program after a few calls. My code is:
From header file:
#define presstankdatabase "presst_database.txt"
In function:
FILE *fidread;
fidread = fopen(presstankdatabase,"r");
if (fidread==NULL) {
printf("Failed to open pressurant tank database: %s\n",presstankdatabase);
return 1;
}
In debugging, I've inserted comment lines just before and just after the line starting with fidread =, and after several calls the program crashes and I get the message "A problem caused the program to stop working correctly. Please close the program." The comment just before the fopen call is displayed, but the comment just after does not. My understanding of fopen is that is should return either a pointer or NULL, but it crashes before it even gets to the check. The only thing I can think of is that somehow I'm having memory problems, but I don't know how that would fit in with fopen crashing. Does anyone know what might be going on? Thanks!
EDIT 1: I increased the size of three variables, and the only places they're used (except in printf() calls), are as shown below.
char *constid = (char*)malloc(sizeof(char)*20);
Used like so:
strcpy(constid,"Propellant");
strcpy(constid,"Propellant tank");
strcpy(constid,"Pressurant tank");
If the variables are sized to 20, as shown above, it crashes. But if they're larger (I've tried 120 and 100), the program runs. The variables aren't used in any other places other than fprintf() or printf() calls.
presstankdatabase should be a pointer to a string containing the filename to open. If fopen() crashes then that pointer is probably invalid (or NULL). Without any more code it is not possible to debug it further. Use the VC debugger to see what's happening...
EDIT:
Another common cause of this is a filename string that suddenly stops being NULL-terminated.
You should add a printf() call to print the filename before opening. It will most probably fail to produce the expected output. If not, then you have a more interesting form of memory corruption that will take some more work to weed out.
EDIT 2:
If the printf() call shows the correct string, then you probably have memory corruption somewhere else in your code that has mangled some internal structure of the C library. A common cause is going beyond the end (or the beginning for that matter) of a static array or a region provided by malloc().

How to see output of TextOutW(...) after each call?

On writing to the display with:
::TextOutW( pDC->m_hDC, x, y, &Out, 1 );
It only shows on the screen after every 15 calls (15 characters).
For debugging purposes only, I would like to see the new character on the display after each call. I have tried ::flushall() and a few other things but no change.
TIA
GDI function calls are accumulated and called in batches for performance reasons.
You can call GdiFlush after the TextOut call to perform the drawing immediately. Alternatively, call GdiSetBatchLimit(1) before outputting the text to disable batching completely.
::flushall() is for iostreams, so it won't affect Windows screen output at all. I've never tried it, but based on the docs, I believe GDIFlush() might be what you want. You should also be able to use GDISetBatchLimit(1); to force each call to run immediately upon being called.

Resources