summaryrefslogtreecommitdiff
path: root/gphoto-m4/gp-set.m4
blob: 0168a263d9a678f183e12802d89ba0ccf4c1369e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
dnl ######################################################################
dnl Set operations using shell
dnl ######################################################################
dnl
dnl This implements a set of set operations ('set' in the sense of
dnl 'set theory') as shell code for use at configure time.  At m4 time
dnl (aka autoreconf time), there already exists a set of m4_set_*
dnl macros, but we cannot use those for user specified and
dnl autodetected changes at configure time.
dnl
dnl Not all set operations are implemented, but a few basic ones we
dnl need for gp-camlibs.m4 are.
dnl
dnl   * Basic definitions:
dnl
dnl       * GP_SET_DEFINE
dnl       * GP_SET_UNDEFINE
dnl
dnl   * Operations on sets:
dnl
dnl       * GP_SET_ADD
dnl       * GP_SET_ADD_ALL
dnl       * GP_SET_REMOVE
dnl
dnl       * GP_SET_CARDINALITY
dnl       * GP_SET_DIFFERENCE
dnl       * GP_SET_UNION
dnl
dnl       * GP_SET_FOREACH
dnl
dnl   * Conditionals:
dnl
dnl       * GP_SET_CONTAINS_IFELSE
dnl       * GP_SET_EMPTY_IFELSE
dnl       * GP_SET_EQUAL_IFELSE
dnl
dnl       * GP_SET_CLEAN_FILES
dnl
dnl   * Internals and debugging help:
dnl
dnl       * GP_SET_CANONICALIZE
dnl       * GP_SET_DUMP_ALL
dnl       * GP_SET_TESTSUITE
dnl
dnl   * Fill shell variables with set contents:
dnl
dnl       * GP_SET_DEBUG_VAR
dnl       * GP_SET_SPACE_VAR
dnl
dnl   * Output AC_MSG_* for GP_SET_* sets:
dnl
dnl       * GP_SET_DEBUG_MSG
dnl       * GP_SET_MSG_DEBUG_RESULT
dnl
dnl       * GP_SET_SPACE_MSG
dnl       * GP_SET_MSG_SPACE_RESULT
dnl
dnl ######################################################################
dnl Remarks on usage and implementation of GP_SET_*
dnl
dnl   * Sets are stored in text files, one element per line. An empty
dnl     file is an empty set, and empty lines mean empty elements.
dnl     Non-empty files not ending with a newline are undefined behaviour.
dnl
dnl   * At this time, GP_SET_* functions work with set elements
dnl     consisting of a limited set of characters, but the storage
dnl     format allows for a future code cleanup to allow for handling
dnl     more arbitrarily called elements.
dnl
dnl   * Set names given to GP_SET_ macros must be defined at m4
dnl     (autoreconf) time, not at sh (configure) time.
dnl
dnl   * Every set must be declared before use with GP_SET_DEFINE so we
dnl     can create an empty file for them and keep track of the name of
dnl     that file for cleaning up later.
dnl
dnl   * Use GP_SET_CLEAN_FILES after your last set operations to remove
dnl     all left over set files.
dnl
dnl   * Set text files may contain set elements in any order, and in
dnl     any number. There is no difference between a set text file
dnl     containing the same line seven times and one which only contains
dnl     it one time.
dnl
dnl   * Some set operations work better or require on sorted files, so
dnl     sometimes the implementation sorts the set text files. If you
dnl     need a set text file sorted for some another reason, use
dnl     GP_SET_CANONICALIZE([set-name]).
dnl
dnl
dnl ######################################################################
dnl
dnl FIXME: Do we need to test ${COMM} works before using it?
dnl FIXME: Do we need a sh-based replacement for ${COMM} if it is not present?
dnl FIXME: Abort if _DIFFERENCE is called with ${COMM} not found/not working.
dnl FIXME: Do we need to stop using shell functions?
dnl
dnl
dnl ######################################################################
dnl Try catching unexpanded macros in the output.
dnl ######################################################################
m4_pattern_forbid([GP_SET_])dnl
m4_pattern_forbid([_GP_SET_])dnl
m4_pattern_allow([GP_SET_EOF])dnl
dnl
dnl
dnl ######################################################################
dnl _GP_SET_INIT
dnl   Called internally before any set operation.
dnl ######################################################################
AC_DEFUN_ONCE([_GP_SET_INIT], [dnl
AC_REQUIRE([AC_PROG_GREP])dnl
AC_REQUIRE([GP_PROG_COMM])dnl
AC_REQUIRE([GP_PROG_SORT])dnl
AC_REQUIRE([GP_PROG_UNIQ])dnl
m4_set_empty([gp_set_all_sets], [], [dnl
  m4_set_foreach([gp_set_all_sets], [elt], [dnl
    m4_errprintn(__file__: __line__:[ Set gp_set_all_sets contains element ]elt)dnl
  ])dnl
  m4_errprintn(__file__:__line__:[ Error: gp_set_all_sets already defined])dnl
  dnl m4_exit(1)dnl
])dnl
])dnl
dnl
dnl
dnl ######################################################################
dnl _GP_SET_FILENAME([set_name])
dnl _GP_SET_FILENAME([set_name], [extra-extension])
dnl   Convert set name to set file name. If present, add the given
dnl   extra-extension to the file name in some position.
dnl ######################################################################
AC_DEFUN([_GP_SET_FILENAME], [dnl
[gp-set-file--][$1]m4_if([$2],[],[],[.$2])])dnl
dnl
dnl
dnl ######################################################################
dnl _GP_SET_CHECK_INIT
dnl   Implement the gp_set_shfn_check() shell function which checks that the
dnl   given set exists and is in general working order.
dnl ######################################################################
AC_DEFUN_ONCE([_GP_SET_CHECK_INIT], [dnl
AC_REQUIRE([_GP_SET_INIT])dnl
gp_set_shfn_check ()
{
  if test -f "[$]1"; then :; else
    AC_MSG_ERROR(["Error: set [$]1 has not been defined yet"])
  fi
} # gp_set_shfn_check
])dnl
dnl
dnl
dnl ######################################################################
dnl _GP_SET_CHECK([set_name])
dnl   Check that the given set exists and is in general working order.
dnl   Works by calling the gp_set_shfn_check() shell function.
dnl ######################################################################
AC_DEFUN([_GP_SET_CHECK], [dnl
AC_REQUIRE([_GP_SET_INIT])dnl
AC_REQUIRE([_GP_SET_CHECK_INIT])dnl
gp_set_shfn_check "_GP_SET_FILENAME([$1])"
])dnl
dnl
dnl
dnl ######################################################################
dnl GP_SET_DUMP_ALL
dnl   Dump all sets to stdout. Intended for helping with debugging.
dnl ######################################################################
AC_DEFUN([GP_SET_DUMP_ALL], [dnl
AC_REQUIRE([_GP_SET_INIT])dnl
for setfile in gp-set-file--*
do
  AS_ECHO(["Set file: ${setfile}"])
  ${SED} 's/^/  * <</; s/$/>>/' "${setfile}"
done
])dnl
dnl
dnl
dnl ######################################################################
dnl GP_SET_DEFINE([set_name])
dnl   Declare a set of given name, initializing it to an empty set.
dnl   Not a shell function, as the emitted shell code is shorter than
dnl   calling a shell function.
dnl ######################################################################
AC_DEFUN([GP_SET_DEFINE], [dnl
AC_REQUIRE([_GP_SET_INIT])dnl
m4_set_add([gp_set_all_sets], [$1])dnl
: > "_GP_SET_FILENAME([$1])"
])dnl
dnl
dnl
dnl ######################################################################
dnl GP_SET_UNDEFINE([set_name])
dnl   Undefine a set of given name, removing its file.
dnl   Not a shell function, as the emitted shell code is shorter than
dnl   calling a shell function.
dnl ######################################################################
AC_DEFUN([GP_SET_UNDEFINE], [dnl
AC_REQUIRE([_GP_SET_INIT])dnl
_GP_SET_CHECK([$1])dnl
rm -f "_GP_SET_FILENAME([$1])"
])dnl
dnl
dnl
dnl ######################################################################
dnl _GP_SET_ADD_INIT
dnl   Implement the gp_set_shfn_set_add() shell function which adds a given
dnl   element to a given set.
dnl ######################################################################
AC_DEFUN_ONCE([_GP_SET_ADD_INIT], [dnl
AC_REQUIRE([_GP_SET_INIT])dnl
AC_REQUIRE([_GP_SET_CHECK_INIT])dnl
gp_set_shfn_set_add ()
{
  gp_set_shfn_check "[$]1"
  AS_ECHO(["[$]2"]) >> "[$]1"
} # gp_set_shfn_set_add
])dnl
dnl
dnl
dnl ######################################################################
dnl GP_SET_ADD([set_name], [element])
dnl   Add the given element to the given set. Implemented by calling the
dnl   gp_set_shfn_set_add() shell function.
dnl   Note: Unlike m4_set_add, this does not handle IF-UNIQ and IF-DUP
dnl   macro parameters.
dnl ######################################################################
AC_DEFUN([GP_SET_ADD], [dnl
AC_REQUIRE([_GP_SET_INIT])dnl
AC_REQUIRE([_GP_SET_ADD_INIT])dnl
gp_set_shfn_set_add "_GP_SET_FILENAME([$1])" "$2"
])dnl
dnl
dnl
dnl ######################################################################
dnl GP_SET_ADD_ALL([set_name], [element]...)
dnl   Add the given elements to the given set, similar to m4_set_add_all.
dnl   This can be very useful for initializing a GP_SET_* set from a
dnl   m4_set_* in one go.
dnl   Not a shell function, as the emitted shell code is shorter than
dnl   calling a shell function.
dnl ######################################################################
AC_DEFUN([GP_SET_ADD_ALL], [dnl
AC_REQUIRE([_GP_SET_INIT])dnl
_GP_SET_CHECK([$1])dnl
cat>>"_GP_SET_FILENAME([$1])"<<_GP_EOF
m4_foreach([myvar], [m4_shift($@)], [dnl
myvar
])dnl
_GP_EOF
])dnl
dnl
dnl
dnl ######################################################################
dnl _GP_SET_REMOVE_INIT
dnl   Implement the gp_set_shfn_remove() shell function removing a given
dnl   element from a given set.
dnl ######################################################################
AC_DEFUN_ONCE([_GP_SET_REMOVE_INIT], [dnl
AC_REQUIRE([_GP_SET_INIT])dnl
gp_set_shfn_remove ()
{
  gp_set_shfn_check "[$]1"
  ${GREP} -v "^[$]2$" < "[$]1" > "[$]1.tmp"
  mv -f "[$]1.tmp" "[$]1"
} # gp_set_shfn_remove
])dnl
dnl
dnl
dnl ######################################################################
dnl GP_SET_REMOVE([set_name], [element])
dnl   Remove a given element from a given set.
dnl   Calls the gp_set_shfn_remove() shell function for the actual work.
dnl ######################################################################
AC_DEFUN([GP_SET_REMOVE], [dnl
AC_REQUIRE([_GP_SET_INIT])dnl
AC_REQUIRE([_GP_SET_REMOVE_INIT])dnl
gp_set_shfn_remove "_GP_SET_FILENAME([$1])" "$2"
])dnl
dnl
dnl
dnl ######################################################################
dnl _GP_SET_UNION_INIT
dnl   Define the gp_set_shfn_union() shell function which defines a
dnl   result set as the union of 0 or more sets.
dnl ######################################################################
AC_DEFUN_ONCE([_GP_SET_UNION_INIT], [dnl
AC_REQUIRE([_GP_SET_INIT])dnl
dnl This functions uses the shell builtin 'shift', so it needs to store
dnl the original $1 in a local variable.
gp_set_shfn_union ()
{
  local result_fname="[$]1"
  gp_set_shfn_check "[$]result_fname"
  if shift; then
    cat "[$]@" > "[$]{result_fname}.tmp"
    mv -f "[$]{result_fname}.tmp" "[$]{result_fname}"
  fi
} # gp_set_shfn_union
])dnl
dnl
dnl
dnl ######################################################################
dnl GP_SET_UNION([result_set], [setname]...)
dnl   Define result_set as the union of 0 or more setnames.
dnl   Calls the gp_set_shfn_union() shell function for the actual work.
dnl ######################################################################
AC_DEFUN([GP_SET_UNION], [dnl
AC_REQUIRE([_GP_SET_INIT])dnl
AC_REQUIRE([_GP_SET_UNION_INIT])dnl
m4_set_add([gp_set_all_sets], [$1])dnl
gp_set_shfn_union m4_foreach([setname], [$@], [ "_GP_SET_FILENAME(setname)"])
])dnl
dnl
dnl
dnl ######################################################################
dnl _GP_SET_DIFFERENCE_INIT([result_set_fname], [set_fname]...)
dnl   This uses comm(1), which is a POSIX command. We can always
dnl   re-implement comm(1) with a lot of speed penalties in a bunch
dnl   of nested sh loops if we run into a system which does not have
dnl   comm(1) installed.
dnl ######################################################################
AC_DEFUN_ONCE([_GP_SET_DIFFERENCE_INIT], [dnl
AC_REQUIRE([_GP_SET_INIT])dnl
AC_REQUIRE([_GP_SET_CHECK_INIT])dnl
AC_REQUIRE([_GP_SET_CANONICALIZE_INIT])dnl
dnl This functions uses the shell builtin 'shift', so it needs to store
dnl the original $1 and $2 in local variables.
gp_set_shfn_difference ()
{
  local result_fname="[$]1"
  gp_set_shfn_check "[$]result_fname"
  if shift; then
    gp_set_shfn_canonicalize "[$]1"
    cat "[$]1" > "[$]result_fname"
    if shift; then
      for gp_s
      do
        gp_set_shfn_canonicalize "[$]gp_s"
        ${COMM} -23 "[$]{result_fname}" "[$]gp_s" > "[$]{result_fname}.tmp"
        mv -f "[$]{result_fname}.tmp" "[$]{result_fname}"
      done
    fi
  fi
} # gp_set_shfn_difference
])dnl
dnl
dnl
dnl ######################################################################
dnl GP_SET_DIFFERENCE([result_set], [setname]...)
dnl   Define result_set as the first setname with the element of all
dnl   the other sets removed from it.
dnl ######################################################################
AC_DEFUN([GP_SET_DIFFERENCE], [dnl
AC_REQUIRE([_GP_SET_INIT])dnl
AC_REQUIRE([_GP_SET_DIFFERENCE_INIT])dnl
m4_set_add([gp_set_all_sets], [$1])dnl
gp_set_shfn_difference m4_foreach([setname], [$@], [ "_GP_SET_FILENAME(setname)"])
])dnl
dnl
dnl
dnl ######################################################################
dnl _GP_SET_CARDINALITY_INIT
dnl   Define gp_set_shfn_cardinality() shell function which writes
dnl   set cardinality to stdout.
dnl ######################################################################
AC_DEFUN_ONCE([_GP_SET_CARDINALITY_INIT], [dnl
AC_REQUIRE([_GP_SET_INIT])dnl
gp_set_shfn_cardinality ()
{
  gp_set_shfn_check "[$]1"
  wc -l < "[$]1"
} # gp_set_shfn_cardinality
])dnl
dnl
dnl
dnl ######################################################################
dnl GP_SET_CARDINALITY([set_name])
dnl   Write set cardinality to stdout.
dnl ######################################################################
AC_DEFUN([GP_SET_CARDINALITY], [dnl
AC_REQUIRE([_GP_SET_INIT])dnl
AC_REQUIRE([_GP_SET_CARDINALITY_INIT])dnl
gp_set_shfn_cardinality "_GP_SET_FILENAME([$1])"])dnl
dnl
dnl
dnl ######################################################################
dnl GP_SET_EMPTY_IFELSE([set_name], [if-empty], [if-not-empty])
dnl   Run if-empty block or if-not-empty block, depending on whether
dnl   the named set is empty or not.
dnl ######################################################################
AC_DEFUN([GP_SET_EMPTY_IFELSE], [dnl
AC_REQUIRE([_GP_SET_INIT])dnl
_GP_SET_CHECK([$1])dnl
AS_IF([test "0" -eq "$(wc -l < "_GP_SET_FILENAME([$1])")"], m4_shift($@))
])dnl
dnl
dnl
dnl ######################################################################
dnl GP_SET_EQUAL_IFELSE([set_a], [set_b], [if-equal], [if-not-equal])
dnl   When set_a and set_b are equal, run the if-equal block. Otherwise,
dnl   run the if-not-equal block.
dnl ######################################################################
AC_DEFUN([GP_SET_EQUAL_IFELSE], [dnl
gp_set_shfn_canonicalize "_GP_SET_FILENAME([$1])"
gp_set_shfn_canonicalize "_GP_SET_FILENAME([$2])"
AS_IF([${CMP} "_GP_SET_FILENAME([$1])" "_GP_SET_FILENAME([$2])" > /dev/null 2>&1],
      m4_shift2($@))
])dnl
dnl
dnl
dnl ######################################################################
dnl GP_SET_CONTAINS_IFELSE([set_name], [element], [yes-block], [no-block])
dnl   If set_name contains element, run the yes-block. Otherwise,
dnl   run the no-block.
dnl ######################################################################
AC_DEFUN([GP_SET_CONTAINS_IFELSE], [dnl
_GP_SET_CHECK([$1])dnl
AS_IF([test "0" -lt "$(${GREP} -c "^$2\$" < "_GP_SET_FILENAME([$1])")"],
      m4_shift2($@))
])dnl
dnl
dnl
dnl ######################################################################
dnl _GP_SET_DEBUG_VAR_INIT
dnl   Define gp_set_shfn_debug_var() shell function which sets a shell
dnl   variable to a string representing a human readable form for of
dnl   the given set.
dnl ######################################################################
AC_DEFUN_ONCE([_GP_SET_DEBUG_VAR_INIT], [dnl
AC_REQUIRE([_GP_SET_INIT])dnl
gp_set_shfn_debug_var ()
{
  gp_set_shfn_check "[$]1"
  gp_set_shfn_canonicalize "[$]1"
  local element
  local gp_set_is_first=:
  local gp_set_saved_ifs="$IFS"
  IFS=""
  while read element
  do
    if "$gp_set_is_first"
    then
      eval "[$]2=\"{ \""
      gp_set_is_first=false
    else
      eval "[$]2=\"\${[$]2}, \""
    fi
    if test "x$element" = "x"
    then
      eval "[$]2=\"\${[$]2}''\""
    else
      eval "[$]2=\"\${[$]2}'\$element'\""
    fi
  done < "[$]1"
  IFS="$gp_set_saved_ifs"
  if "$gp_set_is_first"
  then
    eval "[$]2=\"{ }\""
  else
    eval "[$]2=\"\${[$]2} }\""
  fi
} # gp_set_shfn_debug_var
])dnl
dnl
dnl
dnl ######################################################################
dnl GP_SET_DEBUG_VAR([set_name], [shell_var_name])
dnl   Set shell variable shell_var_name to a string representing a human
dnl   readable for of the given set.
dnl ######################################################################
AC_DEFUN([GP_SET_DEBUG_VAR], [dnl
AC_REQUIRE([_GP_SET_INIT])dnl
AC_REQUIRE([_GP_SET_DEBUG_VAR_INIT])dnl
gp_set_shfn_debug_var "_GP_SET_FILENAME([$1])" "$2"
])dnl
dnl
dnl
dnl ######################################################################
dnl GP_SET_DEBUG_MSG([set-name])
dnl   For a given set, expand to a simple pair of AC_MSG_CHECKING and
dnl   AC_MSG_RESULT showing the GP_SET_DEBUG_VAR, mostly to help with
dnl   debugging.
dnl ######################################################################
AC_DEFUN([GP_SET_DEBUG_MSG], [dnl
AC_REQUIRE([_GP_SET_INIT])dnl
AC_MSG_CHECKING([value of set ]$1)
GP_SET_MSG_DEBUG_RESULT([$1])
])dnl
dnl
dnl
dnl ######################################################################
dnl GP_SET_SPACE_MSG([set-name])
dnl   For a given set, expand to a simple pair of AC_MSG_CHECKING and
dnl   AC_MSG_RESULT showing the GP_SET_SPACE_VAR, both to help with
dnl   debugging gp-set.m4 and possibly for produnction use.
dnl ######################################################################
AC_DEFUN([GP_SET_MSG], [dnl
AC_REQUIRE([_GP_SET_INIT])dnl
AC_MSG_CHECKING([value of set ]$1)
GP_SET_MSG_RESULT([$1])
])dnl
dnl
dnl
dnl ######################################################################
dnl GP_SET_SPACE_VAR([set-name], [var-name])
dnl ######################################################################
AC_DEFUN([GP_SET_SPACE_VAR], [dnl
AC_REQUIRE([_GP_SET_INIT])dnl
$2=""
GP_SET_FOREACH([$1], [element], [dnl
AS_IF([test "x[$]$2" = "x"], [dnl
  $2="[$]element"
], [dnl
  $2="[$]$2 [$]element"
])
])
])dnl
dnl
dnl
dnl ######################################################################
dnl GP_SET_MSG_RESULT([set-name])
dnl   Shortcut for setting a shell variable to a space separated list of
dnl   elements, and then expanding to AC_MSG_RESULT([$shellvar]).
dnl ######################################################################
AC_DEFUN([GP_SET_MSG_RESULT], [dnl
AC_REQUIRE([_GP_SET_INIT])dnl
GP_SET_SPACE_VAR([$1], [gp_set_msg_result_var])dnl
AC_MSG_RESULT([${gp_set_msg_result_var}])
])dnl
dnl
dnl
dnl ######################################################################
dnl GP_SET_MSG_DEBUG_RESULT([set-name])
dnl   Shortcut for setting a shell variable to a human readable list of
dnl   elements, and then expanding to AC_MSG_RESULT([$shellvar]).
dnl ######################################################################
AC_DEFUN([GP_SET_MSG_DEBUG_RESULT], [dnl
AC_REQUIRE([_GP_SET_INIT])dnl
GP_SET_DEBUG_VAR([$1], [gp_set_msg_result_var])dnl
AC_MSG_RESULT([${gp_set_msg_result_var}])
])dnl
dnl
dnl
dnl ######################################################################
dnl _GP_SET_CANONICALIZE_INIT
dnl   Implement the gp_set_shfn_canonicalize() shell function.
dnl ######################################################################
AC_DEFUN_ONCE([_GP_SET_CANONICALIZE_INIT], [dnl
AC_REQUIRE([_GP_SET_INIT])dnl
gp_set_shfn_canonicalize ()
{
  gp_set_shfn_check "[$]1"
  { set -e
    [$]{SORT} < "[$]1" | [$]{UNIQ} > "[$]1.tmp"
    mv -f "[$]1.tmp" "[$]1"; }
} # gp_set_shfn_canonicalize
])dnl
dnl
dnl
dnl ######################################################################
dnl GP_SET_CANONICALIZE([set_name])
dnl   Convert the set file for set_name into a canonical form.
dnl
dnl   Implementation detail: Sorts the lines, and makes them unique.
dnl ######################################################################
AC_DEFUN([GP_SET_CANONICALIZE], [dnl
AC_REQUIRE([_GP_SET_INIT])dnl
AC_REQUIRE([_GP_SET_CANONICALIZE_INIT])dnl
gp_set_shfn_canonicalize "_GP_SET_FILENAME([$1])"
])dnl
dnl
dnl
dnl ######################################################################
dnl GP_SET_FOREACH([set_name], [shell-var], [shell-block])
dnl   For each element in set_name, run the shell-block with the given
dnl   shell variable set to every element in turn.
dnl ######################################################################
AC_DEFUN([GP_SET_FOREACH], [dnl
_GP_SET_CHECK([$1])dnl
gp_set_saved_ifs="$IFS"
IFS=""
while read $2
do
  IFS="$gp_set_saved_ifs"
  $3
done < "_GP_SET_FILENAME([$1])"
IFS="$gp_set_saved_ifs"
])dnl
dnl
dnl
dnl ######################################################################
dnl GP_SET_CLEAN_FILES
dnl   Remove all the files used for storing sets. Invoke this macro near
dnl   the end of configure.ac after you have finished doing anything with
dnl   GP_SET_* sets.
dnl ######################################################################
AC_DEFUN([GP_SET_CLEAN_FILES], [dnl
AC_BEFORE([_GP_SET_INIT], [$0])dnl
AC_BEFORE([GP_SET_DEFINE], [$0])dnl
AC_BEFORE([GP_SET_UNDEFINE], [$0])dnl
AC_BEFORE([GP_SET_ADD], [$0])dnl
AC_BEFORE([GP_SET_ADD_ALL], [$0])dnl
AC_BEFORE([GP_SET_REMOVE], [$0])dnl
AC_BEFORE([GP_SET_EMPTY_IFELSE], [$0])dnl
AC_BEFORE([GP_SET_EQUAL_IFELSE], [$0])dnl
AC_BEFORE([GP_SET_CONTAINS_IFELSE], [$0])dnl
AC_BEFORE([GP_SET_DEBUG_VAR], [$0])dnl
AC_BEFORE([GP_SET_SPACE_VAR], [$0])dnl
dnl
dnl GP_SET_DUMP_ALL()dnl
dnl
dnl m4_set_foreach([gp_set_all_sets], [set_name], [dnl
dnl AS_ECHO(["Set defined somewhere: set_name"])
dnl ])dnl
dnl
[rm -f]m4_set_foreach([gp_set_all_sets], [setname],
                      [ "_GP_SET_FILENAME(setname)"])dnl
])dnl
dnl
dnl
dnl ######################################################################
dnl GP_SET_TESTSUITE()
dnl   Does a number of tests for the GP_SET_* macros.
dnl
dnl   Should be mostly useful while debugging gp-set.m4 itself.
dnl ######################################################################
AC_DEFUN([GP_SET_TESTSUITE], [dnl
# BEGIN $0
_GP_SET_INIT

GP_SET_DEFINE([foo])
GP_SET_DEFINE([bar])
GP_SET_DEFINE([foobar])
GP_SET_DEFINE([everything])

GP_SET_DEBUG_MSG([foo])

GP_SET_DEFINE([bax])
GP_SET_UNDEFINE([bax])

GP_SET_UNDEFINE([bar])
GP_SET_DEFINE([bar])

dnl GP_SET_ADD([moo], [meh])
GP_SET_ADD_ALL([everything], [foo], [bar], [bar ], [bla])

GP_SET_DUMP_ALL

m4_set_add_all([m4testset], [a], [b c], [d e], [f], [g])
AC_MSG_CHECKING([for value of m4 testset])
AC_MSG_RESULT([m4_set_contents([m4testset], [, ])])

GP_SET_ADD_ALL([everything]m4_set_listc([m4testset]))

GP_SET_DUMP_ALL

GP_SET_ADD([foo], [barfoo])
GP_SET_ADD([foo], [foobar])
GP_SET_ADD([foo], [fox])
GP_SET_ADD([foo], [fux])
GP_SET_ADD([foo], [fox])
GP_SET_ADD([foo], [])
GP_SET_ADD([foo], [fox])
GP_SET_ADD([foo], [barfoo])
GP_SET_ADD([foo], [ barfoo])
GP_SET_ADD([foo], ["barfoo "])
GP_SET_ADD([foo], [])
GP_SET_REMOVE([foo], [fox])
GP_SET_ADD([foo], [barfoo])

GP_SET_ADD([foobar], [bar])
GP_SET_ADD([foobar], [foobar])
GP_SET_ADD([foobar], [barfoo])

GP_SET_DEBUG_MSG([foo])

GP_SET_MSG([bar])
GP_SET_MSG([foo])
GP_SET_MSG([foobar])
GP_SET_MSG([everything])

GP_SET_DEFINE([union])
GP_SET_UNION([union], [foo], [bar], [foobar])
AC_MSG_CHECKING([value of union of foo bar foobar])
GP_SET_MSG_RESULT([union])

GP_SET_DEFINE([difference])
GP_SET_DIFFERENCE([difference], [foo], [bar], [foobar])
GP_SET_MSG([difference])

AC_MSG_CHECKING([whether sets foo and bar are equal])
GP_SET_EQUAL_IFELSE([foo], [bar], [AC_MSG_RESULT([yes])], [AC_MSG_RESULT([no])])

AC_MSG_CHECKING([whether set foo is empty])
GP_SET_EMPTY_IFELSE([foo], [AC_MSG_RESULT([yes])], [AC_MSG_RESULT([no])])

AC_MSG_CHECKING([whether set bar is empty])
GP_SET_EMPTY_IFELSE([bar], [AC_MSG_RESULT([yes])], [AC_MSG_RESULT([no])])

AC_MSG_CHECKING([whether set foo contains element bar])
GP_SET_CONTAINS_IFELSE([foo], [bar], [AC_MSG_RESULT([yes])], [AC_MSG_RESULT([no])])

AC_MSG_CHECKING([whether set foobar contains element bar])
GP_SET_CONTAINS_IFELSE([foobar], [bar], [AC_MSG_RESULT([yes])], [AC_MSG_RESULT([no])])

GP_SET_FOREACH([foobar], [gp_set_var], [dnl
  AC_MSG_CHECKING([foobar element])
  AC_MSG_RESULT([${gp_set_var}])
])dnl
GP_SET_FOREACH([foobar], [gp_set_var], [dnl
  AS_ECHO(["  * element ${gp_set_var}"])
])dnl
GP_SET_FOREACH([foobar], [gp_set_var], [echo "  * ELEMENT ${gp_set_var}"])dnl
AS_ECHO(["Moo."])

GP_SET_DUMP_ALL
# END $0
])dnl
dnl
dnl
dnl ####################################################################
dnl
dnl Local Variables:
dnl mode: autoconf
dnl End: