Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
path: root/nss/buf.c
blob: 75c62f9fc8fdb5a681bcc20e3861a89e494102af (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
#define _GNU_SOURCE
#include <errno.h>
#include <stdio.h>
#include <syslog.h>
#include <string.h>
#include <stdarg.h>
#include <stdlib.h>

#include "cgen.h"
#include "buf.h"

#include "config/debug.h"


int write_buf(char** buf, size_t * buflen, const char* val)
{
  /* write_buf will not write outside of (*buf)[0..(*buflen-1)]
   * if *buflen > strlen(val), then write_buf will ensure that *buf points to a null-terminated string.
   * on success, write_buf will advance *buf to the next free char,
   *                            set *buflen to indicate the quantity of remaining space,
   *                            and return 0.
   * on error, write_buf will set errno, return 1, and will not modify *buf or *buflen.
   * *buf and val should not overlap.
   */

  LET(size_t copy_amt = strlen(val) + 1, copy_amt == 0,
      "Integer overflow.", out_err_overflow);

  if (*buflen < copy_amt)
    goto out_err_range;

  memcpy(*buf, val, copy_amt);

  *buf += copy_amt;
  *buflen -= copy_amt;
  return 0;

out_err_overflow:
  errno = EOVERFLOW;
  return 1;

out_err_range:
  errno = ERANGE;
  return 1;
}

int format_buf(char** buf, size_t* buflen, const char* fmt, ...)
{
  /* format_buf will not write outside of (*buf)[0..(*buflen-1)]
   * if *buflen > 0, format_buf will ensure that *buf points to a null-terminated string.
   * on success, format_buf will advance *buf to the next free char,
   *                             set *buflen to indicate the quantity of remaining space,
   *                             and return 0.
   * on error, format_buf will set errno, return 1, and will not modify *buf or *buflen.
   * *buf should not overlap with fmt or any optional arguments.
   */
  if (*buflen < 1)
  {
    errno = ERANGE;
    return 1;
  }

  va_list ap;
  va_start(ap, fmt);

  int status = vsnprintf(*buf, *buflen, fmt, ap);
  int err = errno;

  va_end(ap);

  if (status < 0)
    goto out_err;

  size_t written = (size_t) status;

  err = ERANGE;
  if (written >= *buflen)
    goto out_err;

  err = EOVERFLOW;
  LET(written = written + 1, written == 0,
      "Integer overflow.", out_err);

  *buf += written;
  *buflen -= written;
  return 0;

out_err:
  (*buf)[*buflen-1] = '\0';
  errno = err;
  return 1;
}