strange C program fgets - c

I was going through an open source codebase and I see the following:-
char *buf;
char *line;
#define BUFSIZE 5000
buf = malloc(BUFSIZE)
line = buf;
while(fgets(line, (unsigned)(buf + BUFSIZE -line), in) != NULL) {
// do stuff
// ....
}
Why is the second argument to fgets given as buf + BUFSIZE - line?

That gives the number of characters from line to end of buf. Your //do stuff likely increments line
buf + BUFSIZE is a char * pointing to the first char after the memory allocated for buf
buf + BUFSIZE - line is an integral, the number of chars from line to buf + BUFSIZE - and therefore the number of characters you can safely write to line without overflowing buf

buf + BUFSIZE - line gives the free space in the buffer.
This way line can be a scrolling pointer pointing to the first free byte, where the next read operation can put the data.

Line will probably get incremented during the loop. Thus this expression shrinks the value of BUFSIZE by the size of text already read.
It's a guess, sicne you didn't post the loop.

Related

Append a character at the end of a malloc'd string

I am looking for a '.' character in a file.
I use the function read to look for it.
The problem is that I have a buffer size and I need to loop as long as I don't find the '.' character with read(fd, buffer, bufferSize).
I used malloc to allocate the memory for 1 buffer size (char *buffer = malloc((bufferSize + 1) * sizeof(char))), but I don't know how many times I'll have to loop.
How can I add memory to the buffer depending on the buffer size loops I'll do ?
A string is not needed.
Instead, to use read(), examine its return value to determine how much to search with memchr().
#define BUFFER_SIZE 1000
char buffer[BUF_SIZE];
long long loop_count = 0;
ssize_t size_read;
while ((size_read = read(fd, buffer, sizeof buffer)) > 0) {
void *dot_address = memchr(buffer, '.', size_read);
if (dot_address) {
loop_count += dot_address - buffer;
printf("Found '.' as offset %lld\n", loop_count);
break;
}
loop_count += size_read;
}
OP later adds in a comment, "I have to save all the characters until the dot in the buffer so I have to add memory every time I loop"
Not sure when continually additional requirements will stop.
Lost interest.

Does fgets() hold somehow where it stopped reading from a FILE *?

I am trying to get a sample (shell script) program on how to write to a file:
#include <unistd.h>
#include <stdio.h>
#include <string.h>
int main(int argc, char **argv){
char buff[1024];
size_t len, idx;
ssize_t wcnt;
for (;;){
if (fgets(buff,sizeof(buff),stdin) == NULL)
return 0;
idx = 0;
len = strlen(buff);
do {
wcnt = write(1,buff + idx, len - idx);
if (wcnt == -1){ /* error */
perror("write");
return 1;
}
idx += wcnt;
} while (idx < len);
}
}
So my problem is this: Let's say I want to write a file of 20000 bytes so every time I can only write (at most) 1024 (buffer size).
Let's say that in my first attempt everything is going perfect and fgets() reads 1024 bytes and in my first do while I write 1024 bytes.
Then, since we wrote "len" bytes we exit the do-while loop.
So now what?? The buffer is full from our previous reading. It seems to me that for some reason it is implied that fgets() will now continue reading from the point it reached in in-file the last time. (buf[1024] here).
How come, fgets() knows where it stopped reading in the in-file?
I checked the man page :
fgets() reads in at most one less than size characters from stream and stores them into the buffer pointed to by s. Reading stops after an EOF or a newline. If a newline is read, it is stored in the buffer. A terminating null byte (aq\0aq) is stored after the last character in the buffer.
fgets() return s on success, and NULL on error or when the end of file occurs while no characters have been read.*
So from that, I get that it returns a pointer to the first element of buf, which is always buf[0],
that's why I am confused.
When using aFILE stream, it contains information about the position in the file (among other things). fgets and other functions like freador fwrite merely utilize this information and updates it when an operation is performed.
So, whenever fgets reads from the stream, the stream will be updated to maintain the position, so that the next operation starts off where the previous ended.

windows memory formatting issue

