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