~ubuntu-branches/ubuntu/wily/xfce4-appfinder/wily-proposed

« back to all changes in this revision

Viewing changes to src/appfinder-actions.c

  • Committer: Package Import Robot
  • Author(s): Lionel Le Folgoc, Lionel Le Folgoc, Yves-Alexis Perez
  • Date: 2012-04-08 22:22:48 UTC
  • mfrom: (1.3.19) (4.1.3 sid)
  • Revision ID: package-import@ubuntu.com-20120408222248-iq2by93vf7l5ntac
Tags: 4.9.4-1
[ Lionel Le Folgoc ]
* New upstream development release.
* debian/xfce4-appfinder.1: updated for the new options in 4.9.x.
* debian/control:
  - switch to libxfce4util6-dev for the new api.
  - bump libxfce4ui-1-dev to >= 4.9.0 for the new help api.
  - breaks/replaces pre 4.10 xfce4-utils package, as it
    previously shipped xfrun4.
* debian/links: xfrun4 is now a symlink to xfce4-appfinder, so add a symlink
  for its manpage too.

[ Yves-Alexis Perez ]
* debian/control:
  - update standards version to 3.9.3.
  - update debhelper build-dep to 9.
  - add build-dep on dpkg-dev 1.16.1.
  - drop build-dep on hardening-includes.
  - add buil-dep on libdbus-glib-1-dev.
* debian/compat bumped to 9.
* debian/rules:
  - use debhelper 9 and dpkg-dev 1.16.1 hardening support.
  - build with --parallel.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (C) 2011 Nick Schermer <nick@xfce.org>
 
3
 *
 
4
 * This program is free software; you can redistribute it and/or modify
 
5
 * it under the terms of the GNU General Public License as published by
 
6
 * the Free Software Foundation; either version 2 of the License, or
 
7
 * (at your option) any later version.
 
8
 *
 
9
 * This program is distributed in the hope that it will be useful,
 
10
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
12
 * GNU General Public License for more details.
 
13
 *
 
14
 * You should have received a copy of the GNU General Public License along
 
15
 * with this program; if not, write to the Free Software Foundation, Inc.,
 
16
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 
17
 */
 
18
 
 
19
#ifdef HAVE_CONFIG_H
 
20
#include <config.h>
 
21
#endif
 
22
 
 
23
#ifdef HAVE_STRING_H
 
24
#include <string.h>
 
25
#endif
 
26
 
 
27
#include <libxfce4util/libxfce4util.h>
 
28
#include <libxfce4ui/libxfce4ui.h>
 
29
#include <xfconf/xfconf.h>
 
30
 
 
31
#include <src/appfinder-actions.h>
 
32
#include <src/appfinder-private.h>
 
33
 
 
34
 
 
35
 
 
36
static void xfce_appfinder_actions_finalize (GObject              *object);
 
37
static void xfce_appfinder_actions_free     (XfceAppfinderAction  *action);
 
38
static void xfce_appfinder_actions_load     (XfceAppfinderActions *actions,
 
39
                                             gboolean              steal);
 
40
static void xfce_appfinder_actions_save     (XfceAppfinderActions *actions,
 
41
                                             gboolean              save_actions);
 
42
static void xfce_appfinder_actions_changed  (XfconfChannel        *channel,
 
43
                                             const gchar          *prop_name,
 
44
                                             const GValue         *value,
 
45
                                             XfceAppfinderActions *actions);
 
46
 
 
47
 
 
48
 
 
49
struct _XfceAppfinderActionsClass
 
50
{
 
51
  GObjectClass __parent__;
 
52
};
 
53
 
 
54
struct _XfceAppfinderActions
 
55
{
 
56
  GObject __parent__;
 
57
 
 
58
  XfconfChannel *channel;
 
59
  gulong         property_watch_id;
 
60
 
 
61
  guint          reload_idle_id;
 
62
 
 
63
  GSList        *actions;
 
64
};
 
65
 
 
66
typedef enum
 
67
{
 
68
  XFCE_APPFINDER_ACTION_TYPE_PREFIX,
 
69
  XFCE_APPFINDER_ACTION_TYPE_REGEX
 
70
}
 
71
AppfinderActionType;
 
72
 
 
73
struct _XfceAppfinderAction
 
