~ubuntu-branches/ubuntu/maverick/uim/maverick

« back to all changes in this revision

Viewing changes to uim/uim-notify.c

  • Committer: Bazaar Package Importer
  • Author(s): Masahito Omote
  • Date: 2008-06-25 19:56:33 UTC
  • mfrom: (3.1.18 intrepid)
  • Revision ID: james.westby@ubuntu.com-20080625195633-8jljph4rfq00l8o7
Tags: 1:1.5.1-2
* uim-tcode: provide tutcode-custom.scm, tutcode-bushudic.scm
  and tutcode-rule.scm (Closes: #482659)
* Fix FTBFS: segv during compile (Closes: #483078).
  I personally think this bug is not specific for uim but is a optimization
  problem on gcc-4.3.1. (https://bugs.freedesktop.org/show_bug.cgi?id=16477)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
  Copyright (c) 2003-2008 uim Project http://code.google.com/p/uim/
 
3
 
 
4
  All rights reserved.
 
5
 
 
6
  Redistribution and use in source and binary forms, with or without
 
7
  modification, are permitted provided that the following conditions
 
8
  are met:
 
9
 
 
10
  1. Redistributions of source code must retain the above copyright
 
11
     notice, this list of conditions and the following disclaimer.
 
12
  2. Redistributions in binary form must reproduce the above copyright
 
13
     notice, this list of conditions and the following disclaimer in the
 
14
     documentation and/or other materials provided with the distribution.
 
15
  3. Neither the name of authors nor the names of its contributors
 
16
     may be used to endorse or promote products derived from this software
 
17
     without specific prior written permission.
 
18
 
 
19
  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND
 
20
  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 
21
  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 
22
  ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE
 
23
  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 
24
  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 
25
  OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 
26
  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 
27
  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 
28
  OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 
29
  SUCH DAMAGE.
 
30
 
 
31
*/
 
32
 
 
33
#include <config.h>
 
34
 
 
35
#include <stdio.h>
 
36
#include <string.h>
 
37
#include <stdarg.h>
 
38
#include <dlfcn.h>
 
39
#include <dirent.h>
 
40
#include <unistd.h>
 
41
#include <stdlib.h>
 
42
#include <sys/types.h>
 
43
#include <sys/stat.h>
 
44
#include <fcntl.h>
 
45
#include <errno.h>
 
46
#include <pwd.h>
 
47
 
 
48
#include "uim.h"
 
49
#include "uim-scm.h"
 
50
#include "uim-scm-abbrev.h"
 
51
#include "uim-internal.h"
 
52
#include "uim-notify.h"
 
53
 
 
54
 
 
55
#define NOTIFY_PLUGIN_PATH LIBDIR "/uim/notify"
 
56
#define NOTIFY_PLUGIN_PREFIX "libuimnotify-"
 
57
#define NOTIFY_PLUGIN_SUFFIX ".so"
 
58
 
 
59
#ifndef HAVE_DLFUNC
 
60
typedef void (*my_dlfunc_t)(void);
 
61
#define dlfunc(handle, symbol) \
 
62
  ((my_dlfunc_t)(uintptr_t)dlsym((handle), (symbol)))
 
63
#else
 
64
typedef dlfunc_t my_dlfunc_t;
 
65
#endif
 
66
 
 
67
struct uim_notify_agent {
 
68
  const uim_notify_desc *(*desc)(void);
 
69
  int (*init)(void);
 
70
  void (*quit)(void);
 
71
  int (*notify_info)(const char *);
 
72
  int (*notify_fatal)(const char *);
 
73
};
 
74
 
 
75
static my_dlfunc_t load_func(const char *path, const char *name);
 
76
 
 
77
/* FIXME: Move these decls to the 'stderr' agent section and make
 
78
 * invisible from other part of uim-notify.  -- YamaKen 2008-01-30 */
 
79
static void uim_notify_load_stderr(void);
 
80
static const uim_notify_desc *uim_notify_stderr_get_desc(void);
 
81
 
 
82
 
 
83
static struct uim_notify_agent agent_body;
 
84
static struct uim_notify_agent *agent = &agent_body;
 
85
static void *notify_dlhandle = NULL;
 
86
 
 
87
 
 
88
static my_dlfunc_t
 
89
load_func(const char *path, const char *name)
 
90
{
 
91
  my_dlfunc_t f;
 
92
 
 
93
  f = (my_dlfunc_t)dlfunc(notify_dlhandle, name);
 
94
  if (!f) {
 
95
    fprintf(stderr, "uim-notify: cannot found '%s()' in %s\n", name, path);
 
96
    dlclose(notify_dlhandle);
 
97
    uim_notify_load_stderr();
 
98
    return NULL;
 
99
  }
 
100
  return f;
 
101
}
 
102
 
 
103
uim_bool
 
104
uim_notify_load(const char *name)
 
105
{
 
106
  if (!agent->quit || !agent->desc) {
 
107
    fprintf(stderr, "uim-notify: notification agent module is not loaded\n");
 
108
    uim_notify_load_stderr();
 
109
    return UIM_FALSE;
 
110
  }
 
111
 
 
112
  if (strcmp(agent->desc()->name, name) == 0) {
 
113
    return UIM_TRUE;
 
114
  } else if (strcmp(name, "stderr") == 0) {
 
115
    agent->quit();
 
116
    if (notify_dlhandle)
 
117
      dlclose(notify_dlhandle);
 
118
    uim_notify_load_stderr();
 
119
  } else {
 
120
    char path[PATH_MAX];
 
121
    const char *str;
 
122
 
 
123
    agent->quit();
 
124
    if (notify_dlhandle)
 
125
      dlclose(notify_dlhandle);
 
126
 
 
127
    snprintf(path, sizeof(path), "%s/%s%s%s", NOTIFY_PLUGIN_PATH,
 
128
             NOTIFY_PLUGIN_PREFIX, name, NOTIFY_PLUGIN_SUFFIX);
 
129
 
 
130
    notify_dlhandle = dlopen(path, RTLD_NOW);
 
131
    if ((str = dlerror())) {
 
132
      fprintf(stderr, "uim-notify: load failed %s(%s)\n", path, str);
 
133
      uim_notify_load_stderr();
 
134
      return UIM_FALSE;
 
135
    }
 
136
    agent->desc = (const uim_notify_desc *(*)(void))load_func(path, "uim_notify_plugin_get_desc");
 
137
    if (!agent->desc)
 
138
      return UIM_FALSE;
 
139
 
 
140
    agent->init = (int (*)(void))load_func(path, "uim_notify_plugin_init");
 
141
    if (!agent->init)
 
142
      return UIM_FALSE;
 
143
 
 
144
    agent->quit = (void (*)(void))load_func(path, "uim_notify_plugin_quit");
 
145
    if (!agent->quit)
 
146
      return UIM_FALSE;
 
147
 
 
148
    agent->notify_info = (int (*)(const char *))load_func(path, "uim_notify_plugin_info");
 
149
    if (!agent->notify_info)
 
150
      return UIM_FALSE;
 
151
 
 
152
    agent->notify_fatal = (int (*)(const char *))load_func(path, "uim_notify_plugin_fatal");
 
153
    if (!agent->notify_fatal)
 
154
      return UIM_FALSE;
 
155
 
 
156
    agent->init();
 
157
  }
 
158
  return UIM_TRUE;
 
159
}
 
160
 
 
161
const uim_notify_desc *
 
162
uim_notify_get_desc(void)
 
163
{
 
164
  return agent->desc();
 
165
}
 
166
 
 
167
uim_bool
 
168
uim_notify_init(void)
 
169
{
 
170
  /* Since a cyclic init/quit sequence leaves *agent uncleared,
 
171
   * explicit initialization is required. Such data initialization is
 
172
   * needed for some embedded platforms such as Qtopia.
 
173
   *   -- YamaKen 2008-01-30 */
 
174
  uim_notify_load_stderr();
 
175
 
 
176
  return agent->init();
 
177
}
 
178
 
 
179
void
 
180
uim_notify_quit(void)
 
181
{
 
182
  agent->quit();
 
183
}
 
184
 
 
185
uim_bool
 
186
uim_notify_info(const char *msg_fmt, ...)
 
187
{
 
188
  va_list ap;
 
189
  char msg[BUFSIZ];
 
190
 
 
191
  va_start(ap, msg_fmt);
 
192
  vsnprintf(msg, sizeof(msg), msg_fmt, ap);
 
193
  va_end(ap);
 
194
 
 
195
  return agent->notify_info(msg);
 
196
}
 
197
 
 
198
uim_bool
 
199
uim_notify_fatal(const char *msg_fmt, ...)
 
200
{
 
201
  va_list ap;
 
202
  char msg[BUFSIZ];
 
203
 
 
204
  va_start(ap, msg_fmt);
 
205
  vsnprintf(msg, sizeof(msg), msg_fmt, ap);
 
206
  va_end(ap);
 
207
 
 
208
  return agent->notify_fatal(msg);
 
209
}
 
210
 
 
211
/* Low stack-consumption version of uim_notify_fatal(). */
 
212
uim_bool
 
213
uim_notify_fatal_raw(const char *msg)
 
214
{
 
215
  return agent->notify_fatal(msg);
 
216
}
 
217
 
 
218
/*
 
219
 * Scheme interfaces
 
220
 */
 
221
static uim_lisp
 
222
notify_get_plugins(void)
 
223
{
 
224
  uim_lisp ret_;
 
225
  DIR *dirp;
 
226
  struct dirent *dp;
 
227
  size_t plen, slen;
 
228
  const uim_notify_desc *desc;
 
229
  void *handle;
 
230
  uim_notify_desc *(*desc_func)(void);
 
231
  const char *str;
 
232
 
 
233
  plen = sizeof(NOTIFY_PLUGIN_PREFIX);
 
234
  slen = sizeof(NOTIFY_PLUGIN_SUFFIX);
 
235
 
 
236
  desc = uim_notify_stderr_get_desc();
 
237
  ret_ = CONS(LIST3(MAKE_SYM(desc->name),
 
238
                    MAKE_STR(desc->name),
 
239
                    MAKE_STR(desc->desc)),
 
240
              uim_scm_null());
 
241
  dirp = opendir(NOTIFY_PLUGIN_PATH);
 
242
  if (dirp) {
 
243
    while ((dp = readdir(dirp)) != NULL) {
 
244
      size_t len = strlen(dp->d_name);
 
245
      char path[PATH_MAX];
 
246
      if ((len < plen + slen - 1) ||
 
247
          (PATH_MAX < (sizeof(NOTIFY_PLUGIN_PATH "/") + len)) ||
 
248
          (strcmp(dp->d_name, NOTIFY_PLUGIN_PREFIX) <= 0) ||
 
249
          (strcmp(dp->d_name + len + 1 - slen, NOTIFY_PLUGIN_SUFFIX) != 0))
 
250
        continue;
 
251
 
 
252
      snprintf(path, sizeof(path), "%s/%s", NOTIFY_PLUGIN_PATH, dp->d_name);
 
253
      handle = dlopen(path, RTLD_NOW);
 
254
      if ((str = dlerror()) != NULL) {
 
255
        fprintf(stderr, "load failed %s(%s)\n", path, str);
 
256
        continue;
 
257
      }
 
258
      desc_func = (uim_notify_desc *(*)(void))dlfunc(handle, "uim_notify_plugin_get_desc");
 
259
      if (!desc_func) {
 
260
        fprintf(stderr, "cannot found 'uim_notify_get_desc()' in %s\n", path);
 
261
        dlclose(handle);
 
262
        continue;
 
263
      }
 
264
 
 
265
      desc = desc_func();
 
266
 
 
267
      ret_ = CONS(LIST3(MAKE_SYM(desc->name),
 
268
                        MAKE_STR(desc->name),
 
269
                        MAKE_STR(desc->desc)),
 
270
                  ret_);
 
271
 
 
272
      dlclose(handle);
 
273
    }
 
274
    (void)closedir(dirp);
 
275
  }
 
276
  return uim_scm_callf("reverse", "o", ret_);
 
277
}
 
278
 
 
279
static uim_lisp
 
280
notify_load(uim_lisp name_)
 
281
{
 
282
  const char *name = REFER_C_STR(name_);
 
283
 
 
284
  return MAKE_BOOL(uim_notify_load(name));
 
285
}
 
286
 
 
287
static uim_lisp
 
288
notify_info(uim_lisp msg_)
 
289
{
 
290
  const char *msg = REFER_C_STR(msg_);
 
291
 
 
292
  return MAKE_BOOL(uim_notify_info("%s", msg));
 
293
}
 
294
 
 
295
static uim_lisp
 
296
notify_fatal(uim_lisp msg_)
 
297
{
 
298
  const char *msg = REFER_C_STR(msg_);
 
299
 
 
300
  return MAKE_BOOL(uim_notify_fatal("%s", msg));
 
301
}
 
302
 
 
303
void
 
304
uim_init_notify_subrs(void)
 
305
{
 
306
  uim_scm_init_proc0("uim-notify-get-plugins", notify_get_plugins);
 
307
  uim_scm_init_proc1("uim-notify-load", notify_load);
 
308
  uim_scm_init_proc1("uim-notify-info", notify_info);
 
309
  uim_scm_init_proc1("uim-notify-fatal", notify_fatal);
 
310
}
 
311
 
 
312
 
 
313
/*
 
314
 * builtin 'stderr' notification agent
 
315
 */
 
316
static uim_bool uim_notify_stderr_init(void);
 
317
static void uim_notify_stderr_quit(void);
 
318
static uim_bool uim_notify_stderr_info(const char *);
 
319
static uim_bool uim_notify_stderr_fatal(const char *);
 
320
 
 
321
static const uim_notify_desc uim_notify_stderr_desc = {
 
322
  "stderr",
 
323
  "Standard Error output",
 
324
};
 
325
 
 
326
static void
 
327
uim_notify_load_stderr(void)
 
328
{
 
329
  agent->desc = uim_notify_stderr_get_desc;
 
330
  agent->init = uim_notify_stderr_init;
 
331
  agent->quit = uim_notify_stderr_quit;
 
332
  agent->notify_info = uim_notify_stderr_info;
 
333
  agent->notify_fatal = uim_notify_stderr_fatal;
 
334
  notify_dlhandle = NULL;
 
335
}
 
336
 
 
337
static const uim_notify_desc *
 
338
uim_notify_stderr_get_desc(void)
 
339
{
 
340
  return &uim_notify_stderr_desc;
 
341
}
 
342
 
 
343
static uim_bool
 
344
uim_notify_stderr_init(void)
 
345
{
 
346
  return UIM_TRUE;
 
347
}
 
348
 
 
349
static void
 
350
uim_notify_stderr_quit(void)
 
351
{
 
352
  return;
 
353
}
 
354
 
 
355
static uim_bool
 
356
uim_notify_stderr_info(const char *msg)
 
357
{
 
358
  fputs("libuim: [info] ", stderr);
 
359
  fputs(msg, stderr);
 
360
  fputs("\n", stderr);
 
361
 
 
362
  return UIM_TRUE;
 
363
}
 
364
 
 
365
static uim_bool
 
366
uim_notify_stderr_fatal(const char *msg)
 
367
{
 
368
  /* To reduce stack consumption on hard situations such as memory
 
369
   * exhaustion, printf()s with indirect directives are intentionally
 
370
   * avoided here.  -- YamaKen 2008-02-11 */
 
371
  fputs("libuim: [fatal] ", stderr);
 
372
  fputs(msg, stderr);
 
373
  fputs("\n", stderr);
 
374
 
 
375
  return UIM_TRUE;
 
376
}