as400: what is the C equivalent of SNDRCVF - c

I have a display file for a menu. I successfully made a working CL program which displays the menu and waits for input. Simply enough, all it does is display the file and waits for the user to press F1 to quit.
Display file (approximation):
A R DISPLAY
A CA01(01 'Exit')
A 2 2'some text....'
Creation command: crtdspf file(display) srcfile(test) srcmbr(display)
CL program:
PGM
DCLF FILE(DISPLAY) RCDFMT(DISPLAY)
LOOP: SNDRCVF
IF COND(&IN01 *EQ '1') THEN(DO)
GOTO END
ENDDO
GOTO LOOP
END:
ENDPGM
Compile command: crtclpgm pgm(test) srcfile(test) srcmbr(clsrc) output(*print)
What is the equivalent of SNDRCVF in C?
Here is what I've come with so far. It compiles fine, but when I call it, it does nothing.
#include <stdio.h>
#include <recio.h>
// Include my display file.
#pragma mapinc("display","lib/display(display)", "both", "")
#include "display"
// Shortcuts to the generated structs.
typedef LIB_DISPLAY_DISPLAY_i_t input_t;
typedef LIB_DISPLAY_DISPLAY_o_t output_t;
int main(int argc, char* argv[]){
input_t input;
output_t output;
_RFILE* dspf;
// The file opens fine.
dspf = _Ropen("lib/display", "wr");
if(dspf == NULL){
printf("ERROR: Display file open failed.\n");
return 0;
}
// I tell which record format to use.
_Rformat(dspf, "display");
// Write my file to display?
_Rwrite(dspf, "", 0);
// Wait for input.
_Rreadn(dspf, &input, sizeof(input), __DFT);
// Close it and quit.
_Rclose(dspf);
return 0;
}
Compile command: crtbndc pgm(test) srcfile(test) srcmbr(main) output(*print)
Then call: call test
What am I doing wrong?

I made a few minor changes. First, for your TYPEDEFs, I used this:
// Shortcuts to the generated structs.
typedef MYLIB_CDSPMNU_DISPLAY_both_t input_t;
typedef MYLIB_CDSPMNU_DISPLAY_both_t output_t;
Because you specified "both", the referenced identifier name should have 'both' rather than 'i' or 'o'. It's not clear how you could've successfully compiled as you had it. Perhaps you had an earlier successful compilation so that your CALL command worked, but the compiled program wasn't a current version.
Then I opened the file with this mode:
// The file opens fine.
dspf = _Ropen("mylib/cdspmnu", "rr+");
You had "wr", so it it was opened only for output ("wr"iting). You need it for input and output. Your joblog should show a C2M3005 "File is not opened for read operations." after you CALL your program (depending on what compiled version you actually CALL).
And I changed your _Rformat() function:
// I tell which record format to use.
_Rformat(dspf, "DISPLAY");
From the ILE C/C++ Runtime Library Functions manual, the definition of _Rformat() says:
The fmt parameter is a null-ended C string. The fmt parameter must
be in uppercase.
The format name isn't folded to uppercase like file and library names are in other places. No idea why not; it's just the way it is. Personally, I'd use uppercase wherever it actually means an uppercase name without relying on the compiler; so I'd also change a couple other places in the code.
Technically, I also changed the DSPF source to reference the F3 key rather than the F1 key that you show in your DDS. The F1 key would normally be for 'help' functions while F3 is a standard for 'Exit'. That doesn't really matter, but it's one habit to get started. And a name or two was changed just to fit within my environment.
No spooled files were necessary. Easiest way to view your job's "joblog" after a CALL command is to run a DSPJOBLOG command. Perhaps better, though, is to use the basic command entry display provided by CALL QCMD. Basic joblog messages can be toggled on/off on that display by use of the F10 key to either "Include detailed messages" or "Exclude detailed messages".
All in all, you were pretty close. Not bad at all if this was your first attempt to work with a DSPF.

Related

Get highlighted text & open program with it (replicate clipboard.exe behavior)

