Reputation: 3381
I'm trying to append a capital 'X'
character at the end of every line of a simple text file (while switching all chars to upper case at the same time) and writing the changes to a new file.
So initially, the file faust.txt
contains:
Besonders aber laßt genug geschehn!
Man kommt zu schaun, man will am liebsten sehn.
Wird vieles vor den Augen abgesponnen,
After the call, the file FAUST.txt
should contain:
BESONDERS ABER LAßT GENUG GESCHEHN!X
MAN KOMMT ZU SCHAUN, MAN WILL AM LIEBSTEN SEHN.X
WIRD VIELES VOR DEN AUGEN ABGESPONNEN,X
The copying and conversion to upper case seems to work but the appending is unclear to me:
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <ctype.h>
int main() {
// 1) Open faust source file
int BUF_SIZE = 1;
int faust_fh = open("faust.txt", O_RDONLY);
char src[BUF_SIZE];
// Destination file.
int FAUST_fh = open("FAUST.txt", O_CREAT | O_WRONLY);
int read_bytes = read(faust_fh, &src, BUF_SIZE);
while (read_bytes > 0) {
char c = src[0];
char *C = &c;
src[0] = toupper(*C);
if (src[0] == '\n') {
char *end = &src[0];
strcat(end, "X");
src[0] = *end;
}
write(FAUST_fh, &src, BUF_SIZE);
read_bytes = read(faust_fh, src, BUF_SIZE);
}
close(FAUST_fh);
close(faust_fh);
return 0;
}
Note: I should accomplish this with system calls (if possible).
Upvotes: 0
Views: 85
Reputation: 33601
The caveats about strcat
et. al. from other responders apply (e.g. you can't guarantee the buffer will have an EOS, so you can't use string functions).
Although it may be easiest to do a read
with length 1, it's sometimes more efficient to have a larger buffer size.
Here's a version that works with buffer sizes > 1. I set a size of 10, but it can be whatever size you'd like:
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <ctype.h>
int
main(void)
{
// 1) Open faust source file
#if 0
int BUF_SIZE = 1;
#else
int BUF_SIZE = 10;
#endif
int faust_fh = open("faust.txt", O_RDONLY);
char src[BUF_SIZE];
char Xnewline[] = "X\n";
// Destination file.
// NOTE/BUG: we need to specify the mode with O_CREAT otherwise the
// file is created with a semi-random permission mask
#if 0
int FAUST_fh = open("FAUST.txt", O_CREAT | O_WRONLY);
#else
int FAUST_fh = open("FAUST.txt", O_CREAT | O_WRONLY, 0644);
#endif
char *lhs;
size_t len;
int read_bytes;
while (1) {
lhs = src;
read_bytes = read(faust_fh, lhs, BUF_SIZE);
if (read_bytes <= 0)
break;
char *end = &lhs[read_bytes];
char *cur;
// process/scan all bytes in the buffer
for (cur = lhs; cur < end; ++cur) {
int c = *cur;
*cur = toupper(c);
if (c == '\n') {
// send all data up to, but not including the newline
len = cur - lhs;
if (len > 0)
write(FAUST_fh,lhs,len);
// send X<newline>
write(FAUST_fh,Xnewline,2);
// set new left start into current buffer (just _past_ the
// newline)
lhs = cur + 1;
}
}
// send the remainder of the current buffer [has _no_ newlines in it]
len = cur - lhs;
if (len > 0)
write(FAUST_fh,lhs,len);
}
close(FAUST_fh);
close(faust_fh);
return 0;
}
Upvotes: 0
Reputation: 780871
You're causing undefined behavior when you call strcat(end, "X");
because end
points to src
, and src
doesn't have a null terminator and doesn't have enough bytes allocated to concatenate anything.
If you're reading the file one byte at a time, you don't need an array. Just read into a char
variable. When the character is a newline, write an X
to the output file before writing the character.
Another problem: when you call open()
to create the output file, you have to pass a third argument containing the desired file permissions.
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <ctype.h>
int main() {
// 1) Open faust source file
int BUF_SIZE = 1;
int faust_fh = open("faust.txt", O_RDONLY);
char src;
// Destination file.
int FAUST_fh = open("FAUST.txt", O_CREAT | O_WRONLY, 0644);
int read_bytes = read(faust_fh, &src, BUF_SIZE);
while (read(faust_fh, &src, BUF_SIZE) > 0) {
src = toupper(src);
if (src == '\n') {
write(FAUST_fh, "X", 1);
}
write(FAUST_fh, &src, BUF_SIZE);
}
close(FAUST_fh);
close(faust_fh);
return 0;
}
Upvotes: 2
Reputation: 7490
Since BUF_SIZE
is 1, you are reading the input character by character.
This is fine, but this also mean that src
is just a one-char array, not a nul-terminated string (an array of characters terminated by '\0'
character).
And this mean all string manipulation functions, such as strcat
cannot be used. All of them lead to undefined behavior when it comes to deal with araays that are not null-terminated..
In order to accomplish your task, just perform an extra write
whenever you find an end of line:
if (src[0] == '\n') {
char ecs = 'X';
write(FAUST_fh, &ecs, 1);
// it's always recommended to check the return value of write()
}
All the other characters will be appended as usual. The X
char write is just an insertion on the fly.
Upvotes: 1