I am trying to make this dynamic reallocation work in a portable fashion.
My program accepts a line of text from a user and appends it to a buffer. If the length of text in the buffer is 20 or more, it removes the first 20 characters and moves any characters after that to the start of the buffer.
I have this code which works clean on Linux but when I run it on windows it emits garbage. Does anyone know why/how to make this portable only using malloc. IE not using string.h(strcpy) str... anything but len.
c17 only - no broken stucts(not portable). here is my code. Compiles with no errors gcc 7.3, mingw 7.3. I replace gets and puts with safer functions and I still get garbage on windows. I assume this is a formatting issue...
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <malloc.h>
void wbuff (message)
char *message;
{
FILE *f = fopen("file.txt", "w");
fprintf(f, "%s", message);
fclose(f);
}
char *rean (message)
char *message;
{
/* performs (write) on buffer, trims lefover, then restores */
char buf[80] = "";
puts("enter a line");
gets(buf);
int bln = strlen( buf );
int mln = strlen( message );
int nln = bln + mln;
printf("new length %d\n", nln);
message = realloc(message, nln);
memmove(message + mln, buf, bln);
/* MISTAKE IS HERE?! */
if( nln >= 20 ) {
int exl = nln -20; // leftover length
char *lo = realloc(NULL, exl); // leftover placeholder
memmove(lo, message+20, exl); // copy leftover
wbuff(message); // write clear buff
message = realloc(NULL, nln);
message = realloc(NULL, exl); // resize buffer
memmove(message, lo, exl); // restore leftover
}
return message;
}
void main (void)
{
char *message = "";
message = realloc(NULL, 0);
while ( 1 == 1 ) {
message = rean( message );
puts(message);
}
return;
}
In C, strings are a sequence of characters terminated by a null byte. You have a number of off-by-one errors here mostly related to not accounting for that fact, as well as memory leaks.
When you first set message in main:
char *message = "";
message = realloc(NULL, 0);
message either is NULL to points to 0 bytes of memory. When you call then call rean the first time:
int mln = strlen( message );
You're either attempting to dereference a NULL pointer to read past the end of allocated memory. You want to allocate at least 1 byte to start and set that byte to 0 so you have an empty string:
char *message = realloc(NULL, 1);
message[0] = '\0';
Then later when you copy the buffer into the message:
message = realloc(message, nln);
memmove(message + mln, buf, bln);
You don't allocate enough space for the terminating null byte, nor do you copy it, so you don't really have a string. When you then try to print it, either puts or printf reads past the end of the allocated memory. You need to allocate 1 extra byte and copy 1 extra byte:
message = realloc(message, nln + 1); // allocate 1 extra byte for the null terminator
memmove(message + mln, buf, bln + 1); // copy 1 extra byte
There are similar issues when you recopy anything past 20 characters:
int exl = nln -20; // leftover length
char *lo = realloc(NULL, exl); // leftover placeholder
memmove(lo, message+20, exl); // copy leftover
wbuff(message); // write clear buff
message = realloc(NULL, nln);
message = realloc(NULL, exl); // resize buffer
memmove(message, lo, exl); // restore leftover
lines 2-3: You don't allocate space for the terminating null byte for lo nor do you copy it.
line 5: You leak the memory previously held by message in the first realloc by passing assigning to message while using NULL as the first argument
line 6-7: You leak the memory allocated in line 5 by doing the same thing. Also, you again don't allocate space for the null byte, nor do you copy it on the next line.
As before, allocate 1 extra byte for each allocation and move 1 extra byte to account for the null terminator. Also, free lo at the end of the block, remove the extra realloc for message, and pass the prior value of message to realloc so you don't leak memory:
int exl = nln -20;
char *lo = realloc(NULL, exl + 1); // allocate 1 extra byte
memmove(lo, message+20, exl + 1); // copy 1 extra byte
wbuff(message);
// remove extra realloc
message = realloc(message, exl + 1); // pass in old message, allocate 1 extra
memmove(message, lo, exl + 1); // copy 1 extra byte
free(lo); // free leftover
These issues of reading and writing past the end of allocated memory all invoke undefined behavior, which explains why you see different results on different operating systems.
As far as conforming code goes, use fgets intead of gets:
fgets(line, sizeof(line), stdin);
This function will include a newline in line if there's space for it, so be sure to remove it if that's the case.
Also change main to return int, and remove #include <malloc.h> since the malloc family of function is defined to reside in stdlib.h.
Had you used strcpy and strcat instead of memmove, you wouldn't have had to account for copying the null terminating byte as those functions do that for you. You would still however need to account for that when allocating memory. There's also no conflict between strcpy, malloc, and realloc, as they are all part of the standard and work together properly. Using them together is no problem. If they aren't working properly for you then you aren't using them correctly.
After applying my updates, you can replace this:
memmove(message + mln, buf, bln + 1);
With this:
strcat(message, buf);
And replace this:
memmove(lo, message+20, exl + 1); // copy leftover
...
memmove(message, lo, exl + 1); // restore leftover
With this:
strcpy(lo, message+20);
...
strcpy(message, lo);
And it will still work properly and be conforming.

