I have this piece of code in C
while((i = getopt(argc, argv, ":p:h:s:n:l:f:SLNF")) != -1)
switch(i){
case 'p': printf("Porta obbligatoria\n");
break;
case 'h': printf("hostname\n");
break;
case 's': printf("Surname\n");
break;
case 'n': printf("Name\n");
break;
case 'l': printf("Login\n");
break;
case 'f': printf("Faculty\n");
break;
case 'S': printf("Print Surname\n");
break;
case 'L': printf("Print Login\n");
break;
case 'N': printf("Print First name\n");
break;
case 'F': printf("Print Faculty\n");
break;
case '?': printf("USAGE\n");
break;
default: printf("USAGE default\n");
break;
}
return 0;
}
How can I have only one mandatory parameter? In my case is p.
For example:
./MyProgram -p 80 -h 127.0.0.1
Result ok.
./MyProgram -h 127.0.0.1
Error because missing -p
Only -p.
Thanks in advance.
Usually you use the while loop to store the values and then check the mandatory options after the loop:
int p = -1;
while((i = getopt(argc, argv, ":p:h:s:n:l:f:SLNF")) != -1)
switch(i){
case 'p': p = (int)atol(optarg);
break;
<skipped a few options >
default: printf("USAGE default\n");
break;
}
// Check mandatory parameters:
if (p == -1) {
printf("-p is mandatory!\n");
exit 1;
}
return 0;
}
I'm using getopt function as follows,
char c;
void function(int len,char **data_buff)
{
while ((c = getopt(len, data_buff,
"M:i:h:b:p:s:a:m:c:H:P:f:x:y:l:u:V:D:U:W:O:E:F:R:N:n:B")) != EOF)
{
printf("c==>%c\n", c);
switch (c)
{
case 'M': /** InputMode **/
printf("in case M");
break;
case 'i': / serial input device /
printf("in case i");
break;
case 'B': / bind to incoming UDP stream /
printf("in case B");
break;
case 'V': / Sisnet data server version number /
printf("in case V");
break;
case 'b': / serial input baud rate /
printf("in case b");
break;
case 'a': / Destination caster address /
printf("in case a");
break;
case 'p': / Destination caster port /
printf("in case p");
break;
case 'm': / Destination caster mountpoint for stream upload /
printf("in case m");
break;
case 's': / File name for input data simulation from file /
printf("in case s");
break;
case 'f': / name of an initialization file /
printf("in case f");
break;
case 'x': / user ID to access incoming stream /
printf("in case x");
break;
case 'y': / password to access incoming stream /
printf("in case y");
break;
case 'u': / Sisnet data server user ID /
printf("in case u");
break;
case 'l': / Sisnet data server password /
printf("in case l");
break;
case 'c': / DestinationCaster password for stream upload to mountpoint /
printf("in case c");
break;
case 'H': /* Input host address*/
printf("in case H");
break;
case 'P': / Input port /
printf("in case P");
break;
case 'D': / Source caster mountpoint for stream input /
printf("in case D");
break;
case 'U': / Source caster user ID for input stream access /
printf("in case U");
break;
case 'W': / Source caster password for input stream access /
printf("in case W]");
break;
case 'E': / Proxy Server /
printf("in case E");
break;
case 'F': / Proxy port /
printf("in case F");
break;
case 'R': / maximum delay between reconnect attempts in seconds /
printf("in case R");
break;
case 'O': / OutputMode /
printf("in case O");
break;
case 'n': / Destination caster user ID for stream upload to mountpoint /
printf("in case n");
break;
case 'N': / Ntrip-STR, optional for Ntrip Version 2.0 /
printf("in case N");
break;
case 'h': / print help screen /
printf("in case h");
break;
case '?':
printf("in case ?");
break;
default:
printf("in case default");
break;
}
}
}
I'm passing array of char pointer(as mentioned below) as an argument for the function where the above while is running.
char *ntrip_buff1[19];
ntrip_buff1[0] = "./ntripserver";
ntrip_buff1[1] = "-M";
ntrip_buff1[2] = "1";
ntrip_buff1[3] = "-i";
ntrip_buff1[4] = "/dev/ttymxc5";
ntrip_buff1[5] = "-b";
ntrip_buff1[6] = "115200";
ntrip_buff1[7] = "-O";
ntrip_buff1[8] = "1";
ntrip_buff1[9] = "-a";
ntrip_buff1[10] = "abc.com";
ntrip_buff1[11] = "-p";
ntrip_buff1[12] = "2101";
ntrip_buff1[13] = "-m";
ntrip_buff1[14] = "Mount2";
ntrip_buff1[15] = "-n";
ntrip_buff1[16] = "BroadlySoughtCub";
ntrip_buff1[17] = "-c";
ntrip_buff1[18] = "sauhduhasd";
So I observed that initially it will work fine but, whenever I change the above buffer and pass it to the function as an argument then in that case it is returning -1 always.
For example-
ntrip_buff1[18] = "sauhduhasd";
changed to
ntrip_buff1[18] = "abcd";
So what will be the reason for getting -1 as the return value for the getopt function?
If you are trying to use getopt() to analyze more than one set of arguments in a single run, you have to work out how your particular version of getopt() allows you to do that — if, indeed, it does allow you to do it.
On macOS Big Sur 11.7.1, for example, the manual page documents:
extern int optreset;
…
In order to use getopt() to evaluate multiple sets of arguments, or to evaluate a single set of arguments multiple times, the variable optreset must be set to 1 before the second and each additional set of calls to getopt(), and the variable optind must be initialized […to 1].
Adapting your code a bit and creating an MCVE (Minimal, Complete, Verifiable Example
— or MRE or whatever name SO now uses)
or an
SSCCE (Short, Self-Contained, Correct Example)
— the same idea by a different name — I produced the following code. Note that it has a null pointer at the end of the argument list.
/* SO 7447-0255 */
#include <stdio.h>
#include <unistd.h>
static void function(int len, char **data_buff)
{
int c;
/* Dropped colon after h in option list */
while ((c = getopt(len, data_buff,
"M:i:hb:p:s:a:m:c:H:P:f:x:y:l:u:V:D:U:W:O:E:F:R:N:n:B")) != -1)
{
switch (c)
{
case 'M': /** InputMode **/
printf("in case M [%s]\n", optarg);
break;
case 'i':
/* serial input device */
printf("in case i [%s]\n", optarg);
break;
case 'B':
/* bind to incoming UDP stream */
printf("in case B\n");
break;
case 'V':
/* Sisnet data server version number */
printf("in case V [%s]\n", optarg);
break;
case 'b':
/* serial input baud rate */
printf("in case b [%s]\n", optarg);
break;
case 'a':
/* Destination caster address */
printf("in case a [%s]\n", optarg);
break;
case 'p':
/* Destination caster port */
printf("in case p [%s]\n", optarg);
break;
case 'm':
/* Destination caster mountpoint for stream upload */
printf("in case m [%s]\n", optarg);
break;
case 's':
/* File name for input data simulation from file */
printf("in case s [%s]\n", optarg);
break;
case 'f':
/* name of an initialization file */
printf("in case f [%s]\n", optarg);
break;
case 'x':
/* user ID to access incoming stream */
printf("in case x [%s]\n", optarg);
break;
case 'y':
/* password to access incoming stream */
printf("in case y [%s]\n", optarg);
break;
case 'u':
/* Sisnet data server user ID */
printf("in case u [%s]\n", optarg);
break;
case 'l':
/* Sisnet data server password */
printf("in case l [%s]\n", optarg);
break;
case 'c':
/* DestinationCaster password for stream upload to mountpoint */
printf("in case c [%s]\n", optarg);
break;
case 'H': /* Input host address*/
printf("in case H [%s]\n", optarg);
break;
case 'P':
/* Input port */
printf("in case P [%s]\n", optarg);
break;
case 'D':
/* Source caster mountpoint for stream input */
printf("in case D [%s]\n", optarg);
break;
case 'U':
/* Source caster user ID for input stream access */
printf("in case U [%s]\n", optarg);
break;
case 'W':
/* Source caster password for input stream access */
printf("in case W] [%s]\n", optarg);
break;
case 'E':
/* Proxy Server */
printf("in case E [%s]\n", optarg);
break;
case 'F':
/* Proxy port */
printf("in case F [%s]\n", optarg);
break;
case 'R':
/* maximum delay between reconnect attempts in seconds */
printf("in case R [%s]\n", optarg);
break;
case 'O':
/* OutputMode */
printf("in case O [%s]\n", optarg);
break;
case 'n':
/* Destination caster user ID for stream upload to mountpoint */
printf("in case n [%s]\n", optarg);
break;
case 'N':
/* Ntrip - STR, optional for Ntrip Version 2.0 */
printf("in case N [%s]\n", optarg);
break;
case 'h':
/* print help screen */
printf("in case h\n");
break;
case '?':
printf("in case ?\n");
break;
default:
printf("in case default (option %c)\n", c);
break;
}
}
for (int i = optind; i < len; i++)
printf("Non-option argument %d: [%s]\n", i, data_buff[i]);
}
int main(void)
{
char *ntrip[] =
{
[0] = "./ntripserver",
[1] = "-M",
[2] = "1",
[3] = "-i",
[4] = "/dev/ttymxc5",
[5] = "-b",
[6] = "115200",
[7] = "-O",
[8] = "1",
[9] = "-a",
[10] = "abc.com",
[11] = "-p",
[12] = "2101",
[13] = "-m",
[14] = "Mount2",
[15] = "-n",
[16] = "BroadlySoughtCub",
[17] = "-c",
[18] = "sauhduhasd",
[19] = NULL,
};
enum { NUM_NTRIP = sizeof(ntrip) / sizeof(ntrip[0]) };
printf("Pass 1:\n");
function(NUM_NTRIP-1, ntrip);
printf("Pass 2:\n");
function(NUM_NTRIP-1, ntrip);
/* macOS / *BSD getopt() */
optreset = 1; // Delete this line with GNU getopt
optind = 1;
printf("Pass 3:\n");
function(NUM_NTRIP-1, ntrip);
return 0;
}
When run, it produced:
Pass 1:
in case M [1]
in case i [/dev/ttymxc5]
in case b [115200]
in case O [1]
in case a [abc.com]
in case p [2101]
in case m [Mount2]
in case n [BroadlySoughtCub]
in case c [sauhduhasd]
Pass 2:
Pass 3:
in case M [1]
in case i [/dev/ttymxc5]
in case b [115200]
in case O [1]
in case a [abc.com]
in case p [2101]
in case m [Mount2]
in case n [BroadlySoughtCub]
in case c [sauhduhasd]
Note that Phase 2 without any reset didn't produce any results.
The GNU getopt() manual doesn't document how to reset the argument handling (and doesn't provide the explicit optreset mechanism), but empirically, just resetting optind = 1; works OK. The only thing to be leery of is if you stop the first cycle of parsing part way through the processing of argv[1] and argv[1] is something like -abc (three single-letter options ganged up). You should be OK if you process to the end of the arguments on each cycle.
I have this piece of code in C
while((i = getopt(argc, argv, ":p:h:s:n:l:f:SLNF")) != -1)
switch(i){
case 'p': printf("Porta obbligatoria\n");
break;
case 'h': printf("hostname\n");
break;
case 's': printf("Surname\n");
break;
case 'n': printf("Name\n");
break;
case 'l': printf("Login\n");
break;
case 'f': printf("Faculty\n");
break;
case 'S': printf("Print Surname\n");
break;
case 'L': printf("Print Login\n");
break;
case 'N': printf("Print First name\n");
break;
case 'F': printf("Print Faculty\n");
break;
case '?': printf("USAGE\n");
break;
default: printf("USAGE default\n");
break;
}
return 0;
}
How can I have only one mandatory parameter? In my case is p.
For example:
./MyProgram -p 80 -h 127.0.0.1
Result ok.
./MyProgram -h 127.0.0.1
Error because missing -p
Only -p.
Thanks in advance.
Usually you use the while loop to store the values and then check the mandatory options after the loop:
int p = -1;
while((i = getopt(argc, argv, ":p:h:s:n:l:f:SLNF")) != -1)
switch(i){
case 'p': p = (int)atol(optarg);
break;
<skipped a few options >
default: printf("USAGE default\n");
break;
}
// Check mandatory parameters:
if (p == -1) {
printf("-p is mandatory!\n");
exit 1;
}
return 0;
}
Hey and thanks for reading.
I am making a program which takes 1 argument (directory) and reads all the files in the directory used opendir()/readdir(), and displays the file type (reg, link, directory etc) using stat. I am receiving the error "No Such file or Directory" when I execute me program in the shell (I am using redhat linux). Here is my code:
#define _BSD_SOURCE
#include <stdio.h>
#include <dirent.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[]) {
DIR *dirp;
struct dirent* dent;
struct stat info;
//If no args
if(argc == 1){
argv[1] = ".";
dirp=opendir(argv[1]); // specify directory here: "." is the "current directory"
do {
dent = readdir(dirp);
if (dent)
{
//////////////////////////////////////////////////////////////////////////
if (stat(dent->d_name, &info) == -1) {
perror("stat");
exit(EXIT_FAILURE);
}
switch (info.st_mode & S_IFMT) {
case S_IFBLK: printf("block device\n"); break;
case S_IFCHR: printf("character device\n"); break;
case S_IFDIR: printf("dir "); break;
case S_IFIFO: printf("FIFO/pipe\n"); break;
case S_IFLNK: printf("lnk "); break;
case S_IFREG: printf("reg "); break;
case S_IFSOCK: printf("socket\n"); break;
default: printf("unknown?\n"); break;
}
//////////////////////////////////////////////////////////////////////////
printf("%s \n", dent->d_name);
}
} while (dent);
closedir(dirp);
}
////////////////////////////////////////////////////////////////////////////////////////////////
//If specified directory
if(argc > 1){
dirp=opendir(argv[1]); // specify directory here: "." is the "current directory"
do {
dent = readdir(dirp);
if (dent)
{
/////////////////////////////////////////////////////////////////////////////////////
if (stat(dent->d_name, &info) == -1) {
perror("stat");
exit(EXIT_FAILURE);
}
switch (info.st_mode & S_IFMT) {
case S_IFBLK: printf("block device\n"); break;
case S_IFCHR: printf("character device\n"); break;
case S_IFDIR: printf("dir "); break;
case S_IFIFO: printf("FIFO/pipe\n"); break;
case S_IFLNK: printf("lnk "); break;
case S_IFREG: printf("reg "); break;
case S_IFSOCK: printf("socket\n"); break;
default: printf("unknown?\n"); break;
}
//////////////////////////////////////////////////////////////////////////////////////
// printf("%s\n", argv[1]);
printf("%s \n", dent->d_name);
}
} while (dent);
closedir(dirp);
}
return 0;
}
Any ideas? I'm a bit stuck.
Thanks for your input
Also, are files of type "Link" going to be output using stat, or do I have to use lstat? Not sure how to use lstat in this situation, if I change the struct type to "struct lstat info" it throws an error.
dent->d_name is the name of the file relative to your current directory (e.g "/home/barney/myfile.txt") not the absolute full path to the file (e.g. /home/barney/sources/myfile.txt), which is the one expected by stat.
This is why stat cant find the path. print dent->d_name before each call to stat to observe those incorrect paths.
Edit:
You can try chdir() to change your working directory to argv[1]
here is my question. I want to be able to support this in my application:
./cipher [-devh] [-p PASSWD] infile outfile
I managed to get the [-devh] supported, but I don't know how to get [-p PASSWORD] supported. Of course I can manually check for argc being 2 and then have a bunch of flags but I prefer using getopts and think it would be easier. Here is my code for the [-devh] how can I extend it so it can support them remaining?
while ( (c = getopt(argc, argv, "devh")) != -1) {
switch (c) {
case 'd':
printf ("option d\n");
dopt = 1;
break;
case 'e':
printf ("option e\n");
eopt = 1;
break;
case 'v':
printf ("option v\n");
vopt = 1;
break;
case 'h':
printf ("option h\n");
hopt = 1;
break;
default:
printf ("?? getopt returned character code 0%o ??\n", c);
}
}
Taken directly from the GNU C Library Reference page on getopt:
while ((c = getopt (argc, argv, "abc:")) != -1)
switch (c)
{
case 'a':
aflag = 1;
break;
case 'b':
bflag = 1;
break;
case 'c':
cvalue = optarg;
break;
case '?':
if (optopt == 'c')
fprintf (stderr, "Option -%c requires an argument.\n", optopt);
else if (isprint (optopt))
fprintf (stderr, "Unknown option `-%c'.\n", optopt);
else
fprintf (stderr, "Unknown option character `\\x%x'.\n", optopt);
return 1;
default:
abort();
}
c here is the argument that takes an optional parameter, so this is probably the syntax you were looking for.
What I understand getopt does is loop through the given arguments, parsing them one at a time. So when it gets to the option c (in your case p) where a second argument is required, it is stored in optarg. This is assigned to a variable of your choice (here cvalue) for later processing.