74
{
 
75
  AppfinderActionType  type;
 
76
 
 
77
  gint                 unique_id;
 
78
  gchar               *pattern;
 
79
  gchar               *command;
 
80
  guint                save : 1;
 
81
 
 
82
  GRegex              *regex;
 
83
};
 
84
 
 
85
 
 
86
 
 
87
G_DEFINE_TYPE (XfceAppfinderActions, xfce_appfinder_actions, G_TYPE_OBJECT)
 
88
 
 
89
 
 
90
 
 
91
static void
 
92
xfce_appfinder_actions_class_init (XfceAppfinderActionsClass *klass)
 
93
{
 
94
  GObjectClass *gobject_class;
 
95
 
 
96
  gobject_class = G_OBJECT_CLASS (klass);
 
97
  gobject_class->finalize = xfce_appfinder_actions_finalize;
 
98
}
 
99
 
 
100
 
 
101
 
 
102
static void
 
103
xfce_appfinder_actions_init (XfceAppfinderActions *actions)
 
104
{
 
105
  actions->channel = xfconf_channel_get ("xfce4-appfinder");
 
106
 
 
107
  xfce_appfinder_actions_load (actions, FALSE);
 
108
 
 
109
  actions->property_watch_id =
 
110
    g_signal_connect (G_OBJECT (actions->channel), "property-changed",
 
111
                      G_CALLBACK (xfce_appfinder_actions_changed), actions);
 
112
}
 
113
 
 
114
 
 
115
 
 
116
static void
 
117
xfce_appfinder_actions_finalize (GObject *object)
 
118
{
 
119
  XfceAppfinderActions *actions = XFCE_APPFINDER_ACTIONS (object);
 
120
 
 
121
  if (actions->reload_idle_id != 0)
 
122
    g_source_remove (actions->reload_idle_id);
 
123
 
 
124
  g_signal_handler_disconnect (actions->channel, actions->property_watch_id);
 
125
 
 
126
  g_slist_foreach (actions->actions, (GFunc) xfce_appfinder_actions_free, NULL);
 
127
  g_slist_free (actions->actions);
 
128
 
 
129
  (*G_OBJECT_CLASS (xfce_appfinder_actions_parent_class)->finalize) (object);
 
130
}
 
131
 
 
132
 
 
133
 
 
134
static void
 
135
xfce_appfinder_actions_free (XfceAppfinderAction *action)
 
136
{
 
137
  g_free (action->pattern);
 
138
  g_free (action->command);
 
139
 
 
140
  if (action->regex != NULL)
 
141
    g_regex_unref (action->regex);
 
142
 
 
143
  g_slice_free (XfceAppfinderAction, action);
 
144
}
 
145
 
 
146
 
 
147
 
 
148
static void
 
149
xfce_appfinder_actions_load_defaults (XfceAppfinderActions *actions)
 
150
{
 
151
  guint                i;
 
152
  XfceAppfinderAction *action;
 
153
  XfceAppfinderAction  defaults[] =
 
154
  {
 
155
    /* default actions, sorted */
 
156
    { XFCE_APPFINDER_ACTION_TYPE_REGEX, 0,
 
157
      "^(file|http|https):\\/\\/(.*)$",
 
158
      "exo-open \\0",
 
159
      FALSE,
 
160
      NULL },
 
161
    { XFCE_APPFINDER_ACTION_TYPE_PREFIX, 0,
 
162
      "!",
 
163
      "exo-open --launch TerminalEmulator %s",
 
164
      TRUE,
 
165
      NULL },
 
166
    { XFCE_APPFINDER_ACTION_TYPE_PREFIX, 0,
 
167
      "!w",
 
168
      "exo-open --launch WebBrowser http://en.wikipedia.org/wiki/%s",
 
169
      FALSE,
 
170
      NULL },
 
171
    { XFCE_APPFINDER_ACTION_TYPE_PREFIX, 0,
 
172
      "#",
 
173
      "exo-open --launch TerminalEmulator man %s",
 
174
      FALSE,
 
175
      NULL }
 
176
  };
 
177
 
 
178
  APPFINDER_DEBUG ("loaded default actions");
 
179
 
 
180
  for (i = 0; i < G_N_ELEMENTS (defaults); i++)
 
181
    {
 
182
      action = g_slice_new0 (XfceAppfinderAction);
 
183
      action->type = defaults[i].type;
 
184
      action->unique_id = i + 1;
 
185
      action->pattern = g_strdup (defaults[i].pattern);
 
186
      action->command = g_strdup (defaults[i].command);
 
187
      action->save = defaults[i].save;
 
188
 
 
189
      actions->actions = g_slist_prepend (actions->actions, action);
 
190
    }
 
191
}
 