Is it possible to highlight text with your cursor in any program, like you do with str+c and start a tool with the highlighted text as argument?
As far as I know, in Linux as well as in Windows, one can call a script/program with a custom shortcut. I assume str+c just does the same, calling a little program with the highlighted text as argument. How to replicate this?
For demonstration purposes, let's take this C - program printing the value it was called with:
#include <stdio.h>
int main(int argc, char**argv){
if(argc == 2){
printf("program called with: '%s'\n", argv[1]);
}
}
Can one type the text "HelloWorld" in Word for example, highlight it, and press something like str+alt+p, calling
someprogram.exe HelloWorld
or as for Linux
someprogram HelloWorld
I am really curious if this is possible.
Edit: I'm interested to know, how to replicate the clipboard.exe functionality. I have written a program "write_custom.exe" storing anything given as argument (argv[1]) in a text-file, after deleting it's previous content. Other programs can read the content of this text-file and so are able to use this custom clipboard. It's purpose is mainly for self-teaching.
As I am at the beginning of my codeing career, I only know C, but I am open for solutions in other languages as well. My goal is to run this write_custom.exe, with highlighted text as argument, on my computer and my Linux-VM.
You might want to check out ncurses (Linux) and Console API (Windows). The code will not be cross-platform, but you can pretty easily write some code to make them share some basic behavior :).

Simple C Wrapper Around OpenSSH (with Cygwin on Windows)

I am packaging a program on Windows that expects to be able to externally call OpenSSH. So, I need to package ssh.exe with it and I need to force ssh.exe to always be called with a custom command line parameter (specifically -F to specify a config file it should use). There is no way to force the calling program to do this, and there are no simple ways to do this otherwise in Windows (that I can think of anyway - symlinks or cmd scripts won't work) so I was just going to write a simple wrapper in C to do it.
This is the code I put together:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
int ret;
char **newv = malloc((argc + 2) * sizeof(*newv));
memmove(newv, argv, sizeof(*newv) * argc);
newv[argc] = "-F ssh.conf";
newv[argc+1] = 0;
ret = execv("ssh.orig.exe", newv);
printf("execv failed with return value of %i", ret);
return ret;
}
I then compile this code using GCC 4.6.3 in Cygwin and it runs without error; however, there is a strange behavior with regards to input and output. When you go to type at the console (confirming the authenticity of the host and entering in a password, etc) only part of the input appears on the console. For example, if I type in the word 'yes' and press enter, only the 'e' will appear on the console and SSH will display an error about needing to type 'yes' or 'no'. Doing this from the Windows command prompt will result in your input going back to the command propmt, so when you type 'yes' and press enter, you get the ''yes' is not recognized as an internal or external command...' message as if the input were being typed at the command prompt. Eventually SSH will time out after that.
So, I'm obviously missing something here, and I'm assuming it has something to do with the way execv works (at least the POSIX Cygwin version of it).
Is there something I'm missing here or are there any alternatives? I was wondering if maybe I need to fork it and redirect the I/O to the fork (although fork() doesn't seem to work - but there are other issues there on Windows). I tried using _execv from process.h but I was having issues getting the code right for that (also could have been related to trying to use gcc).
It's also possible that there may be a non-programming way to do this that I haven't thought of, but all of the possibilities I've tried don't seem to work.
Thoughts?
I ended up finding a solution to this problem. I'm sure there were other ways to do this, but this seems to fix the issue and works well. I've replaced the execv line with the following code:
ret = spawnv(P_WAIT, "ssh.orig.exe", newv);
You have to use 'P_WAIT' otherwise the parent process completes and exits and you still have the same problem as before. This causes the parent process to wait, but still transfers input and output to the child process.

Open a file in C

