1 /*
2 * MOC - music on console
3 * Copyright (C) 2004 - 2005 Damian Pietras <daper@daper.net>
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 2 of the License, or
8 * (at your option) any later version.
9 *
10 */
11
12 #ifdef HAVE_CONFIG_H
13 # include "config.h"
14 # undef malloc
15 #endif
16
17 #include <stdio.h>
18 #include <stdarg.h>
19 #include <stdlib.h>
20 #include <string.h>
21 #include <strings.h>
22 #include <ctype.h>
23 #include <assert.h>
24 #include <unistd.h>
25 #include <sys/types.h>
26 #include <pwd.h>
27 #include <errno.h>
28 #ifdef HAVE_SYSLOG
29 #include <syslog.h>
30 #endif
31
32 #include "common.h"
33 #include "server.h"
34 #include "interface.h"
35 #include "interface_elements.h"
36 #include "log.h"
37 #include "options.h"
38
39 static int im_server = 0; /* Am I the server? */
40
error(const char * format,...)41 void error (const char *format, ...)
42 {
43 va_list va;
44 char *msg;
45
46 va_start (va, format);
47 msg = format_msg_va (format, va);
48 va_end (va);
49
50 if (im_server)
51 server_error (msg);
52 else
53 interface_error (msg);
54
55 free (msg);
56 }
57
58 /* End program with a message. Use when an error occurs and we can't recover.
59 * If we're the server, then also log the message to the system log. */
internal_fatal(const char * file ATTR_UNUSED,int line ATTR_UNUSED,const char * function ATTR_UNUSED,const char * format,...)60 void internal_fatal (const char *file ATTR_UNUSED, int line ATTR_UNUSED,
61 const char *function ATTR_UNUSED, const char *format, ...)
62 {
63 va_list va;
64 char *msg;
65
66 windows_reset ();
67
68 va_start (va, format);
69 msg = format_msg_va (format, va);
70 fprintf (stderr, "\nFATAL_ERROR: %s\n\n", msg);
71 #ifndef NDEBUG
72 internal_logit (file, line, function, "FATAL ERROR: %s", msg);
73 #endif
74 va_end (va);
75
76 log_close ();
77
78 #ifdef HAVE_SYSLOG
79 if (im_server)
80 syslog (LOG_USER|LOG_ERR, "%s", msg);
81 #endif
82
83 free (msg);
84
85 exit (EXIT_FATAL);
86 }
87
xmalloc(size_t size)88 void *xmalloc (size_t size)
89 {
90 void *p;
91
92 #ifndef HAVE_MALLOC
93 size = MAX(1, size);
94 #endif
95
96 if ((p = malloc(size)) == NULL)
97 fatal ("Can't allocate memory!");
98 return p;
99 }
100
xcalloc(size_t nmemb,size_t size)101 void *xcalloc (size_t nmemb, size_t size)
102 {
103 void *p;
104
105 if ((p = calloc(nmemb, size)) == NULL)
106 fatal ("Can't allocate memory!");
107 return p;
108 }
109
xrealloc(void * ptr,const size_t size)110 void *xrealloc (void *ptr, const size_t size)
111 {
112 void *p;
113
114 if ((p = realloc(ptr, size)) == NULL && size != 0)
115 fatal ("Can't allocate memory!");
116 return p;
117 }
118
xstrdup(const char * s)119 char *xstrdup (const char *s)
120 {
121 char *n;
122
123 if (s && (n = strdup(s)) == NULL)
124 fatal ("Can't allocate memory!");
125
126 return s ? n : NULL;
127 }
128
set_me_server()129 void set_me_server ()
130 {
131 im_server = 1;
132 }
133
str_repl(char * target,const char * oldstr,const char * newstr)134 char *str_repl (char *target, const char *oldstr, const char *newstr)
135 {
136 size_t oldstr_len = strlen(oldstr);
137 size_t newstr_len = strlen(newstr);
138 size_t target_len = strlen(target);
139 size_t target_max = target_len;
140 size_t s, p;
141 char *needle;
142 for (s = 0; (needle = strstr(target + s, oldstr)) != NULL; s = p + newstr_len) {
143 target_len += newstr_len - oldstr_len;
144 p = needle - target;
145 if (target_len + 1 > target_max) {
146 target_max = MAX(target_len + 1, target_max * 2);
147 target = xrealloc(target, target_max);
148 }
149 memmove(target + p + newstr_len, target + p + oldstr_len, target_len - p - newstr_len + 1);
150 memcpy(target + p, newstr, newstr_len);
151 }
152 target = xrealloc(target, target_len + 1);
153 return target;
154 }
155
156 /* Extract a substring starting at 'src' for length 'len' and remove
157 * any leading and trailing whitespace. Return NULL if unable. */
trim(const char * src,size_t len)158 char *trim (const char *src, size_t len)
159 {
160 char *result;
161 const char *first, *last;
162
163 for (last = &src[len - 1]; last >= src; last -= 1) {
164 if (!isspace (*last))
165 break;
166 }
167 if (last < src)
168 return NULL;
169
170 for (first = src; first <= last; first += 1) {
171 if (!isspace (*first))
172 break;
173 }
174 if (first > last)
175 return NULL;
176
177 last += 1;
178 result = xcalloc (last - first + 1, sizeof (char));
179 strncpy (result, first, last - first);
180 result[last - first] = 0x00;
181
182 return result;
183 }
184
185 /* Format argument values according to 'format' and return it as a
186 * malloc()ed string. */
format_msg(const char * format,...)187 char *format_msg (const char *format, ...)
188 {
189 char *result;
190 va_list va;
191
192 va_start (va, format);
193 result = format_msg_va (format, va);
194 va_end (va);
195
196 return result;
197 }
198
199 /* Format a vararg list according to 'format' and return it as a
200 * malloc()ed string. */
format_msg_va(const char * format,va_list va)201 char *format_msg_va (const char *format, va_list va)
202 {
203 int len;
204 char *result;
205 va_list va_copy;
206
207 va_copy (va_copy, va);
208 len = vsnprintf (NULL, 0, format, va_copy) + 1;
209 va_end (va_copy);
210 result = xmalloc (len);
211 vsnprintf (result, len, format, va);
212
213 return result;
214 }
215
216 /* Return true iff the argument would be a syntactically valid symbol.
217 * (Note that the so-called "peculiar indentifiers" are disallowed here.) */
is_valid_symbol(const char * candidate)218 bool is_valid_symbol (const char *candidate)
219 {
220 size_t len;
221 bool result;
222 const char *first = "+-.0123456789@";
223 const char *valid = "abcdefghijklmnopqrstuvwxyz"
224 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
225 "0123456789"
226 "@?!.+-*/<=>:$%^&_~";
227
228 result = false;
229 len = strlen (candidate);
230 if (len > 0 && len == strspn (candidate, valid) &&
231 strchr (first, candidate[0]) == NULL)
232 result = true;
233
234 return result;
235 }
236
237 /* Return path to a file in MOC config directory. NOT THREAD SAFE */
create_file_name(const char * file)238 char *create_file_name (const char *file)
239 {
240 static char fname[PATH_MAX];
241 char *moc_dir = options_get_str ("MOCDir");
242
243 if (moc_dir[0] == '~') {
244 if (snprintf(fname, sizeof(fname), "%s/%s/%s", get_home (),
245 (moc_dir[1] == '/') ? moc_dir + 2 : moc_dir + 1,
246 file)
247 >= (int)sizeof(fname))
248 fatal ("Path too long!");
249 }
250 else if (snprintf(fname, sizeof(fname), "%s/%s", moc_dir, file)
251 >= (int)sizeof(fname))
252 fatal ("Path too long!");
253
254 return fname;
255 }
256
257 /* Convert time in second to min:sec text format. buff must be 6 chars long. */
sec_to_min(char * buff,const int seconds)258 void sec_to_min (char *buff, const int seconds)
259 {
260 assert (seconds >= 0);
261
262 if (seconds < 6000) {
263
264 /* the time is less than 99:59 */
265 int min, sec;
266
267 min = seconds / 60;
268 sec = seconds % 60;
269
270 snprintf (buff, 6, "%02d:%02d", min, sec);
271 }
272 else if (seconds < 10000 * 60)
273
274 /* the time is less than 9999 minutes */
275 snprintf (buff, 6, "%4dm", seconds/60);
276 else
277 strcpy (buff, "!!!!!");
278 }
279
280 /* Determine and return the path of the user's home directory. */
get_home()281 const char *get_home ()
282 {
283 static const char *home = NULL;
284 struct passwd *passwd;
285
286 if (home == NULL) {
287 home = xstrdup (getenv ("HOME"));
288 if (home == NULL) {
289 errno = 0;
290 passwd = getpwuid (geteuid ());
291 if (passwd)
292 home = xstrdup (passwd->pw_dir);
293 else
294 if (errno != 0)
295 logit ("getpwuid(%d): %s", geteuid (), strerror (errno));
296 }
297 }
298
299 return home;
300 }
301