strategy to fprintf into a file from a buffer but going to a new line after every 100 characters?

Is there any simple function or strategy that will help me fprintf onto a file from a buffer that I have while moving to the next line every 100 characters?
In the general case, not really: fprintf does not come with an automatic line wrapping facility.
But you can take advantage of fprintf's return value: the number of characters that were written. Updating a column count, you can output a linefeed every time you go past a certain value. If your fprintf chunks are small enough, the can be a good approximation of what you are trying to do. To properly compute the column count, you must take into account any linefeeds you may output as part of an fprintf function call.
Otherwise, you can snprintf to a buffer and search for spaces to break the line appropriately or even just break the line arbitrarily at 100 characters.
Another more general solution is to use popen() to pipe the output through a utility that would perform the kind of wrapping you want.
A simple loop:
#include <stdio.h>
#define MAX_LINE 100
int main(void)
{
char str[10000];
char *ptr = str;
int size;
fgets(ptr, sizeof str, stdin);
do {
/* write a maximum of 100 chars to file and a trailing new line */
/* size stores the number of chars written - trailing nl */
size = fprintf(stdout, "%.*s\n", MAX_LINE, ptr) - 1;
/* increment the ptr size positions */
ptr += size;
/* if (end-of-buffer - size < 100) exit loop */
} while (size >= MAX_LINE);
return 0;
}

Remove 20 Spaces before and after buffer C

How do I remove 20 spaces from the beginning of a buffer and 20 at the end?
I can run a for loop starting at 20 and -20 at the end total but how do I copy each char by char to another buffer or is there a simple padding command?
Thanks for all the help so far now works but just displays a about 20 charactors i.e the MFI-40576-021 section from the dump it does now skip the 20 crap bytes at the start.
ReadFile(h,buffer,0x224,&read,NULL);
buffer[read] = '\0';
char newbuff[1000];
memcpy(newbuff,buffer+20,sizeof(buffer)-40);
Create a new buffer of size s-40, do a memcpy from the source+20 to the destination for size s.
int read; //assumed
char buffer[0x224];
ReadFile(h,buffer,0x224,&read,NULL);
if(read-40 <=0) return;
char *newvar = (char*)malloc(read - 40 + 1); // Fails with void to char error
strncpy(newvar, buffer+20, read - 40);
newvar[read-40] = '\0';
If altering the original buffer is acceptable, it may be easiest to use memmove:
char* string = /* insert code here to obtain the string */;
size_t len = strlen(string) - 40; // Number of bytes to move
memmove(string, string + 20, len); // Move string down by 20 bytes
memset(&string[len], 0, 40); // Clear out the remaining buffer
This general procedure will also work if the data in your buffer is not a string. You'll just need to replace the strlen call with whatever code is needed to obtain the original buffer's length.
Use strncpy:
char *string = // however you obtain the string
char *new = malloc(strlen(string) - 40 + 1);
strncpy(new, string + 20, strlen(string) - 40);

Resources