192
 
 
193
 
 
194
 
 
195
static gint
 
196
xfce_appfinder_actions_sort (gconstpointer a,
 
197
                             gconstpointer b)
 
198
{
 
199
  const XfceAppfinderAction *action_a = a;
 
200
  const XfceAppfinderAction *action_b = b;
 
201
 
 
202
  if (action_a->type != action_b->type)
 
203
    return action_a->type == XFCE_APPFINDER_ACTION_TYPE_PREFIX ? -1 : 1;
 
204
 
 
205
  /* reverse the order so prefixes are properly matched */
 
206
  return -g_strcmp0 (action_a->pattern, action_b->pattern);
 
207
}
 
208
 
 
209
 
 
210
 
 
211
static void
 
212
xfce_appfinder_actions_load (XfceAppfinderActions *actions,
 
213
                             gboolean              steal)
 
214
{
 
215
  XfceAppfinderAction *action;
 
216
  gchar                prop[32];
 
217
  gint                 type;
 
218
  gchar               *pattern, *command;
 
219
  gboolean             save;
 
220
  const GValue        *value;
 
221
  guint                i;
 
222
  gint                 unique_id;
 
223
  GPtrArray           *array;
 
224
  GSList              *li, *old_actions = NULL;
 
225
 
 
226
  appfinder_return_if_fail (XFCE_IS_APPFINDER_ACTIONS (actions));
 
227
  appfinder_return_if_fail (steal || actions->actions == NULL);
 
228
 
 
229
  if (steal)
 
230
    {
 
231
      old_actions = actions->actions;
 
232
      actions->actions = NULL;
 
233
    }
 
234
 
 
235
  if (xfconf_channel_has_property (actions->channel, "/actions"))
 
236
    {
 
237
      array = xfconf_channel_get_arrayv (actions->channel, "/actions");
 
238
      if (G_LIKELY (array != NULL))
 
239
        {
 
240
          for (i = 0; i < array->len; i++)
 
241
            {
 
242
              value = g_ptr_array_index (array, i);
 
243
              appfinder_assert (value != NULL);
 
244
              unique_id = g_value_get_int (value);
 
245
 
 
246
              /* look for the id in the old actions */
 
247
              for (li = old_actions; li != NULL; li = li->next)
 
248
                {
 
249
                  action = li->data;
 
250
                  if (action->unique_id == unique_id)
 
251
                    break;
 
252
                }
 
253
 
 
254
              if (li != NULL)
 
255
                {
 
256
                  /* use the old action */
 
257
                  old_actions = g_slist_delete_link (old_actions, li);
 
258
                  actions->actions = g_slist_prepend (actions->actions, action);
 
259
 
 
260
                  continue;
 
261
                }
 
262
 
 
263
              /* no usable actions was found, create a new one */
 
264
              g_snprintf (prop, sizeof (prop), "/actions/action-%d/type", unique_id);
 
265
              type = xfconf_channel_get_int (actions->channel, prop, XFCE_APPFINDER_ACTION_TYPE_PREFIX);
 
266
              if (type < XFCE_APPFINDER_ACTION_TYPE_PREFIX
 
267
                  || type > XFCE_APPFINDER_ACTION_TYPE_REGEX)
 
268
                continue;
 
269
 
 
270
              g_snprintf (prop, sizeof (prop), "/actions/action-%d/pattern", unique_id);
 
271
              pattern = xfconf_channel_get_string (actions->channel, prop, NULL);
 
272
 
 
273
              g_snprintf (prop, sizeof (prop), "/actions/action-%d/command", unique_id);
 
274
              command = xfconf_channel_get_string (actions->channel, prop, NULL);
 
275
 
 
276
              g_snprintf (prop, sizeof (prop), "/actions/action-%d/save", unique_id);
 
277
              save = xfconf_channel_get_bool (actions->channel, prop, FALSE);
 
278
 
 
279
              action = g_slice_new0 (XfceAppfinderAction);
 
280
              action->type = type;
 
281
              action->unique_id = unique_id;
 
282
              action->pattern = pattern;
 
283
              action->command = command;
 
284
              action->save = save;
 
285
 
 
286
              actions->actions = g_slist_prepend (actions->actions, action);
 
287
            }
 
288
 
 
289
          xfconf_array_free (array);
 
290
        }
 
291
    }
 
292
  else
 
293
    {
 
294
      xfce_appfinder_actions_load_defaults (actions);
 
295
      xfce_appfinder_actions_save (actions, TRUE);
 
296
    }
 
297
 
 
298
  if (old_actions != NULL)
 
299
    {
 
300
      g_slist_foreach (old_actions, (GFunc) xfce_appfinder_actions_free, NULL);
 
301
      g_slist_free (old_actions);
 
302
    }
 
303
 
 
304
  actions->actions = g_slist_sort (actions->actions, xfce_appfinder_actions_sort);
 
305
 
 
306
  APPFINDER_DEBUG ("loaded %d actions", g_slist_length (actions->actions));
 
307
}
 
