Getopt ordering, any? - c

I was doing a little program and realize that I will need that the user input his options in the right order so my program would do his job right, but I thought that this is kind of 'bug' an should be avoided, so I tried to make the program work 'order independent', but that doesn't work, so I decided to find a function that do the optarg parse the options in the order that I choose, but, for my surprise, I COULDN'T FIND ANY, so I decided to write my on getopt ordering function... The question is, there is a specific function for this job? (and I wrote all of this code in vain :( ). If there is a function, please tell me. And, independently if a function exists or not, You guys could take a look at the piece of code that I wrote... Thank you in advance.
Obs.: I want to know if exist a C function for the task.
The code is in https://github.com/paolocarrara/getopt_ordering
But here is it too (two files):
/*file _getopt.h (first file)*/
#include <stdlib.h>
char **ordering (int *, char **, char *);
/*file ordering.c (second file)*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define TRUE 1
#define FALSE 0
int get_line_size (char *line) {
return strlen (line);
}
int verify_if_is_option (char *argv) {
if (argv != NULL) {
if (argv[0] == '-')
return TRUE;
else
return FALSE;
}
else
return FALSE;
}
int problem_counter (int argc, char **argv) {
int i;
int number_of_problens;
for (i = 1, number_of_problens = 0; i < argc; i++)
if (verify_if_is_option (argv[i]) == TRUE)
if (get_line_size (argv[i]) > 2)
number_of_problens++;
return number_of_problens;
}
char **malloc_argv (int argc, char **argv, int t_problens) {
char **new;
int i;
new = malloc ((argc+t_problens)*sizeof(char*));
for (i = 0; i < argc; i++)
new[i] = argv[i];
for (; i < argc + t_problens; i++)
new[i] = NULL;
return new;
}
char *get_problematic_line (int argc, char **argv) {
int i;
char *line = NULL;
for (i = 1; i < argc; i++)
if (verify_if_is_option (argv[i]) == TRUE)
if (get_line_size (argv[i]) > 2)
line = argv[i];
return line;
}
char *get_argument (char *line) {
char *argument;
int i;
argument = malloc ((strlen(line)-1)*sizeof(char));
for (i = 2; i < strlen(line); i++)
argument[i-2] = line[i];
argument[i-2] = '\0';
return argument;
}
char **push_down (int argc, char **argv, int i) {
for (; argc > i+1; argc--)
argv[argc-1] = argv[argc-2];
return argv;
}
char **push_one_line_down_from_here (char *line, int argc, char **argv) {
int i;
for (i = 1; i < argc; i++)
if (argv[i] == line){
argv = push_down (argc, argv, i);
i = argc;
}
return argv;
}
char **insert_argument_below_this_line (char *line, char *argument, char **argv) {
int i;
for (i = 1; line != argv[i]; i++);
argv[i+1] = argument;
return argv;
}
void remove_argument_from_problematic_line (char *line) {
line[2] = '\0';
}
char **malloc_and_divide (int *argc, char **argv) {
int t_problens;
char *line;
char *argument;
t_problens = problem_counter (*argc, argv);
argv = malloc_argv (*argc, argv, t_problens);
(*argc) +=t_problens;
for (;t_problens > 0; t_problens--) {
line = get_problematic_line (*argc, argv);
argument = get_argument (line);
argv = push_one_line_down_from_here (line, *argc, argv);
argv = insert_argument_below_this_line (line, argument, argv);
remove_argument_from_problematic_line(line);
}
return argv;
}
char *litteral_to_dinamic (char *literal) {
int i;
char *dinamic = malloc ((strlen(literal)+1)*sizeof(char));
for (i = 0; i < strlen(literal); i++) dinamic[i] = literal[i];
dinamic[i] = '\0';
return dinamic;
}
char get_desired_option (char *optstring) {
char option;
option = optstring[0];
return option;
}
void remove_option_used (char *optstring) {
int i;
for (i = 1; i <= strlen(optstring); i++)
optstring[i-1] = optstring[i];
if (optstring[0] == ':')
remove_option_used (optstring);
}
int is_in_argv (int argc, char **argv, char option) {
int i;
for (i = 1; i < argc; i++)
if (argv[i][0] == '-' && argv[i][1] == option)
return TRUE;
return FALSE;
}
int option_have_argument (char **argv, int position) {
if (argv[position+1][0] == '-')
return TRUE;
else
return FALSE;
}
int both_have_argument (int argc, char **argv, int position, int i) {
if(i < argc-1){
if((argv[position+1][0] != '-') && (argv[i+1][0] != '-'))
return TRUE;
else
return FALSE;
}
else
return FALSE;
}
void change_both_arguments (int argc, char **argv, int position, int i) {
char *aux;
aux = argv[position+1];
argv[position+1] = argv[i+1];
argv[i+1] = aux;
}
int first_have_argument (int argc, char **argv, int position) {
if (position < argc-1)
if (argv[position+1][0] != '-')
return TRUE;
return FALSE;
}
void change_first_argument (int argc, char **argv, int position, int i) {
char *aux;
aux = argv[position+1];
for (position++; position < i; position++)
argv[position] = argv[position+1];
argv[i] = aux;
}
int second_have_argument (int argc, char **argv, int i) {
if (i < argc-1)
if (argv[i+1][0] != '-')
return TRUE;
return FALSE;
}
void change_second_argument (int argc, char **argv, int position, int i) {
char *aux;
int j;
aux = argv[i+1];
for (j=i+1; j > position; j--)
argv[j] = argv[j-1];
argv[position+1] = aux;
}
int verify_arguments (int argc, char **argv, int position, int i) {
if (both_have_argument (argc, argv, position, i) == TRUE) {
change_both_arguments (argc, argv, position, i);
return position+2;
}
else if (first_have_argument (argc, argv, position) == TRUE) {
change_first_argument (argc, argv, position, i);
return position+1;
}
else if (second_have_argument (argc, argv, i) == TRUE) {
change_second_argument (argc, argv, position, i);
return position+2;
}
else
return position+1;
}
int change_option_position (int argc, char **argv, char option, int position) {
int i;
char *aux;
for (i = 1; i < argc; i++)
if (argv[i][0] == '-' && argv[i][1] == option) {
aux = argv[position];
argv[position] = argv[i];
argv[i] = aux;
position = verify_arguments (argc, argv, position, i);
}
return position;
}
char **organize (int argc, char **argv, char *optstring) {
int position = 1;
char option;
optstring = litteral_to_dinamic (optstring);
while (optstring[0] != '\0') {
option = get_desired_option (optstring);
remove_option_used (optstring);
if ((is_in_argv(argc, argv, option)) == TRUE)
position = change_option_position (argc, argv, option, position);
}
return argv;
}
char **ordering (int *argc, char **argv, char *optstring) {
int i;
argv = malloc_and_divide (argc, argv);
argv = organize (*argc, argv, optstring);
return argv;
}

You are correct, there are no functions that will do what you describe. However, why don't you just declare a bitmap and use getopt only to set the values in the bitmap? After that's done, you can then check the bitmap and process the options in whatever order you please. Consider the following example, assuming an arbitrary option 'b' needed to be processed before an arbitrary option 'a'.
#define OPTIONS = "ab"
#define flaga = 0x0001; /* corresponds to a */
#define flagb = 0x0002; /* corresponds to b */
unsigned int flags = 0; /* the bitmap */
char ch = '\0' /* the switch char */
while ((ch = getopt(argc, argv, OPTIONS)) != -1)
{
switch (ch) {
case 'a': /* set flag a */
flags |= flaga;
break;
case 'b':
flags |= flagb;
break;
}
if((flags & flagb) == flagb)
{
//process flag b
}
if((flags & flaga) == flaga)
{
//process flag a
}

Related

C program doesn't output anything

This program is supposed to open a text file, then search for given words in argv. It will search for the words line by line and if it finds one of the given words in that line the program should print it.
This the code I wrote for it:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int existe_mot_cle(char s[1024], int argc, char *argv[])
{
int test = 0;
for (int i = 2; i < argc; i++)
{
if (strstr(s, argv[i]))
test = 1;
break;
}
return test;
}
int open_file(char *argv[], FILE *fp)
{
fp = fopen(argv[1], "a");
}
int main(int argc, char *argv[])
{
FILE *fp;
char s[1024];
if (!open_file(argv, fp))
return 0;
while (fgets(s, 1024, fp))
{
if (existe_mot_cle(s, argc, argv))
printf("%s", s);
}
fclose(fp);
}
The problem is when I run it, nothing happens and I don't know why. I am new to the C language. Can someone give me the solution and explain it please?
You are breaking the for loop right after the first if statement is executed. You should surround it with curly braces:
int existe_mot_cle(char s[1024], int argc, char *argv[])
{
int test = 0;
for (int i = 2; i < argc; i++)
{
if (strstr(s, argv[i])) {
test = 1;
break;
}
}
return test;
}
You can make it simpler and more generic:
bool existe_mot_cle(char s[1024], size_t size, const char *ss[])
{
for (size_t i = 0; i < size; i++) {
if (strstr(s, ss[i]))
return true;
}
return false;
}
Also, your open_file() should return an int, but it is not returning anything. Better remove it from your code since it serves no purpose:
int main(int argc, const char *argv[])
{
if (argc < 3) {
printf("Usage: %s [file] [words]\n", argv[0]);
return 0;
}
const char *filename = argv[1]; // More meaningful
const char **otherarg = argv + 2;
FILE *fp = fopen(filename, "r");
if (!fp) {
printf("Could not open %s.\n", filename);
return 0;
}
char s[1024];
while (fgets(s, sizeof s, fp))
{
if (existe_mot_cle(s, argc-2, otherarg)) // I'm using the second "simpler" version
printf("%s", s);
}
fclose(fp);
}

reading file`s lines char by char into char** array

I wrote the next function that tries to read and enter each line from text file into a string array in c :
int main(int argc,char* argv[])
{
char ** lines;
readFile(argv[1],lines);
}
int readFile(char* filePath,char** lines)
{
char file_char;
int letter_in_line=0;
int line=1;
char* line_string=malloc(1024);
int j=1;
int fd=open(filePath,O_RDONLY);
if (fd < 0)
{
return 0;
}
while (read(fd,&file_char,1) >0)
{
if(file_char != '\n' && file_char != '0x0')
{
line_string[letter_in_line] = file_char;
letter_in_line++;
}
else
{
if(lines != NULL)
{
lines=(char**)realloc(lines,sizeof(char*)*line);
}
else
{
lines=(char**)malloc(sizeof(char*));
}
char* line_s_copy=strdup(line_string);
lines[line-1]=line_s_copy;
line++;
letter_in_line=0;
memset(line_string,0,strlen(line_string));
}
j++;
}
printf("cell 0 : %s",lines[0]);
return 1;
}
I have 2 questions :
1)Whenever the code reaches the print of cell 0, I'm getting
Segmentation fault (core dumped) error. What is wrong ?
2)In case I
want to see the changes in the lines array in my main, I should pass
&lines to the func and get char*** lines as an argument ? In
addition, I will need to replace every 'line' keyword with '*line' ?
*I know that I can use fopen,fget, etc... I decided to implement it in this way for a reason.
There is many issues that make your code core dump.
Here a version very similar to your code. I hope it will help you to understand this.
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <stdlib.h>
int read_file(const char *filename, char ***result)
{
/* open the file */
const int fd = open(filename, O_RDONLY);
if (fd < 0) {
*result = NULL;
return -1;
}
/* read the file characters by characters */
char *buffer = (char *)malloc(sizeof(char) * 1024);
char c;
int column = 0;
int line = 0;
*result = NULL;
/* for each characters in the file */
while (read(fd, &c, 1) > 0) {
/* check for end of line */
if (c != '\n' && c != 0 && column < 1024 - 1)
buffer[column++] = c;
else {
/* string are null terminated in C */
buffer[column] = 0;
column = 0;
/* alloc memory for this line in result */
*result = (char **)realloc(*result, sizeof(char *) *
(line + 1));
/* duplicate buffer and store it in result */
(*result)[line++] = strdup(buffer);
}
}
free(buffer);
return line;
}
int main(int argc, char *argv[])
{
if (argc != 2) {
fprintf(stderr, "usage: %s [filename]", argv[0]);
return 1;
}
char **lines;
int line_count = read_file(argv[1], &lines);
if (line_count < 0) {
fprintf(stderr, "cannot open file %s\n", argv[1]);
return 1;
}
for(int i=0; i < line_count; i++)
printf("%s\n", lines[i]);
return 0;
}
Here an other version:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int read_file(const char *filename, char ***result)
{
/* init result */
*result = NULL;
/* open the file */
FILE *file = fopen(filename, "r");
if (file == NULL)
return -1;
/* read the file line by line */
char *buffer = (char *)malloc(sizeof(char) * 1024);
int line = 0;
while (fgets(buffer, 1024, file)) {
*result = (char **)realloc(*result, sizeof(char *) *
(line + 1));
(*result)[line++] = strdup(buffer);
}
free(buffer);
return line;
}
int main(int argc, char *argv[])
{
if (argc != 2) {
fprintf(stderr, "usage: %s [filename]", argv[0]);
return 1;
}
char **lines;
int line_count = read_file(argv[1], &lines);
if (line_count < 0) {
fprintf(stderr, "cannot open file %s\n", argv[1]);
return 1;
}
for(int i=0; i < line_count; i++)
printf("%s\n", lines[i]);
return 0;
}

Running program from console with parameters [duplicate]

This question already has answers here:
Command-line Parameters in C program?
(5 answers)
Closed 6 years ago.
My question is how to write a fuction with which I will can run a program from console with following parameters:
program.exe -i input.txt -o output.txt -t 1/2/3
#include <stdio.h>
#include <stdlib.h>
char substitute(char letter, char* cipher)
{
int i;
int cipher_length = strlen(cipher);
char substitution = letter;
for(i = 0; i < cipher_length; ++i)
{
if(cipher[i] == substitution)
{
substitution = cipher[(i%2) ? (i-1) : (i+1)];
break;
}
}
return substitution;
}
int main()
{
char c;
int t;
FILE *plik = fopen( "input.txt", "rt" );
FILE *encoded=fopen("output.txt","wt");
char* cipher1 = "GADERYPOLUKIgaderypoluki";
char* cipher2 = "POLITYKARENUpolitykarenu";
char* cipher3 = "KACEMINUTOWYkaceminutowy";
printf("Choose the cipher\n");
printf("[1]GA-DE-RY-PO-LU-KI\n");
printf("[2]PO-LI-TY-KA-RE-NU\n");
printf("[3]KA-CE-MI-NU-TO-WY\n");
scanf("%d",&t);
while(c != EOF)
{
c = getc( plik );
switch(t)
{
case 1:
putc(putchar(substitute(c, cipher1)),encoded);
break;
case 2: putc(putchar(substitute(c, cipher2)),encoded);
break;
case 3: putc(putchar(substitute(c, cipher3)),encoded);
break;
}
}
fclose( plik );
fclose(encoded);
}
I was given sth like this, but I don't know how to use it:
int function(int argc, char*argcv[])
{
int i;
char *string,*input,*output;
for(i=0; i<argc; i++)
{
}
return 0;
}
The parameter int argc contains the number of parameters in the command line.
The parameter char *argv[] is an array with all the strings typed in the command line.
This way, you can retrieve the command line parameters as:
int main(int argc, char *argv[]) {
int i = 0;
for (i = 0; i < argc; i++) {
printf("parameter %d = %s\n", i, argv[i]);
}
}
You can handle then the parameters passed in the command line:
int main(int argc, char *argv[]) {
int i = 0;
for (i = 0; i < argc; i++) {
...
if (strcmp(argv[i], "-i") == 0) {
doSomething(argv[i+1]);
}
...
}
}
To break the string you can use the following code:
// ...
char buffer[256];
char *p1 = NULL;
char *p2 = NULL;
int value = 0;
char old = 0;
strcpy(buffer, argv[7]);
p1 = buffer;
p2 = buffer;
do {
// parse until the delimiter
while (*p1 != '/' && *p1 != '\0') {
p1++;
}
// save delimiter value
old = *p1;
// convert the string to int
*p1 = '\0';
value = atoi(p2);
p1++;
// do something with the value
printf(">> value %d\n", value);
// goto the next token
p2 = p1;
} while (old != '\0');

Why doen't the name of the file increment like the data of the file's array does?

So the title I know is a little misleading with the contents, but my question is: with the code provided here, when I run ./tstats input1.txt input2.txt the output is as follows
5 1 21 input1.txt
2 1 11 input1.txt
So it's obvious that the information from each file is going through but the names of the files aren't. Any idea as to why this is happening? Some small mistake I'm looking over?
Secondly, how would I tally all of the wcount results so that I have:
7 2 32 total
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
enum state
{
START,
WORD,
DELIM,
};
FILE*
input_from_args(int argc, char *argv[])
{
if (argc == 1)
{
return stdin;
}
else
{
return fopen(argv[1], "r");
}
}
char* get_filename_from_args(int argc, char* argv[])
{
int i;
static char stdin_name[] = "-";
if (argc == 1)
{
return stdin_name;
}
else
{
for (i = 1; i < argc; i++)
{
return argv[i];
}
return argv[i];
}
}
void
wcount(FILE *src, FILE *dest, char* src_filename)
{
int ch, wc, lc, cc;
enum state cstate;
wc = lc = cc = 0;
cstate = START;
while ((ch = fgetc(src)) != EOF){
cc++;
switch (cstate) {
case START:
if (isspace(ch)) {
cstate = DELIM;
if (ch == '\n') {
lc++;
}
}
else {
cstate = WORD;
wc++;
}
break;
case DELIM:
if (ch == '\n') {
lc++;
}
else if (!isspace(ch)) {
cstate = WORD;
wc++;
}
break;
case WORD:
if (isspace(ch)) {
cstate = DELIM;
if (ch == '\n') {
lc++;
}
}
break;
}
}
fprintf(dest, "%4d\t%4d\t%4d\t%10s\n", wc, lc, cc, src_filename);
}
int
main(int argc, char* argv[])
{
int i;
FILE *src = input_from_args(argc, argv);
FILE *dest = stdout;
for (i = 1; i < argc; i++)
{
if ((src = fopen(argv[i], "r")) == NULL)
{
fprintf(stderr, "%s: unable to open %s\n", argv[0], argv[i]);
}
wcount(src, dest, get_filename_from_args(argc, argv));
fclose(src);
}
return EXIT_SUCCESS;
}
get_filename_from_args doesn't do what you think it does. Get rid of it entirely and just use argv[i] again at the call site.
regarding this sub question:
Secondly, how would I tally all of the wcount results so that I have:
7 2 32 total
add three global int variables
Then when each value is available, add it to the appropriate global variables.
Then, in the end, printf the contents of those global variables
This line:
'wcount(src, dest, get_filename_from_args(argc, argv));'
is not stepping through the arguments contained in argv.
Suggest:
'wcount(src, dest, argv[i]);'
and eliminating the function:
'char* get_filename_from_args(int argc, char* argv[])'

Adding words to a char *[] in C

I have a program that reads the words of two files (the first a wordlist, and the second an ebook from the Gutenberg project ) into two char *arrays.
I am trying to add all the unique words from the second char *array that don't appear in
the first char *array into a third char *array then print them.
This program adds the correct words, but is adding them more than once.
The error occurs in findOdds().
Note when I use a non-binary search method this program works correctly, but takes a long time.
What is the problem with my program? I apologize for my English.
#include <stdio.h>
#include <stdlib.h> /* for malloc() */
#include <ctype.h>
#include <string.h>
#define MAXCHAR 24
#define MAXLINES 150000
int add2array(FILE *fp, char *lineptr[]);
int findOdds(char *lineptr[], char *lineptr1[], int nlines, int nlines1);
int binsearch1(char *val, char *lineptr[], int nlines);
char *lineptr2[MAXLINES]; /* The unique words not in the word list */
int main(int argc, char *argv[])
{
FILE *my_stream, *my_stream1;
char *lineptr[MAXLINES], *lineptr1[MAXLINES];
int i, nlines, nlines1, nlines2;
/* Load the wordlist. */
my_stream = fopen("words.txt","r");
if(my_stream == NULL) {
printf("error: Couldn't open file\n");
return 2;
} else {
nlines = add2array(my_stream, lineptr);
fclose(my_stream);
}
if(nlines==-1) {
printf("error: Epic Failure to copy words to char *lineptr[]\n");
return -1;
}
/* Load the ebook. */
my_stream1 = fopen("horsemanship.txt","r");
if(my_stream1 == NULL) {
printf("error: Couldn't open file\n");
return 2;
} else {
nlines1 = add2array(my_stream1, lineptr1);
fclose(my_stream1);
}
if(nlines1==-1) {
printf("error: Epic Failure to copy words to char *lineptr[]\n");
return -1;
}
/* Find and print the unique words from the ebook not in the wordlist */
nlines2 = findOdds(lineptr, lineptr1, nlines, nlines1);
for(i=0; i<nlines2; i++)
printf("%s\n",lineptr2[i]);
return 0;
}
/* add2array: read the words from the file into char *lineptr[] */
int add2array(FILE *fp, char *lineptr[])
{
int nlines=0, c=0, pos=0;
char temp[MAXCHAR];
char *p;
while((c = getc(fp)) != EOF) {
if(isalpha(c))
temp[pos++] = tolower(c);
else if(!isalpha(c)) {
temp[pos] = '\0';
pos = 0;
if(isalpha(temp[0])){
if((p = malloc(sizeof(temp)))==NULL)
return -1;
strcpy(p, temp);
lineptr[nlines++] = p;
}
}
}
return nlines;
}
/* Add the unique words from lineptr1 not in lineptr to lineptr2 */
int findOdds(char *lineptr[], char *lineptr1[], int nlines, int nlines1)
{
char *p;
char temp[MAXCHAR];
int i, nlines2=0;
for(i=0; i<nlines1; i++) {
if(binsearch1(lineptr1[i], lineptr, nlines)==-1) {
if(binsearch1(lineptr1[i], lineptr2, nlines2)==-1) {
if((p = malloc(sizeof(temp)))==NULL)
return -1;
strcpy(p, lineptr1[i]);
lineptr2[nlines2++] = p;
}
}
}
return nlines2;
}
int binsearch1(char *val, char *lineptr[], int nlines)
{
int pos;
int start = 0;
int end = nlines-1;
int cond = 0;
while(start <= end){
pos=(start + end)/2;
if((cond = strcmp(lineptr[pos],val)) == 0)
return pos;
else if(cond < 0)
start = pos+1;
else
end = pos-1;
}
return -1;
}
Arrays must be sorted if you want to use binary search, as stated above by n.m.
in main() ...
shellsort1(lineptr1, nlines1);
/* Find and print the unique words from the ebook not in the wordlist */
nlines2 = findOdds(lineptr, lineptr1, nlines, nlines1);
...
int shellsort1(char *v[], int n)
{
int gap, i, j;
char temp[MAXCHAR];
char *p;
for(gap=n/2; gap>0; gap/=2)
for(i=gap; i<n; i++)
for(j=i-gap; j>=0 && strcmp(v[j],v[j+gap])>0; j-=gap) {
if((p = malloc(sizeof(temp)))==NULL)
return -1;
p = v[j];
v[j] = v[j+gap];
v[j+gap] = p;
}
return 0;
}

Resources