Parsing options having a common flag in C - c

I have a C program where I accept multiple arguments. Here, I have a common flag d for both data-store and disk. Is there a way that I can check for the flags in-order and get the value of store before I check with case d. I've tried various ways like adding a while loop before this to check for s and then enter this loop etc.
static void
ParseOptions(int argc, char* argv[])
{
int c, option_index;
int ind = 0;
while((c = getopt_long(argc, argv, "s:d:",
long_options, &option_index))!= -1) {
ind = optind;
switch(c) {
case 's':
optionStore = true;
store = strdup(optarg);
break;
case 'd':
if(strcmp(store,"datastore") == 0){
printf("In datastore\n");
datastore = strdup(optarg);
}
else if(strcmp(store,"disk") == 0){
printf("In disk\n");
disk = strdup(optarg);
}
break;
default:
exit(-1);
}
}
}
Not sure how to go about this.

You need to store optarg returned for flag d in a temporary variable, and use it after the loop exits to set either disk or datastore:
char *temp_disk_or_datastore;
while((c = getopt_long(argc, argv, "s:d:",
long_options, &option_index))!= -1) {
ind = optind;
switch(c) {
case 's':
optionStore = true;
store = strdup(optarg);
break;
case 'd':
temp_disk_or_datastore = strdup(optarg);
break;
default:
exit(-1);
}
}
if (store == NULL) {
printf("Missing storage option");
exit(-1);
}
if(strcmp(store,"datastore") == 0){
printf("In datastore\n");
datastore = temp_disk_or_datastore;
}
else if(strcmp(store,"disk") == 0){
printf("In disk\n");
disk = temp_disk_or_datastore;
}

Related

How to create a shared buffer of a value from the command line in C (producer/consumer multi-threading problem)?

I get the size of a buffer to be created from the command line with this code:
while ((c = getopt(argc, argv, "d:p:t:b:")) != -1)
switch (c) {
case 'd':
root_dir = optarg;
break;
case 'p':
port = atoi(optarg);
break;
case 't':
// NUMBER OF CONSUMER THREADS
n_threads = atoi(optarg);
break;
case 'b':
// BUFFER SIZE
THREAD_BUFFER_SIZE = atoi(optarg);
default:
fprintf(stderr, "usage: wserver [-d basedir] [-p port] [-t threads] [-b buffer] \n");
exit(1);
}
Which is contained in my main() function.
Lets say I execute ./wserver -d . -p 8004 -t 8 -b 10.
I expect to get a buffer of size 10.
This buffer is being shared between producer and consumer threads, whose function implementations lie outside of the main() function. With that, I receive an error stating 'buffer is undeclared.'
I then created a buffer of default size, lets say 4 (int buffer[4];), outside of the main function so that it would be declared. Then inside of the main() function, I add buffer = buffer[THREAD_BUFFER_SIZE], which gets the size requested from the getopt case statement above. Which is obviously wrong, but I do not understand how to replace this code to allow the shared buffer of a size requested to be created.
Any tips?
Default initialized buffer on line 3 and shared buffer commented:
char default_root[] = ".";
int count = 0;
int buffer[10];
void *producer(void *THREAD_BUFFER_SIZE) {
[uses buffer]
}
void *consumer(void *arg) {
[uses buffer]
}
int main(int argc, char *argv[])
{
int c;
char *root_dir = default_root;
int port = 10000;
// I created these
int n_threads;
int THREAD_BUFFER_SIZE;
pthread_t* mythreads; // consumer threads
pthread_t p_id; // producer thread
while ((c = getopt(argc, argv, "d:p:t:b:")) != -1)
switch (c) {
case 'd':
root_dir = optarg;
break;
case 'p':
port = atoi(optarg);
break;
case 't':
// NUMBER OF CONSUMER THREADS
n_threads = atoi(optarg);
break;
case 'b':
// BUFFER SIZE
THREAD_BUFFER_SIZE = atoi(optarg);
default:
fprintf(stderr, "usage: wserver [-d basedir] [-p port]\n");
exit(1);
}
// SHARED BUFFER
buffer = buffer[THREAD_BUFFER_SIZE];
// Create producer thread
if (pthread_create(&p_id, NULL, producer, (void*) THREAD_BUFFER_SIZE) != 0) {
fprintf(stderr, "unable to create producer thread\n");
exit(1);
}
// Create n_threads consumer threads
mythreads = (pthread_t*) malloc(sizeof(pthread_t)*n_threads);
for(int i = 0; i < n_threads; i++) {
if(pthread_create(&mythreads[i], NULL, consumer, NULL) != 0) {
fprintf(stderr, "unable to create consumer thread\n");
exit(1);
}
}
// run out of this directory
chdir_or_die(root_dir);
// now, get to work
int listen_fd = open_listen_fd_or_die(port);
while (1) {
struct sockaddr_in client_addr;
int client_len = sizeof(client_addr);
int conn_fd = accept_or_die(listen_fd, (sockaddr_t *) &client_addr,
(socklen_t *) &client_len);
request_handle(conn_fd);
close_or_die(conn_fd);
}
// Added at end to close and clean
pthread_join(p_id, NULL);
free(mythreads);
pthread_mutex_destroy(&mut);
return 0;
}