I am trying to write a tiny program in C that will open a file and then run the filename in terminal to stream the file to my Apple TV.
The reason I want to do this is so I can right click a media file, select 'Open With', choose 'Apple TV' from the list and then have it stream to my Apple TV via the airstream program.
My code so far is as follows
#include <stdio.h>
#include <string.h>
int main ()
{
char command[50];
strcpy( command, "airstream '/home/steve/media.mp4' -o 192.168.0.2" );
system(command);
return(0);
}
Very simple, but I'm not sure how to handle a file being passed to the application to allow it to get the filename and modify the command.
(First, let me make a comment on strcpy(): as-is, the call to strcpy() is superfluous (and imposes a security issue), because you are using a constant string. You could have written system("airstream '/home/steve/media.mp4' -o 192.168.0.2") instead.)
If you want to construct a command given a filename, you could in theory write
char command[LINE_MAX];
snprintf(command, sizeof command, "some_command %s", argv[1]);
system(command);
But that again rises a security problem, because now your program can be hijacked to execute an arbitrary external program, by passing it a malformed command-line argument, similarly to an SQL injection attack.
You'd be better off finding the library/API the airstream executable uses, and incorporate that directly into your program. If no such thing exists, you have to make sure to at least validate the user input (i. e. escape special characters, etc.) before handing it over to the shell for execution.
You need to use the arguments passed to the main() function. Change the function's signature to:
int main(int argc, char *argv[])
Then loop over the string pointers in argv[], which will be the command-line arguments your program was given.

Running C scripts with terminal instead of Xcode

