Member Avatar for ragnacrap

I'm doing a C program where the user is asked to enter an employee number. I know how to make the program ask again if the number doesn't exist. However, I don't know how to have the program check it from a *.txt file like this.

EMP10-1234,smith_john,2
EMP08-0321,kent_brenda,1
EMP10-0501,delcambre_kory,3
EMP11-0112,pregeant_mark,3

Upon entering a number, the following would be presented:

Employee No.: 10-1234
Smith, John
Manager

Manager is printed because of the number 2.

This is my code so far.

    #include<stdio.h>
    #include <stdlib.h>
    #include<conio.h>
    #include<ctype.h>
    #include<string.h>

    char ch
    FILE *f;

    int main(){
        clrscr();
        CreateTimeFile();
        ReadEmpFile();
        getch();
    }

    CreateTimeFile(){
        f = fopen("time.txt","w");
        fclose(f);
    }

    ReadEmpFile(){
        f = fopen("Employee.txt","r");
        while( ( ch = fgetc(f) ) != EOF )
            printf("%c",ch);
            SplitLines
        fclose(f);
    }

    SplitLines(){

    }


    /*
    Create time.txt
    Read Employee.txt
    Split lines (4)
    Split each lines (EmpNo, EmpName, EmpPos)
    Do Program Requirement (Ask Employee Number)
    Display Program Requirements
    Get TimeIn and TimeOut Each Day
    Append to time.txt all the time-in and time-out
    Convert TimeIn and TimeOut Each Day
    Compute for total time and Salary
    Append Salary to time.txt
    Display Program Requirement
    */

What I don't know is how to "split the lines". Could anybody tell me? The bottom lines are the hints provdied by my teacher.

It would be a lot easier if the whole line was read all at one time instead of a character at a time. fgets() will read an entire line into a buffer, then you can extract the individual words from that buffer. strtok() is handy for doing that. Something like below. But your problem is a little more complicated then the code below because you will have to compare the employee numbers in order to find the row you want to print. To do that you will have to save the split lines in an array of strings so that the comparison can be done with the employee ID.

char line[255];
FILE* in = fopen(...);
while( fgets(in,line,sizeof(line) )
{
    SplitLine(line);
}

void SplitLine(char* line)
{
    char* ptr = strtok(line," ");
    while(ptr != NULL)
    {
        printf("%s\n",ptr);
        ptr = strtok(NULL," ");
    }
}
Member Avatar for ragnacrap

Sounds like an idea.

Hmm... about that ellipsis, what am I supposed to put there? The filename and… ( ,"r")?

Member Avatar for ragnacrap

And could I see what the results would be? Something like a 'simulation' of sorts.

about that ellipsis, what am I supposed to put there? The filename and… ( ,"r")?

The same thing you posted, I was just too lazy to retype it :)

And could I see what the results would be?

Yes, just code it up and test it on your computer.

Member Avatar for ragnacrap

Okay. Now how do I check if a certain employee number exists?

Part of my code to do that is:

AskEmpNumber(){
    printf("Enter employee number: ");
    scanf("%c",&empno);
}

What I'd like to know is the checking in the file part.

Also, I'm getting a "Type mismatch in parameter 'n' in call to fgets in function ReadEmpFile" and a "Type mismatch in redeclaration of 'SplitLine'" with the code you provided.

-----------------
Congratulations! You're no longer a DaniWeb newbie.<br /> <br />
Your DaniWeb account has just been upgraded from newbie status and now you have the ability to take advantage of everything the community has to offer.<br /> <br />
You can now enjoy an advertisement-free DaniWeb by ticking the checkbox to Disable Ads in your profile. You will no longer have to fill out the human verification check when you post. You can also now send unlimited private messages, participate in live chat, contribute new code snippets, and tag articles with never-before-used tags.

did you google fgets() to find out what the parameters are? If you did then you would find the answer (correction) to the error.

SplitLine() needs to save the strings in an array instead of just printing them to the screen. Then after SplitLine() returns the program can compare the strings to see if the row just read has the ID you want. It's just a simple strcmp() call.

Member Avatar for ragnacrap

I see the parameters.

char *fgets(char *str, int n, FILE *stream)

But you gave me this:

fgets(in,line,sizeof(line))

in is a FILE pointer, line is a character array, and sizeof(line) is apparently supposed to be a number, probably an int. Therefore, (I think) you gave me incorrect coding.

SplitLine() needs to save the strings in an array instead of just printing them to the screen. Then after SplitLine() returns the program can compare the strings to see if the row just read has the ID you want. It's just a simple strcmp() call.