How to use nested Switch with commandline arguments?

I have my switch case and statements inside my main function as follows:
int main(int argc, char *argv[])
{
int c;
while((c = getopt(argc,argv,"ABS"))!=-1)
{
switch(c)
{
case 'A':
flag = 0;
printf("open the port\n");
struct can_frame frame_rd;
open_port("vcan0");
printf("vcan0 port is opened");
fflush(stdout);
create_file();
while(1)
{
read_port(&frame_rd);
}
break;
case 'B':
flag = 1;
printf("open the port\n");
open_port("vcan0");
printf("vcan0 port is opened");
fflush(stdout);
create_binfile();
while(1)
{
read_port(&frame_rd);
}
break;
}
}
Now I want to make use of nested switch when user passes an argument -S inside the case A can i do it as follows? Is the following procedure correct?
int main(int argc, char *argv[])
{
int c;
while((c = getopt(argc,argv,"ABS"))!=-1)
{
switch(c)
{
case 'A':
switch(c)
{
case 'S':
size = 100;
break;
}
flag = 0;
printf("open the port\n");
struct can_frame frame_rd;
open_port("vcan0");
printf("vcan0 port is opened");
fflush(stdout);
create_file();
while(1)
{
read_port(&frame_rd);
}
break;
case 'B':
flag = 1;
printf("open the port\n");
open_port("vcan0");
printf("vcan0 port is opened");
fflush(stdout);
create_binfile();
while(1)
{
read_port(&frame_rd);
}
break;
}
}
In the above code can I use same switch(c) for the nested case also , is the usage of nested switch correct?Thanks in advance.
No, within the outer swich case 'A', variable c can be thought of as constant, therefore your nested switch will not find a case to match and does not have a default case.
If you know your arguments are in a particular order, you can address them directly e.g. argv[1] and argv[2] for the first and second arguments.

Qnx message prefix

I can not implement messaging between processes in QNX with the mechanism of the perfixes. I have tried many ways but all in vain.
#define PREFIX_POSITION "stat_pos"
char receiveBuffer = 0;
char replyBuffer[25];
name_attach_t *positionPrefix;
dispatch_t *dpp;
int rcvid;
dpp = dispatch_create();
if (positionPrefix = name_attach(NULL, PREFIX_POSITION, 0) == NULL){
printf("prefix - null\n");
return EXIT_FAILURE;
}
positionPrefix = name_attach(dpp, PREFIX_POSITION, 0);
while(true){
rcvid = MsgReceive(positionPrefix->chid, &receiveBuffer, sizeof(receiveBuffer), NULL);
switch(receiveBuffer){
case 'Q':
//Do something
break;
case 'H':
//Do something
break;
case 'D':
//Do something
break;
case 'S':
//Do something
break;
}
MsgReply(rcvid, REPLY_INDEX, &replyBuffer, sizeof(replyBuffer));
receiveBuffer = 0;
}
return 0;
}
name_attach () function always returns null. What could be the problem?

How to append at end of file for shell in C?

I am trying to write the shell program in C for I/O redirection. The input and output is working fine, but I also have to append output to the end of a file with the '>>', but it's not working. Whenever, I use >> in the command line, it just overwrites the output to the file. And I also get a warning when I run the program: warning: multi-character character constant. I would really appreciate it if someone can please assist me in the right direction to fix this problem.
// Check for redirected input
input = redirect_input(args, &input_filename);
switch(input) {
case -1:
printf("Syntax error!\n");
continue;
break;
case 0:
break;
case 1:
printf("Redirecting input from: %s\n", input_filename);
break;
}
// Check for redirected output
output = redirect_output(args, &output_filename);
switch(output) {
case -1:
printf("Syntax error!\n");
continue;
break;
case 0:
break;
case 1:
printf("Redirecting output to: %s\n", output_filename);
break;
}
// Check for redirected append output
append = redirect_append(args, &append_filename);
switch(append) {
case -1:
printf("Syntax error!\n");
continue;
break;
case 0:
break;
case 1:
printf("Redirecting output to: %s\n", output_filename);
break;
}
// Do the command
do_command(args, block,
input, input_filename,
output, output_filename,
append, append_filename);
}
}
/*
* Do the command
*/
int do_command(char **args, int block,
int input, char *input_filename,
int output, char *output_filename,
int append, char *append_filename) {
int result;
pid_t child_id;
int status;
// Fork the child process
child_id = fork();
// Check for errors in fork()
switch(child_id) {
case EAGAIN:
perror("Error EAGAIN: ");
return;
case ENOMEM:
perror("Error ENOMEM: ");
return;
}
if(child_id == 0) {
// Set up redirection in the child process
if(input)
freopen(input_filename, "r", stdin);
if(output)
freopen(output_filename, "w+", stdout);
if (append)
freopen(append_filename, "a", stdout);
// Execute the command
result = execvp(args[0], args);
exit(-1);
}
// Wait for the child process to complete, if necessary
if(block) {
printf("Waiting for child, pid = %d\n", child_id);
result = waitpid(child_id, &status, 0);
}
}
/*
* Check for input redirection
*/
int redirect_input(char **args, char **input_filename) {
int i;
int j;
for(i = 0; args[i] != NULL; i++) {
// Look for the <
if(args[i][0] == '<') {
//free(args[i]);
// Read the filename
if(args[i+1] != NULL) {
*input_filename = args[i+1];
} else {
return -1;
}
// Adjust the rest of the arguments in the array
for(j = i; args[j-1] != NULL; j++) {
args[j] = args[j+2];
}
return 1;
}
}
return 0;
}
/*
* Check for output redirection
*/
int redirect_output(char **args, char **output_filename) {
int i;
int j;
for(i = 0; args[i] != NULL; i++) {
// Look for the >
if(args[i][0] == '>') {
//free(args[i]);
// Get the filename
if(args[i+1] != NULL) {
*output_filename = args[i+1];
} else {
return -1;
}
// Adjust the rest of the arguments in the array
for(j = i; args[j-1] != NULL; j++) {
args[j] = args[j+2];
}
return 1;
}
}
return 0;
}
/*
* Check for append redirection
*/
int redirect_append(char **args, char **append_filename) {
int i;
int j;
for(i = 0; args[i] != NULL; i++) {
// Look for the >>
if(args[i][0] == '>' && args[i][1] == '>') {
//free(args[i]);
// Read the filename
if(args[i+2] != NULL) {
*append_filename = args[i+2];
} else {
return -1;
}
// Adjust the rest of the arguments in the array
for(j = i; args[j-1] != NULL; j++) {
args[j] = args[j+2];
}
return 1;
}
}
return 0;
}
if(args[i][0] == '>>') {
Should be:
if(args[i][0] == '>' && args[i][1] == '>') {
This is the source of your "multi-character constant" warning as well as your output redirection problem.

I'm getting a really odd timing error, where something is executing before I believe it should

#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
int c, n, E, b, s, v, t, opt, valid = 0;
char current = '\0';
char previous = '\0';
FILE *fp;
/* -n numbers lines
* -E appends a dollar sign to line ends
* -b numbers only non-blank lines
* -s squeezes multiple blank lines down to 1
* -v displays control chars, excluding tab
* -t includes tab in the above
* -e is the same as -E and -v
*/
int setFlags(int argc, char *argv[]) {
int op;
while ((op = getopt(argc, argv, "nEbsvte")) != -1) {
switch (op) {
case 'n': {
n = 1;
break;
} case 'E': {
E = 1;
break;
} case 'b': {
b = 1;
break;
} case 's': {
s = 1;
break;
} case 'v': {
v = 1;
break;
} case 't': {
t = 1;
break;
} case 'e': {
E = 1;
v = 1;
break;
} case '?': {
//fprintf(stderr, "Option `-%c` is not valid.\n", optopt);
return EXIT_FAILURE;
} default: {
abort();
}
}
}
opt = optind;
if(n == 1) {
b = 0;
}
return EXIT_SUCCESS;
}
int checkFile(char *path) {
if (access(path, R_OK) == 0) {
return EXIT_SUCCESS;
} else {
fprintf(stderr, "cat: %s: %s\n", argv[i], strerror(errno));
errno = 0;
return EXIT_FAILURE;
}
}
int doPrint(char *path) {
if (strcmp(path, "stdin") == 0) {
fp = stdin;
} else {
if (checkFile(path) == 1) {
return EXIT_FAILURE;
} else {
fp = fopen(path, "r");
}
}
while ((c = fgetc(fp)) != EOF) {
putchar(c);
}
fclose(fp);
return EXIT_SUCCESS;
}
int main (int argc, char *argv[]) {
if (setFlags(argc, argv) == 1) {
fprintf(stderr, "The program has terminated with an error.\n"
"An invalid option was specified.\n");
return EXIT_FAILURE;
} else {
if ((argc - opt) == 0) {
doPrint("stdin");
} else {
for(int i = opt; i < argc; i++) {
doPrint(argv[i]);
}
}
}
}
I'm getting a really crazy bug, where my program outputs the error line in checkFile, before it finishes writing the contents of the file (always one chat before the end).
It's driving me insane, and no matter where I move that piece of code, it doesn't work as intended.
I'm sure the answer is probably trivial, but it has me stumped. I'd even thrown in sleeps and various other things just before output finished, and it would throw the error, THEN sleep, THEN print the final character.
Any help?
When using printf, stdout output is buffered by default. This means it can be interleaved with other output, often from stderr. stderr is unbuffered by default so that it's output is printed immediately as would normally be desired when an error occurs.
Interleaving can be fixed with judicious use of fflush or by turning off file buffering of stdout using setbuf. Be sure to read the man pages for setbuf as there are some caveats.
In this case, adding fflush(stdout) at the end of the doPrint function should fix the "problem".

Resources