Per the manual, getline() and its sister function getdelim() will realloc() the buffer passed to them if the buffer isn't big enough for the next run of input between delimiters.
Is there any way to prevent this behaviour? Or to get those functions to work with statically allocated buffers, and signal a buffer full condition instead of trying to reallocate?
fgets() works with static buffers, but it has no support for arbitrary delimiter.
The POSIX specification for getline() stipulates:
ssize_t getline(char **restrict lineptr, size_t *restrict n, FILE *restrict stream);`…
The application shall ensure that
*lineptris a valid argument that could be passed to thefree()function. If*nis non-zero, the application shall ensure that*lineptreither points to an object of size at least*nbytes, or is a null pointer.
That requirement rules out the possibility of using buffers not allocated as if by calling malloc() — or a null pointer.
If you want a function that is a hybrid of getdelim() (which specifies the end-of-line character) and fgets() which does not do memory (re)allocation, then you have to write it yourself.
#include <stdio.h>
/* Add this declaration to an appropriate header and include it */
extern char *fgets_delim(char *buffer, int n, int delim, FILE *fp);
char *fgets_delim(char *buffer, int n, int delim, FILE *fp)
{
if (buffer == 0 || fp == 0 || n == 0)
return 0;
char *end = buffer + n - 1;
char *nxt = buffer;
int c;
while (nxt < end && (c = fgetc(fp)) != EOF)
{
*nxt++ = c;
if (c == delim)
break;
}
*nxt = '\0';
if (c == EOF && nxt == buffer)
return 0;
return buffer;
}
#ifdef TEST
#include <string.h>
int main(void)
{
char data[1024];
int fieldnum = 0;
while (fgets_delim(data, sizeof(data), ',', stdin) != 0)
printf("%d (%zu): [[%s]]\n", ++fieldnum, strlen(data), data);
return 0;
}
#endif /* TEST */
Given a home-brew random string generator and some futzing with newlines/null bytes, I got some sample output:
$ random -T '%12:2048l,' -n 3 -z | tr -d '\0' | fgets_delim67
1 (597): [[ohoEDGRxuefdpMLKaYHfFYpzJNVVfLpUMCzyyppKGAQJVdPnWbwvegYuBmdKqIKmZgsscFpLqdNzJFmYeHPbthVrhFlqzkRcWkfPtslhzXaNyGejBhqFzrbydDlMKljGzBSNTfklSjEmLCnOnipaiGrUkvAoIqWPLQIPJNRqfaZcBzYPGjuCdgcGNFnxbCWDTgKkWJZSeCkeuYiTZrPJlzPeQipMhHIdMBCOtZDdzxzLTounfGsEiLzOplcOyskuaHtMiwxlEZJkgkIawpnTjNnICojDwdfBStjfSrFMvcvkcvOukFPuuzXGpCBgbHkhDxnmuphIbCInCiHGFTIcREMCmcxePAHJtwuWMSJYjOlgoGaYFTlSxLvKcUDKBVBgrnqGgRxybiLeyBqRQqrUdJGyVgaUtIRexrigaNZuxcpsyCNvecqwoNTEEVXNLKeMNnTARZzAjIZmdVGyicnlmfwLVnGUtomRPVIzmQBZEtNwJKUwejBGyqdrVZLtIjkKQvIasqIVvZefuATJATNgDfIoouoCIrKqFitlmjvtbmxhIJtlSxQKRcDmBXPrysQrXbpOHrekGHjdeUIzztvu,]]
2 (1023): [[xajwWYzDPMmKxFCQwQychmpJzjHEkHQuvcKmVJpjglnzFOuHkGwyxuYsZWQayjcbRNfdnDoTvqPaTnMUONvKZuaLrFXZjsiuLSFiAJnVTOkgSqVEGSUwCvWlyxFNrTqoAAjqEaxgTMnmcJrPHzMbHATKAOuZcEBNANFbkafqgcgNbzHrVBKnAumanupiEMPKvaedTOQlgTJNcayTwUOCPqIlzxALhkeLdeaFeBIjJeHDzFpfAgatWdFZrpytBvLzkwwMlDZhZIUQADNmxolWhgkpAWkQyjtIrWFHIAQwHdGoCjnyBMfWgfLxNhQQVeKbPMneukjZeKMbhEbVspiYDjuBexyPYXCrWOXKeIUkgebLAWlzJigLbOSVeMrGNRGmhrbtCSpqUqFWxmMhzmiPTwJvfGgXZYWgAmSEDyvsRmfIaLXjypIDBOXAMyJJyuIWadDPqyhHgLhaENmVQzIuHHEaSlWkgwMPrfbPZNTagWHSDdtnzKUYRwPUabaDmXRNtnwfdycnqxnSEYGQOoGjkAAKAmQxethqjJeqQAgFlAMrtEWXjATSpYBbUIKeKvAcNsGBxHFnNevDTcEgLGBgemZuRcAafSxansOHsVBXLcDXvVftGzXLpluAGFMNMLsjZrpUlwNPDlbzRuGepItRHnWOebosqFKUMpwccKUMswBmNQrRNvKXCzFeaCbNMBxcgRRakncJcFqdSVDBqamgPnoahpfhFMuviFJekKjeUKHuhxYFMMRuAJNnvNgbOhLQLmsvGnkhoLofyzjGKEQFjvRAaJTvAOzluCvvRGOEyHgHOeJQFtymfFiuIZiGzKzVlefjHoUUcsRiOIjbQErNEUsdzcZgFaKtJhaQXiWsdDrOsPbKiQQbOKIRwcapKxwtKQvciWPsWHAjmHtjWJPesEZncOjUUVYKWVOvQqrCiwPYAMmbhCLeFTCzQtNAPEMlRFPWOkUoHjZCzBlReCpFxjOYbDDWFcnvraLoLUgVSiJOnorOBEVcTESxbVurVZv]]
3 (955): [[qdEmxjYaxIFmfGKtVXCJBurEoewWsmYDblvyeStbSZnqARPvfswgKLpQcCoIcIBZufoNWEeFRfkMNDIOGoPAlJijDQVqINGiygExpxZMvLAhNQunBvfLdicBcugrCYssiFlszFxQNPTWbTWOIoqfytdDRPKSygRgychwomXITjmRlubjtDzwPoqfhISHtnFYahXbwmBMCMuZaCmFVzCeVYLIvGrNyadekjdnYbhMoDADLZUaAabuIKnJJrvVLPsiHvfgWgacmEOREofejNfXKymcHumJMUxmiHPJBMPMunOQDYXAmaBtysTgEryzVoIQfLXVWkMGHGetRXwCqxNVCJOkfxYnjlhJpBaKxyJDXwGcaQQVzNmvgxTDJRSaVPeofFVznsWQJQnaLmDdAgHlUXnMZjNXqZOOtslaNVpXULZYivRMrBqAYFtBgPiMlVpyvVGPeAECRjzpaFxURgOvrTpfDqmdkwmdJDVIFcBwmkrRcExUGdqIqxgcdNFsdbXnMUcazWiXcxxfxxiihLMbwzDsinBbOdPiRtTebexyRJqgNZOZWmgjvmPnNYkMJfWfINUevNDhHTmJmGESetNAEDlqlRwdmVngVTInXArTDhGpkcyUQWdltVKcJClqXtKZUpoIROpqLsirIdtWwjRtmlIXIjZTUcGSVrykyHZyTBZfPvOEjhmxHnGdchIvqJUyRVLfgvUXHSYbaMkUHKpDxPFVwUmPdsNYqQgLsjubmIGNDxUkZBfoAvXXENrVSJukpOkSJhHtQVuwSSmuMZAizWjxxDmdvyAMbYvpUhtwoDHKudGvqRxWYFbRuIToHCruApJaSTAFOGNjrpSlpPUmRVFyIrpstdVswhGtQfPeMVcwIQgWsYtfPdRapRiHuTESuTNkgSpuwIXuXrCzQjecvnQXrSDGVvQzRNtOIyPGeMMDYhdvceJLXrNZmx,]]
4 (1023): [[qqMsddOBIyGfxGJJtzBlgqmAvbDByPBKkAcDcfOEymotMazQrnbZwIWEVaIUJeKXuojiCFwRCZudbXYUEfYIzedcseKyigRYbwSfeBIRzxYlyxjkdeOQVPEvskMmWzRDQcLYDbQIESzjNLlwaUIkvPhedEaRMvgzllmnmXrVjoKMALaxjkcOFBoTMpNvilxHveqBWFjNRwhGGqLezwoLrRNKZmZiSavMXuLkfiIDFdHvYVXSlplAbWDoGgBCyGfZvowjkqdHSJHcoLJMHQdVPSSgndhkOgIpxAFqaCSGscIslETMphYpwLLovcasKpanfezDdHwOZRxwHpUOKPbGgEYDsZdkjNjVrqchhUzkyhodgHJdIPbPiivFFOYDghifRaxaWBiTYlUSFQBWUjwMrWCgZROzoNnMispMIIxsGWNCtESlCpoQosCnuFfxaAKDeaLJULLJQARSgPqdQFtaxqAcmFqgighSlFjlqnqOGZFHoOiivqhupIvTvCdSJLoLYEmAOlkVQcOJAXSApsUsQiWkbRIUwKjdHCUvhJWVfthBCpLJjpZjsrhmMfeiLSbBVNVREaxpYBggZfmxpGarTPgSLtLKbYqRGsVdCyokEuzDEJgbWPfcxBpqlaHPxEDeGAkPjjDjAVLxygZHlUnOhATDZsNTsjHGgvvazNAMzHIvQjaLOXKSfyPiYowOLCnSjqbDbcEaPAHxDmdtvJsUpSZDdqZdIJwvAeFKdKoURpblvjOGWplGgVbwiIGFOLRyCfUfzNyutyleXGnKSufsOjcfeQsjEBpwNHGckguAQGZqiREoiWWSIRnXbhovHlgBmtnbfbpmprrZUgUPkCHTrDxlLZMIbsDhIEvwMsDjNKOWLXCArKJfFtpBiNfqvkhMoxiOqfJiNdYzXsDPZkUQgPHQgEkYrybGxcdYGwBJvDOpUmojqMeSgdvheQxckjusongcneDhXbXRiYrGlGiqOLJOdlIrBhPYDGrcBtuWutRaxJHtgwMGzjslWdzSVww]]
5 (1022): [[PbcosXvfycCaCmhcoallrXOYztMJNbtBfOqpfwYiVTYUyYiIHmqOmhEXqCtNDGNHzdGLeMFVWKwfjiyapGMtnYUpGyZHpwASQuPzLSzJcBHbQawREpvQBbBCXODNcaxogJHhCPpBkyZWkWWNtOKYAPBfexOZAIEbaWTcOXXDLRkxXCoEOUTTeiXbKVAdOeCPXanPtgybCReHmHkptZbcHlWbmdfWmoARiQomffyKbyjePFUaLNJNuzSYFFvyKhmvvEaxnJZjMeDZyNirCBbswsPGtoClFiLSlDFomGSIWbveYmETmfNHjVdWKLwywcKThWUXQKsvjTVCrKNaXkCxxlcwCPcpopcNyYEnuSBKwaPPyIHScmmUaIglXNBbDKYBYBMMMvJzuHknxEYGiOxkLTVkvaTGWURgWNGxQsGJncoZSHFaFyecfQBKrsCzqMkGwcUOiRZcKAfnTohWoumyJwmxFjNmcOmpPsvPnywCzrkhzmzBhiSnykfYlZBRuCmSqIaIwcMIdxxRvKBsaoYbyGdlfQwJTYRzlVdHRbYRPsNkfIKMalJNmuSOVepiiAihHTibVvAbrzPQwwaHoSBPsyzgcqscKBDupKpOYuWyDUPwHyKrqENLldJGFnttYuxNMsqgjsetGvqYMsnONSZnxmGDJVCqtKKIwFWJLNMWDiTHqZrQHkLqPEPLwTXlQmeDGgSNvkGndAXVPTVabVpfHEenGNXZZmpYMXEasEZDLryBWVnqnfDfZSbcSOpxjkdCLevtforvEOSheclrDpjqXhtfpvSYWaNgUCOsawcgfoDsutwBoNFwQqFQlsrqjQhKKDfyUsaemibkUoJYsUxiPbUdNwACjUJAedcnUVZFowsWEYlYyLUvVrbgKQxoYBQaGvSlOlltBjjtmanqBuoQVYRBCnlTKRYPrABztbIvSgsHumyxQCKXqMrNsJHcpvzMqbXryIzYfPUqYOEerWWYluGPdzyymlkPYcKyLFhFoWFZcrXTSRpYDKzyAFNKx,]]
$
Note that entry 2 read 1023 bytes but did not end with a comma (the specified delimiter); entry 3 completed the input with 955 more bytes. Similarly, entry 4 read 1023 bytes without finding a comma, and entry 5 read 1022 more bytes ending with a comma. This is exactly analogous to what you'd see with fgets() and long lines between newlines.
It would be feasible to modify the function to take a string instead of a single character as a delimiter (const char *delim), and revise the if (c == delim) test to read if (strchr(delim, c) != 0). You'd need to include <string.h> before the function, of course. This would allow you to stipulate comma or newline as the field separators, which is potentially more useful.
Another useful alternative would take a leaf out of the getline() / getdelim() book and return the length of the data that is read, so that embedded null bytes can be managed. I'm not clear why getline() and getdelim() return -1 rather than EOF (even though the two are usually the same). If I were returning the length, I'd return EOF rather than -1 as the indicator.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With