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