308
 
 
309
 
 
310
 
 
311
static gboolean
 
312
xfce_appfinder_actions_reload_idle (gpointer data)
 
313
{
 
314
  xfce_appfinder_actions_load (XFCE_APPFINDER_ACTIONS (data), TRUE);
 
315
  return FALSE;
 
316
}
 
317
 
 
318
 
 
319
 
 
320
static void
 
321
xfce_appfinder_actions_reload_idle_destroyed (gpointer data)
 
322
{
 
323
  XFCE_APPFINDER_ACTIONS (data)->reload_idle_id = 0;
 
324
}
 
325
 
 
326
 
 
327
 
 
328
static void
 
329
xfce_appfinder_actions_save (XfceAppfinderActions *actions,
 
330
                             gboolean              save_actions)
 
331
{
 
332
  XfceAppfinderAction *action;
 
333
  GSList              *li;
 
334
  GValue              *value;
 
335
  GPtrArray           *array;
 
336
  gchar                prop[32];
 
337
 
 
338
  if (actions->property_watch_id > 0)
 
339
    g_signal_handler_block (actions->channel, actions->property_watch_id);
 
340
 
 
341
  array = g_ptr_array_new ();
 
342
 
 
343
  for (li = actions->actions; li != NULL; li = li->next)
 
344
    {
 
345
      value = g_new0 (GValue, 1);
 
346
      g_value_init (value, G_TYPE_INT);
 
347
 
 
348
      action = li->data;
 
349
      g_value_set_int (value, action->unique_id);
 
350
      g_ptr_array_add (array, value);
 
351
 
 
352
      if (save_actions)
 
353
        {
 
354
          g_snprintf (prop, sizeof (prop), "/actions/action-%d/type", action->unique_id);
 
355
          xfconf_channel_set_int (actions->channel, prop, action->type);
 
356
 
 
357
          g_snprintf (prop, sizeof (prop), "/actions/action-%d/pattern", action->unique_id);
 
358
          xfconf_channel_set_string (actions->channel, prop, action->pattern);
 
359
 
 
360
          g_snprintf (prop, sizeof (prop), "/actions/action-%d/command", action->unique_id);
 
361
          xfconf_channel_set_string (actions->channel, prop, action->command);
 
362
 
 
363
          g_snprintf (prop, sizeof (prop), "/actions/action-%d/save", action->unique_id);
 
364
          xfconf_channel_set_bool (actions->channel, prop, action->save);
 
365
        }
 
366
    }
 
367
 
 
368
  xfconf_channel_set_arrayv (actions->channel, "/actions", array);
 
369
 
 
370
  xfconf_array_free (array);
 
371
 
 
372
  if (actions->property_watch_id > 0)
 
373
    g_signal_handler_unblock (actions->channel, actions->property_watch_id);
 
374
}
 
375
 
 
376
 
 
377
 
 
378
 
 
379
static void
 
380
xfce_appfinder_actions_changed (XfconfChannel        *channel,
 
381
                                const gchar          *prop_name,
 
382
                                const GValue         *value,
 
383
                                XfceAppfinderActions *actions)
 
