]>
git.ipfire.org Git - thirdparty/cups.git/blob - scheduler/type.c
2 * "$Id: type.c 177 2006-06-21 00:20:03Z jlovell $"
4 * MIME typing routines for the Common UNIX Printing System (CUPS).
6 * Copyright 1997-2006 by Easy Software Products, all rights reserved.
8 * These coded instructions, statements, and computer programs are the
9 * property of Easy Software Products and are protected by Federal
10 * copyright law. Distribution and use rights are outlined in the file
11 * "LICENSE.txt" which should have been included with this file. If this
12 * file is missing or damaged please contact Easy Software Products
15 * Attn: CUPS Licensing Information
16 * Easy Software Products
17 * 44141 Airport View Drive, Suite 204
18 * Hollywood, Maryland 20636 USA
20 * Voice: (301) 373-9600
21 * EMail: cups-info@cups.org
22 * WWW: http://www.cups.org
26 * mimeAddType() - Add a MIME type to a database.
27 * mimeAddTypeRule() - Add a detection rule for a file type.
28 * mimeFileType() - Determine the type of a file.
29 * mimeType() - Lookup a file type.
30 * compare_types() - Compare two MIME super/type names.
31 * checkrules() - Check each rule in a list.
32 * patmatch() - Pattern matching...
36 * Include necessary headers...
44 #include <cups/string.h>
46 #include <cups/debug.h>
53 typedef struct _mime_filebuf_s
/**** File buffer for MIME typing ****/
55 cups_file_t
*fp
; /* File pointer */
56 int offset
, /* Offset in file */
57 length
; /* Length of buffered data */
58 unsigned char buffer
[MIME_MAX_BUFFER
];/* Buffered data */
66 static int compare_types(mime_type_t
*t0
, mime_type_t
*t1
);
67 static int checkrules(const char *filename
, _mime_filebuf_t
*fb
,
69 static int patmatch(const char *s
, const char *pat
);
73 * 'mimeAddType()' - Add a MIME type to a database.
76 mime_type_t
* /* O - New (or existing) MIME type */
77 mimeAddType(mime_t
*mime
, /* I - MIME database */
78 const char *super
, /* I - Super-type name */
79 const char *type
) /* I - Type name */
81 mime_type_t
*temp
; /* New MIME type */
85 * Range check input...
88 if (!mime
|| !super
|| !type
)
92 * See if the type already exists; if so, return the existing type...
95 if ((temp
= mimeType(mime
, super
, type
)) != NULL
)
99 * The type doesn't exist; add it...
103 mime
->types
= cupsArrayNew((cups_array_func_t
)compare_types
, NULL
);
108 if ((temp
= calloc(1, sizeof(mime_type_t
) - MIME_MAX_TYPE
+
109 strlen(type
) + 1)) == NULL
)
112 strlcpy(temp
->super
, super
, sizeof(temp
->super
));
113 strcpy(temp
->type
, type
); /* Safe: temp->type is allocated */
115 cupsArrayAdd(mime
->types
, temp
);
122 * 'mimeAddTypeRule()' - Add a detection rule for a file type.
125 int /* O - 0 on success, -1 on failure */
126 mimeAddTypeRule(mime_type_t
*mt
, /* I - Type to add to */
127 const char *rule
) /* I - Rule to add */
129 int num_values
, /* Number of values seen */
130 op
, /* Operation code */
131 logic
, /* Logic for next rule */
132 invert
; /* Invert following rule? */
133 char name
[255], /* Name in rule string */
134 value
[3][255], /* Value in rule string */
135 *ptr
, /* Position in name or value */
136 quote
; /* Quote character */
137 int length
[3]; /* Length of each parameter */
138 mime_magic_t
*temp
, /* New rule */
139 *current
; /* Current rule */
143 * Range check input...
150 * Find the last rule in the top-level of the rules tree.
153 for (current
= mt
->rules
; current
; current
= current
->next
)
158 * Parse the rules string. Most rules are either a file extension or a
159 * comparison function:
162 * function(parameters)
165 logic
= MIME_MAGIC_NOP
;
168 DEBUG_printf(("%s/%s: %s\n", mt
->super
, mt
->type
, rule
));
170 while (*rule
!= '\0')
172 while (isspace(*rule
& 255))
177 DEBUG_puts("new parenthesis group");
178 logic
= MIME_MAGIC_NOP
;
181 else if (*rule
== ')')
183 DEBUG_puts("close paren...");
184 if (current
== NULL
|| current
->parent
== NULL
)
187 current
= current
->parent
;
189 if (current
->parent
== NULL
)
190 logic
= MIME_MAGIC_OR
;
192 logic
= current
->parent
->op
;
196 else if (*rule
== '+' && current
!= NULL
)
198 if (logic
!= MIME_MAGIC_AND
&&
199 current
!= NULL
&& current
->prev
!= NULL
&&
200 current
->prev
->prev
!= NULL
)
203 * OK, we have more than 1 rule in the current tree level... Make a
204 * new group tree and move the previous rule to it...
207 if ((temp
= calloc(1, sizeof(mime_magic_t
))) == NULL
)
210 temp
->op
= MIME_MAGIC_AND
;
211 temp
->child
= current
;
212 temp
->parent
= current
->parent
;
213 current
->prev
->next
= temp
;
214 temp
->prev
= current
->prev
;
216 current
->prev
= NULL
;
217 current
->parent
= temp
;
219 DEBUG_printf(("creating new AND group %p...\n", temp
));
223 DEBUG_printf(("setting group %p op to AND...\n", current
->parent
));
224 current
->parent
->op
= MIME_MAGIC_AND
;
227 logic
= MIME_MAGIC_AND
;
230 else if (*rule
== ',')
232 if (logic
!= MIME_MAGIC_OR
&& current
!= NULL
)
235 * OK, we have two possibilities; either this is the top-level rule or
236 * we have a bunch of AND rules at this level.
239 if (current
->parent
== NULL
)
242 * This is the top-level rule; we have to move *all* of the AND rules
243 * down a level, as AND has precedence over OR.
246 if ((temp
= calloc(1, sizeof(mime_magic_t
))) == NULL
)
249 DEBUG_printf(("creating new AND group %p inside OR group\n", temp
));
251 while (current
->prev
!= NULL
)
253 current
->parent
= temp
;
254 current
= current
->prev
;
257 current
->parent
= temp
;
258 temp
->op
= MIME_MAGIC_AND
;
259 temp
->child
= current
;
261 mt
->rules
= current
= temp
;
266 * This isn't the top rule, so go up one level...
269 DEBUG_puts("going up one level");
270 current
= current
->parent
;
274 logic
= MIME_MAGIC_OR
;
277 else if (*rule
== '!')
283 else if (isalnum(*rule
& 255))
286 * Read an extension name or a function...
290 while (isalnum(*rule
& 255) && (ptr
- name
) < (sizeof(name
) - 1))
299 * Read function parameters...
304 num_values
< (sizeof(value
) / sizeof(value
[0]));
307 ptr
= value
[num_values
];
309 while ((ptr
- value
[num_values
]) < (sizeof(value
[0]) - 1) &&
310 *rule
!= '\0' && *rule
!= ',' && *rule
!= ')')
312 if (isspace(*rule
& 255))
315 * Ignore whitespace...
321 else if (*rule
== '\"' || *rule
== '\'')
324 * Copy quoted strings literally...
329 while (*rule
!= '\0' && *rule
!= quote
&&
330 (ptr
- value
[num_values
]) < (sizeof(value
[0]) - 1))
338 else if (*rule
== '<')
342 while (*rule
!= '>' && *rule
!= '\0' &&
343 (ptr
- value
[num_values
]) < (sizeof(value
[0]) - 1))
345 if (isxdigit(rule
[0] & 255) && isxdigit(rule
[1] & 255))
348 *ptr
= (*rule
++ - '0') << 4;
350 *ptr
= (tolower(*rule
++) - 'a' + 10) << 4;
353 *ptr
++ |= *rule
++ - '0';
355 *ptr
++ |= tolower(*rule
++) - 'a' + 10;
371 length
[num_values
] = ptr
- value
[num_values
];
385 * Figure out the function...
388 if (!strcmp(name
, "match"))
389 op
= MIME_MAGIC_MATCH
;
390 else if (!strcmp(name
, "ascii"))
391 op
= MIME_MAGIC_ASCII
;
392 else if (!strcmp(name
, "printable"))
393 op
= MIME_MAGIC_PRINTABLE
;
394 else if (!strcmp(name
, "string"))
395 op
= MIME_MAGIC_STRING
;
396 else if (!strcmp(name
, "istring"))
397 op
= MIME_MAGIC_ISTRING
;
398 else if (!strcmp(name
, "char"))
399 op
= MIME_MAGIC_CHAR
;
400 else if (!strcmp(name
, "short"))
401 op
= MIME_MAGIC_SHORT
;
402 else if (!strcmp(name
, "int"))
404 else if (!strcmp(name
, "locale"))
405 op
= MIME_MAGIC_LOCALE
;
406 else if (!strcmp(name
, "contains"))
407 op
= MIME_MAGIC_CONTAINS
;
414 * This is just a filename match on the extension...
417 snprintf(value
[0], sizeof(value
[0]), "*.%s", name
);
418 length
[0] = strlen(value
[0]);
420 op
= MIME_MAGIC_MATCH
;
424 * Add a rule for this operation.
427 if ((temp
= calloc(1, sizeof(mime_magic_t
))) == NULL
)
430 temp
->invert
= invert
;
433 temp
->parent
= current
->parent
;
434 current
->next
= temp
;
439 temp
->prev
= current
;
441 if (logic
== MIME_MAGIC_NOP
)
444 * Add parenthetical grouping...
447 DEBUG_printf(("making new OR group %p for parenthesis...\n", temp
));
449 temp
->op
= MIME_MAGIC_OR
;
451 if ((temp
->child
= calloc(1, sizeof(mime_magic_t
))) == NULL
)
454 temp
->child
->parent
= temp
;
457 logic
= MIME_MAGIC_OR
;
460 DEBUG_printf(("adding %p: %s, op = %d, logic = %d, invert = %d\n",
461 temp
, name
, op
, logic
, invert
));
464 * Fill in data for the rule...
473 case MIME_MAGIC_MATCH
:
474 if (length
[0] > (sizeof(temp
->value
.matchv
) - 1))
476 strcpy(temp
->value
.matchv
, value
[0]);
478 case MIME_MAGIC_ASCII
:
479 case MIME_MAGIC_PRINTABLE
:
480 temp
->offset
= strtol(value
[0], NULL
, 0);
481 temp
->length
= strtol(value
[1], NULL
, 0);
482 if (temp
->length
> MIME_MAX_BUFFER
)
483 temp
->length
= MIME_MAX_BUFFER
;
485 case MIME_MAGIC_STRING
:
486 case MIME_MAGIC_ISTRING
:
487 temp
->offset
= strtol(value
[0], NULL
, 0);
488 if (length
[1] > sizeof(temp
->value
.stringv
))
490 temp
->length
= length
[1];
491 memcpy(temp
->value
.stringv
, value
[1], length
[1]);
493 case MIME_MAGIC_CHAR
:
494 temp
->offset
= strtol(value
[0], NULL
, 0);
496 temp
->value
.charv
= value
[1][0];
498 temp
->value
.charv
= (char)strtol(value
[1], NULL
, 0);
500 case MIME_MAGIC_SHORT
:
501 temp
->offset
= strtol(value
[0], NULL
, 0);
502 temp
->value
.shortv
= (short)strtol(value
[1], NULL
, 0);
504 case MIME_MAGIC_INT
:
505 temp
->offset
= strtol(value
[0], NULL
, 0);
506 temp
->value
.intv
= (int)strtol(value
[1], NULL
, 0);
508 case MIME_MAGIC_LOCALE
:
509 if (length
[0] > (sizeof(temp
->value
.localev
) - 1))
512 strcpy(temp
->value
.localev
, value
[0]);
514 case MIME_MAGIC_CONTAINS
:
515 temp
->offset
= strtol(value
[0], NULL
, 0);
516 temp
->region
= strtol(value
[1], NULL
, 0);
517 if (length
[2] > sizeof(temp
->value
.stringv
))
519 temp
->length
= length
[2];
520 memcpy(temp
->value
.stringv
, value
[2], length
[2]);
533 * 'mimeFileType()' - Determine the type of a file.
536 mime_type_t
* /* O - Type of file */
537 mimeFileType(mime_t
*mime
, /* I - MIME database */
538 const char *pathname
, /* I - Name of file to check on disk */
539 const char *filename
, /* I - Original filename or NULL */
540 int *compression
) /* O - Is the file compressed? */
542 _mime_filebuf_t fb
; /* File buffer */
543 const char *base
; /* Base filename of file */
544 mime_type_t
*type
; /* File type */
547 DEBUG_printf(("mimeFileType(mime=%p, pathname=\"%s\", filename=\"%s\", "
549 mime
, pathname
? pathname
: "(nil)",
550 filename
? filename
: "(nil)",
554 * Range check input parameters...
557 if (!mime
|| !pathname
)
561 * Try to open the file...
564 if ((fb
.fp
= cupsFileOpen(pathname
, "r")) == NULL
)
571 * Figure out the base filename (without directory portion)...
576 if ((base
= strrchr(filename
, '/')) != NULL
)
581 else if ((base
= strrchr(pathname
, '/')) != NULL
)
587 * Then check it against all known types...
590 for (type
= (mime_type_t
*)cupsArrayFirst(mime
->types
);
592 type
= (mime_type_t
*)cupsArrayNext(mime
->types
))
593 if (checkrules(base
, &fb
, type
->rules
))
597 * Finally, close the file and return a match (if any)...
601 *compression
= cupsFileCompression(fb
.fp
);
603 cupsFileClose(fb
.fp
);
610 * 'mimeType()' - Lookup a file type.
613 mime_type_t
* /* O - Matching file type definition */
614 mimeType(mime_t
*mime
, /* I - MIME database */
615 const char *super
, /* I - Super-type name */
616 const char *type
) /* I - Type name */
618 mime_type_t key
; /* MIME type search key*/
622 * Range check input...
625 if (!mime
|| !super
|| !type
)
629 * Lookup the type in the array...
632 strlcpy(key
.super
, super
, sizeof(key
.super
));
633 strlcpy(key
.type
, type
, sizeof(key
.type
));
635 return ((mime_type_t
*)cupsArrayFind(mime
->types
, &key
));
640 * 'compare_types()' - Compare two MIME super/type names.
643 static int /* O - Result of comparison */
644 compare_types(mime_type_t
*t0
, /* I - First type */
645 mime_type_t
*t1
) /* I - Second type */
647 int i
; /* Result of comparison */
650 if ((i
= strcmp(t0
->super
, t1
->super
)) == 0)
651 i
= strcmp(t0
->type
, t1
->type
);
658 * 'checkrules()' - Check each rule in a list.
661 static int /* O - 1 if match, 0 if no match */
662 checkrules(const char *filename
, /* I - Filename */
663 _mime_filebuf_t
*fb
, /* I - File to check */
664 mime_magic_t
*rules
) /* I - Rules to check */
666 int n
; /* Looping var */
667 int region
; /* Region to look at */
668 int logic
, /* Logic to apply */
669 result
, /* Result of test */
670 intv
; /* Integer value */
671 short shortv
; /* Short value */
672 unsigned char *bufptr
; /* Pointer into buffer */
674 const char * const debug_tests
[] = /* Test names... */
676 "NOP", /* No operation */
677 "AND", /* Logical AND of all children */
678 "OR", /* Logical OR of all children */
679 "MATCH", /* Filename match */
680 "ASCII", /* ASCII characters in range */
681 "PRINTABLE", /* Printable characters (32-255) */
682 "STRING", /* String matches */
683 "CHAR", /* Character/byte matches */
684 "SHORT", /* Short/16-bit word matches */
685 "INT", /* Integer/32-bit word matches */
686 "LOCALE" /* Current locale matches string */
687 "CONTAINS" /* File contains a string */
688 "ISTRING" /* Case-insensitive string matches */
693 DEBUG_printf(("checkrules(filename=\"%s\", fb=%p, rules=%p)\n", filename
,
699 if (rules
->parent
== NULL
)
700 logic
= MIME_MAGIC_OR
;
702 logic
= rules
->parent
->op
;
706 while (rules
!= NULL
)
709 * Compute the result of this rule...
714 case MIME_MAGIC_MATCH
:
715 result
= patmatch(filename
, rules
->value
.matchv
);
718 case MIME_MAGIC_ASCII
:
720 * Load the buffer if necessary...
723 if (fb
->offset
< 0 || rules
->offset
< fb
->offset
||
724 (rules
->offset
+ rules
->length
) > (fb
->offset
+ fb
->length
))
727 * Reload file buffer...
730 cupsFileSeek(fb
->fp
, rules
->offset
);
731 fb
->length
= cupsFileRead(fb
->fp
, (char *)fb
->buffer
,
733 fb
->offset
= rules
->offset
;
737 * Test for ASCII printable characters plus standard control chars.
740 if ((rules
->offset
+ rules
->length
) > (fb
->offset
+ fb
->length
))
741 n
= fb
->offset
+ fb
->length
- rules
->offset
;
745 bufptr
= fb
->buffer
+ rules
->offset
- fb
->offset
;
747 if ((*bufptr
>= 32 && *bufptr
<= 126) ||
748 (*bufptr
>= 8 && *bufptr
<= 13) ||
749 *bufptr
== 26 || *bufptr
== 27)
760 case MIME_MAGIC_PRINTABLE
:
762 * Load the buffer if necessary...
765 if (fb
->offset
< 0 || rules
->offset
< fb
->offset
||
766 (rules
->offset
+ rules
->length
) > (fb
->offset
+ fb
->length
))
769 * Reload file buffer...
772 cupsFileSeek(fb
->fp
, rules
->offset
);
773 fb
->length
= cupsFileRead(fb
->fp
, (char *)fb
->buffer
,
775 fb
->offset
= rules
->offset
;
779 * Test for 8-bit printable characters plus standard control chars.
782 if ((rules
->offset
+ rules
->length
) > (fb
->offset
+ fb
->length
))
783 n
= fb
->offset
+ fb
->length
- rules
->offset
;
787 bufptr
= fb
->buffer
+ rules
->offset
- fb
->offset
;
790 if (*bufptr
>= 128 ||
791 (*bufptr
>= 32 && *bufptr
<= 126) ||
792 (*bufptr
>= 8 && *bufptr
<= 13) ||
793 *bufptr
== 26 || *bufptr
== 27)
804 case MIME_MAGIC_STRING
:
805 DEBUG_printf((" string(%d, \"%s\")\n", rules
->offset
,
806 rules
->value
.stringv
));
809 * Load the buffer if necessary...
812 if (fb
->offset
< 0 || rules
->offset
< fb
->offset
||
813 (rules
->offset
+ rules
->length
) > (fb
->offset
+ fb
->length
))
816 * Reload file buffer...
819 cupsFileSeek(fb
->fp
, rules
->offset
);
820 fb
->length
= cupsFileRead(fb
->fp
, (char *)fb
->buffer
,
822 fb
->offset
= rules
->offset
;
824 DEBUG_printf((" loaded %d byte fb->buffer at %d, starts "
825 "with \"%c%c%c%c\"...\n",
826 fb
->length
, fb
->offset
, fb
->buffer
[0], fb
->buffer
[1],
827 fb
->buffer
[2], fb
->buffer
[3]));
831 * Compare the buffer against the string. If the file is too
832 * short then don't compare - it can't match...
835 if ((rules
->offset
+ rules
->length
) > (fb
->offset
+ fb
->length
))
838 result
= (memcmp(fb
->buffer
+ rules
->offset
- fb
->offset
,
839 rules
->value
.stringv
, rules
->length
) == 0);
840 DEBUG_printf((" result=%d\n", result
));
843 case MIME_MAGIC_ISTRING
:
845 * Load the buffer if necessary...
848 if (fb
->offset
< 0 || rules
->offset
< fb
->offset
||
849 (rules
->offset
+ rules
->length
) > (fb
->offset
+ fb
->length
))
852 * Reload file buffer...
855 cupsFileSeek(fb
->fp
, rules
->offset
);
856 fb
->length
= cupsFileRead(fb
->fp
, (char *)fb
->buffer
,
858 fb
->offset
= rules
->offset
;
862 * Compare the buffer against the string. If the file is too
863 * short then don't compare - it can't match...
866 if ((rules
->offset
+ rules
->length
) > (fb
->offset
+ fb
->length
))
869 result
= (strncasecmp((char *)fb
->buffer
+ rules
->offset
-
871 rules
->value
.stringv
, rules
->length
) == 0);
874 case MIME_MAGIC_CHAR
:
876 * Load the buffer if necessary...
879 if (fb
->offset
< 0 || rules
->offset
< fb
->offset
)
882 * Reload file buffer...
885 cupsFileSeek(fb
->fp
, rules
->offset
);
886 fb
->length
= cupsFileRead(fb
->fp
, (char *)fb
->buffer
,
888 fb
->offset
= rules
->offset
;
892 * Compare the character values; if the file is too short, it
899 result
= (fb
->buffer
[rules
->offset
- fb
->offset
] ==
903 case MIME_MAGIC_SHORT
:
905 * Load the buffer if necessary...
908 if (fb
->offset
< 0 || rules
->offset
< fb
->offset
||
909 (rules
->offset
+ 2) > (fb
->offset
+ fb
->length
))
912 * Reload file buffer...
915 cupsFileSeek(fb
->fp
, rules
->offset
);
916 fb
->length
= cupsFileRead(fb
->fp
, (char *)fb
->buffer
,
918 fb
->offset
= rules
->offset
;
922 * Compare the short values; if the file is too short, it
930 bufptr
= fb
->buffer
+ rules
->offset
- fb
->offset
;
931 shortv
= (bufptr
[0] << 8) | bufptr
[1];
932 result
= (shortv
== rules
->value
.shortv
);
936 case MIME_MAGIC_INT
:
938 * Load the buffer if necessary...
941 if (fb
->offset
< 0 || rules
->offset
< fb
->offset
||
942 (rules
->offset
+ 4) > (fb
->offset
+ fb
->length
))
945 * Reload file buffer...
948 cupsFileSeek(fb
->fp
, rules
->offset
);
949 fb
->length
= cupsFileRead(fb
->fp
, (char *)fb
->buffer
,
951 fb
->offset
= rules
->offset
;
955 * Compare the int values; if the file is too short, it
963 bufptr
= fb
->buffer
+ rules
->offset
- fb
->offset
;
964 intv
= (((((bufptr
[0] << 8) | bufptr
[1]) << 8) |
965 bufptr
[2]) << 8) | bufptr
[3];
966 result
= (intv
== rules
->value
.intv
);
970 case MIME_MAGIC_LOCALE
:
971 #if defined(WIN32) || defined(__EMX__) || defined(__APPLE__)
972 result
= (strcmp(rules
->value
.localev
,
973 setlocale(LC_ALL
, "")) == 0);
975 result
= (strcmp(rules
->value
.localev
,
976 setlocale(LC_MESSAGES
, "")) == 0);
977 #endif /* __APPLE__ */
980 case MIME_MAGIC_CONTAINS
:
982 * Load the buffer if necessary...
985 if (fb
->offset
< 0 || rules
->offset
< fb
->offset
||
986 (rules
->offset
+ rules
->region
) > (fb
->offset
+ fb
->length
))
989 * Reload file buffer...
992 cupsFileSeek(fb
->fp
, rules
->offset
);
993 fb
->length
= cupsFileRead(fb
->fp
, (char *)fb
->buffer
,
995 fb
->offset
= rules
->offset
;
999 * Compare the buffer against the string. If the file is too
1000 * short then don't compare - it can't match...
1003 if ((rules
->offset
+ rules
->length
) > (fb
->offset
+ fb
->length
))
1007 if (fb
->length
> rules
->region
)
1008 region
= rules
->region
- rules
->length
;
1010 region
= fb
->length
- rules
->length
;
1012 for (n
= 0; n
< region
; n
++)
1013 if ((result
= (memcmp(fb
->buffer
+ rules
->offset
- fb
->offset
+ n
,
1014 rules
->value
.stringv
,
1015 rules
->length
) == 0)) != 0)
1021 if (rules
->child
!= NULL
)
1022 result
= checkrules(filename
, fb
, rules
->child
);
1029 * If the logic is inverted, invert the result...
1036 * OK, now if the current logic is OR and this result is true, the this
1037 * rule set is true. If the current logic is AND and this result is false,
1038 * the the rule set is false...
1041 DEBUG_printf((" result of test %p (MIME_MAGIC_%s) is %d\n", rules
,
1042 debug_tests
[rules
->op
], result
));
1044 if ((result
&& logic
== MIME_MAGIC_OR
) ||
1045 (!result
&& logic
== MIME_MAGIC_AND
))
1049 * Otherwise the jury is still out on this one, so move to the next rule.
1052 rules
= rules
->next
;
1060 * 'patmatch()' - Pattern matching...
1063 static int /* O - 1 if match, 0 if no match */
1064 patmatch(const char *s
, /* I - String to match against */
1065 const char *pat
) /* I - Pattern to match against */
1068 * Range check the input...
1071 if (s
== NULL
|| pat
== NULL
)
1075 * Loop through the pattern and match strings, and stop if we come to a
1076 * point where the strings don't match or we find a complete match.
1079 while (*s
!= '\0' && *pat
!= '\0')
1084 * Wildcard - 0 or more characters...
1089 return (1); /* Last pattern char is *, so everything matches... */
1092 * Test all remaining combinations until we get to the end of the string.
1097 if (patmatch(s
, pat
))
1103 else if (*pat
== '?')
1106 * Wildcard - 1 character...
1113 else if (*pat
== '[')
1116 * Match a character from the input set [chars]...
1120 while (*pat
!= ']' && *pat
!= '\0')
1126 if (*pat
== ']' || *pat
== '\0')
1129 while (*pat
!= ']' && *pat
!= '\0')
1137 else if (*pat
== '\\')
1140 * Handle quoted characters...
1147 * Stop if the pattern and string don't match...
1155 * Done parsing the pattern and string; return 1 if the last character
1156 * matches and 0 otherwise...
1159 return (*s
== *pat
);
1164 * End of "$Id: type.c 177 2006-06-21 00:20:03Z jlovell $".