glib-mini.c revision fd77237e061fbae1abac9466c4de604137ffbb5d
1// Copyright 2014 The Android Open Source Project
2//
3// This software is licensed under the terms of the GNU General Public
4// License version 2, as published by the Free Software Foundation, and
5// may be copied, distributed, and modified under those terms.
6//
7// This program is distributed in the hope that it will be useful,
8// but WITHOUT ANY WARRANTY; without even the implied warranty of
9// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10// GNU General Public License for more details.
11
12#include <glib.h>
13
14#include <limits.h>
15#include <stdarg.h>
16#include <stdio.h>
17#include <stdlib.h>
18#include <string.h>
19
20// Print a panic message then exit the program immediately.
21void g_panic(const char* fmt, ...){
22  va_list args;
23  fprintf(stderr, "MiniGLib:PANIC: ");
24  va_start(args, fmt);
25  vfprintf(stderr, fmt, args);
26  va_end(args);
27  exit(1);
28}
29
30
31// Heap allocation.
32
33void* g_malloc(size_t size) {
34  if (size == 0)
35    return NULL;
36
37  void* ptr = malloc(size);
38  if (ptr == NULL)
39    g_panic("Can't allocate %zu bytes!\n", size);
40
41  return ptr;
42}
43
44
45void* g_malloc0(size_t size) {
46  void* ptr = g_malloc(size);
47  if (ptr == NULL)
48    return NULL;
49
50  memset(ptr, 0, size);
51  return ptr;
52}
53
54
55void* g_realloc(void* ptr, size_t size) {
56  if (size == 0) {
57    g_free(ptr);
58    return NULL;
59  }
60  void* new_ptr = realloc(ptr, size);
61  if (new_ptr == NULL)
62    g_panic("Can't reallocate pointer %p to %zu bytes!\n", ptr, size);
63
64  return new_ptr;
65}
66
67
68void g_free(void* ptr) {
69  if (ptr)
70    free(ptr);
71}
72
73// Strings.
74
75char* g_strdup(const char* str) {
76  if (str == NULL)
77    return NULL;
78
79  size_t len = strlen(str);
80  char* copy = g_malloc(len + 1);
81  memcpy(copy, str, len + 1);
82  return copy;
83}
84
85
86char* g_strndup(const char* str, size_t size) {
87  const char *end = memchr(str, 0, size);
88  char *copy;
89
90  if (end)
91    size = end - str;
92
93  copy = g_malloc(size + 1);
94  memcpy(copy, str, size);
95  copy[size] = 0;
96  return copy;
97}
98
99
100char* g_strdup_printf(const char* fmt, ...) {
101  char* result;
102  va_list args;
103  va_start(args, fmt);
104  g_vasprintf(&result, fmt, args);
105  va_end(args);
106  return result;
107}
108
109
110char* g_strdup_vprintf(const char* fmt, va_list args) {
111  char* result;
112  g_vasprintf(&result, fmt, args);
113  return result;
114}
115
116
117int g_vasprintf(char** str, const char* fmt, va_list args) {
118#ifdef _WIN32
119  // On Win32, vsnprintf() is broken and always returns -1 in case of truncation,
120  // so make an educated guess, and try again if that fails with a larger pool.
121  size_t capacity = 128;
122  char* buffer = g_malloc(capacity);
123  for (;;) {
124    va_list args2;
125    va_copy(args2, args);
126    int len = vsnprintf(buffer, capacity, fmt, args2);
127    if (len >= 0) {
128      *str = buffer;
129      return len;
130    }
131    va_end(args2);
132
133    capacity *= 2;
134    if (capacity > INT_MAX)
135      g_panic("Formatted string is too long!\n");
136
137    buffer = g_realloc(buffer, capacity);
138  }
139#else
140  // On other systems, vsnprintf() works properly and returns the size of the
141  // formatted string without truncation.
142  va_list args2;
143  va_copy(args2, args);
144  int len = vsnprintf(NULL, 0, fmt, args2);
145  va_end(args2);
146  if (len < 0)
147    g_panic("Can't format string!\n");
148
149  char* result = g_malloc(len + 1);
150  va_copy(args2, args);
151  vsnprintf(result, (size_t)len, fmt, args2);
152  va_end(args2);
153
154  *str = result;
155  return len;
156#endif
157}
158