For some reason my noecho() initialization is not working, until I give an input twice. The first time I press h, I get an 'h' char on the screen. However, next pressed keys don't appear on the screen. How can I prevent ALL input from showing?
#include <ncurses.h>
int main(){
initscr(); /* Start curses mode */
raw(); /* prevents use of signals from ctl + c
noecho(); /* suppress echo */
mvprintw(10,10,"Hello World!!"); /* Print */
refresh(); /* print it on real screen */
while(true){
char ch = getch(); /* wait for input */
if(ch == 'q')
break;
else if(ch == 'h'){
mvprintw(10,10,"Test");
}
else{
attroff(A_BOLD);
}
}
endwin(); /* end curses mode */
return 0;
}
The comment is un-ended, making the compiler ignore noecho:
raw(); /* prevents use of signals from ctl + c
noecho(); /* suppress echo */
You can see this if you use gcc's warnings:
foo.c:3:5: warning: function declaration isn’t a prototype [-Wstrict-prototypes]
foo.c: In function ‘main’:
foo.c:6:37: warning: "/*" within comment [-Wcomment]
foo.c:12:23: warning: conversion to ‘char’ from ‘int’ may alter its value [-Wconversion]
Related
I'm trying to write a pty I/O transparent filter for a shell.
The following example mostly works. Most programs run as expected with the wrapper. This example does not do any filtering, it's purpose is just to provide a framework.
EDIT: With my answer below I got this example working. I've updated the example here to reflect that.
Here is the now working code:
/*
This example is public domain. Use as you see fit.
The purpose of this example is show how a process can run a shell transparently and be able to filter it's input and output.
This example does not show off any I/O filtering, it only provides the framework on which that could be added.
Tested only on GNU/Linux with recent kernels and recent g++ and clang++
This example is based on original found here:
https://www.scriptjunkie.us/wp-content/uploads/2011/04/stdioterminallogger.c
There were 2 problems with the code this example was based on.
1) Terminal (re)sizing was not being handled
2) Some applications display incorrectly or keys don't work
a) with 'joe', Enter, Ctrl-M, and Ctrl-J don't work
b) 'joe' has display isues
c) 'snake' (game) has display issues
Also, be aware of this:
#define LOGFILELOCATION "/tmp/.shlog"
in the original code, not this example.
This example does not write produce any files. (intermediate or otherwise)
The following programs do seem to work correctly:
vi, vim, nano, mcedit, htop, top
#1 has been solved with a resize handler (see handler and handleTerminalResize)
Use this in shell's profile/bashrc to indicate pty-filter is present
[ "${inptyfilter}" == "true" ] && PS1="(pty-filter) ${PS1}"
Compile with any of the following:
g++ -std=c++11 pty-filter.cpp -lutil -o pty-filter
g++ -std=c++1y pty-filter.cpp -lutil -o pty-filter
g++ -std=c++1z pty-filter.cpp -lutil -o pty-filter
clang++ -std=c++11 pty-filter.cpp -lutil -o pty-filter
clang++ -std=c++1y pty-filter.cpp -lutil -o pty-filter
clang++ -std=c++1z pty-filter.cpp -lutil -o pty-filter
# for stricter compilation:
clang++ -std=c++1z pty-filter.cpp -lutil -o pty-filter -Wall -Werror -Weverything -Wno-c++98-compat -Wno-missing-prototypes -Wno-disabled-macro-expansion -Wno-vla-extension -Wno-vla
*/
// standard C stuff
#include <cstdio>
#include <cstdlib>
#include <csignal>
#include <cerrno>
#include <cstdarg>
// C++ stuff
#include <string>
// Everything else
#include <pty.h>
#include <unistd.h>
#include <termios.h>
#include <sys/mman.h>
#include <sys/wait.h>
// shared globals
struct sharedBookT {
pid_t childPid;
pid_t parentPid;
pid_t shellPid;
int shellFd;
termios oldTerm, newTerm, shellTerm;
bool readyToQuit;
char fromTerminalBuffer [4096];
char toTerminalBuffer [4096];
char padding [3];
};
// avoid non C++ casts (when used with stricter compilation)
typedef const char* constCharPtrT;
typedef void* voidPtr;
typedef sharedBookT* sharedBookPtrT;
static sharedBookPtrT sharedBookPtr = 0;
// sprintf for std::string
std::string Sprintf (const char* fmt, ...) __attribute__ ((format (printf, 1, 2)));
std::string Sprintf (const char* fmt, ...) {
va_list ap;
va_start (ap, fmt);
const auto n = vsnprintf (0, 0, fmt, ap);
va_end (ap);
char result [n+2];
va_start (ap, fmt);
vsnprintf (result, size_t (n+1), fmt, ap);
va_end (ap);
return std::string (result);
}
// c_str and length shortcut operators for std::string
const char* operator* (const std::string& s) { return s.c_str (); }
size_t operator+ (const std::string& s) { return s.length (); }
// resize shell's pty and notifiy chell of change
void handleTerminalResize () {
sharedBookT& shared = *sharedBookPtr;
winsize ws;
ioctl(0, TIOCGWINSZ, &ws);
ioctl(shared.shellFd, TIOCSWINSZ, &ws);
sigqueue (shared.shellPid, SIGWINCH, {0});
}
// log signal, for convience just to stdout
void logsignal (int signal) {
// can't reliably use regular printf from a signal handler
const auto msg = Sprintf ("Got signal %d\n", signal);
write (1, *msg, +msg);
}
// common signal handler
void handler(int signal, siginfo_t * infoP, void *context __attribute__ ((unused))) {
const auto& si = *infoP;
const auto myPid = getpid ();
sharedBookT& shared = *sharedBookPtr;
// using SIGUSR to notify processes of termination
// (processes must check for it after blocking syscalls)
if (signal == SIGUSR2) { // Notification to quit
shared.readyToQuit = true;
return;
}
auto cc = char (-1);
if (myPid == shared.parentPid) {
// only parent process should handle these
// if child processes handle these as well, there are multiple insertions
switch (si.si_signo) {
case SIGINT: cc = 0x03; break; // "Ctrl-C"
case SIGTSTP: cc = 0x1A; break; // "Ctrl-Z"
case SIGQUIT: cc = 0x1C; break; // "Ctrl-\"
case SIGWINCH: handleTerminalResize (); break;
default: logsignal (signal); break;
}
}
// write control character (if any) to shell's pty
if (-1 < cc) write(shared.shellFd, &cc, 1);
}
// Add common signal handler for each signal
void setupsignal(int signal) {
struct sigaction act;
sigaction(signal, NULL, &act);
act.sa_sigaction = handler;
act.sa_flags |= SA_SIGINFO;
sigaction(signal, &act, NULL);
}
// launch shell with new pty
void launchShell () {
sharedBookT& shared = *sharedBookPtr;
tcgetattr(0, &shared.shellTerm);
const auto pid = forkpty(&shared.shellFd, NULL, &shared.shellTerm, NULL);
if (pid == -1 || pid == 0) {
if (pid == 0) {
shared.shellPid = getpid ();
// inform shell it's pty is being filtered
setenv ("inptyfilter", "true", 1);
exit(execlp("/bin/bash", "bash", NULL));
}
else {
perror ("forkpty failed");
exit (1);
}
}
}
int main () {
// create shared globals structure
sharedBookPtr = sharedBookPtrT (mmap (
NULL, sizeof (sharedBookT),
PROT_READ | PROT_WRITE,
MAP_SHARED | MAP_ANONYMOUS, -1, 0
));
sharedBookT& shared = *sharedBookPtr;
launchShell ();
shared.parentPid = getpid ();
//Set up handler for signals
setupsignal(SIGINT);
setupsignal(SIGTSTP);
setupsignal(SIGUSR1);
setupsignal(SIGUSR2);
setupsignal(SIGQUIT);
setupsignal(SIGWINCH);
//setupsignal(SIGTTIN);
//setupsignal(SIGTTOU);
// fork to handle output to the terminal
if (0 == fork ()) {
shared.childPid = getpid ();
// loop while reading and echoing the pty's output
for (;;) {
// read from Shell's Pty
const auto charsRead = read (shared.shellFd, shared.toTerminalBuffer, sizeof (shared.toTerminalBuffer));
// if characters were read, echo them and continue
if (0 < charsRead) {
write (1, shared.toTerminalBuffer, size_t (charsRead));
continue;
}
// if error, check if we are done
if ((charsRead == -1) and (errno == EIO)) {
fprintf (stderr, "\nterminating I/O processes\r\n");
// signal parent to exit
sigqueue (shared.parentPid, SIGUSR2, {0});
break;
}
}
fprintf (stderr, "Exiting pty-filter (toTerminal)\r\n");
exit (0);
}
// wait for pids to be updated
while ((0 == shared.shellPid) or (0 == shared.childPid)) usleep (1);
fprintf (stderr, "parent: %d\n", shared.parentPid);
fprintf (stderr, "shell: %d\n", shared.shellPid);
fprintf (stderr, "child: %d\n", shared.childPid);
tcgetattr(0, &shared.oldTerm); // Disable buffered I/O and echo mode for pty
shared.newTerm = shared.oldTerm;
cfmakeraw (&shared.newTerm);
tcsetattr(0, TCSANOW, &shared.newTerm);
// shell needs intial sizing
handleTerminalResize ();
for (;;) {//loop while processing input from pty
const auto charsRead = read (0, shared.fromTerminalBuffer, sizeof (shared.fromTerminalBuffer));
// SIGUSR1 will drop process out of read so flag can be read
if (shared.readyToQuit) {
fprintf (stderr, "Exiting pty-filter (fromTerminal)\r\n");
break;
}
// in we got input from the terminal, pass it on to the shell's pty
if (0 < charsRead) {
write (shared.shellFd, shared.fromTerminalBuffer, size_t (charsRead));
continue;
}
// if error check if we are done
// However, this is never executed, child fork terminates first
if ((charsRead == -1) and (errno == EIO)) break;
}
tcsetattr(0, TCSANOW, &shared.oldTerm); //reset terminal
// wait for child forks to exit
for (;;) {
auto wpid = wait (0);
if (wpid == -1) break;
fprintf (stderr, "%d is done\n", wpid);
}
perror ("status");
return 0;
}
My question is, what am I missing? What would cause some programs (like joe and snake) to display erratically, while many other programs (like vi, vim, nano, mcedit, htop, top) seem to work just fine.
(On my system joe and snake work just fine without the "pty filter".)
EDIT: As stated above, it now works
Replacing this:
shared.newTerm.c_lflag &= tcflag_t (~ICANON);
shared.newTerm.c_lflag &= tcflag_t (~ECHO);
with this:
shared.newTerm.c_lflag &= tcflag_t (~(ICANON | ISIG | IEXTEN | ECHO));
shared.newTerm.c_iflag &= tcflag_t (~(BRKINT | ICRNL | IGNBRK | IGNCR | INLCR | INPCK | ISTRIP | IXON | PARMRK));
shared.newTerm.c_oflag &= tcflag_t (~OPOST);
shared.newTerm.c_cc[VMIN] = 1; // 1 char at a time input
shared.newTerm.c_cc[VTIME] = 0;
made it start working correctly. However, this seems like it should not have any effect, as this is being done on stdin:
shared.newTerm.c_oflag &= tcflag_t (~OPOST);
EDIT: The following post answers the question about stdin vs stdout for tcsetattr.
When setting terminal attributes via tcsetattr(fd.....), can fd be either stdout or stdin?
But anyways, it works now. I will update my original post to reflect this.
EDIT: This post was marked as related: Using the linux pseudo terminal API for multiple debug terminals
While the answer was not on that post, it pointed to a site that had the information I needed: http://www.man7.org/tlpi/code/online/dist/tty/tty_functions.c.html
EDIT: Replacing the above with the following also works. I will update my original post accordingly.:
cfmakeraw (&shared.newTerm);
I use the Intel-Pin to instrument pthread_mutex_lock and pthread_mutex_unlock in Linux. I insert functions before and after this two lock function's invocation respectively, so I expect that the tool will output strings before and after the lock functions. The instrument code is as follow
#include "pin.H"
#include <iostream>
#include <fstream>
/* ===================================================================== */
/* Names of pthread_mutex_lock and pthread_mutex_unlock */
/* ===================================================================== */
#define PTHREAD_MUTEX_INIT "pthread_mutex_init"
#define PTHREAD_MUTEX_DESTROY "pthread_mutex_destroy"
#define PTHREAD_MUTEX_LOCK "pthread_mutex_lock"
#define PTHREAD_MUTEX_UNLOCK "pthread_mutex_unlock"
/* ===================================================================== */
/* Global Variables */
/* ===================================================================== */
PIN_LOCK lock;
std::ofstream TraceFile;
/* ===================================================================== */
/* Commandline Switches */
/* ===================================================================== */
KNOB<string> KnobOutputFile(KNOB_MODE_WRITEONCE, "pintool",
"o", "malloctrace.out", "specify trace file name");
/* ===================================================================== */
/* ===================================================================== */
/* Analysis routines */
/* ===================================================================== */
VOID Pthread_mutex_lock_callBefore( ADDRINT lockaddr)
{
PIN_GetLock(&lock, 1);
printf("Pthread_mutex_lock_callBefore\n");
PIN_ReleaseLock(&lock);
}
VOID Pthread_mutex_lock_callAfter(ADDRINT ret)
{
if(ret != 0)
return;
PIN_GetLock(&lock, 2);
printf("Pthread_mutex_lock_callAfter\n");
PIN_ReleaseLock(&lock);
}
VOID Pthread_mutex_unlock_callBefore(ADDRINT lockaddr)
{
PIN_GetLock(&lock, 3);
printf("Pthread_mutex_unlock_callBefore\n");
PIN_ReleaseLock(&lock);
}
static VOID Pthread_mutex_unlock_callAfter(ADDRINT ret)
{
if(ret != 0)
return;
PIN_GetLock(&lock, 4);
printf("Pthread_mutex_unlock_callAfter\n");
PIN_ReleaseLock(&lock);
}
/* ===================================================================== */
/* Instrumentation routines */
/* ===================================================================== */
VOID Image(IMG img, VOID *v)
{
RTN pmlRtn = RTN_FindByName(img, PTHREAD_MUTEX_LOCK);
if (RTN_Valid(pmlRtn) && PIN_IsApplicationThread() )
{
RTN_Open(pmlRtn);
RTN_InsertCall(pmlRtn, IPOINT_BEFORE, (AFUNPTR)Pthread_mutex_lock_callBefore,
IARG_FUNCARG_ENTRYPOINT_VALUE, 0,
IARG_END);
RTN_InsertCall(pmlRtn, IPOINT_AFTER, (AFUNPTR)Pthread_mutex_lock_callAfter,
IARG_FUNCRET_EXITPOINT_VALUE,
IARG_END);
RTN_Close(pmlRtn);
}
//pthread_mutex_unlock
pmlRtn = RTN_FindByName(img, PTHREAD_MUTEX_UNLOCK);
if (RTN_Valid(pmlRtn) )
{
RTN_Open(pmlRtn);
RTN_InsertCall(pmlRtn, IPOINT_BEFORE, (AFUNPTR)Pthread_mutex_unlock_callBefore,
IARG_FUNCARG_ENTRYPOINT_VALUE, 0,
IARG_END);
RTN_InsertCall(pmlRtn, IPOINT_AFTER, (AFUNPTR)Pthread_mutex_unlock_callAfter,
IARG_FUNCRET_EXITPOINT_VALUE,
IARG_END);
RTN_Close(pmlRtn);
}
}
/* ===================================================================== */
VOID Fini(INT32 code, VOID *v)
{
TraceFile.close();
}
/* ===================================================================== */
/* Print Help Message */
/* ===================================================================== */
INT32 Usage()
{
cerr << "This tool produces a trace of calls to malloc." << endl;
cerr << endl << KNOB_BASE::StringKnobSummary() << endl;
return -1;
}
/* ===================================================================== */
/* Main */
/* ===================================================================== */
int main(int argc, char *argv[])
{
// Initialize pin & symbol manager
PIN_InitLock(&lock);
PIN_InitSymbols();
if( PIN_Init(argc,argv) )
{
return Usage();
}
// Write to a file since cout and cerr maybe closed by the application
TraceFile.open(KnobOutputFile.Value().c_str());
TraceFile << hex;
TraceFile.setf(ios::showbase);
// Register Image to be called to instrument functions.
IMG_AddInstrumentFunction(Image, 0);
PIN_AddFiniFunction(Fini, 0);
// Never returns
PIN_StartProgram();
return 0;
}
/* ===================================================================== */
/* eof */
/* ===================================================================== */
compile this tool
make obj-ia32/mytool.so TARGET=ia32
use this tool to instrument a simple test
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
#include <stdlib.h>
pthread_mutex_t m;
void * fun1(void *arg)
{
pthread_mutex_lock(&m);
pthread_mutex_unlock(&m);
}
int main(int argc,char* argv[])
{
pthread_t npid1;
pthread_mutex_init(&m,NULL);
pthread_create(&npid1,NULL,fun1,NULL);
pthread_join(npid1,NULL);
return 0;
}
compile this test
gcc -g t.c -o t -lpthread
At last, I use the my tool to instrument this test
sudo ./pin -t obj-ia32/mytool.so -- ./t
the result is
lab#lab:~/MyPinTool$ sudo ./pin -t obj-ia32/mytool.so -- ./t
Pthread_mutex_lock_callBefore
Pthread_mutex_lock_callAfter
Pthread_mutex_unlock_callBefore
Pthread_mutex_lock_callBefore
Pthread_mutex_lock_callAfter
Pthread_mutex_unlock_callBefore
Pthread_mutex_lock_callBefore
Pthread_mutex_lock_callAfter
Pthread_mutex_unlock_callBefore
You can see there is no Pthread_mutex_unlock_callAfter, I have insert a function after the pthread_mutex_unlock, why this function have not been callded? PS :the Pin API say that
VOID LEVEL_PINCLIENT::RTN_InsertCall ( RTN rtn,
IPOINT action,
AFUNPTR funptr,
...
)
Insert call relative to a rtn.
Parameters:
rtn Routine to instrument
action Use IPOINT_BEFORE to call funptr before execution, or IPOINT_AFTER for immediately before the return NOTE: IPOINT_AFTER is implemented by instrumenting each return instruction in a routine. Pin tries to find all return instructions, but success is not guaranteed
funptr Analysis function to call
... IARG_TYPE. Arguments to pass to funptr
As Nitzan said already, the APIs says it all: Pin tries to instrument each ret instruction of the function, but success is not garanteed. Think what would happen if an exception is thrown within the function, or if a long jump outside of the function happens...
There are many reasons for a function to be interrupted before reaching the return statement.
I gone through the Documentation of NCURSES. I am not getting that if I use getch without initscr then why this program is not working. Is there any other approach to get arrow keys input without clearing screen (that initscr do).
#include <ncurses.h>
#include <unistd.h>
int main()
{
int ch;
//initscr();
//raw();
//keypad(stdscr, TRUE);
//noecho();
while(1)
{
ch = getch();
switch(ch)
{
case KEY_UP:
printw("\nUp Arrow");
break;
case KEY_DOWN:
printw("\nDown Arrow");
break;
case KEY_LEFT:
printw("\nLeft Arrow");
break;
case KEY_RIGHT:
printw("\nRight Arrow");
break;
}
if(ch == KEY_UP)
break;
}
//endwin();
}
Alternatively you may use change the terminal attribute through tcsetattr in termios. If you cycle between the canonical mode (requires new line for the process to begin) and non-canonocal mode (Keypress is more than enough).
The following program works as follows - THe process waits for user input. If up arrow key is pressed, it prints 'Arrow key pressed' and exits. If something else is pressed, it waits for the user to press Enter and then prints the user inpu. Exits after the inut is printed.
#include <termios.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
int main()
{
struct termios oldt, newt;
char ch, command[20];
int oldf;
tcgetattr(STDIN_FILENO, &oldt);
newt = oldt;
newt.c_lflag &= ~(ICANON | ECHO);
tcsetattr(STDIN_FILENO, TCSANOW, &newt);
oldf = fcntl(STDIN_FILENO, F_GETFL, 0);
fcntl(STDIN_FILENO, F_SETFL, oldf | O_NONBLOCK);
while(1)
{
ch = getchar();
if (ch == '\033')
{ printf("Arrow key\n"); ch=-1; break;}
else if(ch == -1) // by default the function returns -1, as it is non blocking
{
continue;
}
else
{
break;
}
}
tcsetattr(STDIN_FILENO, TCSANOW, &oldt);
fcntl(STDIN_FILENO, F_SETFL, oldf);
if(ch != EOF)
{
ungetc(ch,stdin);ith
putchar(ch);
scanf("%s",command);
printf("\n%s\n",command);
return 1;
}
return 0;
}
getch is the same as wgetch(stdscr). It assumes that the screen has been initialized. ncurses (any curses implementation) has to do a couple of things to make wgetch usable:
read the terminal description
initialize the terminal I/O modes
allocate a screen to draw on.
The last is because wgetch does a wrefresh on the window for which it was called, before doing a read.
You could use newterm with filter to avoid clearing the screen, and doing line-oriented input. The filter program in ncurses-examples demonstrates how to do this.
I have a solution without ncurses
You can use simple-getch like this:
t_key keys[] = {
{"[A", K_UP},
{"[B", K_DOWN},
{"[D", K_LEFT},
{"[C", K_RIGHT},
{NULL, K_UNK},
};
int key;
ch_init();
while ((key = ch_get(keys)) != K_BACK)
{
printf("%d\n", key);
}
ch_end();
keys array is a list of escape sequences which will be used, (when you type an arrow key in a terminal, it will write an escape key followed by multiples characters to define the key.)
This sequences may/will change between terminals, you should use termcap to properly set this sequences.
Working in z/os mainframe, I have the following situation. I can't record a transaction.
here is my code,
it is written for transaction using jcl. Bur something goes wrong.
/* Include standard C header files */
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* Include WebSphere MQ API header file */
#include <cmqc.h>
/* Boolean constants */
#define TRUE 1
#define FALSE 0
/* Function prototypes */
void displayUsage (char *programName);
void displayMQError (char *message, MQLONG compCode, MQLONG reason);
double parseAmount (char *amountString);
/* Main Program */
int main (int argc, char *argv[])
{
/* Variable definitions */
double paymentAmount; /* Payment amount */
MQBYTE msgBuffer[1024]; /* Buffer for messages */
MQCHAR* qmgrName; /* Queue manager name */
MQCHAR* requestQueueName; /* Request queue name */
MQCHAR* replyQueueName; /* Reply queue name */
MQCHAR* userID; /* Contestant user ID */
MQCHAR* paymentDescription; /* Payment description */
MQGMO getMsgOptions = {MQGMO_DEFAULT}; /* Get options */
MQHCONN hConn = MQHC_UNUSABLE_HCONN; /* Connection handle */
MQHOBJ requestHObj = MQHO_UNUSABLE_HOBJ; /* Request queue handle */
MQHOBJ replyHObj = MQHO_UNUSABLE_HOBJ; /* Reply queue handle */
MQLONG compCode; /* API completion code */
MQLONG openOptions; /* Open queue options */
MQLONG reason; /* API reason code */
MQLONG replyMsgLength = 0; /* Reply msg length */
MQMD requestMsgDesc = {MQMD_DEFAULT}; /* Message descriptor */
MQMD replyMsgDesc = {MQMD_DEFAULT}; /* Message descriptor */
MQOD requestQueueDesc = {MQOD_DEFAULT}; /* Object descriptor */
MQOD replyQueueDesc = {MQOD_DEFAULT}; /* Object descriptor */
MQPMO putMsgOptions = {MQPMO_DEFAULT}; /* Put options */
/*****************************************/
/* Initialisation and parameter checking */
/*****************************************/
printf ("********************************************************\n");
printf ("Credit card payment unit test tool\n");
printf ("********************************************************\n");
printf (" \n");
switch (argc)
{
case 7 : qmgrName = argv[1];
requestQueueName = argv[2];
replyQueueName = argv[3];
userID = argv[4];
paymentAmount = parseAmount (argv[5]);
if ( ( paymentAmount < 0.01 )
|| ( paymentAmount > 9999.99 ) )
{
printf ("The payment amount must be a valid numeric " \
"within the range 0.01 to 9999.99\n");
displayUsage (argv[0]);
return (1);
}
paymentDescription = argv[6];
if ( ( strlen (paymentDescription) < 1 )
|| ( strlen (paymentDescription) > 35 ) )
{
printf ("The payment description must be 1-35 " \
"characters\n");
displayUsage (argv[0]);
return (1);
}
break;
default : printf ("Incorrect usage!\n");
displayUsage (argv[0]);
return (1);
}
printf ("You have requested a payment of %.2f with description " \
"'%s' for contestant %s\n", paymentAmount,
paymentDescription, userID);
printf (" \n");
Can you help me?
I don't know how to write my Parm parameters...
When you have a problem, try to track all the outputs back to the inputs via the program.
From one of your other questions:
********************************************************
Credit card payment unit test tool
********************************************************
Incorrect usage!
Program Usage
-------------
PAYMENT <queue manager> <cics request queue> <reply queue> <userid> <payment value> <payment description>
The payment description has a maximum length of 35 characters.
The monetary value must be within the range 0.01 - 9999.99
The first two lines are easy to explain. The last two lines, not so. They are there to blinker us, as that exact text appears in the program. However, it seems that the exact same text is used in the displayUsage function.
It is bad to display identical text in different error circumstances. That's why we use message numbers - the message may then be the same, but the number will identify exactly where it has come from.
A clue is that you can't even get a very simple PARM to be accepted.
A further clue is that Incorrect usage!.
When does that message get printed? When there are other than seven parameters. Err... but you only supply six.
So, if there are supposed to be six parameters, the program is wrong. If you should be supplying seven parameters, your PARM is wrong.
You can demonstrate this with
// PARM='A,B,C,D,1,F,G'
That will work.
As an aside, why was switch used instead of a simple if anyway? Using if would have made the problem more obvious.
We are running a ksh script that calls a ProC program that updates a table.
The program runs successfully in UNIX but when we run it in LINUX RHEL55 , it is causing a memory fault error
When we tried to debug where the last statement before the Memory fault error, it points to the point after we do a Fetch on the cursor and tries to use the values fetched to update a table
Here is a snippet of the code
#define PROGRAM "n377wlocgeo" /* name of this program */
#define USERNAME "/" /* ORACLE username */
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
/* Include the ORACLE communication Area, a structure through which
ORACLE makes additional runtime Status available to the program
The ORACA=YES must be specified to enable use of oraca */
EXEC SQL INCLUDE ORACA;
EXEC ORACLE OPTION (ORACA=YES);
EXEC SQL INCLUDE SQLCA;
/*---------------------------------------------------------------------------
WORKING STORAGE */
/* GLOBAL EXTERNAL VARIABLES */
char *ptr; /* pointer for record layout */
char timestamp[26] = "\0"; /* current date and time */
/* Counters */
int rec_err_ctr = 0;
int cnt_rec = 0;
long update_no_ctr = 0;
long update_geo_ctr = 0;
long update_no_pr_ctr = 0;
long update_no_us_ctr = 0;
int no_fetch_rec_ctr = 0;
int geo_fetch_rec_ctr = 0;
int commit_ctr = 0;
int ws_err_sqlcode;
char para_name[25]; /* hold for displaying what paragraph abended */
char err_para_name[25]; /* hold for displaying what paragraph abended */
char abend_msg[240];
/*Pgm Control Vars */
char error_in_job = 'N';
char no_fetch_ended = 'N';
char geo_fetch_ended = 'N';
char clear_psl_cd[12];
/* UNIX ENVIRONMENT VARIABLES */
char debug[2];
/* Function delarations */
void initpara(); /* connect to Oracle */
void get_env_vars(); /* get the unix environment variables into C program */
void get_timestamp(); /* get the date and time from the system */
void connect_oracle();
void disconnect_oracle();
void get_update_timestamp();
void end_transaction();
void error_routine();
void echofields(); /* for debugging, echo all fields parsed */
void no_geo_cursor_process();
void geo_cursor_process();
void sql_no_update();
void sql_geo_update();
void sql_no_pr_update();
void sql_no_us_update();
EXEC SQL BEGIN DECLARE SECTION;
varchar hv_psl_cd[12];
varchar hv_rec_udt_ts[20];
varchar hv_geo_cny_cd[03];
varchar hv_geo_psl_cd[12];
varchar hv_geo_typ_cd[4];
varchar hv_cny_cd[03];
/* Cursor to set defaults for countries with no geo classification */
EXEC SQL DECLARE NO_GEO_CUR CURSOR FOR
SELECT CNY_CD
,PSL_CD
FROM TDLOCTN_BASE
WHERE CNY_CD NOT IN ('US', 'PR')
AND GEO_ARA_PSL_CSF_CD is null
GROUP BY CNY_CD, PSL_CD
ORDER BY CNY_CD, PSL_CD;
EXEC SQL DECLARE GEO_CUR CURSOR FOR
SELECT GEO_CNY_CD,
GEO_PSL_CD,
GEO_TYP_CD
FROM TDLOC_GEO_CD_EXT
GROUP BY GEO_CNY_CD,GEO_PSL_CD,GEO_TYP_CD
ORDER BY GEO_CNY_CD,GEO_PSL_CD;
EXEC SQL END DECLARE SECTION;
/*----------------------------------------------------------
PROCEDURE DIVISION
------------------------------------------------------------
MAINLINE */
/*------------------------------------------------------------*/
int main(int argc, char **argv)
{
printf ("Starting");
get_timestamp();
printf("PGM BEGIN DATE/TIME : %s \n", timestamp );
initpara();
if ( strcmp(debug, "Y") == 0 )
get_timestamp();
printf("main while loop: %s\n", timestamp);
/* get max rec_udt_tms for cursor process */
get_update_timestamp();
/* open the cursor and fetch all rows for defaults . */
no_geo_cursor_process();
if ( error_in_job == 'Y' )
exit(2);
else
exit(0);
}
/*------------------------------------------------------------*/
void get_timestamp()
{
strcpy(para_name, "Para = get_timestamp");
if ( strcmp(debug, "Y") == 0 )
printf("function: get_timestamp\n");
struct tm *tm_now;
time_t secs_now;
/no_geo_cursor
EXEC SQL
SELECT TRUNC(MAX(REC_UDT_TS))
INTO :hv_rec_udt_ts
FROM TDLOCTN_BASE;
if ( sqlca.sqlcode == 0 )
printf("CHAR %-25s : %s \n", "hv_rec_udt_ts", hv_rec_udt_ts.arr);
else
{
printf("SQL Select Error in - get_update_timestamp: %s\n");
strcpy(abend_msg, sqlca.sqlerrm.sqlerrmc);
printf("SQL ERROR CODE: %d\n", sqlca.sqlcode);
printf("SQL ERROR MSG: %s\n", abend_msg);
error_routine();
}
}
void no_geo_cursor_process ()
{
strcpy(para_name, "Para = no_geo_cursor_process");
if ( strcmp(debug, "Y") == 0 )
printf("function: no_geo_cursor_process\n");
EXEC SQL
OPEN NO_GEO_CUR;
if ( sqlca.sqlcode == 0 )
printf("Cursor Opened: %s\n");
else
{
printf("SQL Open Error in - no_geo_cursor_process: %s\n");
strcpy(abend_msg, sqlca.sqlerrm.sqlerrmc);
printf("SQL ERROR CODE: %d\n", sqlca.sqlcode);
printf("SQL ERROR MSG: %s\n", abend_msg);
error_routine();
}
char para_name[25];
strcpy(para_name, "Para = no_geo_cursor_process");
// 1 2
// 12345678901234567890123456789 (one extra for the NULL).
That's one thing that's probably not going to work. It's undefined behaviour if you write past the end of an array (you cant put twenty-nine biscuits into a biscuit tin built for twenty-five (a))
Increase the size of para_name to fix that problem.
The reason it may work on some systems is that one of the possible outcomes of undefined behaviour is that it just works. That doesn't make it a good idea, of course. You should avoid it as much as possible.
In addition, as pointed out in the comments, you have a few lines where you provide printf format strings with no corresponding values:
printf("SQL Select Error in - get_update_timestamp: %s\n");
printf("Cursor Opened: %s\n");
This is also undefined behaviour and will likely cause problems, usually by using whatever values happens to have been placed on the stack as a string pointer. You can just remove the offending %s from the string or, alternatively, figure out what string you wanted to include in the message and add that to the printf arguments.
(a) Unless you want biscuit crumble, of course :-)