Searching for a string, have it return multiple results

As the title suggess, i'm trying to search for a string, and have it return all results matching that string. Here's my code so far:

int search_contact()
{

  if (chdir(getenv("HOME")) == 0)
  {

        FILE *fp;
        fp=fopen(".igterm/hosts4.txt", "a+"); //hosts2.txt
        if ( NULL == fp )
        {
                printf("couldn't open <%s>\n");
                return 1;
        }

        attron(A_BOLD | COLOR_PAIR(2));
        mvaddstr(6,0, "Search      : ");
        attroff(A_BOLD | COLOR_PAIR(2));
        char needle[200];

        scanw("%s",needle);

        char haystack[200];

        int iteration=0;
        char *ptr2needle = NULL;

        while( fgets( haystack, sizeof(haystack),fp) !=NULL)
        {

                header();

                haystack[strlen(haystack)-1] = '\0'; // get rid of the \n

                ptr2needle = strstr(haystack, needle);
                if (ptr2needle)
                {
                        printf("\e[9;01H\e[1;34mSearching for \e[0;37m[\e[1;37m%s\e[0;37m]\e[1;34m... \e[1;34mfound... \e[11;04H\e[0;37m[\e[1;37m%s\e[0;37m]", needle, haystack);
                        break;
                }
        }
        fclose(fp);
        askyesno();
 }
}

So, my question is, how do I make the code return multiple results?

header() and askyesno() aren't important enough to elaborate on.

Any and all help is greatly appreciated.

Hi @ignatius,

your printf() is a bit obscure. For testing, simplify the code (no break):

if (strstr(haystack, needle))
    puts(haystack);

Why do you open your file in a+ mode instead of r?

I've applied that code, and it breaks the return of the strings. In fact, it will only return 1 different string. If I use the right search criteria.

The fp=fopen(".igterm/hosts4.txt", "a+"); is there because, in other parts of the code, it adds strings (1 at a time) to that file. I guess I could change it to r+...

Thanks.

why should removing the break break the return of the strings? break interrupts the while loop, so in that case you always get at most one string.

No, no. I didn't mean that break, I meant that it literally broke the return of the strings.

Ok. I got it working, but I don't see how it's any better than how i'm doing things. I actually need those escape sequences in the code for it to display right.

Thanks.

post the updated code pls.

I actually reverted to how I had it before.

Thanks.

did you remove the redundant variables (below) , and that break statement ?

int iteration=0;
char *ptr2needle = NULL;

if you are using curses (ncurses) why not use it to output results rather than that hideous printf ?

The int iteration=0 is redundant, but char *ptr2needle = NULL; isn't, as illustrated below.

ptr2needle = strstr(haystack, needle);
                if (ptr2needle)

When I comment them out, the code refuses to compile.

Thanks.

EDIT: I commented out eveyrthing that has to do with ptr2needle. It compiles, but I cannot get any string results from a search.

If you don't use ptr2needle later on, you don't need it.

char *ptr2needle = NULL;
ptr2needle = strstr(haystack, needle);
// or
// char *ptr2needle = strstr(haystack, needle);
if (ptr2needle) ...
// no further use of ptr2needlde from here

works just liike

if (strstr(haystack, needle)) ...

ptr2needle points to the beginning of the substring found, if any. So it includes the rest of the haystack, too. It's more meaningful to print the complete containing string.

char needle[] = "foo";
char haystack[] = "the foos have bars";
char *ptr2needle = strstr(haystack, needle);
if (ptr2needle) {
    puts(ptr2needle);  // prints "foos have bars"
    puts(haystack);
}
else
    puts("nothing found");

I noticed that you used a few arrays. Is there any way to encompass everything that's in hosts4.txt as an array, and then access the strings within the array?

an array only makes sense if you want to store the data for further processing. Otherwise, you just read the file and process the lines without storing, but printing.

In C, it's quite cumbersome to dynamically read lines from a file into an array, i.e. if the number of lines is unknown beforehand. An array in C ist not a real data structure, it's just a pointer to a memory area that has to be allocated (e.g. via malloc() or realloc()) before it can be filled with data. And has to be deallocated at the end of the program via free().

It's easier then to set a constant max size for both the number of lines and their lengths. That of course has the disadvantage that lines may not be read correctly, if that numbers are too small:

#define MAXLINES 1000
#define MAXCHARS 255  // per line

