I am trying to implement the rev linux call in C using only system calls. I was able to implement it but my code also reverses the lines of the files as well so line 1 is the last line in the file now. The last line also does not jump into a new line on stdout. I'm not sure why it is doing this.
Here is my code:
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <sys/types.h>
#define LINE_BUFFER 1024
int charCount(const char *name1);
int main(int argc, char* argv[]) {
if(argc ==2){
charCount(argv[1]);
}else{
printf("Provide a file\n");
}
return 0;
}
int charCount(const char *name1)
{
char buffer[LINE_BUFFER];
int fd;
int nread;
int i = 0;
if ((fd = open(name1, O_RDONLY)) == -1)
{
perror("Error in opening file");
return (-1);
}
int size = lseek(fd,-1,SEEK_END);
while(size>=0)
{
nread=read(fd,buffer,1);
write(1,buffer,1);
lseek(fd, -2,SEEK_CUR);
size--;
}
close(fd);
return(0);
}
input
Contents of file 1:
Hello World
Hi World
Output
dlroW iH
dlroW olleH
Desired output:
dlroW olleH
dlroW iH
Your code clearly reads the file backwards, one character at a time, printing each character as it reads it. Why would you think it would reverse line by line? It makes no attempt to even notice where each line ends.
If you read a file backwards, the last character you'll read (and therefore the last character you'll print) is the first character in the file, which is not normally a newline character.
Related
I want to create a text file with mulitple lines using system calls in C and populate it with the text provided as command line arguments.
This is what I wrote:
#include <stdio.h>
#include <fcntl.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#define MAX_SZ 1024
int main(int argc, char *argv[]) {
if (argc != 3) {
printf("Invalid Number of arguments\n");
printf("USAGE: ./a.out file_name \"msg\"\n");
} else {
int fd_creat, fd_open, fd_write;
char file_name[MAX_SZ];
char *msg = (char *)malloc(strlen(argv[2]) * sizeof(char));
strcpy(file_name, argv[1]);
fd_creat = creat(file_name, 0777);
if (fd_creat < 2) {
printf("ERROR: File could not be created\n");
} else {
fd_open = open(file_name, O_WRONLY);
strcpy(msg, argv[2]);
fd_write = write(fd_open, msg, strlen(msg));
close(fd_open);
}
}
return 0;
}
If I execute this program as:
./a.out test.txt "Foo\nBar"
It writes the whole thing into test.txt as it is. Basically, I want 'Foo' and 'Bar' in their separate lines.
There's two problems here:
The way you're handling arguments and failing to allocate enough memory for the data involved,
Interpreting escape sequences like \n correctly since the shell will give them to you as-is, raw.
#include <stdio.h>
#include <fcntl.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
// This moves overlapping strings from src -> dest but only
// if dest is before src
void cc_str_drag(char* dest, char* src) {
while (*dest) {
*dest = *src;
++dest;
++src;
}
}
// This interprets the \n sequence and can be extended to handle others, like
// \t, \\, or even \g.
void cc_interpret(char* str) {
for (;*str; ++str) {
// If this is a sequence start...
if (*str == '\\') {
// ...find out which one...
switch (str[1]) {
case 'n':
// Shift back...
cc_str_drag(str, &str[1]);
// ...and replace it.
*str = '\n';
break;
}
}
}
}
int main(int argc, char *argv[]) {
if (argc != 3) {
printf("Invalid Number of arguments\n");
// Remember argv[0] is the name of the program
printf("USAGE: %s file_name \"msg\"\n", argv[0]);
return -1;
}
// Since it's not the 1970s, use fopen() and FILE*
FILE* output = fopen(argv[1], "w");
if (!output) {
printf("ERROR: File could not be created\n");
return -2;
}
// Copying here to avoid tampering with argv
char* str = strdup(argv[2]);
// Replace any escape sequences
cc_interpret(str);
// Then just dump it directly into the file
fwrite(str, 1, strlen(str), output);
fclose(output);
return 0;
}
Note the tools used here:
strdup is a way quicker method of copying a C string than malloc(strlen(s)) and then copying it. That's asking for dreaded off-by-one errors.
FILE* performs much better because it's buffered. open() is used for low-level operations that can't be buffered. Know when to use which tool.
Don't be afraid to write functions that manipulate string contents. C strings are really important to understand, not fear.
If I`ve got a TXT file with a pre-determined structure, is there any way I can read some of the text directly from the file without having to parse or tokenize a string? For instance, if I have the following code:
#include <stdlib.h>
#include <stdio.h>
#include <cstring>
#include <fstream>
int main(int argc, char** argv) {
FILE* test = fopen("test.txt","w+");
char* read;
fprintf(test,"(foo,_TEMP71_,_,_)\n");
fprintf(test,"(foo,_TEMP52_,_,_)\n");
fprintf(test,"(foo,_TEMP43_,_,_)\n");
fprintf(test,"(foo,_TEMP24_,_,_)\n");
fprintf(test,"(foo,_TEMP15_,_,_)\n");
fprintf(test,"(foo,_TEMP06_,_,_)\n");
fseek(test, 0, SEEK_SET); //returns the file pointer to start of file
while(feof(test) == 0)
{
fscanf(test, "_%s_", read); //or fscanf(test, "_TEMP%s_", read);
printf("%s\n", read);
}
fclose(test);
}
Note that on the fscanf line, I read from this website that you could specify a certain string of characters to be read, but I don`t think I understood quite how it works.
I am trying to write a program for some classwork that reads in a file using fscanf, and then stores each word into an array with one word in each element. Then I need to print each element of the array out on to a new line on the console.
The getty.txt file has the Gettysburg address in it with appropriate spacing, punctuation, and is multiline.
What I think is happening is that the entire text is being stored in the first element of the array, but I am not 100% sure as I am still learning to debug and write in C.
Any advice as to what I am doing wrong would be great! I currently only seem to be getting the last word and some extra characters.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
void readFile();
void writeFile(char* buffer, int bufferlen);
FILE *fpread;
FILE *fpwrite;
char filebuffer[1000];
int filebufferlen = 0;
int main(int argc, char *argv[]) {
fpwrite = fopen("csis.txt", "w");
readFile();
writeFile(filebuffer, filebufferlen);
fclose(fpwrite);
return 0;
}
void readFile() {
char c;
filebufferlen = 0;
if(!(fpread = fopen("getty.txt", "r"))){
printf("File %s could not be opened. \n", "getty.txt");
fprintf(fpwrite,"File %s could not be opened. \n", "getty.txt");
exit(1);
}
while (!feof(fpread)) {
fscanf(fpread, "%s", filebuffer);
filebufferlen++;
}
}
void writeFile(char* filebuffer, int filebufferlen) {
for (int i = 0; i < filebufferlen; ++i){
printf("%c\n", filebuffer[i]);
}
}
After fixing the compile problems:
the code does not contain any code nor data declarations to contain an array of 'words.' So naturally, nothing but the last word is actually saved so it can be printed out.
when i use open() as
int ff=open("/home/user/desktop/bla/test",O_RDONLY);
it works fine.
but when i use a string as the (same path stored in a string) path it doesn't work.
int ff=open(string,O_RDONLY);
why is this?
this is my whole code. i'm confused. i know it should work. but i doesn't. i can't find the bug.
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <string.h>
void bla(char *);
int main(void)
{
// int i;
FILE * fp=fopen("path","r");
char line[256];
while( fgets(line,255,fp)!=NULL){
bla(line);
}
return 0;
}
void bla(char * line){
int status;
printf("%s",line);
pid_t pid=fork();
char string[256];
if(pid==0){
pid=wait(&status);
int ff=open(line,O_RDONLY);
if(ff<0){
printf("\topen error!\n\n");
return;}
int ret=read(ff,string,255);
if(ret<0){
printf("read error!\n");
return;}
printf("%s",string);
close(ff);
exit(0);
}
if (pid>0){
return;
}
}
in bla function, if i replace 'line' with the path, it works. i used a printf to make sure. path is the same (it seems the same).
I call shenanigans :-)
Obviously, if string were exactly the same value as your string literal, and all others things remained the same, it would work fine.
So, if all other things are the same, string is obviously not set to the value you think it is, to wit "/home/user/desktop/bla/test".
My advice would be to print it out (along with an error string) to be sure, something like:
fprintf (stderr, "DEBUG: string is [%s]\n", string);
int ff = open (string, O_RDONLY);
if (ff < 0)
perror ("Could not open file");
And, now that you've posted the code, your problem is obvious: fgets() does not remove the trailing newline so, were you to add the code I proposed above, you would see:
DEBUG: string is [/home/user/desktop/bla/test
]
and deduce the problem.
A quick way to fix this is to remove the newline yourself, with something like:
while (fgets (line, 255, fp) != NULL) {
size_t ln = strlen (line); // Add these
if ((ln > 0) && (line[ln-1] == '\n')) // three
line[ln-1] = '\0'; // lines.
bla (line);
}
log.txt :
Hello world
world is not enough
to show our knowledge
cpp file :
#include <stdio.h>
#include <string.h>
int main()
{
char szLine[512+1]={0};
FILE *fp=fopen("log.txt", "r");
while(!feof(fp))
{
fscanf(fp, "%512[^\n]", szLine);
puts(szLine);
getchar();
}
return 0;
}
Acually expected output for this program has to read line by line. But it read only first line alone. What is the mistake on this code. thanks advance.
you can change your program like this:
#include <stdio.h>
#include <string.h>
int main()
{
char szLine[512+1]={0};
FILE *fp=fopen("log.txt", "r");
while(!feof(fp))
{
fgets(szLine,512,fp);
puts(szLine);
getchar();
}
return 0;
}
because the offset of the file stream always be 0, so you read
"%512[^\n]" does not read the endline character. The remaining part of the file starts with \n and fscanf fails to read the line(it return 0 instead of 1). You need to read the endline character !
#include <stdio.h>
#include <string.h>
int main()
{
int bla;
char szLine[512+1]={0};
FILE *fp=fopen("log.txt", "r");
while(!feof(fp))
{
bla= fscanf(fp, "%512[^\n]", szLine);
if(bla==1){
printf("%d\n",bla);
puts(szLine);
getchar();
fgetc(fp);
}
}
return 0;
}
Using getline() may be a more reliable solution.
getline(&szLine,&size,fp);
Bye,
Francis
try this
while(fscanf(fp, " %512[^\n]", szLine)==1)
{
puts(szLine);
getchar();
}