Using just I/O system calls, I should write I program in C that takes a file as input and prints in output its contents splitting each line in half. More specifically, if a line is n characters long, the program must print the first n/2 characters of a line, followed by a '\n' print, followed by its second n/2 characters. I wrote down a possible solution but it doesn't working very well, splitting the correct lines for a half of the file content and ignoring the rest.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#define LEN 5000
void half_rows (char* f);
void freebuf (char arr[], int n);
int main (int argc, char* argv[]){
if (argc != 2)
fprintf (stderr, "Usage %s: <file>\n", argv[0]), exit(1);
char* file = argv[1];
half_rows (file);
return 0;
}
void half_rows (char* f){
char c;
char buf[LEN];
int fd, nread, n, rest, up;
if (( fd = open (f, O_RDONLY)) < 0)
perror("opening error"), exit(1);
int cur = lseek (fd, 0, SEEK_CUR);
int finalpos = lseek (fd, 0, SEEK_END);
// lseek (fd, cur, SEEK_SET);
do{
lseek (fd, cur, SEEK_SET);
if ((nread = read (fd, &c, sizeof(c))) < 0)
perror("reading error"), exit(1);
buf[cur] = c;
if ( buf[cur] == '\n' || buf[cur] == '\0'){
rest = cur % 2;
if (rest == 0)
n = cur / 2;
else{
up = cur + 2 - rest;
n = up / 2;
}
buf[n] = '\n';
buf[n+1] = '\0';
}
++cur;
}while (cur < finalpos);
write (STDOUT_FILENO, buf, finalpos);
}
Well, you can let printf
do it all for you, without a copy or injection or you can copy or inject, or do it char-by-char as @WilliamPursell shows (all are fine), e.g.
With Printf
#include <stdio.h>
#include <string.h>
#define MAXC 1024 /* if you need a constant, #define one (or more) */
int main (void) {
char line[MAXC]; /* buffer to hold entire line */
while (fgets (line, MAXC, stdin)) { /* read/validate line */
int len = strlen(line); /* get length of line */
if (len == 1) { /* if line only 1-char */
putchar (line[0]); /* can't split 1 - output char */
continue; /* get next line */
}
/* output first 1/2 and second 1/2 */
printf ("%.*s\n%s", len/2, line, line + len/2);
}
}
Using a 2nd Buffer
#include <stdio.h>
#include <string.h>
#define MAXC 1024 /* if you need a constant, #define one (or more) */
int main (void) {
char line[MAXC]; /* buffer to hold entire line */
while (fgets (line, MAXC, stdin)) { /* read/validate line */
size_t len = strlen(line); /* get length of line */
char first[MAXC/2 + 1]; /* buffer to hold 1st 1/2 */
if (len == 1) { /* if line only 1-char */
putchar (line[0]); /* can't split 1 - output char */
continue; /* get next line */
}
memcpy (first, line, len/2); /* copy 1st 1/2 to first */
first[len/2] = '\n'; /* add newline (or just use puts) */
first[len/2+1] = 0; /* nul-termiante */
fputs (first, stdout); /* output 1st 1/2 */
fputs (line + len/2, stdout); /* output rest */
}
}
Both will give equivalent output, e.g.
Example Input File
$ cat dat/tosplit.txt
1234
56789
123
bc
Example Use/Output
$ ./bin/splitline < dat/tosplit.txt
12
34
567
89
12
3
b
c
There is always more than one way to skin-the-cat in C. Let me know if you have further questions.