I'm quite confused as to the strtok operates. I think I'm changing the code to:

void SplitLine(char* line)
{
/* get the first token */
char* ptr = strtok(line,",");
/* walk through other tokens */
while(ptr != NULL)
{
printf("%s\n",ptr);
ptr = strtok(NULL,",");
}
}

Does this take into account the fact that I have four lines in the Employee.txt file?

But you gave me this:

Then correct it in your program.

Does this take into account the fact that I have four lines in the Employee.txt file?

No -- strtok() only works on one line. Notice that SplitLine() is called repeatedly for each line in the file.

Member Avatar for ragnacrap

I'm confused as to how to do this. Giving me a code I can't work with... much. I mean, I did show you the contents of the txt file I wante to work with as well.

It's really not all that complex. You already posted most of code, just expand it a little. Add another parameter to SplitLine() that contains the ID that it should look for.

For each line read in the file
    call SplitLine() to split the line into words
    compare the ID from the line with the ID you want
    if the two are the same then print the contents of the line
end of loop 
Member Avatar for ragnacrap

Judging by the coding, I will have to have the program split the line after inputting the employee number, right?

Well, yes. You can't compare something before you know what to compare it with.

Member Avatar for ragnacrap

Will this code work?

#include<stdio.h>
#include <stdlib.h>
#include<conio.h>
#include<ctype.h>
#include<string.h>

char ch, no, line[255];
char empno[10];
FILE *f;
FILE* in;

int main(){
    clrscr();
    CreateTimeFile();
    AskEmpNumber();
    getch();
}

CreateTimeFile(){
    f = fopen("time.txt","w");
    fclose(f);
}

AskEmpNumber(){
    printf("Enter employee number: ");
    scanf("%c",&no);
    strcpy(empno,  "EMP");
    empno = strcat(empno,no);
    ReadEmpFile();
}

ReadEmpFile(){
    in = fopen("Employee.txt","r");
    while( fgets(in,line,sizeof(line) )){
        SplitLine();
        if(strstr(line, empno) != NULL) {
            puts(line);
        }
    }
    fclose(f);
}

void SplitLine(char* line){
    char* ptr = strtok(line," ");

    while(ptr != NULL){
        printf("%s\n",ptr);
        ptr = strtok(NULL," ");
    }
}

So far, it's supposed to print the line like you said. but eventually I want to figure out how to make it print this.

Employee No.: 10-1234
Smith, John
Manager

"Manager" would be printed upon reading the "2" in this line after I input "10-1234".

EMP10-1234,smith_john,2

Will this code work?

No. That could easily be determined by trying to compile it. Let's remove the complication of functions for a moment and consider how to get the result you want. There are two issues:

  1. "EMP" needs to be eliminated from the employee number result.
  2. A numeric identifier for the employee type needs to be converted to a display name.

#1 is simple enough if you're sure that the token matches the pattern correctly, just shift the pointer forward by 3 characters. #2 is slightly more complex, but the core concept is to use the numeric identifier as either an index or key into a collection of display names.

Here's an example. Robust error handling has been omitted for brevity:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

static const char *employee_type[] = {
    "", "Owner", "Manager", "Grunt"
};

int main(void)
{
    char empno[BUFSIZ];

    fputs("Employee #: ", stdout);
    fflush(stdout);

    if (fgets(empno, sizeof empno, stdin) != NULL) {
        FILE *in = fopen("test.txt", "r");

        empno[strcspn(empno, "\n")] = '\0'; /* Trim the newline */

        if (in == NULL) {
            perror("Error opening file");
            return EXIT_FAILURE;
        }
        else {
            char line[BUFSIZ];

            while (fgets(line, sizeof line, in) != NULL) {
                line[strcspn(line, "\n")] = '\0'; /* Trim the newline */

                if (strstr(line, empno) != NULL) {
                    printf("Employee #: %s\n", strtok(line, ",") + 3);
                    puts(strtok(NULL, ","));
                    puts(employee_type[atoi(strtok(NULL, ","))]);
                    break;
                }
            }
        }
    }

    return EXIT_SUCCESS;
}
Member Avatar for ragnacrap

By the way, can you find out a way to make the program print…

Employee No.: 10-1234
Smith, John
Manager

from reading the line…

EMP10-1234,smith_john,2

By the way, can you find out a way to make the program print…

Did you not read my post?

Member Avatar for ragnacrap

Oops. Made the reply before your post appeared.

