summaryrefslogtreecommitdiffstats
path: root/lib/tstring.h
blob: 4dd45edb150b320d5996162d5ebc3a9ba82ca9d2 (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
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
/* Temporary string handling -- header
 * Copyright (C) 2009 Chris Hall (GMCH), Highwayman
 *
 * This file is part of GNU Zebra.
 *
 * GNU Zebra is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published
 * by the Free Software Foundation; either version 2, or (at your
 * option) any later version.
 *
 * GNU Zebra is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with GNU Zebra; see the file COPYING.  If not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 */

#ifndef _ZEBRA_TSTRING_H
#define _ZEBRA_TSTRING_H

#include "misc.h"
#include "zassert.h"
#include "memory.h"

/*==============================================================================
 * tstrings are allocated on the stack, but if (unexpectedly) the standard
 * size is not enough, then they can be allocated dynamically.
 *
 * To declare a "tstring":
 *
 *   tstring(foo, 64) ;   // creates a "tstring" variable called "foo"
 *                        // with 64 char buffer.
 *
 * Can then:
 *
 *   s = tstring_set_len(foo, n) ;  // ensures have buffer for n+1 chars
 *   s = tstring_set(foo, "...") ;  // copies "..." (with '\0') to buffer
 *   s = tstring_set_n(foo, q, n) ; // copies n characters from q to buffer
 *                                     and '\0' terminates
 *
 * If can fit stuff in the buffer, will do so.  Otherwise will allocate an
 * MTYPE_TMP buffer to work in.
 *
 * And before leaving the scope of "foo" must:
 *
 *   tstring_free(foo) ;    // releases any dynamically allocated memory.
 */

struct tstring
{
  usize   size ;
  char*   str ;
  char*   alloc ;
} ;

typedef struct tstring tstring[1] ;

/* tstring(foo, 93) ;   -- declare the variable "foo".          */
#define tstring_t(name, sz) \
  char      _zlxq_##name##_b[ ((sz) + 7) & 0xFFFFFFF8] ; \
  tstring name = { { .size  = ((sz) + 7) & 0xFFFFFFF8, \
                                      .str   = _zlxq_##name##_b, \
                                      .alloc = NULL } }

/*------------------------------------------------------------------------------
 * Ensure the tstring "foo" can accomodate at least "len" characters plus the
 * terminating '\0'.
 *
 * Returns: address of buffer
 *
 * NB: address of buffer may not be the same as returned by a previous operation
 *     on foo.  Also, previous contents of foo may be lost.
 */
Inline char*
tstring_set_len(struct tstring* ts, usize len)
{
  if (len >= ts->size)
    {
      ts->size = len + 1 ;
      ts->str  = ts->alloc = XREALLOC(MTYPE_TMP, ts->alloc, len + 1) ;
    } ;

  return ts->str ;
} ;

/*------------------------------------------------------------------------------
 * Copy "len" characters from "src" to the tstring "foo", and append a
 * terminating '\0'.
 *
 * The "src" address is ignored if "len" == 0 (sets "foo" to be empty string).
 *
 * Returns: address of buffer
 *
 * NB: address of buffer may not be the same as returned by a previous operation
 *     on foo.  Also, previous contents of foo may be lost.
 */
static inline char*
tstring_set_n(struct tstring* ts, const char* str, usize len)
{
  char* tss = tstring_set_len(ts, len) ;

  if (len > 0)
    memcpy(tss, str, len) ;
  *(tss + len) = '\0' ;

  return tss ;
} ;

/*------------------------------------------------------------------------------
 * Copy the string "str" to the tstring "foo", with terminating '\0'.
 *
 * If "str" is NULL, sets "foo" to be an empty string.
 *
 * Returns: address of buffer
 *
 * NB: address of buffer may not be the same as returned by a previous operation
 *     on foo.  Also, previous contents of foo may be lost.
 */
static inline char*
tstring_set(struct tstring* ts, const char* str)
{
  return tstring_set_n(ts, str, (str != NULL) ? strlen(str) : 0) ;
} ;

/*------------------------------------------------------------------------------
 * If have dynamically allocated buffer for tstring "foo", release it now.
 */
static inline void
tstring_free(struct tstring* ts)
{
  if (ts->alloc != NULL)
    XFREE(MTYPE_TMP, ts->alloc) ;       /* sets ts->alloc NULL  */
} ;

#endif /* _ZEBRA_TSTRING_H */