• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #include <stdio.h>
2 #include <errno.h>
3 #include <fcntl.h>
4 #include <unistd.h>
5 #include <stdlib.h>
6 #include <stdarg.h>
7 #include <string.h>
8 #include <limits.h>
9 #include <sys/time.h>
10 #include <time.h>
11 #include <sys/types.h>
12 #include <sys/wait.h>
13 #include <fcntl.h>
14 #include <sys/stat.h>
15 #include <sys/mman.h>
16 #include <sys/file.h>
17 #include <ctype.h>
18 #include <dlfcn.h>
19 #include <dirent.h>
20 #include <signal.h>
21 
22 #include <gmain.h>
23 
24 struct timeout {
25 	guint id;
26 	guint interval;
27 	struct timeval expiration;
28 	gpointer data;
29 	GSourceFunc function;
30 };
31 
32 struct _GIOChannel {
33 	int fd;
34 	int ref_count;
35 	gboolean closed;
36 	gboolean close_on_unref;
37 };
38 
39 struct child_watch {
40 	guint id;
41 	GPid pid;
42 	GChildWatchFunc function;
43 	gpointer user_data;
44 };
45 
46 struct _GMainContext {
47 	guint next_id;
48 	glong next_timeout;
49 
50 	GSList *timeouts;
51 	GSList *proc_timeouts;
52 	gboolean timeout_lock;
53 
54 	GSList *io_watches;
55 	GSList *proc_io_watches;
56 	gboolean io_lock;
57 
58 	GSList *child_watches;
59 	GSList *proc_child_watches;
60 	gboolean child_lock;
61 };
62 
63 struct _GMainLoop {
64 	gboolean is_running;
65 	GMainContext *context;
66 };
67 
68 struct _GDir
69 {
70 	DIR *dirp;
71 };
72 
g_io_channel_read(GIOChannel * channel,gchar * buf,gsize count,gsize * bytes_read)73 GIOError g_io_channel_read(GIOChannel *channel, gchar *buf, gsize count,
74 				gsize *bytes_read)
75 {
76 	int fd = channel->fd;
77 	gssize result;
78 
79 	if (channel->closed)
80 		return G_IO_STATUS_ERROR;
81 
82 	/* At least according to the Debian manpage for read */
83 	if (count > SSIZE_MAX)
84 		count = SSIZE_MAX;
85 
86 retry:
87 	result = read (fd, buf, count);
88 
89 	if (result < 0) {
90 		*bytes_read = 0;
91 
92 		switch (errno) {
93 #ifdef EINTR
94 		case EINTR:
95 			goto retry;
96 #endif
97 #ifdef EAGAIN
98 		case EAGAIN:
99 			return G_IO_STATUS_AGAIN;
100 #endif
101 		default:
102 			return G_IO_STATUS_ERROR;
103 		}
104 	}
105 
106 	*bytes_read = result;
107 
108 	return (result > 0) ? G_IO_STATUS_NORMAL : G_IO_STATUS_EOF;
109 }
110 
g_io_channel_write(GIOChannel * channel,const gchar * buf,gsize count,gsize * bytes_written)111 GIOError g_io_channel_write(GIOChannel *channel, const gchar *buf, gsize count,
112 				gsize *bytes_written)
113 {
114 	int fd = channel->fd;
115 	gssize result;
116 
117 	if (channel->closed)
118 		return G_IO_STATUS_ERROR;
119 
120 	/* At least according to the Debian manpage for read */
121 	if (count > SSIZE_MAX)
122 		count = SSIZE_MAX;
123 
124 retry:
125 	result = write(fd, buf, count);
126 
127 	if (result < 0) {
128 		*bytes_written = 0;
129 
130 		switch (errno) {
131 #ifdef EINTR
132 		case EINTR:
133 			goto retry;
134 #endif
135 #ifdef EAGAIN
136 		case EAGAIN:
137 			return G_IO_STATUS_AGAIN;
138 #endif
139 		default:
140 			return G_IO_STATUS_ERROR;
141 		}
142 	}
143 
144 	*bytes_written = result;
145 
146 	return (result > 0) ? G_IO_STATUS_NORMAL : G_IO_STATUS_EOF;
147 }
148 
g_io_channel_close(GIOChannel * channel)149 void g_io_channel_close(GIOChannel *channel)
150 {
151 	if (!channel || channel->closed)
152 		return;
153 
154 	close(channel->fd);
155 
156 	channel->closed = TRUE;
157 }
158 
g_io_channel_unref(GIOChannel * channel)159 void g_io_channel_unref(GIOChannel *channel)
160 {
161 	if (!channel)
162 		return;
163 
164 	if (--channel->ref_count > 0)
165 		return;
166 
167 	if (channel->close_on_unref && channel->fd >= 0)
168 		g_io_channel_close(channel);
169 
170 	g_free(channel);
171 }
172 
g_io_channel_ref(GIOChannel * channel)173 GIOChannel *g_io_channel_ref(GIOChannel *channel)
174 {
175 	channel->ref_count++;
176 	return channel;
177 }
178 
g_io_channel_unix_new(int fd)179 GIOChannel *g_io_channel_unix_new(int fd)
180 {
181 	GIOChannel *channel;
182 
183 	channel = g_new0(GIOChannel, 1);
184 
185 	channel->fd = fd;
186 	channel->ref_count = 1;
187 
188 	return channel;
189 }
190 
g_io_channel_set_close_on_unref(GIOChannel * channel,gboolean do_close)191 void g_io_channel_set_close_on_unref(GIOChannel *channel, gboolean do_close)
192 {
193 	channel->close_on_unref = do_close;
194 }
195 
g_io_channel_unix_get_fd(GIOChannel * channel)196 gint g_io_channel_unix_get_fd(GIOChannel *channel)
197 {
198 	if (channel->closed)
199 		return -1;
200 
201 	return channel->fd;
202 }
203 
set_flags(int fd,long flags)204 static int set_flags(int fd, long flags)
205 {
206 	long arg;
207 
208 	arg = fcntl(fd, F_GETFL);
209 	if (arg < 0)
210 		return -errno;
211 
212 	/* Return if already set */
213 	if ((arg & flags) == flags)
214 		return 0;
215 
216 	arg |= flags;
217 	if (fcntl(fd, F_SETFL, arg) < 0)
218 		return -errno;
219 
220 	return 0;
221 }
222 
g_io_channel_set_flags(GIOChannel * channel,GIOFlags flags,GError ** error)223 GIOStatus g_io_channel_set_flags(GIOChannel *channel, GIOFlags flags,
224 				GError **error)
225 {
226 	int err, fd;
227 	long fd_flags = 0;
228 
229 	if (!channel || channel->closed)
230 		return G_IO_STATUS_ERROR;
231 
232 	fd = g_io_channel_unix_get_fd(channel);
233 
234 	if (flags & G_IO_FLAG_APPEND)
235 		fd_flags |= O_APPEND;
236 	if (flags & G_IO_FLAG_NONBLOCK)
237 		fd_flags |= O_NONBLOCK;
238 
239 	err = set_flags(fd, fd_flags);
240 	if (err < 0) {
241 		if (error)
242 			g_set_error(error, 0, 0, "Unable to set flags: %s",
243 					strerror(-err));
244 		return G_IO_STATUS_ERROR;
245 	}
246 
247 	return G_IO_STATUS_NORMAL;
248 }
249 
250 struct io_watch {
251 	guint id;
252 	GIOChannel *channel;
253 	gint priority;
254 	GIOCondition condition;
255 	short *revents;
256 	GIOFunc func;
257 	gpointer user_data;
258 	GDestroyNotify destroy;
259 };
260 
261 static GMainContext *default_context = NULL;
262 
watch_free(struct io_watch * watch)263 static void watch_free(struct io_watch *watch)
264 {
265 	if (watch->destroy)
266 		watch->destroy(watch->user_data);
267 	g_io_channel_unref(watch->channel);
268 	g_free(watch);
269 }
270 
g_main_context_default()271 static GMainContext *g_main_context_default()
272 {
273 	if (default_context)
274 		return default_context;
275 
276 	default_context = g_new0(GMainContext, 1);
277 
278 	default_context->next_timeout = -1;
279 	default_context->next_id = 1;
280 
281 	return default_context;
282 }
283 
g_io_remove_watch(GMainContext * context,guint id)284 static gboolean g_io_remove_watch(GMainContext *context, guint id)
285 {
286 	GSList *l;
287 	struct io_watch *w;
288 
289 	for (l = context->io_watches; l != NULL; l = l->next) {
290 		w = l->data;
291 
292 		if (w->id != id)
293 			continue;
294 
295 		context->io_watches = g_slist_remove(context->io_watches, w);
296 		watch_free(w);
297 
298 		return TRUE;
299 	}
300 
301 	for (l = context->proc_io_watches; l != NULL; l = l->next) {
302 		w = l->data;
303 
304 		if (w->id != id)
305 			continue;
306 
307 		context->proc_io_watches = g_slist_remove(context->proc_io_watches, w);
308 		watch_free(w);
309 
310 		return TRUE;
311 	}
312 
313 	return FALSE;
314 }
315 
g_timeout_remove(GMainContext * context,const guint id)316 static gboolean g_timeout_remove(GMainContext *context, const guint id)
317 {
318 	GSList *l;
319 	struct timeout *t;
320 
321 	l = context->timeouts;
322 
323 	while (l) {
324 		t = l->data;
325 		l = l->next;
326 
327 		if (t->id != id)
328 			continue;
329 
330 		context->timeouts = g_slist_remove(context->timeouts, t);
331 		g_free(t);
332 
333 		return TRUE;
334 	}
335 
336 	l = context->proc_timeouts;
337 
338 	while (l) {
339 		t = l->data;
340 		l = l->next;
341 
342 		if (t->id != id)
343 			continue;
344 
345 		context->proc_timeouts = g_slist_remove(context->proc_timeouts, t);
346 		g_free(t);
347 
348 		return TRUE;
349 	}
350 
351 	return FALSE;
352 }
353 
watch_prio_cmp(struct io_watch * w1,struct io_watch * w2)354 int watch_prio_cmp(struct io_watch *w1, struct io_watch *w2)
355 {
356 	return w1->priority - w2->priority;
357 }
358 
359 #define watch_list_add(l, w) g_slist_insert_sorted((l), (w), (GCompareFunc) watch_prio_cmp)
360 
g_io_add_watch_full(GIOChannel * channel,gint priority,GIOCondition condition,GIOFunc func,gpointer user_data,GDestroyNotify notify)361 guint g_io_add_watch_full(GIOChannel *channel, gint priority,
362 				GIOCondition condition, GIOFunc func,
363 				gpointer user_data, GDestroyNotify notify)
364 {
365 	struct io_watch *watch;
366 	GMainContext *context = g_main_context_default();
367 
368 	watch = g_new(struct io_watch, 1);
369 
370 	watch->id = context->next_id++;
371 	watch->channel = g_io_channel_ref(channel);
372 	watch->priority = priority;
373 	watch->condition = condition;
374 	watch->func = func;
375 	watch->user_data = user_data;
376 	watch->destroy = notify;
377 
378 	if (context->io_lock)
379 		context->proc_io_watches = watch_list_add(context->proc_io_watches, watch);
380 	else
381 		context->io_watches = watch_list_add(context->io_watches, watch);
382 
383 	return watch->id;
384 }
385 
g_io_add_watch(GIOChannel * channel,GIOCondition condition,GIOFunc func,gpointer user_data)386 guint g_io_add_watch(GIOChannel *channel, GIOCondition condition,
387 					GIOFunc func, gpointer user_data)
388 {
389 	return g_io_add_watch_full(channel, 0, condition,
390 						func, user_data, NULL);
391 }
392 
g_main_loop_new(GMainContext * context,gboolean is_running)393 GMainLoop *g_main_loop_new(GMainContext *context, gboolean is_running)
394 {
395 	GMainLoop *ml;
396 
397 	if (!context)
398 		context = g_main_context_default();
399 
400 	ml = g_new0(GMainLoop, 1);
401 
402 	ml->context = context;
403 	ml->is_running = is_running;
404 
405 	return ml;
406 }
407 
timeout_handlers_prepare(GMainContext * context)408 static void timeout_handlers_prepare(GMainContext *context)
409 {
410 	GSList *l;
411 	struct timeval tv;
412 	glong msec, timeout = LONG_MAX;
413 
414 	gettimeofday(&tv, NULL);
415 
416 	for (l = context->timeouts; l != NULL; l = l->next) {
417 		struct timeout *t = l->data;
418 
419 		/* calculate the remainning time */
420 		msec = (t->expiration.tv_sec - tv.tv_sec) * 1000 +
421 				(t->expiration.tv_usec - tv.tv_usec) / 1000;
422 		if (msec < 0)
423 			msec = 0;
424 
425 		timeout = MIN_TIMEOUT(timeout, msec);
426 	}
427 
428 	/* set to min value found or NO timeout */
429 	context->next_timeout = (timeout != LONG_MAX ? timeout : -1);
430 }
431 
ptr_cmp(const void * t1,const void * t2)432 static int ptr_cmp(const void *t1, const void *t2)
433 {
434 	return t1 - t2;
435 }
436 
timeout_handlers_check(GMainContext * context)437 static void timeout_handlers_check(GMainContext *context)
438 {
439 	struct timeval tv;
440 
441 	gettimeofday(&tv, NULL);
442 
443 	context->timeout_lock = TRUE;
444 
445 	while (context->timeouts) {
446 		struct timeout *t = context->timeouts->data;
447 		glong secs, msecs;
448 		gboolean ret;
449 
450 		if (timercmp(&tv, &t->expiration, <)) {
451 			context->timeouts = g_slist_remove(context->timeouts, t);
452 			context->proc_timeouts = g_slist_append(context->proc_timeouts, t);
453 			continue;
454 		}
455 
456 		ret = t->function(t->data);
457 
458 		/* Check if the handler was removed/freed by the callback
459 		 * function */
460 		if (!g_slist_find_custom(context->timeouts, t, ptr_cmp))
461 			continue;
462 
463 		context->timeouts = g_slist_remove(context->timeouts, t);
464 
465 		if (!ret) {
466 			g_free(t);
467 			continue;
468 		}
469 
470 		/* update the next expiration time */
471 		secs = t->interval / 1000;
472 		msecs = t->interval - secs * 1000;
473 
474 		t->expiration.tv_sec = tv.tv_sec + secs;
475 		t->expiration.tv_usec = tv.tv_usec + msecs * 1000;
476 		if (t->expiration.tv_usec >= 1000000) {
477 			t->expiration.tv_usec -= 1000000;
478 			t->expiration.tv_sec++;
479 		}
480 
481 		context->proc_timeouts = g_slist_append(context->proc_timeouts, t);
482 	}
483 
484 	context->timeouts = context->proc_timeouts;
485 	context->proc_timeouts = NULL;
486 	context->timeout_lock = FALSE;
487 }
488 
g_main_loop_run(GMainLoop * loop)489 void g_main_loop_run(GMainLoop *loop)
490 {
491 	int open_max = sysconf(_SC_OPEN_MAX);
492 	struct pollfd *ufds;
493 	GMainContext *context = loop->context;
494 
495 	ufds = g_new(struct pollfd, open_max);
496 
497 	loop->is_running = TRUE;
498 
499 	while (loop->is_running) {
500 		int nfds;
501 		GSList *l;
502 		struct io_watch *w;
503 
504 		for (nfds = 0, l = context->io_watches; l != NULL; l = l->next, nfds++) {
505 			if (nfds == open_max) {
506 				error("Number of io_watches exceeds open_max in g_main_loop_run. We probably have a leak.");
507 				abort();
508 			}
509 			w = l->data;
510 			ufds[nfds].fd = w->channel->fd;
511 			ufds[nfds].events = w->condition;
512 			ufds[nfds].revents = 0;
513 			w->revents = &ufds[nfds].revents;
514 		}
515 
516 		/* calculate the next timeout */
517 		timeout_handlers_prepare(context);
518 
519 		if (poll(ufds, nfds, context->next_timeout) < 0)
520 			continue;
521 
522 		context->io_lock = TRUE;
523 
524 		while (context->io_watches) {
525 			gboolean ret;
526 
527 			w = context->io_watches->data;
528 
529 			if (!w || !w->revents || !*w->revents) {
530 				context->io_watches = g_slist_remove(context->io_watches, w);
531 				context->proc_io_watches = watch_list_add(context->proc_io_watches, w);
532 				continue;
533 			}
534 
535 			ret = w->func(w->channel, *w->revents, w->user_data);
536 
537 			/* Check if the watch was removed/freed by the callback
538 			 * function */
539 			if (!g_slist_find_custom(context->io_watches, w, ptr_cmp))
540 				continue;
541 
542 			context->io_watches = g_slist_remove(context->io_watches, w);
543 
544 			if (!ret) {
545 				watch_free(w);
546 				continue;
547 			}
548 
549 			context->proc_io_watches = watch_list_add(context->proc_io_watches, w);
550 		}
551 
552 		context->io_watches = context->proc_io_watches;
553 		context->proc_io_watches = NULL;
554 		context->io_lock = FALSE;
555 
556 		/* check expired timers */
557 		timeout_handlers_check(loop->context);
558 	}
559 
560 	g_free(ufds);
561 }
562 
g_main_loop_quit(GMainLoop * loop)563 void g_main_loop_quit(GMainLoop *loop)
564 {
565 	loop->is_running = FALSE;
566 }
567 
g_main_loop_unref(GMainLoop * loop)568 void g_main_loop_unref(GMainLoop *loop)
569 {
570 	if (!loop->context)
571 		return;
572 
573 	g_slist_foreach(loop->context->io_watches, (GFunc)watch_free, NULL);
574 	g_slist_free(loop->context->io_watches);
575 
576 	g_slist_foreach(loop->context->timeouts, (GFunc)g_free, NULL);
577 	g_slist_free(loop->context->timeouts);
578 
579 	g_free(loop->context);
580 	loop->context = NULL;
581 }
582 
g_timeout_add(guint interval,GSourceFunc function,gpointer data)583 guint g_timeout_add(guint interval, GSourceFunc function, gpointer data)
584 {
585 	GMainContext *context = g_main_context_default();
586 	struct timeval tv;
587 	guint secs;
588 	guint msecs;
589 	struct timeout *t;
590 
591 	t = g_new0(struct timeout, 1);
592 
593 	t->interval = interval;
594 	t->function = function;
595 	t->data = data;
596 
597 	gettimeofday(&tv, NULL);
598 
599 	secs = interval /1000;
600 	msecs = interval - secs * 1000;
601 
602 	t->expiration.tv_sec = tv.tv_sec + secs;
603 	t->expiration.tv_usec = tv.tv_usec + msecs * 1000;
604 
605 	if (t->expiration.tv_usec >= 1000000) {
606 		t->expiration.tv_usec -= 1000000;
607 		t->expiration.tv_sec++;
608 	}
609 
610 	/* attach the timeout the default context */
611 	t->id = context->next_id++;
612 
613 	if (context->timeout_lock)
614 		context->proc_timeouts = g_slist_prepend(context->proc_timeouts, t);
615 	else
616 		context->timeouts = g_slist_prepend(context->timeouts, t);
617 
618 	return t->id;
619 }
620 
g_timeout_add_seconds(guint interval,GSourceFunc function,gpointer data)621 guint g_timeout_add_seconds(guint interval, GSourceFunc function, gpointer data)
622 {
623 	return g_timeout_add(interval, function, data);
624 }
625 
g_idle_add(GSourceFunc function,gpointer data)626 guint g_idle_add(GSourceFunc function, gpointer data)
627 {
628 	return g_timeout_add(1, function, data);
629 }
630 
631 /* GError */
632 
g_error_new_literal(GQuark domain,gint code,const gchar * message)633 GError* g_error_new_literal(GQuark domain, gint code, const gchar *message)
634 {
635 	GError *err;
636 
637 	err = g_new(GError, 1);
638 
639 	err->domain = domain;
640 	err->code = code;
641 	err->message = g_strdup(message);
642 
643 	return err;
644 }
645 
g_set_error(GError ** err,GQuark domain,gint code,const gchar * format,...)646 void g_set_error(GError **err, GQuark domain, gint code,
647 			const gchar *format, ...)
648 {
649 	gchar msg[1024];
650 	va_list ap;
651 
652 	if (!err)
653 		return;
654 
655 	va_start(ap, format);
656 
657 	vsnprintf(msg, sizeof(msg) - 1, format, ap);
658 
659 	va_end(ap);
660 
661 	*err = g_error_new_literal(domain, code, msg);
662 }
663 
g_error_free(GError * err)664 void g_error_free(GError *err)
665 {
666 	g_free(err->message);
667 	g_free(err);
668 }
669 
670 /* Spawning related functions */
671 
672 static int child_watch_pipe[2] = { -1, -1 };
673 
sigchld_handler(int signal)674 static void sigchld_handler(int signal)
675 {
676 	int ret;
677 	ret = write(child_watch_pipe[1], "B", 1);
678 }
679 
child_watch_remove(GMainContext * context,guint id)680 static gboolean child_watch_remove(GMainContext *context, guint id)
681 {
682 	GSList *l;
683 	struct child_watch *w;
684 
685 	for (l = context->child_watches; l != NULL; l = l->next) {
686 		w = l->data;
687 
688 		if (w->id != id)
689 			continue;
690 
691 		context->child_watches =
692 			g_slist_remove(context->child_watches, w);
693 		g_free(w);
694 
695 		return TRUE;
696 	}
697 
698 	for (l = context->proc_child_watches; l != NULL; l = l->next) {
699 		w = l->data;
700 
701 		if (w->id != id)
702 			continue;
703 
704 		context->proc_child_watches =
705 			g_slist_remove(context->proc_child_watches, w);
706 		g_free(w);
707 
708 		return TRUE;
709 	}
710 
711 
712 	return FALSE;
713 }
714 
child_watch(GIOChannel * io,GIOCondition cond,gpointer user_data)715 static gboolean child_watch(GIOChannel *io, GIOCondition cond, gpointer user_data)
716 {
717 	int ret;
718 	char b[20];
719 	GMainContext *context = g_main_context_default();
720 
721 	ret = read(child_watch_pipe[0], b, 20);
722 
723 	context->child_lock = TRUE;
724 
725 	while (context->child_watches) {
726 		gint status;
727 		struct child_watch *w = context->child_watches->data;
728 
729 		if (waitpid(w->pid, &status, WNOHANG) <= 0) {
730 			context->child_watches =
731 				g_slist_remove(context->child_watches, w);
732 			context->proc_child_watches =
733 				watch_list_add(context->proc_child_watches, w);
734 			continue;
735 		}
736 
737 		w->function(w->pid, status, w->user_data);
738 
739 		/* Check if the callback already removed us */
740 		if (!g_slist_find(context->child_watches, w))
741 			continue;
742 
743 		context->child_watches = g_slist_remove(context->child_watches, w);
744 		g_free(w);
745 	}
746 
747 	context->child_watches = context->proc_child_watches;
748 	context->proc_child_watches = NULL;
749 	context->child_lock = FALSE;
750 
751 	return TRUE;
752 }
753 
init_child_pipe(void)754 static void init_child_pipe(void)
755 {
756 	struct sigaction action;
757 	GIOChannel *io;
758 
759 	if (pipe(child_watch_pipe) < 0) {
760 		fprintf(stderr, "Unable to initialize child watch pipe: %s (%d)\n",
761 				strerror(errno), errno);
762 		abort();
763 	}
764 
765 	fcntl(child_watch_pipe[1], F_SETFL,
766 			O_NONBLOCK | fcntl(child_watch_pipe[1], F_GETFL));
767 
768 	action.sa_handler = sigchld_handler;
769 	sigemptyset(&action.sa_mask);
770 	action.sa_flags = SA_NOCLDSTOP;
771 	sigaction(SIGCHLD, &action, NULL);
772 
773 	io = g_io_channel_unix_new(child_watch_pipe[0]);
774 	g_io_add_watch(io, G_IO_IN, child_watch, NULL);
775 	g_io_channel_unref(io);
776 }
777 
exec_child(const gchar * working_directory,gchar ** argv,gchar ** envp,GSpawnFlags flags,GSpawnChildSetupFunc child_setup,gpointer user_data)778 static void exec_child(const gchar *working_directory,
779 			gchar **argv, gchar **envp,
780 			GSpawnFlags flags,
781 			GSpawnChildSetupFunc child_setup,
782 			gpointer user_data)
783 {
784 	int null;
785 
786 	if (working_directory && chdir(working_directory) < 0)
787 		_exit(EXIT_FAILURE);
788 
789 	if (!(flags & G_SPAWN_LEAVE_DESCRIPTORS_OPEN)) {
790 		int open_max, fd, ret;
791 
792 		ret = 0;
793 		open_max = sysconf(_SC_OPEN_MAX);
794 		for (fd = 3; fd < open_max && ret == 0; fd++)
795 			ret = fcntl(fd, F_SETFD, FD_CLOEXEC);
796 	}
797 
798 	null = open("/dev/null", O_RDWR);
799 	if (!(flags & G_SPAWN_CHILD_INHERITS_STDIN))
800 		dup2(null, STDIN_FILENO);
801 	if (flags & G_SPAWN_STDOUT_TO_DEV_NULL)
802 		dup2(null, STDOUT_FILENO);
803 	if (flags & G_SPAWN_STDERR_TO_DEV_NULL)
804 		dup2(null, STDERR_FILENO);
805 	if (null > 2)
806 		close(null);
807 
808 	if (child_setup)
809 		child_setup(user_data);
810 
811 	if (envp)
812 		execve(argv[0], argv, envp);
813 	else
814 		execv(argv[0], argv);
815 
816 	/* exec failed if we get here */
817 	_exit(EXIT_FAILURE);
818 }
819 
g_spawn_async(const gchar * working_directory,gchar ** argv,gchar ** envp,GSpawnFlags flags,GSpawnChildSetupFunc child_setup,gpointer user_data,GPid * child_pid,GError ** error)820 gboolean g_spawn_async(const gchar *working_directory,
821 			gchar **argv, gchar **envp,
822 			GSpawnFlags flags,
823 			GSpawnChildSetupFunc child_setup,
824 			gpointer user_data,
825 			GPid *child_pid,
826 			GError **error)
827 {
828 	GPid pid;
829 
830 	if (access(argv[0], X_OK) < 0) {
831 		g_set_error(error, 0, 0, "%s is not executable", argv[0]);
832 		return FALSE;
833 	}
834 
835 	if (child_watch_pipe[0] < 0)
836 		init_child_pipe();
837 
838 	/* Flush output streams so child doesn't get them */
839 	fflush(NULL);
840 
841 	switch (pid = fork()) {
842 	case -1:
843 		g_set_error(error, 0, 0, "fork failed: %s", strerror(errno));
844 		return FALSE;
845 	case 0:
846 		exec_child(working_directory, argv, envp, flags,
847 				child_setup, user_data);
848 		break;
849 	default:
850 		if (child_pid)
851 			*child_pid = pid;
852 		return TRUE;
853 	}
854 
855 	/* Never reached */
856 	return FALSE;
857 }
858 
g_spawn_close_pid(GPid pid)859 void g_spawn_close_pid(GPid pid)
860 {
861 	return;
862 }
863 
g_child_watch_add(GPid pid,GChildWatchFunc func,gpointer user_data)864 guint g_child_watch_add(GPid pid, GChildWatchFunc func, gpointer user_data)
865 {
866 	struct child_watch *w;
867 	GMainContext *context = g_main_context_default();
868 
869 	if (child_watch_pipe[0] < 0)
870 		init_child_pipe();
871 
872 	w = g_new(struct child_watch, 1);
873 
874 	w->id = context->next_id++;
875 	w->pid = pid;
876 	w->function = func;
877 	w->user_data = user_data;
878 
879 	if (context->child_lock)
880 		context->proc_child_watches =
881 			watch_list_add(context->proc_child_watches, w);
882 	else
883 		context->child_watches =
884 			watch_list_add(context->child_watches, w);
885 
886 	return w->id;
887 }
888 
g_source_remove(guint tag)889 gboolean g_source_remove(guint tag)
890 {
891 	GMainContext *context = g_main_context_default();
892 
893 	if (g_io_remove_watch(context, tag))
894 		return TRUE;
895 
896 	if (g_timeout_remove(context, tag))
897 		return TRUE;
898 
899 	if (child_watch_remove(context, tag))
900 		return TRUE;
901 
902 	return FALSE;
903 }
904 
905 /* UTF-8 Validation: approximate copy/paste from glib2. */
906 
907 #define UNICODE_VALID(c)			\
908 	((c) < 0x110000 &&			\
909 	(((c) & 0xFFFFF800) != 0xD800) &&	\
910 	((c) < 0xFDD0 || (c) > 0xFDEF) &&	\
911 	((c) & 0xFFFE) != 0xFFFE)
912 
913 #define CONTINUATION_CHAR(c, val)				\
914 	do {							\
915 		if (((c) & 0xc0) != 0x80) /* 10xxxxxx */	\
916 			goto failed;				\
917 		(val) <<= 6;					\
918 		(val) |= (c) & 0x3f;				\
919 	} while (0)
920 
921 #define INCREMENT_AND_CHECK_MAX(p, i, max_len)					\
922 	do {									\
923 		(i)++;								\
924 		if ((p)[(i)] == '\0' || ((max_len) >= 0 && (i) >= (max_len)))	\
925 			goto failed;						\
926 	} while (0)
927 
928 
g_utf8_validate(const gchar * str,gssize max_len,const gchar ** end)929 gboolean g_utf8_validate(const gchar *str, gssize max_len, const gchar **end)
930 {
931 	unsigned long val, min, i;
932 	const unsigned char *p, *last;
933 
934 	min = val = 0;
935 
936 	for (p = (unsigned char *) str, i = 0; p[i]; i++) {
937 		if (max_len >= 0 && i >= max_len)
938 			break;
939 
940 		if (p[i] < 128)
941 			continue;
942 
943 		last = &p[i];
944 
945 		if ((p[i] & 0xe0) == 0xc0) { /* 110xxxxx */
946 			if ((p[i] & 0x1e) == 0)
947 				goto failed;
948 			INCREMENT_AND_CHECK_MAX(p, i, max_len);
949 			if ((p[i] & 0xc0) != 0x80)
950 				goto failed; /* 10xxxxxx */
951 		} else {
952 			if ((p[i] & 0xf0) == 0xe0) {
953 				/* 1110xxxx */
954 				min = (1 << 11);
955 				val = p[i] & 0x0f;
956 				goto two_remaining;
957 			} else if ((p[i] & 0xf8) == 0xf0) {
958 				/* 11110xxx */
959 				min = (1 << 16);
960 				val = p[i] & 0x07;
961 			} else
962 				goto failed;
963 
964 			INCREMENT_AND_CHECK_MAX(p, i, max_len);
965 			CONTINUATION_CHAR(p[i], val);
966 two_remaining:
967 			INCREMENT_AND_CHECK_MAX(p, i, max_len);
968 			CONTINUATION_CHAR(p[i], val);
969 
970 			INCREMENT_AND_CHECK_MAX(p, i, max_len);
971 			CONTINUATION_CHAR(p[i], val);
972 
973 			if (val < min || !UNICODE_VALID(val))
974 				goto failed;
975 		}
976 	}
977 
978 	if (end)
979 		*end = (const gchar *) &p[i];
980 
981 	return TRUE;
982 
983 failed:
984 	if (end)
985 		*end = (const gchar *) last;
986 
987 	return FALSE;
988 }
989 
990 /* GSList functions */
991 
g_slist_append(GSList * list,void * data)992 GSList *g_slist_append(GSList *list, void *data)
993 {
994 	GSList *entry, *tail;
995 
996 	entry = g_new(GSList, 1);
997 
998 	entry->data = data;
999 	entry->next = NULL;
1000 
1001 	if (!list)
1002 		return entry;
1003 
1004 	/* Find the end of the list */
1005 	for (tail = list; tail->next; tail = tail->next);
1006 
1007 	tail->next = entry;
1008 
1009 	return list;
1010 }
1011 
g_slist_prepend(GSList * list,void * data)1012 GSList *g_slist_prepend(GSList *list, void *data)
1013 {
1014 	GSList *entry;
1015 
1016 	entry = g_new(GSList, 1);
1017 
1018 	entry->data = data;
1019 	entry->next = list;
1020 
1021 	return entry;
1022 }
1023 
g_slist_insert_sorted(GSList * list,void * data,GCompareFunc cmp_func)1024 GSList *g_slist_insert_sorted(GSList *list, void *data, GCompareFunc cmp_func)
1025 {
1026 	GSList *tmp, *prev, *entry;
1027 	int cmp;
1028 
1029 	entry = g_new(GSList, 1);
1030 
1031 	entry->data = data;
1032 	entry->next = NULL;
1033 
1034 	if (!list)
1035 		return entry;
1036 
1037 	prev = NULL;
1038 	tmp = list;
1039 
1040 	cmp = cmp_func(data, tmp->data);
1041 
1042 	while (tmp->next && cmp > 0) {
1043 		prev = tmp;
1044 		tmp = tmp->next;
1045 
1046 		cmp = cmp_func(data, tmp->data);
1047 	}
1048 
1049 	if (!tmp->next && cmp > 0) {
1050 		tmp->next = entry;
1051 		return list;
1052 	}
1053 
1054 	if (prev) {
1055 		prev->next = entry;
1056 		entry->next = tmp;
1057 		return list;
1058 	} else {
1059 		entry->next = list;
1060 		return entry;
1061 	}
1062 }
1063 
g_slist_remove(GSList * list,void * data)1064 GSList *g_slist_remove(GSList *list, void *data)
1065 {
1066 	GSList *l, *next, *prev = NULL, *match = NULL;
1067 
1068 	if (!list)
1069 		return NULL;
1070 
1071 	for (l = list; l != NULL; l = l->next) {
1072 		if (l->data == data) {
1073 			match = l;
1074 			break;
1075 		}
1076 		prev = l;
1077 	}
1078 
1079 	if (!match)
1080 		return list;
1081 
1082 	next = match->next;
1083 
1084 	g_free(match);
1085 
1086 	/* If the head was removed, return the next element */
1087 	if (!prev)
1088 		return next;
1089 
1090 	prev->next = next;
1091 
1092 	return list;
1093 }
1094 
g_slist_find(GSList * list,gconstpointer data)1095 GSList *g_slist_find(GSList *list, gconstpointer data)
1096 {
1097 	GSList *l;
1098 
1099 	for (l = list; l != NULL; l = l->next) {
1100 		if (l->data == data)
1101 			return l;
1102 	}
1103 
1104 	return NULL;
1105 }
1106 
g_slist_find_custom(GSList * list,const void * data,GCompareFunc cmp_func)1107 GSList *g_slist_find_custom(GSList *list, const void *data,
1108 			GCompareFunc cmp_func)
1109 {
1110 	GSList *l;
1111 
1112 	for (l = list; l != NULL; l = l->next) {
1113 		if (!cmp_func(l->data, data))
1114 			return l;
1115 	}
1116 
1117 	return NULL;
1118 }
1119 
g_slist_sort_merge(GSList * l1,GSList * l2,GCompareFunc cmp_func)1120 static GSList *g_slist_sort_merge(GSList *l1, GSList *l2,
1121 					GCompareFunc cmp_func)
1122 {
1123 	GSList list, *l;
1124 	int cmp;
1125 
1126 	l = &list;
1127 
1128 	while (l1 && l2) {
1129 		cmp = cmp_func(l1->data, l2->data);
1130 
1131 		if (cmp <= 0) {
1132 			l = l->next = l1;
1133 			l1 = l1->next;
1134 		} else {
1135 			l = l->next = l2;
1136 			l2 = l2->next;
1137 		}
1138 	}
1139 
1140 	l->next = l1 ? l1 : l2;
1141 
1142 	return list.next;
1143 }
1144 
g_slist_sort(GSList * list,GCompareFunc cmp_func)1145 GSList *g_slist_sort(GSList *list, GCompareFunc cmp_func)
1146 {
1147 	GSList *l1, *l2;
1148 
1149 	if (!list || !list->next)
1150 		return list;
1151 
1152 	l1 = list;
1153 	l2 = list->next;
1154 
1155 	while ((l2 = l2->next) != NULL) {
1156 		if ((l2 = l2->next) == NULL)
1157 			break;
1158 		l1 = l1->next;
1159 	}
1160 
1161 	l2 = l1->next;
1162 	l1->next = NULL;
1163 
1164 	return g_slist_sort_merge(g_slist_sort(list, cmp_func),
1165 				g_slist_sort(l2, cmp_func), cmp_func);
1166 }
1167 
g_slist_length(GSList * list)1168 int g_slist_length(GSList *list)
1169 {
1170 	int len;
1171 
1172 	for (len = 0; list != NULL; list = list->next)
1173 		len++;
1174 
1175 	return len;
1176 }
1177 
g_slist_foreach(GSList * list,GFunc func,void * user_data)1178 void g_slist_foreach(GSList *list, GFunc func, void *user_data)
1179 {
1180 	while (list) {
1181 		GSList *next = list->next;
1182 		func(list->data, user_data);
1183 		list = next;
1184 	}
1185 }
1186 
g_slist_free(GSList * list)1187 void g_slist_free(GSList *list)
1188 {
1189 	GSList *l, *next;
1190 
1191 	for (l = list; l != NULL; l = next) {
1192 		next = l->next;
1193 		g_free(l);
1194 	}
1195 }
1196 
g_slist_nth(GSList * list,guint n)1197 GSList *g_slist_nth(GSList *list, guint n)
1198 {
1199 	while (n-- > 0 && list)
1200 		list = list->next;
1201 
1202 	return list;
1203 }
1204 
g_slist_nth_data(GSList * list,guint n)1205 gpointer g_slist_nth_data(GSList *list, guint n)
1206 {
1207 	while (n-- > 0 && list)
1208 		list = list->next;
1209 
1210 	return list ? list->data : NULL;
1211 }
1212 
g_slist_position(GSList * list,GSList * link)1213 gint g_slist_position(GSList *list, GSList *link)
1214 {
1215 	gint i;
1216 
1217 	for (i = 0; list; list = list->next, i++) {
1218 		if (list == link)
1219 			return i;
1220 	}
1221 
1222 	return -1;
1223 }
1224 
g_slist_last(GSList * list)1225 GSList* g_slist_last(GSList *list)
1226 {
1227 	if (list)
1228 		while (list->next)
1229 			list = list->next;
1230 
1231 	return list;
1232 }
1233 
_g_slist_remove_link(GSList * list,GSList * link)1234 static inline GSList* _g_slist_remove_link(GSList *list, GSList *link)
1235 {
1236 	GSList *tmp;
1237 	GSList *prev;
1238 
1239 	prev = NULL;
1240 	tmp = list;
1241 
1242 	while (tmp) {
1243 		if (tmp == link) {
1244 			if (prev)
1245 				prev->next = tmp->next;
1246 			if (list == tmp)
1247 				list = list->next;
1248 
1249 			tmp->next = NULL;
1250 			break;
1251 		}
1252 
1253 		prev = tmp;
1254 		tmp = tmp->next;
1255 	}
1256 
1257 	return list;
1258 }
1259 
g_slist_delete_link(GSList * list,GSList * link)1260 GSList* g_slist_delete_link(GSList *list, GSList *link)
1261 {
1262 	list = _g_slist_remove_link(list, link);
1263 	g_free(link);
1264 
1265 	return list;
1266 }
1267 
1268 /* Memory allocation functions */
1269 
g_malloc(gulong n_bytes)1270 gpointer g_malloc(gulong n_bytes)
1271 {
1272 	gpointer mem;
1273 
1274 	if (!n_bytes)
1275 		return NULL;
1276 
1277 	mem = malloc((size_t) n_bytes);
1278 	if (!mem) {
1279 		fprintf(stderr, "g_malloc: failed to allocate %lu bytes",
1280 				n_bytes);
1281 		abort();
1282 	}
1283 
1284 	return mem;
1285 }
1286 
g_malloc0(gulong n_bytes)1287 gpointer g_malloc0(gulong n_bytes)
1288 {
1289 	gpointer mem;
1290 
1291 	if (!n_bytes)
1292 		return NULL;
1293 
1294 	mem = g_malloc(n_bytes);
1295 
1296 	memset(mem, 0, (size_t) n_bytes);
1297 
1298 	return mem;
1299 }
1300 
g_try_malloc(gulong n_bytes)1301 gpointer g_try_malloc(gulong n_bytes)
1302 {
1303 	if (!n_bytes)
1304 		return NULL;
1305 
1306 	return malloc((size_t) n_bytes);
1307 }
1308 
g_try_malloc0(gulong n_bytes)1309 gpointer g_try_malloc0(gulong n_bytes)
1310 {
1311 	gpointer mem;
1312 
1313 	mem = g_try_malloc(n_bytes);
1314 	if (mem)
1315 		memset(mem, 0, (size_t) n_bytes);
1316 
1317 	return mem;
1318 }
1319 
g_realloc(gpointer mem,gulong n_bytes)1320 gpointer g_realloc(gpointer mem, gulong n_bytes)
1321 {
1322 	mem = realloc(mem, n_bytes);
1323 	if (!mem) {
1324 		fprintf(stderr, "g_realloc: failed to allocate %lu bytes",
1325 				n_bytes);
1326 		abort();
1327 	}
1328 
1329 	return mem;
1330 }
1331 
g_free(gpointer mem)1332 void g_free(gpointer mem)
1333 {
1334 	if (mem)
1335 		free(mem);
1336 }
1337 
g_strdup(const gchar * str)1338 gchar *g_strdup(const gchar *str)
1339 {
1340 	gchar *s;
1341 
1342 	if (!str)
1343 		return NULL;
1344 
1345 	s = strdup(str);
1346 	if (!s) {
1347 		fprintf(stderr, "strdup: failed to allocate new string");
1348 		abort();
1349 	}
1350 
1351 	return s;
1352 }
1353 
g_strdup_printf(const gchar * format,...)1354 gchar *g_strdup_printf(const gchar *format, ...)
1355 {
1356 	va_list args;
1357 	gchar buffer[1024];
1358 	gint length;
1359 
1360 	va_start(args, format);
1361 	length = vsnprintf(buffer, sizeof(buffer) - 1, format, args);
1362 	va_end(args);
1363 
1364 	return g_strdup(buffer);
1365 }
1366 
g_strdelimit(gchar * string,const gchar * delimiters,gchar new_delim)1367 gchar *g_strdelimit(gchar *string, const gchar *delimiters, gchar new_delim)
1368 {
1369 	register gchar *c;
1370 
1371 	if (!string)
1372 		return NULL;
1373 
1374 	for (c = string; *c; c++)
1375 		if (strchr(delimiters, *c))
1376 			*c = new_delim;
1377 
1378 	return string;
1379 }
1380 
g_strconcat(const gchar * string1,...)1381 gchar *g_strconcat(const gchar *string1, ...)
1382 {
1383 	gsize l;
1384 	va_list args;
1385 	gchar *s, *concat;
1386 
1387 	if (!string1)
1388 		return NULL;
1389 
1390 	l = 1 + strlen(string1);
1391 	va_start(args, string1);
1392 	s = va_arg(args, gchar *);
1393 	while (s) {
1394 		l += strlen(s);
1395 		s = va_arg(args, gchar *);
1396 	}
1397 	va_end (args);
1398 
1399 	concat = g_new(gchar, l);
1400 	concat[0] = '\0';
1401 
1402 	va_start(args, string1);
1403 	s = va_arg(args, gchar*);
1404 	while (s) {
1405 		strcat(concat, s);
1406 		s = va_arg(args, gchar *);
1407 	}
1408 	va_end (args);
1409 
1410 	return concat;
1411 }
1412 
g_strlcat(gchar * dest,const gchar * src,gsize dest_size)1413 gsize g_strlcat(gchar *dest, const gchar *src, gsize dest_size)
1414 {
1415 	gchar *d = dest;
1416 	const gchar *s = src;
1417 	gsize bytes_left = dest_size;
1418 	gsize dlength;  /* Logically, MIN(strlen(d), dest_size) */
1419 
1420 	if (!d || !s)
1421 		return 0;
1422 
1423 	/* Find the end of dst and adjust bytes left but don't go past end */
1424 	while (*d != 0 && bytes_left-- != 0)
1425 		d++;
1426 	dlength = d - dest;
1427 	bytes_left = dest_size - dlength;
1428 
1429 	if (bytes_left == 0)
1430 		return dlength + strlen(s);
1431 
1432 	while (*s != 0) {
1433 		if (bytes_left != 1) {
1434 			*d++ = *s;
1435 			bytes_left--;
1436 		}
1437 		s++;
1438 	}
1439 	*d = 0;
1440 
1441 	return dlength + (s - src);  /* count does not include NULL */
1442 }
1443 
g_strsplit(const gchar * string,const gchar * delimiter,gint max_tokens)1444 gchar **g_strsplit(const gchar *string, const gchar *delimiter, gint max_tokens)
1445 {
1446 	GSList *string_list = NULL, *slist;
1447 	gchar **str_array, *s;
1448 	guint n = 0;
1449 	const gchar *remainder;
1450 
1451 	if (string == NULL || delimiter == NULL || delimiter[0] == '\0')
1452 		return NULL;
1453 
1454 	if (max_tokens < 1)
1455 		max_tokens = INT_MAX;
1456 
1457 	remainder = string;
1458 	s = strstr(remainder, delimiter);
1459 	if (s) {
1460 		gsize delimiter_len = strlen(delimiter);
1461 
1462 		while (--max_tokens && s) {
1463 			gsize len;
1464 			gchar *tmp;
1465 
1466 			len = s - remainder;
1467 			tmp = g_new(char, len);
1468 			memcpy(tmp, remainder, len);
1469 			string_list = g_slist_prepend(string_list, tmp);
1470 			n++;
1471 			remainder = s + delimiter_len;
1472 			s = strstr(remainder, delimiter);
1473 		}
1474 	}
1475 	if (*string) {
1476 		n++;
1477 		string_list = g_slist_prepend(string_list, g_strdup(remainder));
1478 	}
1479 
1480 	str_array = g_new(gchar *, n + 1);
1481 
1482 	str_array[n--] = NULL;
1483 	for (slist = string_list; slist; slist = slist->next)
1484 		str_array[n--] = slist->data;
1485 
1486 	g_slist_free(string_list);
1487 
1488 	return str_array;
1489 }
1490 
g_ascii_strup(const gchar * str,gssize len)1491 gchar *g_ascii_strup(const gchar *str, gssize len)
1492 {
1493 	int i;
1494 	gchar *s;
1495 
1496 	s = g_strdup(str);
1497 	if (!s)
1498 		return NULL;
1499 
1500 	if (len < 0)
1501 		len = strlen(s);
1502 
1503 	for (i = 0; i < len; i++)
1504 		s[i] = toupper(s[i]);
1505 
1506 	return s;
1507 }
1508 
g_str_equal(gconstpointer v1,gconstpointer v2)1509 gboolean g_str_equal(gconstpointer v1, gconstpointer v2)
1510 {
1511 	const gchar *string1 = v1;
1512 	const gchar *string2 = v2;
1513 
1514 	return strcmp(string1, string2) == 0;
1515 }
1516 
g_str_has_prefix(const gchar * str,const gchar * prefix)1517 gboolean g_str_has_prefix(const gchar *str, const gchar *prefix)
1518 {
1519 	int str_len;
1520 	int prefix_len;
1521 
1522 	if (str == NULL || prefix == NULL)
1523 		return FALSE;
1524 
1525 	str_len = strlen (str);
1526 	prefix_len = strlen (prefix);
1527 
1528 	if (str_len < prefix_len)
1529 		return FALSE;
1530 
1531 	return strncmp(str, prefix, prefix_len) == 0;
1532 }
1533 
g_str_has_suffix(const gchar * str,const gchar * suffix)1534 gboolean g_str_has_suffix(const gchar *str, const gchar *suffix)
1535 {
1536 	int str_len;
1537 	int suffix_len;
1538 
1539 	if (!str || !suffix)
1540 		return FALSE;
1541 
1542 	str_len = strlen(str);
1543 	suffix_len = strlen(suffix);
1544 
1545 	if (str_len < suffix_len)
1546 		return FALSE;
1547 
1548 	return strcmp(str + str_len - suffix_len, suffix) == 0;
1549 }
1550 
g_strfreev(gchar ** str_array)1551 void g_strfreev(gchar **str_array)
1552 {
1553 	int i;
1554 
1555 	if (str_array == NULL)
1556 		return;
1557 
1558 	for(i = 0; str_array[i] != NULL; i++)
1559 		g_free(str_array[i]);
1560 
1561 	g_free(str_array);
1562 }
1563 
1564 /* GKeyFile */
1565 
1566 struct _GKeyFile {
1567 	gchar *filename;
1568 };
1569 
g_key_file_new(void)1570 GKeyFile *g_key_file_new(void)
1571 {
1572 	return g_new0(GKeyFile, 1);
1573 }
1574 
g_key_file_free(GKeyFile * key_file)1575 void g_key_file_free(GKeyFile *key_file)
1576 {
1577 	g_free(key_file->filename);
1578 	g_free(key_file);
1579 }
1580 
g_key_file_load_from_file(GKeyFile * key_file,const gchar * file,GKeyFileFlags flags,GError ** error)1581 gboolean g_key_file_load_from_file(GKeyFile *key_file,
1582 				const gchar *file,
1583 				GKeyFileFlags flags,
1584 				GError **error)
1585 {
1586 	key_file->filename = g_strdup(file);
1587 	return TRUE;
1588 }
1589 
next_line(const char * ptr)1590 static char *next_line(const char *ptr)
1591 {
1592 	char *nl;
1593 
1594 	nl = strchr(ptr, '\n');
1595 	if (!nl)
1596 		return NULL;
1597 
1598 	if (nl[1] == '\0')
1599 		return NULL;
1600 
1601 	return nl + 1;
1602 }
1603 
g_key_file_get_string(GKeyFile * key_file,const gchar * group_name,const gchar * key,GError ** error)1604 gchar *g_key_file_get_string(GKeyFile *key_file,
1605 				const gchar *group_name,
1606 				const gchar *key,
1607 				GError **error)
1608 {
1609 	struct stat st;
1610 	char *map, *line, *group = NULL, *value = NULL;
1611 	off_t size;
1612 	size_t key_len, group_len;
1613 	int fd, err = 0;
1614 
1615 	fd = open(key_file->filename, O_RDONLY);
1616 	if (fd < 0) {
1617 		g_set_error(error, 0, 0, "%s: %s", key_file->filename,
1618 				strerror(errno));
1619 		return NULL;
1620 	}
1621 
1622 	if (flock(fd, LOCK_SH) < 0) {
1623 		err = errno;
1624 		goto close;
1625 	}
1626 
1627 	if (fstat(fd, &st) < 0) {
1628 		err = errno;
1629 		goto unlock;
1630 	}
1631 
1632 	size = st.st_size;
1633 
1634 	map = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0);
1635 	if (!map || map == MAP_FAILED) {
1636 		err = errno;
1637 		goto unlock;
1638 	}
1639 
1640 	group_len = strlen(group_name);
1641 	key_len = strlen(key);
1642 
1643 	for (line = map; line != NULL; line = next_line(line)) {
1644 		int i;
1645 		size_t to_copy, value_len;
1646 		char tmp[1024], *nl;
1647 
1648 		if (*line == '#')
1649 			continue;
1650 
1651 		if (!group) {
1652 			if (line[0] != '[' || strncmp(line + 1, group_name, group_len))
1653 				continue;
1654 			if (line[group_len + 1] == ']')
1655 				group = line + 1;
1656 			continue;
1657 		}
1658 
1659 		if (strncmp(line, key, key_len))
1660 			continue;
1661 
1662 		for (i = key_len; line[i] != '\n'; i++) {
1663 			if (line[i] == '=')
1664 				break;
1665 			if (!isspace(line[i]))
1666 				break;
1667 		}
1668 
1669 		if (line[i] != '=')
1670 			continue;
1671 
1672 		nl = strchr(line, '\n');
1673 		if (!nl)
1674 			continue;
1675 
1676 		value_len = nl - (line + i + 1);
1677 		to_copy = value_len > (sizeof(tmp) - 1) ? sizeof(tmp) - 1 : value_len;
1678 		memset(tmp, 0, sizeof(tmp));
1679 		strncpy(tmp, line + i + 1, to_copy);
1680 
1681 		value = g_strdup(tmp);
1682 		break;
1683 	}
1684 
1685 	munmap(map, size);
1686 
1687 unlock:
1688 	flock(fd, LOCK_UN);
1689 
1690 close:
1691 	close(fd);
1692 
1693 	if (err)
1694 		g_set_error(error, 0, 0, "%s: %s", key_file->filename,
1695 				strerror(err));
1696 	else if (!group)
1697 		g_set_error(error, 0, 0, "%s: group %s not found",
1698 				key_file->filename, group_name);
1699 	else if (!value)
1700 		g_set_error(error, 0, 0, "%s: key %s not found",
1701 				key_file->filename, key);
1702 
1703 	return value;
1704 }
1705 
g_key_file_get_boolean(GKeyFile * key_file,const gchar * group_name,const gchar * key,GError ** error)1706 gboolean g_key_file_get_boolean(GKeyFile *key_file,
1707 				const gchar *group_name,
1708 				const gchar *key,
1709 				GError **error)
1710 {
1711 	gboolean ret;
1712 	gchar *str;
1713 
1714 	str = g_key_file_get_string(key_file, group_name, key, error);
1715 	if (!str)
1716 		return FALSE;
1717 
1718 	if (strcmp(str, "true") == 0 || strcmp(str, "1") == 0)
1719 		ret = TRUE;
1720 	else
1721 		ret = FALSE;
1722 
1723 	g_free(str);
1724 
1725 	return ret;
1726 }
1727 
g_key_file_get_integer(GKeyFile * key_file,const gchar * group_name,const gchar * key,GError ** error)1728 gint g_key_file_get_integer(GKeyFile *key_file,
1729 				const gchar *group_name,
1730 				const gchar *key,
1731 				GError **error)
1732 {
1733 	int ret;
1734 	gchar *str;
1735 
1736 	str = g_key_file_get_string(key_file, group_name, key, error);
1737 	if (!str)
1738 		return 0;
1739 
1740 	ret = atoi(str);
1741 
1742 	g_free(str);
1743 
1744 	return ret;
1745 }
1746 
g_key_file_get_string_list(GKeyFile * key_file,const gchar * group_name,const gchar * key,gsize * length,GError ** error)1747 gchar **g_key_file_get_string_list(GKeyFile *key_file, const gchar *group_name,
1748 					const gchar *key, gsize *length,
1749 					GError **error)
1750 {
1751 	gchar *str, *item, **list;
1752 	int items = 0;
1753 
1754 	str = g_key_file_get_string(key_file, group_name, key, error);
1755 	if (!str)
1756 		return NULL;
1757 
1758 	items = 0;
1759 	list = g_new0(char *, 1);
1760 
1761 	item = strtok(str, ",");
1762 	while (item) {
1763 		items++;
1764 
1765 		list = g_renew(char *, list, items + 1);
1766 
1767 		list[items - 1] = g_strdup(item);
1768 		list[items] = NULL;
1769 
1770 		item = strtok(NULL, ",");
1771 	}
1772 
1773 	g_free(str);
1774 
1775 	return list;
1776 }
1777 
1778 /* GString */
1779 
1780 #define MY_MAXSIZE ((gsize)-1)
1781 
nearest_power(gsize base,gsize num)1782 static gsize nearest_power(gsize base, gsize num)
1783 {
1784 	gsize n = base;
1785 
1786 	if (num > MY_MAXSIZE / 2)
1787 		return MY_MAXSIZE;
1788 
1789 	while (n < num)
1790 		n <<= 1;
1791 
1792 	return n;
1793 }
1794 
g_string_maybe_expand(GString * string,gsize len)1795 static void g_string_maybe_expand(GString *string, gsize len)
1796 {
1797 	if (string->len + len < string->allocated_len)
1798 		return;
1799 
1800 	string->allocated_len = nearest_power(1, string->len + len + 1);
1801 	string->str = g_realloc(string->str, string->allocated_len);
1802 }
1803 
g_string_sized_new(gsize dfl_size)1804 static GString *g_string_sized_new(gsize dfl_size)
1805 {
1806 	GString *string;
1807 
1808 	string = g_new0(GString, 1);
1809 
1810 	g_string_maybe_expand(string, dfl_size);
1811 	string->str[0] = '\0';
1812 
1813 	return string;
1814 }
1815 
g_string_append_len(GString * string,const gchar * val,gssize len)1816 static GString *g_string_append_len(GString *string, const gchar *val, gssize len)
1817 {
1818 	g_string_maybe_expand(string, len);
1819 
1820 	if (len == 1)
1821 		string->str[string->len] = *val;
1822 	else
1823 		memcpy(string->str + string->len, val, len);
1824 
1825 	string->len += len;
1826 	string->str[string->len] = '\0';
1827 
1828 	return string;
1829 }
1830 
g_string_new(const gchar * init)1831 GString *g_string_new(const gchar *init)
1832 {
1833 	GString *string;
1834 	gint len;
1835 
1836 	if (init == NULL || *init == '\0')
1837 		return g_string_sized_new(2);
1838 
1839 	len = strlen(init);
1840 	string = g_string_sized_new(len + 2);
1841 
1842 	g_string_append_len(string, init, len);
1843 
1844 	return string;
1845 }
1846 
g_string_append_printf(GString * string,const gchar * format,...)1847 void g_string_append_printf(GString *string, const gchar *format, ...)
1848 {
1849 	gchar buffer[1024];
1850 	gint length;
1851 	va_list args;
1852 
1853 	va_start(args, format);
1854 	length = vsnprintf(buffer, sizeof(buffer) - 1, format, args);
1855 	va_end(args);
1856 
1857 	g_string_append_len(string, buffer, length);
1858 }
1859 
g_string_free(GString * string,gboolean free_segment)1860 gchar *g_string_free(GString *string, gboolean free_segment)
1861 {
1862 	gchar *segment;
1863 
1864 	if (free_segment) {
1865 		g_free(string->str);
1866 		segment = NULL;
1867 	} else
1868 		segment = string->str;
1869 
1870 	g_free(string);
1871 
1872 	return segment;
1873 }
1874 
1875 /* GMarkup */
1876 
1877 struct _GMarkupParseContext {
1878 	char dummy;
1879 };
1880 
g_markup_parse_context_new(const GMarkupParser * parser,GMarkupParseFlags flags,gpointer user_data,GDestroyNotify user_data_dnotify)1881 GMarkupParseContext *g_markup_parse_context_new(const GMarkupParser *parser,
1882 					GMarkupParseFlags flags,
1883 					gpointer user_data,
1884 					GDestroyNotify user_data_dnotify)
1885 {
1886 	return g_new0(GMarkupParseContext, 1);
1887 }
1888 
g_markup_parse_context_parse(GMarkupParseContext * context,const gchar * text,gssize text_len,GError ** error)1889 gboolean g_markup_parse_context_parse(GMarkupParseContext *context,
1890 					const gchar *text, gssize text_len,
1891 					GError **error)
1892 {
1893 	g_set_error(error, 0, 0, "Not implemented");
1894 	return FALSE;
1895 }
1896 
g_markup_parse_context_free(GMarkupParseContext * context)1897 void g_markup_parse_context_free(GMarkupParseContext *context)
1898 {
1899 	g_free(context);
1900 }
1901 
g_build_pathname_va(const gchar * first_element,va_list args,gpointer * data)1902 static gchar *g_build_pathname_va(const gchar *first_element,
1903 						va_list args, gpointer *data)
1904 {
1905 	gchar result[PATH_MAX], *element;
1906 
1907 	strncpy(result, first_element, PATH_MAX);
1908 	element = va_arg(args, gchar *);
1909 
1910 	while (element) {
1911 		g_strlcat(result, "/", PATH_MAX);
1912 		g_strlcat(result, element, PATH_MAX);
1913 		element = va_arg(args, gchar *);
1914 	}
1915 
1916 	va_end(args);
1917 
1918 	return g_strdup(result);
1919 }
1920 
g_build_filename(const gchar * first_element,...)1921 gchar *g_build_filename(const gchar *first_element, ...)
1922 {
1923 	gchar *str;
1924 	va_list args;
1925 
1926 	va_start(args, first_element);
1927 	str = g_build_pathname_va(first_element, args, NULL);
1928 	va_end(args);
1929 
1930 	return str;
1931 }
1932 
1933 /* GDir */
1934 
g_dir_open(const gchar * path,guint flags,GError ** error)1935 GDir *g_dir_open(const gchar *path, guint flags, GError **error)
1936 {
1937 	GDir *dir;
1938 
1939 	if (path == NULL)
1940 		return NULL;
1941 
1942 	dir = g_new(GDir, 1);
1943 
1944 	dir->dirp = opendir(path);
1945 
1946 	if (dir->dirp)
1947 		return dir;
1948 
1949 	/* error case */
1950 	g_set_error(error, 0, 0, "Error opening directory '%s': %s",
1951 						path, strerror(errno));
1952 
1953 	g_free(dir);
1954 
1955 	return NULL;
1956 }
1957 
g_dir_read_name(GDir * dir)1958 const gchar *g_dir_read_name(GDir *dir)
1959 {
1960 	struct dirent *entry;
1961 
1962 	if (dir == NULL)
1963 		return NULL;
1964 
1965 	entry = readdir(dir->dirp);
1966 
1967 	while (entry && (strcmp(entry->d_name, ".") == 0 ||
1968 					strcmp(entry->d_name, "..") == 0))
1969 		entry = readdir(dir->dirp);
1970 
1971 	return entry ? entry->d_name : NULL;
1972 }
1973 
g_dir_close(GDir * dir)1974 void g_dir_close(GDir *dir)
1975 {
1976 	if (dir == NULL)
1977 		return;
1978 
1979 	closedir(dir->dirp);
1980 	g_free(dir);
1981 }
1982