Member Avatar for ragnacrap

So, do you know how to shift a pointer by any number of characters?

Okay, your program works. Just need to figure out how to do the name part. And how to turn the results into strings that I can print again later in the program.

Member Avatar for ragnacrap

So, how do I make it so that when the program reads:

EMP10-1234,smith_john,2

It will produce:

Employee No.: 10-1234
Smith, John
Manager

Member Avatar for ragnacrap

Emphasis on second line, btw. Sorry for thread-bumping.

It's fairly straightforward. You already know how to split a line, so it should be a simple matter of splitting using an underscore as the delimiter, making the first letter of each token upper case, then outputing the tokens with a comma in between.

Member Avatar for ragnacrap

I can see how one can make the first letter of each token uppercase from a string, but not when it's being printed from a text file being read.

puts() makes new lines each time, and I'm not sure where else I can properly apply the strtok aside from that and printf().

When I tried doing this:

if (strstr(line, empno) != NULL) {
    printf("Employee #: %s\n", strtok(line, ",") + 3);
    printf ("%s %s\n", strtok(NULL, "_"), strtok(NULL, ","));
    puts(employee_type[atoi(strtok(NULL, ","))]);
    break;

I get this:

Employee #: 10-1234
2 smith_john

Adding: puts(strtok(NULL, "_")); to the original code (not the one above, but the one without the printf ("%s %s\n", strtok(NULL, "_"), strtok(NULL, ",")); and with puts(strtok(NULL, ","));) changes nothing and still results in a "smith_john" being printed.

What am I doing wrong?

I can see how one can make the first letter of each token uppercase from a string, but not when it's being printed from a text file being read.

You're reading from the file into a string.

I'm not sure where else I can properly apply the strtok aside from that and printf().

strtok cannot be used recursively. You can perform some magic by changing the delimiter briefly, but another option is to separate the name a different way. Here's an example (without error handling) using strchr.

#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

static const char *employee_type[] = {
    "", "Owner", "Manager", "Grunt"
};

char *format_name(const char *name, char *buf)
{
    const char *sep = strchr(name, '_');

    buf[0] = '\0';
    strncat(buf, name, sep - name);
    buf[0] = toupper(buf[0]);
    strcat(buf, ", ");
    strcat(buf, sep + 1);
    buf[strlen(buf) - strlen(sep + 1)] = toupper(sep[1]);

    return buf;
}

int main(void)
{
    char empno[BUFSIZ];

    fputs("Employee #: ", stdout);
    fflush(stdout);

    if (fgets(empno, sizeof empno, stdin) != NULL) {
        FILE *in = fopen("test.txt", "r");

        empno[strcspn(empno, "\n")] = '\0'; /* Trim the newline */

        if (in == NULL) {
            perror("Error opening file");
            return EXIT_FAILURE;
        }
        else {
            char line[BUFSIZ], name[BUFSIZ];

            while (fgets(line, sizeof line, in) != NULL) {
                line[strcspn(line, "\n")] = '\0'; /* Trim the newline */

                if (strstr(line, empno) != NULL) {
                    printf("Employee #: %s\n", strtok(line, ",") + 3);
                    puts(format_name(strtok(NULL, ","), name));
                    puts(employee_type[atoi(strtok(NULL, ","))]);
                    break;
                }
            }
        }
    }

    return EXIT_SUCCESS;
}

And here's the tricky way to do it strictly using strtok:

#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

static const char *employee_type[] = {
    "", "Owner", "Manager", "Grunt"
};

int main(void)
{
    char empno[BUFSIZ];

    fputs("Employee #: ", stdout);
    fflush(stdout);

    if (fgets(empno, sizeof empno, stdin) != NULL) {
        FILE *in = fopen("test.txt", "r");

        empno[strcspn(empno, "\n")] = '\0'; /* Trim the newline */

        if (in == NULL) {
            perror("Error opening file");
            return EXIT_FAILURE;
        }
        else {
            char line[BUFSIZ], *tok;

            while (fgets(line, sizeof line, in) != NULL) {
                line[strcspn(line, "\n")] = '\0'; /* Trim the newline */

                if (strstr(line, empno) != NULL) {
                    printf("Employee #: %s\n", strtok(line, ",") + 3);

                    tok = strtok(NULL, "_");
                    *tok = toupper(*tok);
                    fputs(tok, stdout);

                    tok = strtok(NULL, ",");
                    *tok = toupper(*tok);
                    printf(", %s\n", tok);

                    puts(employee_type[atoi(strtok(NULL, ","))]);
                    break;
                }
            }
        }
    }

    return EXIT_SUCCESS;
}
Member Avatar for ragnacrap

Thanks. It works. However, is there a way to save those printed lines so I can print them again later?

Member Avatar for ragnacrap

Also, do you know how to make a program that calculates your work hours. I tried this code, but it's going all wrong.

#include<stdio.h>
#include<stdlib.h>
#include<conio.h>
#include<ctype.h>
#include<string.h>
#include<time.h>


char* timein[5], timeout[5], p;
int totaltime, ticktock, hour, minute, rate;

FILE* f;


int main(){
    clrscr();
    CreateTimeFile();
    GetTimes();
    DisplayFinalInfo();
    getch();
}

CreateTimeFile(){
    f = fopen("time.txt","w");
    fclose(f);
}

GetTimes(){
    f = fopen("time.txt","a");
    printf("\nEnter time in 24-hour format. \nWARNING: An error at any point in the input will result in needing to repeat the process.\nEnter time-in for Monday: ");
    scanf("%c",&timein);
    ValidateTimeIn();
    printf("\nEnter time-out for Monday: ");
    scanf("%c",&timeout);
    ValidateTimeOut();
    AppendTimes();

    printf("\nEnter time-in for Tuesday: ");
    scanf("%c",&timein);
    ValidateTimeIn();
    printf("\nEnter time-out for Tuesday: ");
    scanf("%c",&timeout);
    ValidateTimeOut();
    AppendTimes();

    printf("\nEnter time-in for Wednesday: ");
    scanf("%c",&timein);
    ValidateTimeIn();
    printf("\nEnter time-out for Wednesday: ");
    scanf("%c",&timeout);
    ValidateTimeOut();
    AppendTimes();

    printf("\nEnter time-in for Thursday: ");
    scanf("%c",&timein);
    ValidateTimeIn();
    printf("\nEnter time-out for Thursday: ");
    scanf("%c",&timeout);
    ValidateTimeOut();
    AppendTimes();

    printf("\nEnter time-in for Friday: ");
    scanf("%c",&timein);
    ValidateTimeIn();
    printf("\nEnter time-out for Friday: ");
    scanf("%c",&timeout);
    ValidateTimeOut();
    AppendTimes();

    fclose(f);
/*  ComputeSalary();    */
/*  DisplayTime();      */
}

ValidateTimeIn(){
    if (timein[0] > 2 || timein[3] > 5){
        printf("Input Error! Restarting input process.\n");
        GetTimes();
    }
    if (timein[0] = 2 && timein[1] > 3){
        printf("Input Error! Restarting input process.\n");
        GetTimes();
        }
}

ValidateTimeOut(){
    if (timeout[0] > 2 || timeout[3] > 5){
        printf("Input Error! Restarting input process.\n");
        GetTimes();
    }
    if (timeout[0] = 2 && timeout[1] > 3){
        printf("Input Error! Restarting input process.\n");
        GetTimes();
        }
}

AppendTimes(){
    fprintf(f,"%s %s|",timein, timeout);
    AddToTotalTime();
}

AddToTotalTime(){
    /*-convert timein and timeout to time-*/
    p = timeout;
    atoi(p) = hour;
    while (*p){
        if (*p++ == ':')
            atoi(p) = minute;
    }
    timeout = (hour * 60) + minute;

    p = timein;
    atoi(p) = hour;
    while (*p){
        if (*p++ == ':')
            atoi(p) = minute;
    }
    timein = (hour * 60) + minute;

    ticktock = timeout - timein;
    totaltime += ticktock;
}

DisplayFinalInfo(){

    hour = totaltime / 60;
    minute = totaltime % 60;
    printf("Total Work Time: %i Hours and %i Minutes\n", hour, minute);
}

I know I'm doing plenty of mistakes here. I just on't know what exactly.

P.S. This is just a portion I need to add to the employee program. In there, whatever is the number at the end of the line, it not only determines the job title, it also determines the work rate, which I would multiply to the total hours to get an employee's salary.

is there a way to save those printed lines so I can print them again later?

Yes, of course. Store them in an array or other collection rather than print them directly. Since you don't necessarily know the size of the file, I'd suggest a linked list instead of an array. They're easier to grow dynamically.

Member Avatar for ragnacrap

Linked list?

Member Avatar for ragnacrap

How exactly do I use the linked lists to turn two characters on either 'side' of the colon into integers?

And what about the rest of my code? Please answer in this thread.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.