0

I have a .csv file that I want to parse as a database with rows and column numbers The solution I found uses strtok() (which might be not the perfect solution but I am happy to hear other suggestions). To my understanding strtok() progressively moves the pointer within the file. If you want to parse the file again, for example to access another cell, I have to close and reopen the file to set the pointer back to the beginning of the file. Is it possible to set the pointer at the beginning of the file (without having to close and reopen it)?

/* database.c */
#include <stdlib.h>
#include "main.h"

#define BUFFLEN 1024

void print_entire_file(FILE *fp) {
    char buffer[BUFFLEN];
    int row = 0;
    int column = 0;

    while (fgets(buffer, BUFFLEN, fp)) {
        column = 0;
        row++;

        char *value = strtok(buffer, &csv_separator);

        while (value) {
            if (column == 0) {
                printf("\t");
            }

            if (column == 1) {
                printf("\t");
            }

            if (column == 2) {
                printf("\t");
            }

            printf("%s", value);
            value = strtok(NULL, &csv_separator);
            column++;
        }
    }
}

struct s_df_dim get_file_height(FILE *fp) {
    struct s_df_dim df_dim;
  
    char buffer[BUFFLEN];
    int row = 0;
    int column = 0;
    while (fgets(buffer, BUFFLEN, fp)) {
        column = 0;
        row++;
        if (row == 1)
            continue;
        char *value = strtok(buffer, &csv_separator);
        while (value) {
            value = strtok(NULL, &csv_separator);
            column++;
        }
    }
    df_dim.nrow = row;
    df_dim.ncol = column;

    fclose(fp);
    return df_dim;
}

void print_cell(FILE *fp, int colid, int rowid) {
    char buffer[BUFFLEN];
    int row = 0;
    int column = 0;

    while (fgets(buffer, BUFFLEN, fp)) {
        column = 0;
        row++;

        char *value = strtok(buffer, &csv_separator);

        while (value) {
            if ((row == rowid) && (column == colid)) {
              printf("%s", value);
            }
            value = strtok(NULL, &csv_separator);
            column++;
        }
    }
}
/* main.h */

char csv_separator = ';'; // choose between ',' and ';'

struct s_df_dim {
    int nrow;
    int ncol;
};
/* functions.h */

#include <stdlib.h>
#include "main.h"

#define BUFFLEN 1024

void print_entire_file(FILE *fp) {
    char buffer[BUFFLEN];
    int row = 0;
    int column = 0;

    while (fgets(buffer, BUFFLEN, fp)) {
        column = 0;
        row++;

        char *value = strtok(buffer, &csv_separator);

        while (value) {
            if (column == 0) {
                printf("\t");
            }

            if (column == 1) {
                printf("\t");
            }

            if (column == 2) {
                printf("\t");
            }

            printf("%s", value);
            value = strtok(NULL, &csv_separator);
            column++;
        }
    }
}

struct s_df_dim get_file_height(FILE *fp) {

    struct s_df_dim df_dim;
  
    char buffer[BUFFLEN];
    int row = 0;
    int column = 0;
    while (fgets(buffer, BUFFLEN, fp)) {
        column = 0;
        row++;
        if (row == 1)
            continue;
        char *value = strtok(buffer, &csv_separator);
        while (value) {
            value = strtok(NULL, &csv_separator);
            column++;
        }
    }
    df_dim.nrow = row;
    df_dim.ncol = column;

    fclose(fp);
    return df_dim;
}

void print_cell(FILE *fp, int colid, int rowid) {
    char buffer[BUFFLEN];
    int row = 0;
    int column = 0;

    while (fgets(buffer, BUFFLEN, fp)) {
        column = 0;
        row++;

        char *value = strtok(buffer, &csv_separator);

        while (value) {
            if ((row == rowid) && (column == colid)) {
              printf("%s", value);
            }
            value = strtok(NULL, &csv_separator);
            column++;
        }
    }
}
#makefile

CC = gcc 
CFLAGS = -g -Wall

BINC=database

allc: $(BINC) 

$(BINC): $(BINC).c *.h
    $(CC) $(CFLAGS) $< -o $@

clean:
    $(RM) -rf $(BINC) *.dSYM

runc: allc
    ./$(BINC)

and file.csv:

asdf;8234;a
sdfasg;3479;z
rasdb;10984;d
adwekrj;23460;c
chqrlie
  • 131,814
  • 10
  • 121
  • 189
ecjb
  • 5,169
  • 12
  • 43
  • 79
  • 1
    `strtok()` operates on strings, not on files. It has no interaction with file pointers, in any plausible sense of that term. – John Bollinger Feb 16 '23 at 21:03
  • That's `ssv` ... (ba-dump dump) – jxh Feb 16 '23 at 21:05
  • 2
    However, `strtok()` aside, yes, provided that a file is seekable, you can return the logical file position to the beginning of the file. The `rewind()` function is specific to this purpose, and it can also be achieved easily with the more general `fseek()` function. Or if you prepare for it via a call to `fgetpos()` immediately after opening the file, then you can return to the beginning via `fsetpos()` (assuming, again, a seekable file). – John Bollinger Feb 16 '23 at 21:06
  • 1
    If you want to parse the **string** again with different delimiters, you have to use another copy, because `strtok` changes the string it parses. – Weather Vane Feb 16 '23 at 21:09
  • Quite so, @WeatherVane. I considered whether the OP might be saying "file" where they really meant "string", but everything seems consistent with them really meaning "file", except only supposing that `strtok()` would be applicable. – John Bollinger Feb 16 '23 at 21:15
  • 4
    `strtok(buffer, &csv_separator);` Not right... `csv_separator` is a single character. The 2nd parameter to the function must be a string. – Fe2O3 Feb 16 '23 at 21:16
  • @JohnBollinger yes, perhaps the `fseek` is a brutal way needed to obtain another copy. – Weather Vane Feb 16 '23 at 21:18
  • Thanks a lot all for your comments: I used fseek() which solved the problem – ecjb Feb 16 '23 at 21:42

0 Answers0