Edit

kc3-lang/kc3/libc3/buf_parse_s16.c

Branch :

  • libc3/buf_parse_s16.c
  • /* c3
     * Copyright 2022,2023 kmx.io <contact@kmx.io>
     *
     * Permission is hereby granted to use this software granted the above
     * copyright notice and this permission paragraph are included in all
     * copies and substantial portions of this software.
     *
     * THIS SOFTWARE IS PROVIDED "AS-IS" WITHOUT ANY GUARANTEE OF
     * PURPOSE AND PERFORMANCE. IN NO EVENT WHATSOEVER SHALL THE
     * AUTHOR BE CONSIDERED LIABLE FOR THE USE AND PERFORMANCE OF
     * THIS SOFTWARE.
     */
    /* Gen from buf_parse_s.c.in BITS=16 bits=16 */
    #include "buf.h"
    #include "buf_parse.h"
    #include "buf_save.h"
    #include "c3_main.h"
    #include "ceiling.h"
    #include "str.h"
    
    sw buf_parse_s16 (s_buf *buf, s16 *dest)
    {
      s_buf_save digits;
      e_bool negative = false;
      sw r;
      sw r1;
      sw result = 0;
      s_buf_save save;
      s16 tmp;
      s16 tmp1;
      buf_save_init(buf, &save);
      if ((r = buf_read_1(buf, "-")) < 0)
        goto clean;
      if (r > 0) {
        result += r;
        negative = true;
      }
      if ((r = buf_read_1(buf, "0b")) < 0)
        goto restore;
      if (r > 0) {
        result += r;
        if ((r = buf_parse_s16_base(buf, &g_c3_base_binary,
                                        negative, dest)) <= 0)
          goto restore;
        result += r;
        goto ok;
      }
      if ((r = buf_read_1(buf, "0o")) < 0)
        goto restore;
      if (r > 0) {
        result += r;
        if ((r = buf_parse_s16_base(buf, &g_c3_base_octal,
                                        negative, dest)) <= 0)
          goto restore;
        result += r;
        goto ok;
      }
      if ((r = buf_read_1(buf, "0x")) < 0)
        goto restore;
      if (r > 0) {
        result += r;
        buf_save_init(buf, &digits);
        if ((r = buf_parse_s16_base(buf,
                                        g_c3_bases_hexadecimal,
                                        negative, &tmp)) < 0) {
          buf_save_clean(buf, &digits);
          goto restore;
        }
        buf_save_restore_rpos(buf, &digits);
        buf_save_clean(buf, &digits);
        if ((r1 = buf_parse_s16_base(buf, g_c3_bases_hexadecimal + 1,
                                         negative, &tmp1)) < 0) {
          r = r1;
          goto restore;
        }
        if (r == 0 && r1 == 0) {
          if (negative)
            warnx("invalid number: -0x");
          else
            warnx("invalid number: 0x");
          goto restore;
        }
        if (r > r1) {
          result += r;
          *dest = tmp;
        }
        else {
          result += r1;
          *dest = tmp1;
        }
        goto ok;
      }
      if ((r = buf_parse_s16_base(buf, &g_c3_base_decimal,
                                      negative, dest)) <= 0)
        goto restore;
      result += r;
     ok:
      r = result;
      goto clean;
     restore:
      buf_save_restore_rpos(buf, &save);
     clean:
      buf_save_clean(buf, &save);
      return r;
    }
    
    sw buf_parse_s16_base (s_buf *buf, const s_str *base,
                               bool negative, s16 *dest)
    {
      u8 digit;
      sw r;
      sw radix;
      sw result = 0;
      s_buf_save save;
      u16 u = 0;
      assert(buf);
      assert(base);
      assert(dest);
      buf_save_init(buf, &save);
      radix = str_length_utf8(base);
      if (radix < 2 || radix > S16_MAX) {
        buf_save_clean(buf, &save);
        assert(! "buf_parse_s16_base: invalid radix");
        errx(1, "buf_parse_s16_base: invalid radix: %ld",
             radix);
        return -1;
      }
      while ((r = buf_parse_digit(buf, base, &digit)) > 0) {
        result += r;
        if (digit >= radix) {
          buf_save_clean(buf, &save);
          assert(! "buf_parse_s16_base: digit greater than or equal to"
                 " radix");
          errx(1, "buf_parse_s16_base: digit greater than or equal to"
               " radix: %u",
               digit);
          return -1;
        }
        if (u > (u16) ceiling_s16 (S16_MAX, radix)) {
          warnx("buf_parse_s16_base: *: integer overflow");
          r = -1;
          goto restore;
        }
        u *= radix;
        if (negative ? -u < (u16) S16_MIN + digit :
            u > (u16) (S16_MAX - digit)) {
          warnx("buf_parse_s16_base: +: integer overflow");
          r = -1;
          goto restore;
        }
        u += digit;
      }
      *dest = negative ? -u : u;
      r = result;
      goto clean;
     restore:
      buf_save_restore_rpos(buf, &save);
     clean:
      buf_save_clean(buf, &save);
      return r;
    }