• R/O
  • SSH
  • HTTPS

caitsith: Commit


Commit MetaInfo

Revision168 (tree)
Time2015-08-04 21:44:56
Authorkumaneko

Log Message

(empty log message)

Change Summary

Incremental Difference

--- trunk/caitsith-tools/kernel_test/caitsith_wildcard_test.c (nonexistent)
+++ trunk/caitsith-tools/kernel_test/caitsith_wildcard_test.c (revision 168)
@@ -0,0 +1,693 @@
1+#include <stdio.h>
2+#include <string.h>
3+#include <stdlib.h>
4+
5+#define bool _Bool
6+#define true 1
7+#define false 0
8+#define u32 unsigned int
9+#define u8 unsigned char
10+
11+struct cs_path_info {
12+ const char *name;
13+ u32 hash; /* = full_name_hash(name, strlen(name)) */
14+ u32 total_len; /* = strlen(name) */
15+ u32 const_len; /* = cs_const_part_length(name) */
16+};
17+
18+static void out_of_memory(void)
19+{
20+ fprintf(stderr, "Out of memory\n");
21+ exit(1);
22+}
23+
24+/* Copied from Linux kernel source code. */
25+static unsigned int full_name_hash(const unsigned char *name, unsigned int len)
26+{
27+ unsigned long hash = 0;
28+ while (len--) {
29+ unsigned long c = *name++;
30+ hash = (hash + (c << 4) + (c >> 4)) * 11;
31+ }
32+ return (unsigned int) hash;
33+}
34+
35+/**
36+ * cs_pathcmp - strcmp() for "struct cs_path_info" structure.
37+ *
38+ * @a: Pointer to "struct cs_path_info".
39+ * @b: Pointer to "struct cs_path_info".
40+ *
41+ * Returns true if @a != @b, false otherwise.
42+ */
43+static inline bool cs_pathcmp(const struct cs_path_info *a,
44+ const struct cs_path_info *b)
45+{
46+ return a->hash != b->hash || strcmp(a->name, b->name);
47+}
48+
49+/**
50+ * cs_const_part_length - Evaluate the initial length without a pattern in a token.
51+ *
52+ * @filename: The string to evaluate. Maybe NULL.
53+ *
54+ * Returns the initial length without a pattern in @filename.
55+ */
56+static int cs_const_part_length(const char *filename)
57+{
58+ char c;
59+ int len = 0;
60+ if (!filename)
61+ return 0;
62+ while (1) {
63+ c = *filename++;
64+ if (!c)
65+ break;
66+ if (c != '\\') {
67+ len++;
68+ continue;
69+ }
70+ c = *filename++;
71+ switch (c) {
72+ case '0': /* "\ooo" */
73+ case '1':
74+ case '2':
75+ case '3':
76+ c = *filename++;
77+ if (c < '0' || c > '7')
78+ break;
79+ c = *filename++;
80+ if (c < '0' || c > '7')
81+ break;
82+ len += 4;
83+ continue;
84+ }
85+ break;
86+ }
87+ return len;
88+}
89+
90+/**
91+ * cs_fill_path_info - Fill in "struct cs_path_info" members.
92+ *
93+ * @ptr: Pointer to "struct cs_path_info" to fill in.
94+ *
95+ * Returns nothing.
96+ *
97+ * The caller sets "struct cs_path_info"->name.
98+ */
99+static void cs_fill_path_info(struct cs_path_info *ptr)
100+{
101+ const char *name = ptr->name;
102+ const int len = strlen(name);
103+ ptr->total_len = len;
104+ ptr->const_len = cs_const_part_length(name);
105+ ptr->hash = full_name_hash((const unsigned char *) name, len);
106+}
107+
108+/**
109+ * cs_byte_range - Check whether the string is a \ooo style octal value.
110+ *
111+ * @str: Pointer to the string.
112+ *
113+ * Returns true if @str is a \ooo style octal value, false otherwise.
114+ */
115+static bool cs_byte_range(const char *str)
116+{
117+ return *str >= '0' && *str++ <= '3' &&
118+ *str >= '0' && *str++ <= '7' &&
119+ *str >= '0' && *str <= '7';
120+}
121+
122+/**
123+ * cs_decimal - Check whether the character is a decimal character.
124+ *
125+ * @c: The character to check.
126+ *
127+ * Returns true if @c is a decimal character, false otherwise.
128+ */
129+static bool cs_decimal(const char c)
130+{
131+ return c >= '0' && c <= '9';
132+}
133+
134+/**
135+ * cs_hexadecimal - Check whether the character is a hexadecimal character.
136+ *
137+ * @c: The character to check.
138+ *
139+ * Returns true if @c is a hexadecimal character, false otherwise.
140+ */
141+static bool cs_hexadecimal(const char c)
142+{
143+ return (c >= '0' && c <= '9') ||
144+ (c >= 'A' && c <= 'F') ||
145+ (c >= 'a' && c <= 'f');
146+}
147+
148+/**
149+ * cs_alphabet_char - Check whether the character is an alphabet.
150+ *
151+ * @c: The character to check.
152+ *
153+ * Returns true if @c is an alphabet character, false otherwise.
154+ */
155+static bool cs_alphabet_char(const char c)
156+{
157+ return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z');
158+}
159+
160+/**
161+ * cs_file_matches_pattern2 - Pattern matching without '/' character and "\-" pattern.
162+ *
163+ * @filename: The start of string to check.
164+ * @filename_end: The end of string to check.
165+ * @pattern: The start of pattern to compare.
166+ * @pattern_end: The end of pattern to compare.
167+ *
168+ * Returns true if @filename matches @pattern, false otherwise.
169+ */
170+static bool cs_file_matches_pattern2(const char *filename,
171+ const char *filename_end,
172+ const char *pattern,
173+ const char *pattern_end)
174+{
175+ while (filename < filename_end && pattern < pattern_end) {
176+ char c;
177+ if (*pattern != '\\') {
178+ if (*filename++ != *pattern++)
179+ return false;
180+ continue;
181+ }
182+ c = *filename;
183+ pattern++;
184+ switch (*pattern) {
185+ int i;
186+ int j;
187+ case '?':
188+ if (c == '/') {
189+ return false;
190+ } else if (c == '\\') {
191+ if (cs_byte_range(filename + 1))
192+ filename += 3;
193+ else
194+ return false;
195+ }
196+ break;
197+ case '+':
198+ if (!cs_decimal(c))
199+ return false;
200+ break;
201+ case 'x':
202+ if (!cs_hexadecimal(c))
203+ return false;
204+ break;
205+ case 'a':
206+ if (!cs_alphabet_char(c))
207+ return false;
208+ break;
209+ case '0':
210+ case '1':
211+ case '2':
212+ case '3':
213+ if (c == '\\' && cs_byte_range(filename + 1)
214+ && !strncmp(filename + 1, pattern, 3)) {
215+ filename += 3;
216+ pattern += 2;
217+ break;
218+ }
219+ return false; /* Not matched. */
220+ case '*':
221+ case '@':
222+ for (i = 0; i <= filename_end - filename; i++) {
223+ if (cs_file_matches_pattern2(filename + i,
224+ filename_end,
225+ pattern + 1,
226+ pattern_end))
227+ return true;
228+ c = filename[i];
229+ if (c == '.' && *pattern == '@')
230+ break;
231+ if (c != '\\')
232+ continue;
233+ if (cs_byte_range(filename + i + 1))
234+ i += 3;
235+ else
236+ break; /* Bad pattern. */
237+ }
238+ return false; /* Not matched. */
239+ default:
240+ j = 0;
241+ c = *pattern;
242+ if (c == '$') {
243+ while (cs_decimal(filename[j]))
244+ j++;
245+ } else if (c == 'X') {
246+ while (cs_hexadecimal(filename[j]))
247+ j++;
248+ } else if (c == 'A') {
249+ while (cs_alphabet_char(filename[j]))
250+ j++;
251+ }
252+ for (i = 1; i <= j; i++) {
253+ if (cs_file_matches_pattern2(filename + i,
254+ filename_end,
255+ pattern + 1,
256+ pattern_end))
257+ return true;
258+ }
259+ return false; /* Not matched or bad pattern. */
260+ }
261+ filename++;
262+ pattern++;
263+ }
264+ /* Ignore trailing "\*" and "\@" in @pattern. */
265+ while (*pattern == '\\' &&
266+ (*(pattern + 1) == '*' || *(pattern + 1) == '@'))
267+ pattern += 2;
268+ return filename == filename_end && pattern == pattern_end;
269+}
270+
271+/**
272+ * cs_file_matches_pattern - Pattern matching without '/' character.
273+ *
274+ * @filename: The start of string to check.
275+ * @filename_end: The end of string to check.
276+ * @pattern: The start of pattern to compare.
277+ * @pattern_end: The end of pattern to compare.
278+ *
279+ * Returns true if @filename matches @pattern, false otherwise.
280+ */
281+static bool cs_file_matches_pattern(const char *filename,
282+ const char *filename_end,
283+ const char *pattern,
284+ const char *pattern_end)
285+{
286+ const char *pattern_start = pattern;
287+ bool first = true;
288+ bool result;
289+ if (filename_end > filename && memchr(filename, '/', filename_end - filename)) {
290+ printf("'");
291+ fwrite(filename, 1, filename_end - filename, stdout);
292+ printf("', '");
293+ fwrite(pattern, 1, pattern_end - pattern, stdout);
294+ printf("'\n");
295+ }
296+ if (pattern_end > pattern && memchr(pattern, '/', pattern_end - pattern)) {
297+ printf("'");
298+ fwrite(filename, 1, filename_end - filename, stdout);
299+ printf("', '");
300+ fwrite(pattern, 1, pattern_end - pattern, stdout);
301+ printf("'\n");
302+ }
303+ while (pattern < pattern_end - 1) {
304+ /* Split at "\-" pattern. */
305+ if (*pattern++ != '\\' || *pattern++ != '-')
306+ continue;
307+ result = cs_file_matches_pattern2(filename, filename_end,
308+ pattern_start, pattern - 2);
309+ if (first)
310+ result = !result;
311+ if (result)
312+ return false;
313+ first = false;
314+ pattern_start = pattern;
315+ }
316+ result = cs_file_matches_pattern2(filename, filename_end,
317+ pattern_start, pattern_end);
318+ return first ? result : !result;
319+}
320+
321+/**
322+ * cs_path_matches_pattern2 - Do pathname pattern matching.
323+ *
324+ * @f: The start of string to check.
325+ * @p: The start of pattern to compare.
326+ *
327+ * Returns true if @f matches @p, false otherwise.
328+ */
329+static bool cs_path_matches_pattern2(const char *f, const char *p)
330+{
331+ const char *f_delimiter;
332+ const char *p_delimiter;
333+ while (*f && *p) {
334+ f_delimiter = strchr(f + 1, '/');
335+ if (!f_delimiter)
336+ f_delimiter = f + strlen(f);
337+ p_delimiter = strchr(p + 1, '/');
338+ if (!p_delimiter)
339+ p_delimiter = p + strlen(p);
340+ if (*p == '/' && *(p + 1) == '\\') {
341+ if (*(p + 2) == '(') {
342+ /* Check zero repetition. */
343+ if (cs_path_matches_pattern2(f, p_delimiter))
344+ return true;
345+ /* Check one or more repetition. */
346+ goto repetition;
347+ }
348+ if (*(p + 2) == '{')
349+ goto repetition;
350+
351+ }
352+ if ((*f == '/' || *p == '/') && *f++ != *p++)
353+ return false;
354+ if (!cs_file_matches_pattern(f, f_delimiter, p, p_delimiter))
355+ return false;
356+ f = f_delimiter;
357+ p = p_delimiter;
358+ }
359+ /* Ignore trailing "\*" and "\@" in @pattern. */
360+ while (*p == '\\' && (*(p + 1) == '*' || *(p + 1) == '@'))
361+ p += 2;
362+ return !*f && !*p;
363+repetition:
364+ do {
365+ /* Compare current component with pattern. */
366+ if (!cs_file_matches_pattern(f + 1, f_delimiter,
367+ p + 3, p_delimiter - 2))
368+ break;
369+ /* Proceed to next component. */
370+ f = f_delimiter;
371+ if (!*f)
372+ break;
373+ /* Continue comparison. */
374+ if (cs_path_matches_pattern2(f, p_delimiter))
375+ return true;
376+ f_delimiter = strchr(f + 1, '/');
377+ } while (f_delimiter);
378+ return false; /* Not matched. */
379+}
380+
381+/**
382+ * cs_path_matches_pattern - Check whether the given filename matches the given pattern.
383+ *
384+ * @filename: The filename to check.
385+ * @pattern: The pattern to compare.
386+ *
387+ * Returns true if matches, false otherwise.
388+ *
389+ * The following patterns are available.
390+ * \ooo Octal representation of a byte.
391+ * \* Zero or more repetitions of characters other than '/'.
392+ * \@ Zero or more repetitions of characters other than '/' or '.'.
393+ * \? 1 byte character other than '/'.
394+ * \$ One or more repetitions of decimal digits.
395+ * \+ 1 decimal digit.
396+ * \X One or more repetitions of hexadecimal digits.
397+ * \x 1 hexadecimal digit.
398+ * \A One or more repetitions of alphabet characters.
399+ * \a 1 alphabet character.
400+ *
401+ * \- Subtraction operator.
402+ *
403+ * /\{dir\}/ '/' + 'One or more repetitions of dir/' (e.g. /dir/ /dir/dir/
404+ * /dir/dir/dir/ ).
405+ *
406+ * /\(dir\)/ '/' + 'Zero or more repetitions of dir/' (e.g. / /dir/
407+ * /dir/dir/ ).
408+ */
409+static bool cs_path_matches_pattern(const struct cs_path_info *filename,
410+ const struct cs_path_info *pattern)
411+{
412+ const char *f = filename->name;
413+ const char *p = pattern->name;
414+ const int len = pattern->const_len;
415+ /* If @pattern doesn't contain pattern, I can use strcmp(). */
416+ if (len == pattern->total_len)
417+ return !cs_pathcmp(filename, pattern);
418+ /* Compare the initial length without patterns. */
419+ if (len) {
420+ if (strncmp(f, p, len))
421+ return false;
422+ f += len - 1;
423+ p += len - 1;
424+ }
425+ return cs_path_matches_pattern2(f, p);
426+}
427+
428+/**
429+ * cs_correct_word - Check whether the given string follows the naming rules.
430+ *
431+ * @string: The string to check.
432+ * @allow_pattern: True if allow use of patterns, false otherwise.
433+ *
434+ * Returns true if @string follows the naming rules, false otherwise.
435+ */
436+static bool cs_correct_word(const char *string, bool allow_pattern)
437+{
438+ u8 recursion = 20;
439+ const char *const start = string;
440+ u8 in_repetition = 0;
441+ if (!*string)
442+ goto out;
443+ while (*string) {
444+ unsigned char c = *string++;
445+ if (in_repetition && c == '/')
446+ goto out;
447+ if (c <= ' ' || c >= 127)
448+ goto out;
449+ if (c != '\\')
450+ continue;
451+ c = *string++;
452+ if (c >= '0' && c <= '3') {
453+ unsigned char d;
454+ unsigned char e;
455+ d = *string++;
456+ if (d < '0' || d > '7')
457+ goto out;
458+ e = *string++;
459+ if (e < '0' || e > '7')
460+ goto out;
461+ c = ((c - '0') << 6) + ((d - '0') << 3) + (e - '0');
462+ if (c <= ' ' || c >= 127 || c == '\\')
463+ continue;
464+ goto out;
465+ }
466+ if (!allow_pattern)
467+ goto out;
468+ switch (c) {
469+ case '+': /* "\+" */
470+ case '?': /* "\?" */
471+ case 'x': /* "\x" */
472+ case 'a': /* "\a" */
473+ case '-': /* "\-" */
474+ continue;
475+ }
476+ /* Reject too deep wildcard that consumes too much stack. */
477+ if (!recursion--)
478+ goto out;
479+ switch (c) {
480+ case '*': /* "\*" */
481+ case '@': /* "\@" */
482+ case '$': /* "\$" */
483+ case 'X': /* "\X" */
484+ case 'A': /* "\A" */
485+ continue;
486+ case '{': /* "/\{" */
487+ if (string - 3 < start || *(string - 3) != '/')
488+ goto out;
489+ in_repetition = 1;
490+ continue;
491+ case '}': /* "\}/" */
492+ if (in_repetition != 1 || *string++ != '/')
493+ goto out;
494+ in_repetition = 0;
495+ continue;
496+ case '(': /* "/\(" */
497+ if (string - 3 < start || *(string - 3) != '/')
498+ goto out;
499+ in_repetition = 2;
500+ continue;
501+ case ')': /* "\)/" */
502+ if (in_repetition != 2 || *string++ != '/')
503+ goto out;
504+ in_repetition = 0;
505+ continue;
506+ }
507+ goto out;
508+ }
509+ if (in_repetition)
510+ goto out;
511+ return true;
512+out:
513+ return false;
514+}
515+
516+/**
517+ * cs_get_name - Allocate memory for string data.
518+ *
519+ * @name: The string to save.
520+ *
521+ * Returns pointer to "struct cs_path_info" on success, NULL otherwise.
522+ */
523+static struct cs_path_info *cs_get_name(const char *name)
524+{
525+ struct cs_path_info *ptr =
526+ (struct cs_path_info *) malloc(sizeof(struct cs_path_info));
527+ if (!ptr)
528+ out_of_memory();
529+ ptr->name = strdup(name);
530+ if (!ptr->name)
531+ out_of_memory();
532+ cs_fill_path_info(ptr);
533+ return ptr;
534+}
535+
536+/**
537+ * cs_put_name - Free memory for string data.
538+ *
539+ * @name: Pointer to "struct cs_path_info". Maybe NULL.
540+ *
541+ * Returns nothing.
542+ */
543+static void cs_put_name(struct cs_path_info *name)
544+{
545+ if (name) {
546+ free((void *) name->name);
547+ free(name);
548+ }
549+}
550+
551+/**
552+ * cs_normalize_line - Format string.
553+ *
554+ * @buffer: The line to normalize.
555+ *
556+ * Returns nothing.
557+ *
558+ * Leading and trailing whitespaces are removed.
559+ * Multiple whitespaces are packed into single space.
560+ */
561+static void cs_normalize_line(char *buffer)
562+{
563+ unsigned char *sp = (unsigned char *) buffer;
564+ unsigned char *dp = (unsigned char *) buffer;
565+ bool first = true;
566+ while (*sp && (*sp <= ' ' || *sp >= 127))
567+ sp++;
568+ while (*sp) {
569+ if (!first)
570+ *dp++ = ' ';
571+ first = false;
572+ while (*sp > ' ' && *sp < 127)
573+ *dp++ = *sp++;
574+ while (*sp && (*sp <= ' ' || *sp >= 127))
575+ sp++;
576+ }
577+ *dp = '\0';
578+}
579+
580+static struct testcase {
581+ const char *pathname;
582+ const char *pattern;
583+ _Bool match;
584+} testcases[] = {
585+ { "/tmp/000", "/tmp/\\*", 1 },
586+ { "/tmp/000", "/tmp/\\@", 1 },
587+ { "/tmp/000", "/tmp/\\?\\?\\?", 1 },
588+ { "/tmp/000", "/tmp/\\*\\$\\@\\$", 1 },
589+ { "/tmp/000\\040111", "/tmp/\\*", 1 },
590+ { "/tmp/000\\040111", "/tmp/\\X", 0 },
591+ { "/tmp/000\\040111", "/tmp/\\$\\?\\$", 1 },
592+ { "/tmp/000111", "/tmp/\\(\\*\\)/\\*", 1 },
593+ { "/tmp/000/111", "/tmp/\\(\\*\\)/\\*", 1 },
594+ { "/tmp/0/0/0/1/1/1", "/tmp/\\(\\*\\)/\\*", 1 },
595+ { "/tmp/0/0/0/1/1/1", "/tmp/\\{\\$\\}/\\$", 1 },
596+ { "/tmp/0/0/0/1/1/1", "/tmp/\\{\\a\\}/\\$", 0 },
597+ { "/tmp/0/0/0/1/1/1", "/tmp/\\{\\$\\-\\a\\}/\\$", 1 },
598+ { "/tmp/0/0/0/1/1/1", "/tmp/\\{\\x\\-\\a\\}/\\$", 1 },
599+ { "/tmp/\\001/\\002/\\040/^/$", "/tmp/\\{\\*\\-\\a\\}/\\?", 1 },
600+ { "/tmp/\\001/\\002/\\040/^/$", "/tmp/\\{\\*\\-\\a\\-\\x\\}/\\?", 1 },
601+ { "/tmp/$", "/tmp/\\*\\-\\a\\-\\x", 1 },
602+ { "/bin/true", "/bin/\\*", 1 },
603+ { "/bin/true", "/bin\\@\\*/\\*", 1 },
604+ { "/usr/local/", "/usr/\\*/", 1 },
605+ { "/usr/local/", "/usr/\\*\\*\\@\\*/", 1 },
606+ { "pipe:[12345]", "pipe:[\\$]", 1 },
607+ { "socket:[family=1:type=2:protocol=3]", "socket:[family=1:type=2:protocol=\\$]", 1 },
608+ { "http://tomoyo.osdn.jp/", "\\*/\\*/\\*/", 1 },
609+ { "http://tomoyo.osdn.jp/index.html", "\\*/\\*/\\*/\\*", 1 },
610+ { "http://tomoyo.osdn.jp/index.html", "\\*/\\*/\\*/\\*\\*\\@\\*\\@", 1 },
611+ { "http://tomoyo.osdn.jp/index.html", "\\*/\\@\\*/\\*\\@/\\*\\@\\*\\@\\*", 1 },
612+ { "http://tomoyo.osdn.jp/1.8/index.html", "http://\\{\\*\\}/\\@.html", 1 },
613+ { "http://tomoyo.osdn.jp/index.html", "\\*://\\@.osdn.jp/\\*", 1 },
614+ { "http://tomoyo.osdn.jp/index.html", "\\*://\\@.osdn.jp/\\*", 1 },
615+ { "http://osdn.jp/projects/tomoyo/svn/view/trunk/1.8.x/ccs-patch/security/ccsecurity/?root=tomoyo", "\\*://\\@osdn.jp/\\{\\*\\}/?root=tomoyo", 1 },
616+ { "http://osdn.jp/projects/tomoyo/svn/view/trunk/1.8.x/ccs-patch/security/?root=tomoyo", "\\*://\\@osdn.jp/\\{\\*\\}/?root=tomoyo", 1 },
617+ { "http://osdn.jp/projects/tomoyo/svn/view/trunk/1.8.x/ccs-patch/?root=tomoyo", "\\*://\\@osdn.jp/\\{\\*\\}/?root=tomoyo", 1 },
618+ { "http://osdn.jp/projects/tomoyo/svn/view/trunk/1.8.x//ccs-patch///security//ccsecurity///?root=tomoyo", "\\*://\\@osdn.jp/\\{\\*\\-.\\-..\\-\\*%\\*\\}/?root=tomoyo\\*\\*", 1 },
619+ { "/var/www/html/test/test/test/index.html", "/var/www/html/\\{test\\}/\\*.html", 1 },
620+ { "/etc/skel/", "/etc/\\{\\*\\}/\\*/", 0 },
621+ { "/etc/passwd", "/etc/\\{\\*\\}/\\*", 0 },
622+ { "/bin/true", "/bin/\\*/", 0 },
623+ { "/bin/", "/bin/\\*", 1 },
624+ { "/bin/", "/bin/\\@", 1 },
625+ { "/bin/", "/bin/\\@\\@", 1 },
626+ { "http://tomoyo.osdn.jp/", "\\*/\\*/\\*/\\?", 0 },
627+ { "http://tomoyo.osdn.jp/index.html", "\\*/\\*/\\*/\\@", 0 },
628+ { "http://tomoyo.osdn.jp/index.html", "http://\\*/\\@", 0 },
629+ { "socket:[family=1:type=2:protocol=3]", "/\\{\\*\\}/socket:[\\*]", 0 },
630+ { "/", "/\\(\\*\\)/\\*", 1 },
631+ { "/", "/\\{\\*\\}/\\*", 0 },
632+ { "/foo/", "/foo/\\(\\*\\)/\\(\\*\\)/\\(\\*\\)/\\(\\*\\)/\\(\\*\\)/\\*", 1 },
633+ { "/foo/", "/foo/\\{\\*\\}/\\*", 0 },
634+ { "/foo/bar/", "/foo/\\(\\*\\)/\\(\\*\\)/\\(\\*\\)/\\(\\*\\)/\\(\\*\\)/\\*", 1 },
635+ { "/foo/bar/", "/foo/\\{\\*\\}/\\*", 1 },
636+ { "/foo/bar", "/foo/\\(\\*\\)/\\(\\*\\)/\\(\\*\\)/\\(\\*\\)/\\(\\*\\)/bar", 1 },
637+ { "/foo/bar", "/foo/\\{\\*\\}/bar", 0 },
638+ { "/foo/bar", "/foo/\\*/\\(\\*\\)/\\(\\*\\)/\\(\\*\\)/\\(\\*\\)/\\(\\*\\)/\\*", 0 },
639+ { "/foo/bar/", "/foo/\\(\\*\\)/", 1 },
640+ { "/foo/bar/", "/foo/\\*/\\(\\*\\)/", 1 },
641+ { "/foo/bar/", "/foo/\\*/\\*/\\(\\*\\)/", 0 },
642+ { "/foo/bar/", "/foo/\\*/\\(\\*\\)/\\*/", 0 },
643+ { "/foo/", "/foo/\\(\\*\\)/", 1 },
644+ { "abc", "abc", 1 },
645+ { "abc", "\\A\\A\\A", 1 },
646+ { "abc", "\\X\\X\\X", 1 },
647+ { "abc", "\\*\\*\\*", 1 },
648+ { "abc", "\\@\\@\\@", 1 },
649+ { "abc", "\\a\\@\\x", 1 },
650+ { "abc", "\\?\\?\\?", 1 },
651+ { "abc", "\\?\\@\\?\\*", 1 },
652+ { "abc", "\\?\\@\\?\\*\\?", 1 },
653+ { "abc", "def", 0 },
654+ { "abc/def", "\\*/\\(\\X\\)/\\X", 1 },
655+ { "abc/def", "\\*/\\{\\X\\}/\\X", 0 },
656+ { "abc/def/012", "\\*/\\(\\X\\)/\\X", 1 },
657+ { "abc/def/012", "\\*/\\{\\X\\}/\\X", 1 },
658+ { "abc/def/012/345/6789", "\\*/\\(\\X\\)/\\X", 1 },
659+ { "abc/def/012/345/6789", "\\*/\\{\\X\\}/\\X", 1 },
660+ { "abc/345/012/def/6789", "\\*/\\(\\$\\)/\\X", 0 },
661+ { "abc/345/012/def/6789", "\\*/\\(\\*\\)/\\*/", 0 },
662+ { "abc/345/012/def/6789/////1//23///", "\\*/\\(\\*\\)/\\*/", 1 },
663+ { "abc/345/012/def/6789/////1//23//./", "\\*/\\(\\*\\)/\\?/", 1 },
664+ { "abc/345/012/def/6789//1//23//.", "\\*/\\(\\*\\)/\\?/", 0 },
665+ { "abc/345/012/def/6789//1//23//", "\\*/\\(\\*\\)/\\?", 0 },
666+ { "abc", "abc/\\*", 0 },
667+ { "abc/", "abc/\\*", 1 },
668+ { NULL, NULL, 0 },
669+};
670+
671+int main(int argc, char *argv[])
672+{
673+ struct testcase *ptr;
674+ struct cs_path_info *path;
675+ struct cs_path_info *pattern;
676+ for (ptr = testcases; ptr->pathname; ptr++) {
677+ if (!cs_correct_word(ptr->pathname, 0)) {
678+ printf("Bad path: %s\n", ptr->pathname);
679+ continue;
680+ } else if (!cs_correct_word(ptr->pattern, 1)) {
681+ printf("Bad pattern: %s\n", ptr->pattern);
682+ continue;
683+ }
684+ path = cs_get_name(ptr->pathname);
685+ pattern = cs_get_name(ptr->pattern);
686+ if (cs_path_matches_pattern(path, pattern) != ptr->match)
687+ printf("Failed (\"%s\", \"%s\") == %d\n",
688+ ptr->pathname, ptr->pattern, ptr->match);
689+ cs_put_name(path);
690+ cs_put_name(pattern);
691+ }
692+ return 0;
693+}
Show on old repository browser