Currently I am developing a couple of C programs on my mac using Xcode. There however is 1 problem. My study requires me to use some sort of input field through the coding. So for instance if the users wants to run the program 10 times or wants the program to create 10 answers. I am using "atoi(argv[1])" just to get the input from the user.
This is exactly the problem. As soon as I run the program it just starts to bug, which is normal I quess because he is waiting for the input and not receiving it or something else. Anyways I tried to solve this problem with this link: How to run command-line application from the terminal?
This unfortunately didnt solve it either. I have already tried to re-install xcode, because just entering gcc in my terminal doesnt work either, but everytime the app store auto instals it for me.
Does anyone has a fix for my problem. I would greatly appreciate it due to the fact that next friday I have another deadline :( and I wont be getting a sufficient grade if my user input is not working.
Your help is again much appreciated!
Greetings,
Kipt Scriddy
EDIT: To clarify the problem. When running the script I want it to pop up in Terminal and wether there is an input field reguired it should ask for input. At the moment he is crashing immediatly due to the lack of input. He is not waiting for the argument to be passed from the users. He is skipping that part
HOWTO Pass command line arguments to your program from Xcode IDE
Open your project's active Scheme. Easiest way to do this is from the main menu. Select Product/Scheme/Edit Scheme...
In the schema editor, you'll see several build targets on the left side; the one you want is the "Run YourProjectName" target. Select it.
On the right side you'll see four sub-tabs, including Info, Arguments, Options, and Diagnostics. Select Arguments
Add/Remove any arguments you need. In your case, add /phi as the first argument, then 10 as the second.
Noteworthy: This is also where you can specify the current working directory of your program at launch rather than the long, temp path Xcode uses when building your binaries. To do so:
Perform steps 1-2 from above.
Select the Options sub-tab
Click the "Use custom working directory" checkbox.
Specify the full path where you want Xcode to execute your program from.
That in combination with getting your parameter handling fixed in your program should get you up and running.
Sounds to me like you want to get your arguments from the command line and if they are missing, prompt the user for them
Lets assume you want the arguments: number word number
#include <stdio.h>
#include <string.h>
int number1;
char word[128];
int number2;
int main(int argc, const char **argv)
{
if (argc == 4)
{
number1 = atoi(argv[1]);
strcpy(word, argv[2]);
number2 = atoi(argv[3]);
}
else
{
do
printf("Enter number word number: ");
while (scanf("%d %s %d", &number1, word, &number2) != 3);
}
printf("I got %d '%s' %d\n", number1, word, number2);
return 0;
}
Which gives:
$ ./test
Enter number word number: 1 andy 12
I got 1 'andy' 12
$ ./test 2 pandy 56
I got 2 'pandy' 56
Note that the error-checking is poor in this example and can be improved alot (not using atoi() is one way to start).
It sounds like you need to check argc in the program as RageD points out, otherwise when launching the program with insufficient arguments will cause problems.
gcc is the c compiler - it produces an executable. When you hit 'Run' in Xcode it compiles your program and then runs the executable file created. The executable created is named the same as your Xcode project name.
To run the program you built in Xcode from the command line:
In Xcode's project navigator find the executable in the 'Products' folder
Drag the executable file into Terminal (You will get an absolute url to the executable)
add any arguments you need to run your program
Hit enter!
The result will look something similar to the snippet below (for my 'MyCommandLineApp' project):
$ /Users/pliskin/Library/Developer/Xcode/DerivedData/MyCommandLineApp-hbpuxhguakaagvdlpdmqczucadim/Build/Products/Debug/MyCommandLineApp argument1 argument2

Using popen() to open a program in command line?

Is it possible to open a program using another program? For example:
I want to make a command line application in C that will prompt the user to type in the name of a program (lets say Microsoft Word.app), and that program will launch. Would I do something like this:
#include <stdio.h>
#include <time.h>
int main (int argc, const char * argv[]) {
char programName[1000];
printf("Type in the name of the program you would like to open: ");
scanf("%s", programName);
popen(programName);
}
However, popen() asks me for another char. How would I go about using popen() to open the program?
EDIT: The following code works!
#include <stdio.h>
#include <time.h>
int main (int argc, const char * argv[]) {
char programName[1000];
char app[100] = ".app";
char openApp[100] = "open /Applications/";
printf("Type in the name of the program you would like to open: ");
scanf("%s", programName);
strcat(openApp, programName);
strcat(openApp, app);
system(openApp);
}
popen lets you launch a program and get a file descriptor to its input or output, much like fopen works for files. For instance, if you wanted to read the output of your program, you'd use popen("program", "r"). On the other hand, if you want to write to its input, you would use popen("program", "w"). Mac OS X also allows for r+, which lets you read the output and write to the input but this capability isn't standard and shouldn't be relied on for cross-platform code.
If you just want to launch a program, you might as well use the system function, which does that and waits until the program exits, at which point it returns the status code. system actually invokes the shell to work, so arguments will undergo expansion (environment variables, ~, etc).
EDIT Following your comment that system("Microsoft Word.app") doesn't work as you'd expect: there are several reasons for this, actually. Starting with the message you get: this is because what you wrote is equivalent to opening a terminal window and typing Microsoft Word.app. In other words, it tries to find a program called "Microsoft", then pass it the argument "Word.app". You would need to either quote the program name or escape spaces to have the shell understand it's a whole program name and not a program name then an argument: system("Microsoft\ Word.app")
Now, this should complain saying that the shell can't find the program "Microsoft Word.app", which is already a step forward.
This is because on Mac OS, app files aren't executable files: they're folders that the Finder displays as a single file. You can verify that by ctrl+clicking (or right-clicking) an app and selecting "Show package contents" (this will open the app folder). The actual executable for Microsoft Word.app must be somewhere along the path of Microsoft Word.app/Contents/MacOS/Microsoft Word.
As you can see, this is getting kind of complex. Luckily enough, Apple provides the open executable, which can use a bunch of OS services to figure out those details. It allows to launch applications in the following fashion:
open -a Microsoft\ Word
This should launch Word. (Notice how you still need to escape the spaces.) In pure C code, that would get you something like this:
system("open -a Microsoft\\ Word");
If you choose to use Objective-C and Cocoa, however, there is a very simple way to open applications:
NSString* appName = #"Microsoft Word"; // no escape!
[[NSWorkspace sharedWorkspace] launchApplication:appName];
NSString objects can be created from C string easily enough:
NSString* appName = [[NSString alloc] initWithCString:programName encoding:NSUTF8StringEncoding];
[[NSWorkspace sharedWorkspace] launchApplication:appName];
[appName release];
It would be better to use system(3) for this purpose.
The popen(3) function establishes a pipeline that can be read or written by the caller. But GUI applications do not use standard input and standard output, they connect to the graphical interface server, sometimes called the "window server". This server is already running and already has decided what its keyboard input will be, and it is always writing its output to the video device.
To start a .app you should actually run the open(1) program, so try something like:
system("open /Applications/MacVim.app");

Resources