Thread: How to send a signal from one program to another and tell it stop reading

  1. #1
    Registered User
    Join Date
    May 2015
    Posts
    228

    How to send a signal from one program to another and tell it stop reading

    So I have two programs in their entirety.

    DateValidater.c

    Code:
    #include <stdio.h>
    #include <stdlib.h> /*To be able to use the #define constant EXIT_SUCCESS*/
    #include <string.h>
    #include <limits.h>
    #include <errno.h>
    #include <ctype.h>
    #include "Dates.h"
    
    #define BASE 10
    #define NOTVALIDENTRY -1
    #define DELIMITER "/"
    #define FOUR 4
    #define ONEHUNDRED 100
    #define FOURHUNDRED 400
    #define MAXCHARS 80
    #define MAXLINES 256
    
    int getNumOfEntries(char *);
    void getDates(char [MAXLINES][MAXCHARS], int *, int);
    int checkDate(char []);
    const char *parseDate(const char *, int *, const char *);
    int isValidDate(int, int, int);
    void sendAllDates(char [MAXLINES][MAXCHARS], int);
    int isLeapYear(int);
    
    typedef enum {FALSE, TRUE} Bool;
    
    int main(int argc, char *argv[])
    {
        int numOfEntries = 0;
        int numOfLines = 0;
        char dates[MAXLINES][MAXCHARS];
    
        numOfEntries = getNumOfEntries(argv[1]);
    
        if(numOfEntries < 0)
        {
            puts("You have either enter an entry too small, too big or");
            puts("an entry that is not completely numerical. Please try again.");
            return EXIT_FAILURE;
        }
    
        getDates(dates, &numOfLines, numOfEntries);
        sendAllDates(dates, numOfLines);
        return EXIT_SUCCESS;
    }
    
    
    void getDates(char dates[MAXLINES][MAXCHARS], int *numOfLines, int numOfEntries)
    {
        char strDate[MAXCHARS];
    
        int allEntries = FALSE;
    
        if(numOfEntries == 0)
        {
            allEntries = TRUE;
        }
    
        while(fgets(strDate, MAXCHARS, stdin) != NULL)
        {
            if(numOfEntries > 0 || allEntries)
            {
                if(checkDate(strDate))
                {
                    fputs(strDate, stdout);
                    numOfEntries--;
                }
            }
    
            strcpy(dates[*numOfLines], strDate);
            (*numOfLines)++;
        }
    }
    
    
    int checkDate(char strDate[])
    {
        int month = 0, days = 0, year = 0;
        const char *DATEPTR = strDate;
    
        if(strDate[0] == '-')
        {
            DATEPTR++;
        }
    
        DATEPTR = parseDate(DATEPTR, &month, DELIMITER);
        DATEPTR = parseDate(DATEPTR, &days, DELIMITER);
        DATEPTR = parseDate(DATEPTR, &year, NULL);
    
        if(DATEPTR && *DATEPTR == '\0')
        {
            if(isValidDate(month, days, year))
            {
                return TRUE;
            }
        }
    
        return FALSE;
    }
    
    
    const char *parseDate(const char *DATEPTR, int *dateNumber, const char *DATEDELIMITER)
    {
        if(DATEPTR)
        {
            char *endPtr = NULL;
            long temp = 0;
    
    
            errno = 0;
            temp = strtol(DATEPTR, &endPtr, BASE);
    
            if(errno == ERANGE)
            {
                return NULL;
            }
            else if(temp > INT_MAX || temp < INT_MIN )
            {
                return NULL;
            }
            else if(endPtr == DATEPTR)
            {
                return NULL;
            }
    
            *dateNumber = (int)temp;
    
            while(isspace((unsigned char)*endPtr))
            {
                endPtr++;
            }
    
            if(DATEDELIMITER)
            {
                if(*endPtr != *DATEDELIMITER)
                {
                    return NULL;
                }
                endPtr++;
            }
    
            return endPtr;
        }
    
        return NULL;
    }
    
    
    int isValidDate(int month, int days, int year)
    {
        if((month < JAN || month > DEC) || (days < 1 || days > THIRTYONE))
        {
            return FALSE;
        }
    
        if(month == FEB)
        {
            if(isLeapYear(year))
            {
                if(days > TWENTYNINE)
                {
                    return FALSE;
                }
            }
            else
            {
                if(days > TWENTYEIGHT)
                {
                    return FALSE;
                }
            }
        }
        else if(month == APR || month == JUN || month == SEP || month == NOV)
        {
            if(days > THIRTY)
            {
                return FALSE;
            }
        }
        else
        {
            if(days > THIRTYONE)
            {
                return FALSE;
            }
        }
    
        return TRUE;
    }
    
    
    int isLeapYear(int year)
    {
        return (year % FOURHUNDRED == 0) || (year % FOUR == 0 && year % ONEHUNDRED != 0);
    }
    
    
    int getNumOfEntries(char *numOfEntries)
    {
        char *endPtr = NULL;
        long temp = 0;
    
        errno = 0;
        temp = strtol(numOfEntries, &endPtr, BASE);
    
    
        if(errno == ERANGE)
        {
            return NOTVALIDENTRY;
        }
        else if(temp > INT_MAX || temp < INT_MIN )
        {
            return NOTVALIDENTRY;
        }
        else if(endPtr == numOfEntries || *endPtr != '\0')
        {
            return NOTVALIDENTRY;
        }
    
        return (int)temp;
    }
    
    
    void sendAllDates(char dates[MAXLINES][MAXCHARS], int numOfLines)
    {
        int index;
    
        for(index = 0; index < numOfLines; index++)
        {
            fputs(dates[index], stdout);
        }
    }
    DateConverter.c

    Code:
    #include <stdio.h>
    #include <stdlib.h>
    
    #define MAXCHARS 80
    
    const char *ABBREVMONTH[] = {"JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC"};
    
    void convertDateFormat(char []);
    void appendDatesToFile(char []);
    
    
    int main(void)
    {
        char strDate[MAXCHARS];
        convertDateFormat(strDate);
        appendDatesToFile(strDate);
        return EXIT_SUCCESS;
    }
    
    
    void convertDateFormat(char strDate[])
    {
        const char *STRMONTH = NULL;
        int month = 0, days = 0, year = 0;
    
        fputs("List Of all valid dates found.\n\n", stdout);
    
        while(fgets(strDate, MAXCHARS, stdin) != NULL)
        {
            sscanf(strDate, "%d /%d /%d ", &month, &days, &year);
            STRMONTH = ABBREVMONTH[month - 1];
            fprintf(stdout, "%d %s %d\n", days, STRMONTH, year);
        }
    }
    
    void appendDatesToFile(char strDate[])
    {
       fputs("List of all dates in the input file.\n\n", stdout);
    
       while(fgets(strDate, MAXCHARS, stdin) != NULL)
       {
           fputs(strDate, stdout);
       }
    }
    Separate they work fine, but when combined, causes a seg fault(core dump). My professor said that I need to send some kind signal to the second program(DateConverter.c) to tell it to stop reading. I figured that since I'm using fgets to read in the dates, then once I'm done sending all the files from the first program to the second, I can then pipe EOF to the second program to tell it stop reading. My assumption for why this is not working is that before program 2 can finish appending the dates to the file, program 1 might already be sending an EOF to program 2 and causes it to prematurely. What do you guys think?
    Last edited by deathslice; 03-30-2016 at 07:57 AM.

  2. #2
    Registered User
    Join Date
    Jun 2015
    Posts
    1,640
    How can we possibly help you with the code you've posted?
    Your programs aren't communicating at all.
    Where's the pipe?

    Also, what exactly do you mean by "pipe EOF to the second program"?

  3. #3
    Registered User
    Join Date
    Jan 2016
    Posts
    52
    Quote Originally Posted by algorism View Post
    How can we possibly help you with the code you've posted?
    Your programs aren't communicating at all.
    Where's the pipe?

    Also, what exactly do you mean by "pipe EOF to the second program"?
    I would imagine he is doing something like this:

    Code:
    ./DateValidator 03302016 | ./DateConverter
    Hence he needs to "pipe EOF to the second program"

  4. #4
    Registered User
    Join Date
    Jun 2015
    Posts
    1,640
    Quote Originally Posted by jdodle View Post
    I would imagine he is doing something like this:
    Code:
    ./DateValidator 03302016 | ./DateConverter
    Hence he needs to "pipe EOF to the second program"
    Good point. That makes sense.

    In that case, however, there's no need to "pipe EOF to the second program" (whatever that might mean). It happens automatically when the left-hand program exits. Now that I look more closely at the programs it looks like DateConverter's loops are wrong.

  5. #5
    Registered User
    Join Date
    May 2015
    Posts
    228
    Quote Originally Posted by algorism View Post
    Good point. That makes sense.

    In that case, however, there's no need to "pipe EOF to the second program" (whatever that might mean). It happens automatically when the left-hand program exits. Now that I look more closely at the programs it looks like DateConverter's loops are wrong.
    Are you sure? Wouldn't the while loops in the second program hang because there is no indication that you are done reading the file in program1.

    What I mean by sending EOF to the second program(DateConverter.c), was that the only way the while loop ends if fgets reaches EOF. So When fgets in the first program(DateValidater.c) or reaches EOF, the while loop in the second program should also end.

    Also Algorism, sorry for not telling you what Jdodle told you. That was a mistake on my part.
    Last edited by deathslice; 03-30-2016 at 12:11 PM.

  6. #6
    Registered User
    Join Date
    Jun 2015
    Posts
    1,640
    Quote Originally Posted by deathslice View Post
    Are you sure?
    No.

    Quote Originally Posted by deathslice View Post
    Also Algorism, sorry for not telling you what Jdodle told you. That was a mistake on my part.
    I should've been able to figure that out myself.

    I'll take a look at your program if you post Date.h and also show some input and expected output so I can fully understand what's going on.

  7. #7
    Lurking whiteflags's Avatar
    Join Date
    Apr 2006
    Location
    United States
    Posts
    9,612
    Quote Originally Posted by deathslice View Post
    Are you sure?
    This post makes me think that you aren't aware how pipes work. The diagram on this page should help.

    The whole point of piping program A to program B is that program A's output will become program B's input without the use of an explicit file.

    ./DateValidator 4 | ./DateConverter

    You type 4 dates, 1 wrong in the validator program:
    03-30-2016
    04-04-2016
    04-18-2016
    01-APR-2016


    That looks about right. So, what should happen is the program validates those and outputs a new list with all 3 valid, except for the last, lines. Those lines become DateConverter's input. Once input is exhausted then end-of-file will occur.

    Code:
    #define FOUR 4
    #define ONEHUNDRED 100
    #define FOURHUNDRED 400
    What is the point of these? They don't really mean anything more than the numbers themselves. Perhaps you should explain the leap year formula in a comment instead, iff you are paranoid.
    Last edited by whiteflags; 03-30-2016 at 01:07 PM.

  8. #8
    Registered User
    Join Date
    Jun 2015
    Posts
    1,640
    Quote Originally Posted by whiteflags View Post
    Code:
    #define FOUR 4
    #define ONEHUNDRED 100
    #define FOURHUNDRED 400
    What is the point of these? They don't really mean anything more than the numbers themselves. Perhaps you should explain the leap year formula in a comment instead, iff you are paranoid.
    Exactly! It's an example of overdoing a good thing to the point of making it a bad thing!

    To deathslice:

    It's not always wrong to have a bare number in your code. If the number will NEVER change and its meaning is OBVIOUS (when the reader completely understands the problem) then it is not a MAGIC NUMBER and does not need to be named and probably shouldn't be. One rule is that if you can't think of a better name for 100 then ONEHUNDRED, it doesn't need to be named! You apparently have a few more in Date.h. They all make the program HARDER to read, not EASIER, since we have no choice but to find the definitions and ensure that ONEHUNDRED actually is 100. If you just put 100 directly in your code, that wouldn't be necessary.

    If 100 indicates a size, then calling it SIZE actually adds information and allows it to be changed more easily. In your case, 100 simply means 100 and there's no advantage to naming it.


    Also, is it possible that your problem is that you don't know how to enter an end-of-file signal from the command line? It's Ctrl-D in *nix and Ctrl-Z in windows.

    EDIT: Looking at DateConverter.c I notice that it's trying to read up to the end-of-file twice. That might be the problem.
    Last edited by algorism; 03-30-2016 at 01:34 PM.

  9. #9
    Registered User
    Join Date
    May 2015
    Posts
    228
    Normally I would agree but this is a coding style guideline that my professor expects to fellow(The defined constants). Even if it is obvious, he says it has to be a constant. I've tried to persuade him but to no avail. So there is not much I can do about that(believe me when I say that would not do it like this). I'm sending EOF twice because I have two while loops in the dateconverter.c that need to terminate. I should have also mention that I not typing the dates but it is coming from an input file and outputting to another file.

    ex: ./program1 < input.dat 4| ./program2 > output.dat

    dates.h

    Code:
    #ifndef DATES_H_INCLUDED
    #define DATES_H_INCLUDED
    
    
    typedef enum
    {
    JAN = 1,
    FEB,
    MAR,
    APR,
    MAY,
    JUN,
    JUL,
    AUG,
    SEP,
    OCT,
    NOV,
    DEC
    }Month;
    
    
    typedef enum {TWENTYEIGHT = 28, TWENTYNINE, THIRTY, THIRTYONE}MonthLength;
    
    
    #endif /* DATEVALIDATER_H_INCLUDED */
    Hopefully my situation is a lot clearer now
    Last edited by deathslice; 03-30-2016 at 03:22 PM.

  10. #10
    Registered User
    Join Date
    Jun 2015
    Posts
    1,640
    Quote Originally Posted by deathslice View Post
    Normally I would agree but this is a coding style guideline that my professor expects to fellow(The defined constants). Even if it is obvious, he says it has to be a constant. I've tried to persuade him but to no avail.
    As long as you know it's idiotic then it's okay. I understand your quandary.

    Quote Originally Posted by deathslice View Post
    ex: ./program1 < input.dat 4| ./program2 > output.dat
    You need to show some input and expected output, too.

  11. #11
    Registered User
    Join Date
    May 2015
    Posts
    228
    Alright so here is my expected input and output.

    let say we have this input.dat file.

    12/29/1757
    5/22/1775
    12/5/1778
    10/3/1804
    9/7/1815

    and we wanted to find one valid entry.

    So we validate the first date and see that it passes. So we convert it 29 DEC 1757 and append it to the output.dat file. Now since we have found one valid entry, we read in the rest of dates(not to validate them) and append them to the output.dat file.

    The output.dat should look like this now:

    29 DEC 1757

    12/29/1757
    5/22/1775
    12/5/1778
    10/3/1804
    9/7/1815

    I hope everything is now clear.

  12. #12
    Registered User
    Join Date
    Jun 2015
    Posts
    1,640
    If you need to send stuff twice you need some other signal besides an end-of-file signal. How about a blank line? So DateValidator would send a blank line after the first bunch of lines, and the first function in DateConverter would stop looping when it encounters a blank line, i.e., when the first character is '\n'.

    That's it for me on this one as your project baffles me!

  13. #13
    Lurking whiteflags's Avatar
    Join Date
    Apr 2006
    Location
    United States
    Posts
    9,612
    I still think there is a misconception about piping going on here. Pipes are dumb. They send all of the input and all of the output, there is no control beyond that.


    If you really want this

    ./program1 < input.dat 4| ./program2 > output.dat

    To do this...
    input.dat:
    12/29/1757
    5/22/1775
    12/5/1778
    10/3/1804
    9/7/1815


    output.dat:
    29 DEC 1757

    12/29/1757
    5/22/1775
    12/5/1778
    10/3/1804
    9/7/1815


    The programs will need to validate one date, then output the rest, then convert one date, and output the rest. It means programming another variable based on the command line in both programs to do the right thing. Honestly I'm more prepared to believe that you misunderstand something about this project. I'm baffled too.

    Last edited by whiteflags; 03-30-2016 at 05:14 PM.

  14. #14
    Registered User
    Join Date
    May 2015
    Posts
    228
    Well here a couple of excerpts from the assignment specifications:

    output file will be the result of appending the input file (dates.dat), which is accessed by the first program, with the result output file (output.dat), generated by the second program.

    Accept input for the first program via the command-line arguments
    . This validated input will then be piped out to the second program. The second program will accept these validated dates in the month/day/year format and convert each of them to the day, abbreviated month & year format. These converted results will be redirected to the output file (output.dat), followed by a copy of the original (dates.dat) data.

  15. #15
    Lurking whiteflags's Avatar
    Join Date
    Apr 2006
    Location
    United States
    Posts
    9,612
    It sounds like the second program should do this:

    29 Dec. 1757
    22 May 1775
    5 Dec. 1778
    3 Oct. 1804
    7 Sep. 1815

    12/29/1757
    5/22/1775
    12/5/1778
    10/3/1804
    9/7/1815

    To do that, it's best if you store the input in a character matrix in the second program, too, and just output it toward the end of the program.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. reading wifi signal level with C
    By occam25 in forum Linux Programming
    Replies: 2
    Last Post: 07-19-2010, 03:12 PM
  2. reading wifi signal level with C
    By occam25 in forum Networking/Device Communication
    Replies: 4
    Last Post: 07-19-2010, 04:58 AM
  3. send signal every time input comes in on stdin
    By crs_zxf in forum C Programming
    Replies: 0
    Last Post: 11-04-2009, 07:38 AM
  4. Child process can't send signal to itself.
    By arunj in forum C Programming
    Replies: 2
    Last Post: 03-23-2008, 11:19 AM
  5. send a signal
    By l2u in forum Windows Programming
    Replies: 1
    Last Post: 08-03-2006, 11:19 AM