1 /* pk-utils.c - Common utility functions for poke. */
2
3 /* Copyright (C) 2020, 2021 Jose E. Marchesi */
4
5 /* This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 #include <config.h>
20
21 #include <stdio.h>
22 #include <errno.h>
23 #include <unistd.h>
24 #include <stdint.h>
25 #include <stdlib.h>
26 #include <sys/stat.h>
27 #include <gettext.h>
28 #define _(str) dgettext (PACKAGE, str)
29 #include <stdarg.h> /* va_... */
30 #include <stddef.h> /* size_t */
31 #include <string.h> /* strcpy */
32 #include <ctype.h> /* isspace */
33
34 #include "pk-utils.h"
35
36 char *
pk_file_readable(const char * filename)37 pk_file_readable (const char *filename)
38 {
39 static char errmsg[4096];
40 struct stat statbuf;
41 if (0 != stat (filename, &statbuf))
42 {
43 char *why = strerror (errno);
44 snprintf (errmsg, 4096, _("Cannot stat %s: %s\n"), filename, why);
45 return errmsg;
46 }
47
48 if (S_ISDIR (statbuf.st_mode))
49 {
50 snprintf (errmsg, 4096, _("%s is a directory\n"), filename);
51 return errmsg;
52 }
53
54 if (access (filename, R_OK) != 0)
55 {
56 char *why = strerror (errno);
57 snprintf (errmsg, 4096, _("%s: file cannot be read: %s\n"),
58 filename, why);
59 return errmsg;
60 }
61
62 return 0;
63 }
64
65 #define PK_POW(NAME,TYPE) \
66 TYPE \
67 NAME (TYPE base, uint32_t exp) \
68 { \
69 TYPE result = 1; \
70 while (1) \
71 { \
72 if (exp & 1) \
73 result *= base; \
74 exp >>= 1; \
75 if (!exp) \
76 break; \
77 base *= base; \
78 } \
79 return result; \
80 }
81
PK_POW(pk_ipow,int64_t)82 PK_POW (pk_ipow, int64_t)
83 PK_POW (pk_upow, uint64_t)
84
85 #undef PK_POW
86
87 void
88 pk_print_binary (void (*puts_fn) (const char *str),
89 uint64_t val, int size, int sign)
90 {
91 char b[65];
92
93 for (int z = 0; z < size; z++) {
94 b[size-1-z] = ((val >> z) & 0x1) + '0';
95 }
96 b[size] = '\0';
97
98 puts_fn (b);
99
100 if (size == 64)
101 puts_fn (sign ? "L" : "UL");
102 else if (size == 16)
103 puts_fn (sign ? "H" : "UH");
104 else if (size == 8)
105 puts_fn (sign ? "B" : "UB");
106 else if (size == 4)
107 puts_fn (sign ? "N" : "UN");
108 }
109
110 /* Concatenate 2+ strings.
111 * Last argument must be NULL.
112 * Returns the malloc'ed concatenated string or NULL when out of memory.
113 */
114 char *
pk_str_concat(const char * s0,...)115 pk_str_concat (const char *s0, ...)
116 {
117 va_list args;
118 size_t len = 0;
119 const char *s;
120 char *d, *res;
121
122 va_start (args, s0);
123 for (s = s0; s; s = va_arg (args, const char *))
124 len += strlen (s);
125 va_end (args);
126
127 res = malloc (len + 1);
128 if (!res)
129 return NULL;
130
131 va_start (args, s0);
132 for (d = res, s = s0; s; s = va_arg (args, const char *))
133 {
134 strcpy (d, s);
135 d += strlen (s);
136 }
137 va_end (args);
138
139 return res;
140 }
141
142 /* Replace all occurrences of SEARCH within IN by REPLACE.
143 * Return IN when SEARCH was not found, else
144 * return a new allocated string with the replaced sequences.
145 * Return NULL on allocation failure.
146 */
147 char *
pk_str_replace(const char * in,const char * search,const char * replace)148 pk_str_replace (const char *in, const char *search, const char *replace)
149 {
150 const char *s, *e;
151 char *out, *d;
152 int num = 0;
153
154 /* count number of occurrences of 'search' within IN */
155 for (s = in; (s = strstr (s, search)); s++, num++)
156 ;
157
158 if (!num)
159 return (char *) in;
160
161 size_t search_len = strlen (search);
162 size_t replace_len = strlen (replace);
163 size_t in_len = strlen (in);
164
165 d = out = malloc (in_len + (replace_len - search_len) * num + 1);
166 if (!out)
167 return NULL;
168
169 for (s = in; (e = strstr (s, search)); s = e + search_len)
170 {
171 memcpy (d, s, e - s);
172 d += e - s;
173
174 memcpy (d, replace, replace_len);
175 d += replace_len;
176 }
177
178 /* copy rest of IN + trailing zero */
179 strcpy (d, s);
180
181 return out;
182 }
183
184 void
pk_str_trim(char ** str)185 pk_str_trim (char **str)
186 {
187 char *end;
188
189 while (isspace (**str))
190 (*str)++;
191 end = *str + strlen (*str);
192 while (isspace (*--end));
193 *(end + 1) = '\0';
194 }
195