Re: String parsing program



pereges <Broli00@xxxxxxxxx> writes:

On Jul 4, 2:14 am, Ben Bacarisse <ben.use...@xxxxxxxxx> wrote:

<snip>
The simplest way to scan for a number whilst reporting bad input is to
use the signed strtol function. You check that errno has not been set
to ERANGE and that the end-pointer is not the string you passed in.
If you like, you can now check that nothing but white space is left in
the string. Finally, you confirm the input is the range your program
expects. The signed version lets you detect input like -123. The down
side is that you loose half the range of possible inputs. If that
matters, you can (probably) go up to strtoll.
<snip>


My input is of following format :

45 5666 16000

^^ All of that is just a single string. I need to read the three
numbers into 3 different size_t variables. There can be white space
amongst them but no alphabets or any other characters. It is possible
check if *endp character is nothing but white space (This must be done
when errno != ERANGE and s != endp i.e. when one usually expects
correct output), but any character other than that means data is
erroneous. With unsigned long, you can check if the first non white
space character is a '-' or not. This should solve the problem of
negative numbers as well and prevent their conversion to some unsigned
value before hand.

Here is one way based on using the widest signed type for input. It
is not ideal, but then without very details specs, what could be? If
you need to accept input right up to SIZE_MAX and you have an
implementation where intmax_t can't hold that value, then you will
need to use strtoumax and check for the - manually, so to speak. That
would not be a big change to parse_size.

#include <stdio.h>
#include <stdbool.h>
#include <inttypes.h>
#include <stdint.h>
#include <errno.h>
#include <ctype.h>

size_t parse_size(const char *num, const char **endp, bool *error)
{
char *ep;
errno = 0;
intmax_t imax = strtoimax(num, &ep, 10);
if (errno == ERANGE || imax < 0 || imax > SIZE_MAX) {
while (isspace(*num))
num++;
fprintf(stderr, "Input \"%.*s\" out of range.\n",
ep - num, num);
if (error)
*error = true;
}
else if (ep == num) {
/* Skip to the next space-delimited portion of the string. */
while (isspace(*ep))
ep++;
num = ep;
while (*ep != '\0' && !isspace(*ep))
ep++;
fprintf(stderr, "Input \"%.*s\" could not be converted.\n",
ep - num, num);
if (error)
*error = true;
}
if (endp)
*endp = ep;
return imax;
}

void parse_three_sizes(const char *input)
{
bool errors = false;
const char *ep;
size_t s1 = parse_size(input, &ep, &errors);
size_t s2 = parse_size(ep, &ep, &errors);
size_t s3 = parse_size(ep, &ep, &errors);

if (!errors) {
/* Check that everything parsed. */
const char *save_ep = ep;
while (isspace(*ep))
ep++;
if (*ep != '\0')
fprintf(stderr, "Superfluous input found: \"%s\"\n", save_ep);
printf("Got: %zu %zu %zu\n", s1, s2, s3);
}
}

int main(int argc, char **argv)
{
if (argc > 1)
parse_three_sizes(argv[1]);
return 0;
}



--
Ben.
.



Relevant Pages

  • Re: detabbing again
    ... as a pointer to pointer. ... Pointer to pointer to char. ... fprintf(stderr, " stderr has the following error %d\n ", errno); ... printf(" endp is %p\n", endp); ...
    (comp.lang.c)
  • Re: detabbing again
    ... stderr has the following error 0 ... errno is 0 ... endp is 003D2445 ... unsigned exptab(int n, char *path) ...
    (comp.lang.c)
  • Re: detabbing again
    ... want to remove the test on *endp in the previous if. ... errno is 34 ... int exptab(int n, const char *path) ...
    (comp.lang.c)
  • Re: detabbing again
    ... want to remove the test on *endp in the previous if. ... errno is 34 ... int exptab(int n, const char *path) ...
    (comp.lang.c)
  • Can I save ADODB.Command into a file?
    ... char buf; ... ULONG uread = 0; ... num = file.gcount; ... int main ...
    (microsoft.public.vc.atl)