You read the line in line , so you have to go through line to regexec() . You also need to consider whether the new line at the end of the line affects patterns. (It was correct to use fgets() , but remember that it saves a new line at the end.)
You should also do return -1; (or any other value that is not 0 modulo 256), and not just return without a value. In addition, you must verify that the file has been opened; I had to use an alternate name because there is no /etc/rc.conf file on my machine - MacOS X.
This works for me:
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <errno.h> #include <sys/types.h> #include <regex.h> #define tofind "[az AZ] $" int main(int argc, char **argv) { FILE *fp; char line[1024]; int retval = 0; regex_t re; //this file has this line "DAEMONS=(sysklogd network sshd !netfs !crond)" const char *filename = "/etc/rc.conf"; if (argc > 1) filename = argv[1]; if (regcomp(&re, tofind, REG_EXTENDED) != 0) { fprintf(stderr, "Failed to compile regex '%s'\n", tofind); return EXIT_FAILURE; } fp = fopen(filename, "r"); if (fp == 0) { fprintf(stderr, "Failed to open file %s (%d: %s)\n", filename, errno, strerror(errno)); return EXIT_FAILURE; } while ((fgets(line, 1024, fp)) != NULL) { line[strlen(line)-1] = '\0'; if ((retval = regexec(&re, line, 0, NULL, 0)) == 0) printf("<<%s>>\n", line); } return EXIT_SUCCESS; }
If you need help writing regular expressions instead of writing C code that uses them, we need to design the regular expression according to the line you are displaying.
^DAEMONS=([^)]*) *$
This will match the string while it is being written, as shown. If you can have spaces between " S " and " = " or between " = " and " ( ", you need appropriate changes. I allowed to make blanks - people are often messy; but if they use trailing tabs, the line will not be selected.
Once you find the string, you need to break it into pieces. You can choose to “copy” the brackets or just use strchr() to find the open bracket, and then a suitable technique for separating the daemon names - I would avoid strtok() and probably use strspn() or strcspn() to find the words .
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <errno.h> #include <sys/types.h> #include <regex.h> #define tofind "^DAEMONS=\\(([^)]*)\\)[ \t]*$" int main(int argc, char **argv) { FILE *fp; char line[1024]; int retval = 0; regex_t re; regmatch_t rm[2]; //this file has this line "DAEMONS=(sysklogd network sshd !netfs !crond)" const char *filename = "/etc/rc.conf"; if (argc > 1) filename = argv[1]; if (regcomp(&re, tofind, REG_EXTENDED) != 0) { fprintf(stderr, "Failed to compile regex '%s'\n", tofind); return EXIT_FAILURE; } fp = fopen(filename, "r"); if (fp == 0) { fprintf(stderr, "Failed to open file %s (%d: %s)\n", filename, errno, strerror(errno)); return EXIT_FAILURE; } while ((fgets(line, 1024, fp)) != NULL) { line[strlen(line)-1] = '\0'; if ((retval = regexec(&re, line, 2, rm, 0)) == 0) { printf("<<%s>>\n", line); printf("Line: <<%.*s>>\n", (int)(rm[0].rm_eo - rm[0].rm_so), line + rm[0].rm_so); printf("Text: <<%.*s>>\n", (int)(rm[1].rm_eo - rm[1].rm_so), line + rm[1].rm_so); char *src = line + rm[1].rm_so; char *end = line + rm[1].rm_eo; while (src < end) { size_t len = strcspn(src, " "); if (src + len > end) len = end - src; printf("Name: <<%.*s>>\n", (int)len, src); src += len; src += strspn(src, " "); } } } return EXIT_SUCCESS; }
There is a lot of code for debugging there, but it won't take you a long time to get the response you request. I get:
<<DAEMONS=(sysklogd network sshd !netfs !crond)>> Line: <<DAEMONS=(sysklogd network sshd !netfs !crond)>> Text: <<sysklogd network sshd !netfs !crond>> Name: <<sysklogd>> Name: <<network>> Name: <<sshd>> Name: <<!netfs>> Name: <<!crond>>
Beware: if you want a backslash in a regular expression, you need to write two backslashes in the C source code.