int main()
{
    FILE *fp = fopen("foo.txt", "r");
    char array[MAXLINES][MAXCHARS];
    int ln, i;

    for (ln = 0; ln < MAXLINES && fgets(array[ln], MAXCHARS, fp); ln++)
        array[ln][strlen(array[ln])-1] = 0;  // strip NL
    for (i = 0; i < ln; i++)
        printf("%d: %s\n", i+1, array[i]);

    fclose(fp);
}

Or you switch e.g. to C++, where exists a) the template data structure vector<type>, which can be dynamically increased (but under the hood it uses *alloc(), too) and b) a string type.

Thank you for the code. I think I can wrap my head around it. But, what about a "searching" feature?

I have some, new updated code (the do while loop within the fgets loop):

int search_contact()
{

  if (chdir(getenv("HOME")) == 0)
  {

        FILE *fp;
        fp=fopen(".igterm/hosts4.txt", "r+"); //hosts2.txt
        if ( NULL == fp )
        {
                printf("couldn't open <%s>\n");
                return 1;
        }

        attron(A_BOLD | COLOR_PAIR(2));
        mvaddstr(6,0, "Search      : ");
        attroff(A_BOLD | COLOR_PAIR(2));



        scanw("%s",needle);

        char haystack[200];

        int iteration=0;
        char *ptr2needle = NULL;


 while( fgets( haystack, sizeof(haystack),fp) !=NULL)
        {

                header();
                haystack[strlen(haystack)-1] = '\0'; // get rid of the \n

        do {

                haystack = ptr2needle + 1; // start searching from here
                ptr2needle = strstr(haystack, needle);

        } while (ptr2needle);


                if (ptr2needle)
                {
                        printf("\e[9;01H\e[1;34mSearching for \e[0;37m[\e[1;37m%s\e[0;37m]\e[1;34m... \e[1;34mfound... \e[11;04H\e[0;37m[\e[1;37m%s\e[0;37m]", needle, haystack);
                        break;
                }

        }

        fclose(fp);
        askyesno();
 }
}

Problem is, I can't get it to compile.

Thanks.

show the compilation line (gcc ..... )
and all the output it produces (copy/paste)

am pretty sure you have been reminded more than once the 'it doesn't work' is completely useless wrt to be given corrective assistance- but you seem unable to pay due attention to advice/requests .

Ok. I will contribute some logs, but first how do I do that? When I try to compile it, and do a make the code that's being compiled, quickly disappears and cannot be retrieved.
I have tried make >> output.log but that doesn't seem to work. And I cannot facilitate the scrollback buffer. Any advice?

Redirect stderr in addition to stdout.
Standard shells:

make > output.log 2>&1

Use tee to dup the output to terminal screen AND file:

make 2>&1 | tee output.log

Some shells require

make >& output.log
make |& tee output.log

Thank you, @MadeInGermany

Here's some new, updated code:

int search_contact()
{
  if (chdir(getenv("HOME")) == 0)
  {
        FILE *fp;
        fp=fopen(".igterm/hosts4.txt", "r+"); //hosts2.txt
        if ( NULL == fp )
        {
                printf("couldn't open <%s>\n");
                return 1;
        }
        attron(A_BOLD | COLOR_PAIR(2));
        mvaddstr(6,0, "Search      : ");
        attroff(A_BOLD | COLOR_PAIR(2));
        char needle[200];
        scanw("%s",needle);
        char haystack[200];
        int iteration=0;
        char *ptr2needle = NULL;
        while( fgets( haystack, sizeof(haystack),fp) !=NULL)
        {
                header();
        do {
                haystack[strlen(haystack)-1] = '\0'; // get rid of th /////////

                haystack = ptr2needle + 1; // start searching from here
                ptr2needle = strstr(haystack, needle);

        } while (ptr2needle);

                ptr2needle = strstr(haystack, needle);
                // if ( ptr2needle == 0 ) // try that in place of the line below and see the difference in behaviour

                if (ptr2needle)
                {
                        printf("\e[9;01H\e[1;34mSearching for \e[0;37m[\e[1;37m%s\e[0;37m]\e[1;34m... \e[1;34mfound... \e[11;04H\e[0;37m[\e[1;37m%s\e[0;37m]", needle, haystack);
                        break;
                }
        }
        fclose(fp);
        askyesno();
 }
}

And here's output.log:

https://anonpaste.io/share/outputlog-b4adb744b4

It looks like

networking/telnet.c:1036:26: error: assignment to expression with array type
1036 |                 haystack = ptr2needle + 1; // start searching from here

Is the culprit.

So, the question is, why doesn't it work? It seems to be declared correctly.