LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Programming (https://www.linuxquestions.org/questions/programming-9/)
-   -   programming problem....C programming..not sure whether this can be done or not (https://www.linuxquestions.org/questions/programming-9/programming-problem-c-programming-not-sure-whether-this-can-be-done-or-not-912639/)

nikhidet1 11-09-2011 09:04 AM

programming problem....C programming..not sure whether this can be done or not
 
Hey all,
i am in the middle of having trouble now....last time i did program php and i realized that there is some function that really useful for reading the content of text file....for example file_get_contents(...).
so using this idea i want to create a c program that read the text file line by line.I noticed that there are some functions can do that for example fgets(...),fscanf(..).but when i tried them they dont give me something that i wish to do..what i want to do is that my c program read the text file line by line and give me the array output of string.
For example mytext.txt have something like below:
A:Berlin
B:Munich
C:Sydney
D:London
so i would have ArrayString[0] is equal to A:Berlin.
can i do this with c programming..please help me if u guys have any ideas

NevemTeve 11-09-2011 09:13 AM

If you use GNU/linux, start with function getline: it allocates a buffer bug enough to store the loaded line.

Sergei Steshenko 11-09-2011 09:33 AM

Quote:

Originally Posted by nikhidet1 (Post 4519734)
Hey all,
i am in the middle of having trouble now....last time i did program php and i realized that there is some function that really useful for reading the content of text file....for example file_get_contents(...).
so using this idea i want to create a c program that read the text file line by line.I noticed that there are some functions can do that for example fgets(...),fscanf(..).but when i tried them they dont give me something that i wish to do..what i want to do is that my c program read the text file line by line and give me the array output of string.
For example mytext.txt have something like below:
A:Berlin
B:Munich
C:Sydney
D:London
so i would have ArrayString[0] is equal to A:Berlin.
can i do this with c programming..please help me if u guys have any ideas

In addition to what's been already said - start from here: http://www.and.org/vstr/comparison .

nikhidet1 11-10-2011 02:30 AM

thanks for the information...will take a look at it today...will be back with questions later...

nikhidet1 11-10-2011 04:19 AM

hey i guys i have tried to used getline and i can say i quite understand the document and i learnt it by hard.but when i tried it still doesn't give me the result that i want...for example this is my code, i got it from an example
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main()
{
FILE *fp;
char *line= NULL;
size_t len = 0;
ssize_t read;

fp = fopen("mytext.txt", "r");
if (fp == NULL)
exit(EXIT_FAILURE);

while ((read = getline(&line, &len, fp)) != -1) {
// printf("Retrieved line of length %zu :\n", read);
//printf("%s", line);
printf("%c",line[0]);
}
free(line);
return 0;
}
And my text.file looks like this:
A:Munich
B:Berlin
C:London
D:New York
unfortunately when i compiled the c codes above, the output is like this
A
B
C
D
what i want is to have the entire line
for example
line[0] would give me A:Munich
line[1] would give me B:Berlin
till
line[3] D:New York
can i do that?i keep on trying from last night and i couldn't get it..please help me

NevemTeve 11-10-2011 04:27 AM

Code:

while (line= NULL, (read = getline(&line, &len, fp)) != -1) {
    len= strlen (line);
    if (len>0 && line[len-1]=='\n') line[--len]= '\0';
    printf ("Retrieved line '%s' (len=%d)\n", line, (int)len);
    free (line);
}


Cedrik 11-10-2011 04:57 AM

Quote:

Originally Posted by nikhidet1 (Post 4520427)
what i want is to have the entire line
for example
line[0] would give me A:Munich
...

line[0] is the first char of the line string
If you want array of strings, it's like :
char lines[10][128];
(declare an array of 10 strings with max 127 chars + 1 (for the \0 terminating char)

then strncpy line to lines[x] in getline while loop

nikhidet1 11-10-2011 05:49 AM

Quote:

Originally Posted by Cedrik (Post 4520463)
line[0] is the first char of the line string
If you want array of strings, it's like :
char lines[10][128];
(declare an array of 10 strings with max 127 chars + 1 (for the \0 terminating char)

then strncpy line to lines[x] in getline while loop

Are sure we can do this...if im not mistaken strcpy only takes char with the same array..but in this case lines would be a 2 dimensional array wheares my lines in getline is only one dimensional..could u help me by telling me ur ideas...thanks in advanced

Cedrik 11-10-2011 06:31 AM

A string is an array by itself (an array of chars), so a list of strings is an array of arrays
if I use strncpy(lines[0], line, len), then line string is copied into lines[0]

NevemTeve 11-10-2011 07:12 AM

Code:

/* getlinetest.c */

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

int main (void)
{
    FILE *fp;
    char *line= NULL;
    size_t buflen, linelen;
    ssize_t read;
    char **lines= NULL;
    size_t nlines= 0, nmaxlines= 0;
    size_t i;

    fp = fopen("mytext.txt", "r");
    if (fp == NULL) exit(EXIT_FAILURE);

    line= NULL;
    buflen= 0;
    while ((read = getline (&line, &buflen, fp)) != -1) {
        linelen= strlen (line);
        if (linelen>0 && line[linelen-1]=='\n') line[--linelen]= '\0';

        if (nlines==nmaxlines) {
            nmaxlines= nmaxlines? 2*nmaxlines: 64;
            lines= realloc (lines, nmaxlines*sizeof(char *));
        }
        lines [nlines++] = strdup (line);
    }
    free (line);

    for (i=0; i<nlines; ++i) {
        printf ("%d '%s'\n", (int)i+1, lines[i]);
    }

    for (i=0; i<nlines; ++i) {
        free (lines[i]);
    }

    return 0;
}


Nominal Animal 11-10-2011 09:32 PM

Here is my example, linearray.h:
Code:

#ifndef  LINEARRAY_H
#define  LINEARRAY_H

#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>

#ifndef  READSIZE
#define  READSIZE  65536
#endif

ssize_t flinearray(const int descriptor,
                  char ***linelistptr, size_t **sizelistptr, char **memptr)
{
        char                **linelist = NULL;
        size_t                *sizelist = NULL;
        size_t                  lines, zeros;
        unsigned char        *data = NULL, *temp;
        size_t                  size = 0;

        ssize_t                  bytes;

        if (descriptor == -1 || (linelistptr && !memptr) || (!linelistptr && memptr)) {
                errno = EINVAL;
                return (ssize_t)-1;
        }

        while (1) {

                /* Grow data by one chunk. */
                temp = realloc(data, size + READSIZE);
                if (!temp) {
                        if (data)
                                free(data);
                        errno = ENOMEM;
                        return (ssize_t)-1;
                }
                data = temp;

                /* Read chunk. */
                do {
                        bytes = read(descriptor, data + size, READSIZE);
                } while (bytes == (ssize_t)-1 && errno == EINTR);

                if (bytes > (ssize_t)0)
                        size += (size_t)bytes;

                else
                if (bytes == (ssize_t)0)
                        break;

                else {
                        const int errnum = (bytes == (ssize_t)-1) ? errno : EIO;

                        if (data)
                                free(data);

                        errno = errnum;
                        return (ssize_t)-1;
                }
        }

        /* Find newlines and ASCII nuls. */
        {
                unsigned char        *src = data;
                unsigned char *const  end = data + size;

                lines = 0;
                zeros = 0;

                /* Zero sentinel to help with newline detection.
                * Note: there are READSIZE unused bytes after data. */

                while (src < end)
                        if (*src == '\n') {
                                lines++;
                                if (*(++src) == '\r')
                                        src++;
                        } else
                        if (*src == '\r') {
                                lines++;
                                if (*(++src) == '\n')
                                        src++;
                        } else
                        if (!*(src++))
                                zeros++;
        }

        /* Grow data area to exactly the size we need. Note that size contains zeros. */
        temp = realloc(data, size + lines + (size_t)2);
        if (!temp) {
                if (data)
                        free(data);
                errno = ENOMEM;
                return (ssize_t)-1;
        }

        /* Move the data area down. */
        memmove(data + lines + (size_t)1, data, size);

        /* Allocate pointer and size lists. */
        linelist = malloc(sizeof(char *) * (size_t)(lines + zeros + (size_t)2));
        sizelist = malloc(sizeof(size_t) * (size_t)(lines + zeros + (size_t)2));
        if (!linelist || !sizelist) {
                if (sizelist)
                        free(sizelist);
                if (linelist)
                        free(linelist);
                if (data)
                        free(data);
                errno = ENOMEM;
                return (ssize_t)-1;
        }

        {
                unsigned char *src = data + lines + (size_t)1;
                unsigned char *end = data + lines + (size_t)1 + size;
                unsigned char *dst = data;

                /* End of string mark for the final string. */
                *end = 0;

                /* Add end-of-string byte after each newline. */
                while (src < end)
                        if (*src == '\n') {
                                *(dst++) = *(src++);
                                if (*src == '\r')
                                        *(dst++) = *(src++);
                                *(dst++) = 0;
                        } else
                        if (*src == '\r') {
                                *(dst++) = *(src++);
                                if (*src == '\n')
                                        *(dst++) = *(src++);
                                *(dst++) = 0;
                        } else
                                *(dst++) = *(src++);

                /* src == end, dst == end - 1. Be paranoid anyway. */
                end = dst;
                *end = 0;

                /* Scan the lines into the list. */
                src  = data;
                dst  = data;
                lines = 0;

                while (src < end)
                        if (!*src) {
                                linelist[lines] = (char *)dst;
                                sizelist[lines] = (size_t)(src - dst);
                                dst = ++src;
                                lines++;
                        } else
                                src++;

                if (dst < end) {
                        linelist[lines] = (char *)dst;
                        sizelist[lines] = (size_t)(end - dst);
                        lines++;
                }

                /* Append a NULL pointer, for easier list scanning. */
                linelist[lines] = NULL;
                sizelist[lines] = 0;

                /* Save return values. */
                if (linelistptr)
                        *linelistptr = linelist;
                else
                        free(linelist);

                if (sizelistptr)
                        *sizelistptr = sizelist;
                else
                        free(sizelist);

                if (memptr)
                        *memptr = (char *)data;
                else
                        free(data);

                return lines;
        }
}

ssize_t linearray(const char *const filename,
                  char ***linelistptr, size_t **sizelistptr, char **memptr)
{
        char        **linelist = NULL;
        size_t        *sizelist = NULL;
        char        *mem      = NULL;

        int          descriptor, result, errnum;
        ssize_t          returned;

        if (!filename || !*filename) {
                errno = EINVAL;
                return (ssize_t)-1;
        }

        /* If linelistptr or memptr is NULL, the other must be NULL also. */
        if ((!memptr && linelistptr) || (memptr && !linelistptr)) {
                errno = EINVAL;
                return (ssize_t)-1;
        }

        do {
                descriptor = open(filename, O_RDONLY);
        } while (descriptor == -1 && errno == EINTR);
        if (descriptor == -1)
                return (ssize_t)-1;

        returned = flinearray(descriptor, &linelist, &sizelist, &mem);
        if (returned == (ssize_t)-1)
                errnum = errno;
        else
                errnum = 0;

        do {
                result = close(descriptor);
        } while (result == -1 && errno == EINTR);
        if (result == -1) {
                if (!errnum)
                        errnum = errno;

                if (sizelist) free(sizelist);
                if (linelist) free(linelist);
                if (mem)      free(mem);
        }

        if (errnum) {
                errno = errnum;
                return (ssize_t)-1;
        }

        if (!linelistptr) {
                free(linelist);
                linelist = NULL;
        } else
                *linelistptr = linelist;

        if (!sizelistptr) {
                free(sizelist);
                sizelist = NULL;
        } else
                *sizelistptr = sizelist;

        if (!memptr) {
                free(mem);
                mem = NULL;
        } else
                *memptr = mem;

        return returned;
}

#endif /* LINEARRAY_H */

It uses the low-level I/O routines to read the specified file in 64k chunks, then inserts end-of-string bytes (ASCII NULs) after each newline (LF, CR, CR LF, or LF CR -- i.e. any newline convention), and allocates and fills in an array of pointers to the beginning of each line, and optionally an array of line lengths. The strings will contain the newlines. (If not, then that line was either at the end of the file, or contained an ASCII NUL.)

It is pretty efficient, although not optimal. It does one extra copy of the data, which can be avoided using much more complex code for the newline detection, by supporting single-byte newlines, or by trimming newlines. It should be faster than anything using fgets() or getline().

It reads the input file in 64k chunks, reallocating the buffer each time. This is not too efficient, but works for all input types (like pipes and sockets). For files, the reallocations can be minimized by first checking the file size.

It is easy to modify the code so that newlines are stripped out (which also eliminates the extra copy). Leading and trailing whitespace and empty lines can be removed as well, with almost zero extra computing cost, by expanding the newline counting loop to trim whitespace around newlines.

The downside is that extending a line returned by this function is a bit complicated. You basically have to allocate a new line, and copy the old line into it. Because the lines are all allocated in one big chunk, you cannot just reallocate one line.

Here is an example program using the above code. It outputs each line indented by one tab.
Code:

#include <stdio.h>
#include <string.h>
#include <errno.h>
#include "linearray.h"

int main(int argc, char *argv[])
{
        int          arg;

        ssize_t          lines;
        char        **line;
        size_t        *size;
        char        *data;

        ssize_t          i;

        if (argc < 2) {
                fprintf(stderr, "\nUsage: %s file(s)...\n\n", argv[0]);
                return 1;
        }

        for (arg = 1; arg < argc; arg++) {

                lines = linearray(argv[arg], &line, &size, &data);
                if (lines == (ssize_t)-1) {
                        fprintf(stderr, "%s: %s.\n", argv[arg], strerror(errno));
                        return 1;
                }

                fprintf(stderr, "%s: %lu lines:\n", argv[arg], (unsigned long)lines);
                fflush(stderr);
                for (i = 0; i < lines; i++) {
                        fputc('\t', stdout);
                        fputs(line[i], stdout);
                        if (size[i] < 1 || (line[i][size[i]-1] != '\n' && line[i][size[i]-1] != '\r'))
                                fputc('\n', stdout);
                }
                fflush(stdout);

                free(line); line = NULL;
                free(size); size = NULL;
                free(data); data = NULL;
        }

        return 0;
}

When processing configuration files, I use a different approach, where the interface is something like
Code:

struct command {
    const char      *string;
    int            (*callback)(int tokens, char *token[], const char *filename, unsigned long line, void *state);
};

int parse(const char *filename, int commands, const struct command *command, void *state);

In this approach, you specify a callback function for each command (command being the first token on each line). The parse function reads the file, splits it into lines, and lines to tokens. It de-escapes escape sequences, removes quotes, and applies variable expansion. It calls the relevant callback function with the relevant tokens (parameters) in an array, for each command it parses from the input. The type and contents of the state is completely opaque to the parse function; normally it describes the entire configuration. If you were to use the above to create a simple shell, then state would contain at least all (environment) variables and their values. A full efficient implementation of something like this is pretty large, maybe a thousand lines of code. I thought that would be a bit too large to discuss here.

nikhidet1 11-15-2011 02:17 AM

thanks guys....u all really help me a lot...now my task is to understand what do u guys means from the code...anyways thanks a lot....really appreciate the codes and all your helps....thanks again

nikhidet1 11-15-2011 03:58 AM

while ((read = getline (&line, &buflen, fp)) != -1) {
linelen= strlen (line);
if (linelen>0 && line[linelen-1]=='\n') line[--linelen]= '\0';

if (nlines==nmaxlines) {
nmaxlines= nmaxlines? 2*nmaxlines: 64;
lines= realloc (lines, nmaxlines*sizeof(char *));
}
lines [nlines++] = strdup (line);
}
free (line);
hey i couldn't understand this code nmaxlines= nmaxlines? 2*nmaxlines: 64;..what it's means..is it means that if (nmaxlines=nmaxlines) take the values of 2*nmaxlines else take value 64...am i right?

NevemTeve 11-15-2011 04:22 AM

In other words:
Code:

if (nlines==nmaxlines) {
    if (nmaxlines!=0) nmaxlines= 2*nmaxlines;
    else              nmaxlines= 64;
    lines= realloc (lines, nmaxlines*sizeof(char *));
}


nikhidet1 11-15-2011 05:02 AM

thanks now i understand ur code well...thanks for the explanation..


All times are GMT -5. The time now is 06:31 PM.