384
{
 
385
  gint                 unique_id;
 
386
  gchar                field[32];
 
387
  GSList              *li;
 
388
  XfceAppfinderAction *action;
 
389
 
 
390
  if (prop_name == NULL)
 
391
    return;
 
392
 
 
393
  if (strcmp (prop_name, "/actions") == 0)
 
394
    {
 
395
      if (actions->reload_idle_id == 0)
 
396
        {
 
397
          actions->reload_idle_id = g_idle_add_full (G_PRIORITY_LOW,
 
398
              xfce_appfinder_actions_reload_idle, actions,
 
399
              xfce_appfinder_actions_reload_idle_destroyed);
 
400
        }
 
401
    }
 
402
  else if (sscanf (prop_name, "/actions/action-%d/%30s",
 
403
                   &unique_id, field) == 2)
 
404
    {
 
405
      for (li = actions->actions; li != NULL; li = li->next)
 
406
        {
 
407
          action = li->data;
 
408
 
 
409
          if (action->unique_id == unique_id)
 
410
            {
 
411
              if (strcmp (field, "type") == 0
 
412
                  && G_VALUE_HOLDS_INT (value))
 
413
                {
 
414
                  action->type = g_value_get_int (value);
 
415
                }
 
416
              else if (strcmp (field, "pattern") == 0
 
417
                       && G_VALUE_HOLDS_STRING (value))
 
418
                {
 
419
                  g_free (action->pattern);
 
420
                  action->pattern = g_value_dup_string (value);
 
421
 
 
422
                  if (action->regex != NULL)
 
423
                    {
 
424
                      g_regex_unref (action->regex);
 
425
                      action->regex = NULL;
 
426
                    }
 
427
                }
 
428
              else if (strcmp (field, "command") == 0
 
429
                       && G_VALUE_HOLDS_STRING (value))
 
430
                {
 
431
                  g_free (action->command);
 
432
                  action->command = g_value_dup_string (value);
 
433
                }
 
434
              else if (strcmp (field, "save") == 0
 
435
                       && G_VALUE_HOLDS_BOOLEAN (value))
 
436
                {
 
437
                  action->save = g_value_get_boolean (value);
 
438
                }
 
439
 
 
440
              break;
 
441
            }
 
442
        }
 
443
    }
 
444
}
 
445
 
 
446
 
 
447
 
 
448
static gchar *
 
449
xfce_appfinder_actions_expand_command (XfceAppfinderAction *action,
 
450
                                       const gchar         *text)
 
451
{
 
452
  GString     *string;
 
453
  const gchar *p;
 
454
  gsize        len;
 
455
  gchar       *trim;
 
456
 
 
457
  if (G_UNLIKELY (action->command == NULL))
 
458
    return NULL;
 
459
 
 
460
  string = g_string_sized_new (128);
 
461
  len = strlen (action->pattern);
 
462
 
 
463
  for (p = action->command; *p != '\0'; ++p)
 
464
    {
 
465
      if (G_UNLIKELY (p[0] == '%' && p[1] != '\0'))
 
466
        {
 
467
          switch (*++p)
 
468
            {
 
469
            case 's':
 
470
              trim = g_strdup (text + len);
 
471
              g_string_append (string, g_strchug (trim));
 
472
              g_free (trim);
 
473
              break;
 
474
 
 
475
            case 'S':
 
476
              g_string_append (string, text);
 
477
              break;
 
478
 
 
479
            case '%':
 
480
              g_string_append_c (string, '%');
 
481
              break;
 
482
            }
 
483
        }
 
484
      else
 
485
        {
 
486
          g_string_append_c (string, *p);
 
487
        }
 
488
    }
 
489
 
 
490
  return g_string_free (string, FALSE);
 
491
}
 
492
 
 
493
 
 
494
 
 
495
XfceAppfinderActions *
 
496
xfce_appfinder_actions_get (void)
 
497
{
 
498
  static XfceAppfinderActions *actions = NULL;
 
499
 
 
500
  if (G_LIKELY (actions != NULL))
 
501
    {
 
502
      g_object_ref (G_OBJECT (actions));
 
503
    }
 
504
  else
 
505
    {
 
506
      actions = g_object_new (XFCE_TYPE_APPFINDER_ACTIONS, NULL);
 
507
      g_object_add_weak_pointer (G_OBJECT (actions), (gpointer) &actions);
 
508
      appfinder_refcount_debug_add (G_OBJECT (actions), "actions");
 
509
    }
 
510
 
 
511
  return actions;
 
512
}
 
