0

I need to write the Solaris the 'line' application on Solaris, which is very simple, on Linux. It was developed for scripting, it takes one line of stdin and outputs it to stdout. I wrote an extraordinarily simple C program to do this. I used both getline and fgets and they produce the same outcome:

int main(int argc, char* argv[])
{
    char buf[256];
    char* line = NULL;

    if (fgets(line, 256, stdin) != NULL)
    //if (getline(&line, &len, stdin) != -1)
    {
        printf("%s", line);
    }
    return EXIT_SUCCESS;
}

The C-Shell script, loop_file looks like this:

#!/bin/csh -f
while(1)
    set line = `app`
    echo "Got Line : $line"
end

I kick off the process using the following: ./loop_file < textFile.txt

It's a large file, the first line is printed out just but the next line is almost 4096 characters after, the third line is almost 4096 after that, etc. It is not a line-by-line read. I've even tried forgetting using C and using awk in the while loop instead.

Any ideas?

By the way, don't say - don't use CSH - it's legacy code I'm required to port :)

while(1)
set line = `app`

    set name = $line[0];
    set address = $line[1];
    set purpose = $line[2];
end
jiveturkey
  • 2,484
  • 1
  • 23
  • 41
  • What, exactly, is your goal? Right now, you seem to have a C program that will simply write the first 256 bytes of the input file to standard output, and calling it from your shell script will just repeat the same 256 bytes *ad infinitum*. – chepner Jun 03 '13 at 16:19
  • You have a C program which prints the string whose address is in line, but line is set to NULL and never changed; it uses a variable buffer which it never declares. How did this ever compile, much less produce output? – Scott Hunter Jun 03 '13 at 16:20
  • I apologize `buffer` needed to be `line`. This is a test script. The actual script takes column delimited fields from each line read in. I've added a slightly more detailed example of the purpose of the script above. – jiveturkey Jun 03 '13 at 16:35
  • Now you have a C program which reads into, and prints from, a pointer (line) which is initialized to NULL and never changed, and has an array (buf) which is never used. – Scott Hunter Jun 03 '13 at 16:39
  • If you change `app` to `cat` in your script, does it do what you expect it to do? – jxh Jun 03 '13 at 16:40
  • `cat` didn't work, I get a `Word too long.` error. I suppose the csh variable cannot maintain the data. Thanks Scott - My code was actually buf[]. – jiveturkey Jun 03 '13 at 16:47
  • `stdin` is by default fully buffered (I think), try setting it to unbuffered mode i.e. `setvbuf(fd, NULL, _IONBF, 0)` or [equivalent](http://stackoverflow.com/questions/1647927/unbuffered-i-o-in-ansi-c) before `fgets` call in your C program – another.anon.coward Jun 03 '13 at 16:50
  • another.anon.coward - You are awesome!! It worked! Post the answer. – jiveturkey Jun 03 '13 at 16:55
  • `head -n 1` reads one line from stdin and prints it to stdout -- and it doesn't limit the line length to 256 characters. But if you really want a C program to do that, just read and write a character at a time until you see `'\n'` or `EOF`. BTW, @another.anon.coward won't be notified of your comment unless you precede the name with an at-sign (as I've done here). – Keith Thompson Jun 03 '13 at 17:45
  • @KeithThompson: You are spot on sir! The `line` utility does seem to read character by character – another.anon.coward Jun 03 '13 at 17:47

1 Answers1

2

stdin is buffered which could be the reason why some of the lines from the text file are missed out. You could possibly make stdin unbuffered using setvbuf(fd, NULL, _IONBF, 0) or equivalent before fgets call in your C program and address this issue.
Alternatively, you can read character by character following the suit of line utility. Maybe something on the lines of :

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

int main(void)
{
    char c;
    while(read(STDIN_FILENO , &c, 1) > 0 && c != '\n')
        putchar(c);
    return  EXIT_SUCCESS;
}

Hope this helps!

Community
  • 1
  • 1
another.anon.coward
  • 11,087
  • 1
  • 32
  • 38