513
 
 
514
 
 
515
 
 
516
gint
 
517
xfce_appfinder_actions_get_unique_id (XfceAppfinderActions *actions)
 
518
{
 
519
  static gint          unique_id = 1;
 
520
  GSList              *li;
 
521
  XfceAppfinderAction *action;
 
522
 
 
523
  appfinder_return_val_if_fail (XFCE_IS_APPFINDER_ACTIONS (actions), -1);
 
524
 
 
525
  for (; unique_id < G_MAXINT; unique_id++)
 
526
    {
 
527
      for (li = actions->actions; li != NULL; li = li->next)
 
528
        {
 
529
          action = li->data;
 
530
          if (action->unique_id == unique_id)
 
531
            break;
 
532
        }
 
533
 
 
534
      if (li == NULL)
 
535
        return unique_id;
 
536
    }
 
537
 
 
538
  return -1;
 
539
}
 
540
 
 
541
 
 
542
 
 
543
gchar *
 
544
xfce_appfinder_actions_execute (XfceAppfinderActions  *actions,
 
545
                                const gchar           *text,
 
546
                                gboolean              *save_cmd,
 
547
                                GError               **error)
 
548
{
 
549
  GSList              *li;
 
550
  XfceAppfinderAction *action;
 
551
  GError              *err = NULL;
 
552
  gchar               *cmd = NULL;
 
553
  GMatchInfo          *match_info = NULL;
 
554
  gboolean             found = FALSE;
 
555
 
 
556
  appfinder_return_val_if_fail (error != NULL && *error == NULL, NULL);
 
557
  appfinder_return_val_if_fail (XFCE_IS_APPFINDER_ACTIONS (actions), NULL);
 
558
  appfinder_return_val_if_fail (text != NULL, NULL);
 
559
 
 
560
  for (li = actions->actions; li != NULL; li = li->next)
 
561
    {
 
562
      action = li->data;
 
563
 
 
564
      /* skip empty actions */
 
565
      if (!IS_STRING (action->pattern)
 
566
          || !IS_STRING (action->command))
 
567
        continue;
 
568
 
 
569
      switch (action->type)
 
570
        {
 
571
        case XFCE_APPFINDER_ACTION_TYPE_PREFIX:
 
572
          if (g_str_has_prefix (text, action->pattern))
 
573
            {
 
574
              cmd = xfce_appfinder_actions_expand_command (action, text);
 
575
              found = TRUE;
 
576
            }
 
577
          break;
 
578
 
 
579
        case XFCE_APPFINDER_ACTION_TYPE_REGEX:
 
580
          if (action->regex == NULL)
 
581
            {
 
582
              /* allocate the regex */
 
583
              action->regex = g_regex_new (action->pattern, 0, 0, &err);
 
584
              if (action->regex == NULL)
 
585
                {
 
586
                  g_message ("Failed to create regex for \"%s\": %s",
 
587
                             action->pattern, err->message);
 
588
                  g_error_free (err);
 
589
 
 
590
                  break;
 
591
                }
 
592
            }
 
593
 
 
594
          if (g_regex_match (action->regex, text, 0, &match_info))
 
595
            {
 
596
              /* expand the command string */
 
597
              cmd = g_match_info_expand_references (match_info, action->command, &err);
 
598
              if (G_UNLIKELY (err != NULL))
 
599
                {
 
600
                  *error = err;
 
601
                  cmd = NULL;
 
602
                }
 
603
 
 
604
              found = TRUE;
 
605
            }
 
606
 
 
607
          if (match_info != NULL)
 
608
            g_match_info_free (match_info);
 
609
 
 
610
          break;
 
611
        }
 
612
 
 
613
      if (found)
 
614
        {
 
615
          if (save_cmd != NULL)
 
616
            *save_cmd = action->save;
 
617
          break;
 
618
        }
 
619
    }
 
620
 
 
621
  appfinder_assert ((cmd != NULL) == found);
 
622
 
 
623
  return cmd;
 
624
}