]>
git.ipfire.org Git - thirdparty/cups.git/blob - scheduler/type.c
2 * "$Id: type.c 4613 2005-08-30 12:41:48Z mike $"
4 * MIME typing routines for the Common UNIX Printing System (CUPS).
6 * Copyright 1997-2005 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() - 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 static int compare(mime_type_t
**, mime_type_t
**);
54 static int checkrules(const char *, cups_file_t
*, mime_magic_t
*);
55 static int patmatch(const char *, const char *);
59 * 'mimeAddType()' - Add a MIME type to a database.
62 mime_type_t
* /* O - New (or existing) MIME type */
63 mimeAddType(mime_t
*mime
, /* I - MIME database */
64 const char *super
, /* I - Super-type name */
65 const char *type
) /* I - Type name */
67 mime_type_t
*temp
, /* New MIME type */
68 **types
; /* New MIME types array */
72 * Range check input...
75 if (mime
== NULL
|| super
== NULL
|| type
== NULL
)
78 if (strlen(super
) > (MIME_MAX_SUPER
- 1) ||
79 strlen(type
) > (MIME_MAX_TYPE
- 1))
83 * See if the type already exists; if so, return the existing type...
86 if ((temp
= mimeType(mime
, super
, type
)) != NULL
)
90 * The type doesn't exist; add it...
93 if ((temp
= calloc(1, sizeof(mime_type_t
))) == NULL
)
96 if (mime
->num_types
== 0)
97 types
= (mime_type_t
**)malloc(sizeof(mime_type_t
*));
99 types
= (mime_type_t
**)realloc(mime
->types
, sizeof(mime_type_t
*) * (mime
->num_types
+ 1));
108 types
+= mime
->num_types
;
112 strlcpy(temp
->super
, super
, sizeof(temp
->super
));
113 if ((temp
->type
= strdup(type
)) == NULL
)
119 if (mime
->num_types
> 1)
120 qsort(mime
->types
, mime
->num_types
, sizeof(mime_type_t
*),
121 (int (*)(const void *, const void *))compare
);
128 * 'mimeAddTypeRule()' - Add a detection rule for a file type.
131 int /* O - 0 on success, -1 on failure */
132 mimeAddTypeRule(mime_type_t
*mt
, /* I - Type to add to */
133 const char *rule
) /* I - Rule to add */
135 int num_values
, /* Number of values seen */
136 op
, /* Operation code */
137 logic
, /* Logic for next rule */
138 invert
; /* Invert following rule? */
139 char name
[255], /* Name in rule string */
140 value
[3][255], /* Value in rule string */
141 *ptr
, /* Position in name or value */
142 quote
; /* Quote character */
143 int length
[3]; /* Length of each parameter */
144 mime_magic_t
*temp
, /* New rule */
145 *current
; /* Current rule */
149 * Range check input...
152 if (mt
== NULL
|| rule
== NULL
)
156 * Find the last rule in the top-level of the rules tree.
159 for (current
= mt
->rules
; current
!= NULL
; current
= current
->next
)
160 if (current
->next
== NULL
)
164 * Parse the rules string. Most rules are either a file extension or a
165 * comparison function:
168 * function(parameters)
171 logic
= MIME_MAGIC_NOP
;
174 DEBUG_printf(("%s/%s: %s\n", mt
->super
, mt
->type
, rule
));
176 while (*rule
!= '\0')
178 while (isspace(*rule
& 255))
183 DEBUG_puts("new parenthesis group");
184 logic
= MIME_MAGIC_NOP
;
187 else if (*rule
== ')')
189 DEBUG_puts("close paren...");
190 if (current
== NULL
|| current
->parent
== NULL
)
193 current
= current
->parent
;
195 if (current
->parent
== NULL
)
196 logic
= MIME_MAGIC_OR
;
198 logic
= current
->parent
->op
;
202 else if (*rule
== '+' && current
!= NULL
)
204 if (logic
!= MIME_MAGIC_AND
&&
205 current
!= NULL
&& current
->prev
!= NULL
&& current
->prev
->prev
!= NULL
)
208 * OK, we have more than 1 rule in the current tree level... Make a
209 * new group tree and move the previous rule to it...
212 if ((temp
= calloc(1, sizeof(mime_magic_t
))) == NULL
)
215 temp
->op
= MIME_MAGIC_AND
;
216 temp
->child
= current
;
217 temp
->parent
= current
->parent
;
218 current
->prev
->next
= temp
;
219 temp
->prev
= current
->prev
;
221 current
->prev
= NULL
;
222 current
->parent
= temp
;
224 DEBUG_printf(("creating new AND group %p...\n", temp
));
228 DEBUG_printf(("setting group %p op to AND...\n", current
->parent
));
229 current
->parent
->op
= MIME_MAGIC_AND
;
232 logic
= MIME_MAGIC_AND
;
235 else if (*rule
== ',')
237 if (logic
!= MIME_MAGIC_OR
&& current
!= NULL
)
240 * OK, we have two possibilities; either this is the top-level rule or
241 * we have a bunch of AND rules at this level.
244 if (current
->parent
== NULL
)
247 * This is the top-level rule; we have to move *all* of the AND rules
248 * down a level, as AND has precedence over OR.
251 if ((temp
= calloc(1, sizeof(mime_magic_t
))) == NULL
)
254 DEBUG_printf(("creating new AND group %p inside OR group\n", temp
));
256 while (current
->prev
!= NULL
)
258 current
->parent
= temp
;
259 current
= current
->prev
;
262 current
->parent
= temp
;
263 temp
->op
= MIME_MAGIC_AND
;
264 temp
->child
= current
;
266 mt
->rules
= current
= temp
;
271 * This isn't the top rule, so go up one level...
274 DEBUG_puts("going up one level");
275 current
= current
->parent
;
279 logic
= MIME_MAGIC_OR
;
282 else if (*rule
== '!')
288 else if (isalnum(*rule
& 255))
291 * Read an extension name or a function...
294 for (ptr
= name
; isalnum(*rule
& 255) && (ptr
- name
) < (sizeof(name
) - 1);)
303 * Read function parameters...
308 num_values
< (sizeof(value
) / sizeof(value
[0]));
311 ptr
= value
[num_values
];
313 while ((ptr
- value
[num_values
]) < (sizeof(value
[0]) - 1) &&
314 *rule
!= '\0' && *rule
!= ',' && *rule
!= ')')
316 if (isspace(*rule
& 255))
319 * Ignore whitespace...
325 else if (*rule
== '\"' || *rule
== '\'')
328 * Copy quoted strings literally...
333 while (*rule
!= '\0' && *rule
!= quote
&&
334 (ptr
- value
[num_values
]) < (sizeof(value
[0]) - 1))
342 else if (*rule
== '<')
346 while (*rule
!= '>' && *rule
!= '\0' &&
347 (ptr
- value
[num_values
]) < (sizeof(value
[0]) - 1))
349 if (isxdigit(rule
[0] & 255) && isxdigit(rule
[1] & 255))
352 *ptr
= (*rule
++ - '0') << 4;
354 *ptr
= (tolower(*rule
++) - 'a' + 10) << 4;
357 *ptr
++ |= *rule
++ - '0';
359 *ptr
++ |= tolower(*rule
++) - 'a' + 10;
375 length
[num_values
] = ptr
- value
[num_values
];
389 * Figure out the function...
392 if (strcmp(name
, "match") == 0)
393 op
= MIME_MAGIC_MATCH
;
394 else if (strcmp(name
, "ascii") == 0)
395 op
= MIME_MAGIC_ASCII
;
396 else if (strcmp(name
, "printable") == 0)
397 op
= MIME_MAGIC_PRINTABLE
;
398 else if (strcmp(name
, "string") == 0)
399 op
= MIME_MAGIC_STRING
;
400 else if (strcmp(name
, "istring") == 0)
401 op
= MIME_MAGIC_ISTRING
;
402 else if (strcmp(name
, "char") == 0)
403 op
= MIME_MAGIC_CHAR
;
404 else if (strcmp(name
, "short") == 0)
405 op
= MIME_MAGIC_SHORT
;
406 else if (strcmp(name
, "int") == 0)
408 else if (strcmp(name
, "locale") == 0)
409 op
= MIME_MAGIC_LOCALE
;
410 else if (strcmp(name
, "contains") == 0)
411 op
= MIME_MAGIC_CONTAINS
;
418 * This is just a filename match on the extension...
421 snprintf(value
[0], sizeof(value
[0]), "*.%s", name
);
422 length
[0] = strlen(value
[0]);
424 op
= MIME_MAGIC_MATCH
;
428 * Add a rule for this operation.
431 if ((temp
= calloc(1, sizeof(mime_magic_t
))) == NULL
)
434 temp
->invert
= invert
;
437 temp
->parent
= current
->parent
;
438 current
->next
= temp
;
443 temp
->prev
= current
;
445 if (logic
== MIME_MAGIC_NOP
)
448 * Add parenthetical grouping...
451 DEBUG_printf(("making new OR group %p for parenthesis...\n", temp
));
453 temp
->op
= MIME_MAGIC_OR
;
455 if ((temp
->child
= calloc(1, sizeof(mime_magic_t
))) == NULL
)
458 temp
->child
->parent
= temp
;
461 logic
= MIME_MAGIC_OR
;
464 DEBUG_printf(("adding %p: %s, op = %d, logic = %d, invert = %d\n",
465 temp
, name
, op
, logic
, invert
));
468 * Fill in data for the rule...
477 case MIME_MAGIC_MATCH
:
478 if (length
[0] > (sizeof(temp
->value
.matchv
) - 1))
480 strcpy(temp
->value
.matchv
, value
[0]);
482 case MIME_MAGIC_ASCII
:
483 case MIME_MAGIC_PRINTABLE
:
484 temp
->offset
= strtol(value
[0], NULL
, 0);
485 temp
->length
= strtol(value
[1], NULL
, 0);
486 if (temp
->length
> MIME_MAX_BUFFER
)
487 temp
->length
= MIME_MAX_BUFFER
;
489 case MIME_MAGIC_STRING
:
490 case MIME_MAGIC_ISTRING
:
491 temp
->offset
= strtol(value
[0], NULL
, 0);
492 if (length
[1] > sizeof(temp
->value
.stringv
))
494 temp
->length
= length
[1];
495 memcpy(temp
->value
.stringv
, value
[1], length
[1]);
497 case MIME_MAGIC_CHAR
:
498 temp
->offset
= strtol(value
[0], NULL
, 0);
500 temp
->value
.charv
= value
[1][0];
502 temp
->value
.charv
= (char)strtol(value
[1], NULL
, 0);
504 case MIME_MAGIC_SHORT
:
505 temp
->offset
= strtol(value
[0], NULL
, 0);
506 temp
->value
.shortv
= (short)strtol(value
[1], NULL
, 0);
508 case MIME_MAGIC_INT
:
509 temp
->offset
= strtol(value
[0], NULL
, 0);
510 temp
->value
.intv
= (int)strtol(value
[1], NULL
, 0);
512 case MIME_MAGIC_LOCALE
:
513 if (length
[0] > (sizeof(temp
->value
.localev
) - 1))
516 strcpy(temp
->value
.localev
, value
[0]);
518 case MIME_MAGIC_CONTAINS
:
519 temp
->offset
= strtol(value
[0], NULL
, 0);
520 temp
->region
= strtol(value
[1], NULL
, 0);
521 if (length
[2] > sizeof(temp
->value
.stringv
))
523 temp
->length
= length
[2];
524 memcpy(temp
->value
.stringv
, value
[2], length
[2]);
537 * 'mimeFileType()' - Determine the type of a file.
540 mime_type_t
* /* O - Type of file */
541 mimeFileType(mime_t
*mime
, /* I - MIME database */
542 const char *pathname
, /* I - Name of file to check */
543 int *compression
) /* O - Is the file compressed? */
545 int i
; /* Looping var */
546 cups_file_t
*fp
; /* File pointer */
547 mime_type_t
**types
; /* File types */
548 const char *filename
; /* Base filename of file */
551 DEBUG_printf(("mimeFileType(mime=%p, pathname=\"%s\", compression=%p)\n",
552 mime
, pathname
? pathname
: "(nil)", compression
));
555 * Range check input parameters...
558 if (mime
== NULL
|| pathname
== NULL
)
562 * Try to open the file...
565 if ((fp
= cupsFileOpen(pathname
, "r")) == NULL
)
569 * Figure out the filename (without directory portion)...
572 if ((filename
= strrchr(pathname
, '/')) != NULL
)
578 * Then check it against all known types...
581 for (i
= mime
->num_types
, types
= mime
->types
; i
> 0; i
--, types
++)
582 if (checkrules(filename
, fp
, (*types
)->rules
))
586 * Finally, close the file and return a match (if any)...
590 *compression
= cupsFileCompression(fp
);
602 * 'mimeType()' - Lookup a file type.
605 mime_type_t
* /* O - Matching file type definition */
606 mimeType(mime_t
*mime
, /* I - MIME database */
607 const char *super
, /* I - Super-type name */
608 const char *type
) /* I - Type name */
610 mime_type_t key
, /* MIME type search key*/
611 *keyptr
, /* Key pointer... */
612 **match
; /* Matching pointer */
615 * Range check input...
618 if (mime
== NULL
|| super
== NULL
|| type
== NULL
)
621 if (strlen(super
) > (MIME_MAX_SUPER
- 1) ||
622 strlen(type
) > (MIME_MAX_TYPE
- 1))
625 if (mime
->num_types
== 0)
629 * Lookup the type in the array...
632 strlcpy(key
.super
, super
, sizeof(key
.super
));
633 key
.type
= (char *)type
;
637 match
= (mime_type_t
**)bsearch(&keyptr
, mime
->types
, mime
->num_types
,
638 sizeof(mime_type_t
*),
639 (int (*)(const void *, const void *))compare
);
649 * 'compare()' - Compare two MIME super/type names.
652 static int /* O - Result of comparison */
653 compare(mime_type_t
**t0
, /* I - First type */
654 mime_type_t
**t1
) /* I - Second type */
656 int i
; /* Result of comparison */
659 if ((i
= strcasecmp((*t0
)->super
, (*t1
)->super
)) == 0)
660 i
= strcasecmp((*t0
)->type
, (*t1
)->type
);
667 * 'checkrules()' - Check each rule in a list.
670 static int /* O - 1 if match, 0 if no match */
671 checkrules(const char *filename
, /* I - Filename */
672 cups_file_t
*fp
, /* I - File to check */
673 mime_magic_t
*rules
) /* I - Rules to check */
675 int n
; /* Looping var */
676 int region
; /* Region to look at */
677 int logic
, /* Logic to apply */
678 result
, /* Result of test */
679 intv
; /* Integer value */
680 short shortv
; /* Short value */
681 unsigned char buffer
[MIME_MAX_BUFFER
],/* Input buffer */
682 *bufptr
; /* Current buffer position */
683 int bufoffset
, /* Offset in file for buffer */
684 buflength
; /* Length of data in buffer */
686 const char * const debug_tests
[] = /* Test names... */
688 "NOP", /* No operation */
689 "AND", /* Logical AND of all children */
690 "OR", /* Logical OR of all children */
691 "MATCH", /* Filename match */
692 "ASCII", /* ASCII characters in range */
693 "PRINTABLE", /* Printable characters (32-255) in range */
694 "STRING", /* String matches */
695 "CHAR", /* Character/byte matches */
696 "SHORT", /* Short/16-bit word matches */
697 "INT", /* Integer/32-bit word matches */
698 "LOCALE" /* Current locale matches string */
699 "CONTAINS" /* File contains a string */
700 "ISTRING" /* Case-insensitive string matches */
705 DEBUG_printf(("checkrules(filename=\"%s\", fp=%p, rules=%p)\n", filename
,
711 if (rules
->parent
== NULL
)
712 logic
= MIME_MAGIC_OR
;
714 logic
= rules
->parent
->op
;
720 while (rules
!= NULL
)
723 * Compute the result of this rule...
728 case MIME_MAGIC_MATCH
:
729 result
= patmatch(filename
, rules
->value
.matchv
);
732 case MIME_MAGIC_ASCII
:
734 * Load the buffer if necessary...
737 if (bufoffset
< 0 || rules
->offset
< bufoffset
||
738 (rules
->offset
+ rules
->length
) > (bufoffset
+ buflength
))
741 * Reload file buffer...
744 cupsFileSeek(fp
, rules
->offset
);
745 buflength
= cupsFileRead(fp
, (char *)buffer
, sizeof(buffer
));
746 bufoffset
= rules
->offset
;
750 * Test for ASCII printable characters plus standard control chars.
753 if ((rules
->offset
+ rules
->length
) > (bufoffset
+ buflength
))
754 n
= bufoffset
+ buflength
- rules
->offset
;
758 bufptr
= buffer
+ rules
->offset
- bufoffset
;
760 if ((*bufptr
>= 32 && *bufptr
<= 126) ||
761 (*bufptr
>= 8 && *bufptr
<= 13) ||
762 *bufptr
== 26 || *bufptr
== 27)
773 case MIME_MAGIC_PRINTABLE
:
775 * Load the buffer if necessary...
778 if (bufoffset
< 0 || rules
->offset
< bufoffset
||
779 (rules
->offset
+ rules
->length
) > (bufoffset
+ buflength
))
782 * Reload file buffer...
785 cupsFileSeek(fp
, rules
->offset
);
786 buflength
= cupsFileRead(fp
, (char *)buffer
, sizeof(buffer
));
787 bufoffset
= rules
->offset
;
791 * Test for 8-bit printable characters plus standard control chars.
794 if ((rules
->offset
+ rules
->length
) > (bufoffset
+ buflength
))
795 n
= bufoffset
+ buflength
- rules
->offset
;
799 bufptr
= buffer
+ rules
->offset
- bufoffset
;
802 if (*bufptr
>= 128 ||
803 (*bufptr
>= 32 && *bufptr
<= 126) ||
804 (*bufptr
>= 8 && *bufptr
<= 13) ||
805 *bufptr
== 26 || *bufptr
== 27)
816 case MIME_MAGIC_STRING
:
817 DEBUG_printf((" string(%d, \"%s\")\n", rules
->offset
,
818 rules
->value
.stringv
));
821 * Load the buffer if necessary...
824 if (bufoffset
< 0 || rules
->offset
< bufoffset
||
825 (rules
->offset
+ rules
->length
) > (bufoffset
+ buflength
))
828 * Reload file buffer...
831 cupsFileSeek(fp
, rules
->offset
);
832 buflength
= cupsFileRead(fp
, (char *)buffer
, sizeof(buffer
));
833 bufoffset
= rules
->offset
;
835 DEBUG_printf((" loaded %d byte buffer at %d, starts with \"%c%c%c%c\"...\n",
836 buflength
, bufoffset
, buffer
[0], buffer
[1],
837 buffer
[2], buffer
[3]));
841 * Compare the buffer against the string. If the file is too
842 * short then don't compare - it can't match...
845 if ((rules
->offset
+ rules
->length
) > (bufoffset
+ buflength
))
848 result
= (memcmp(buffer
+ rules
->offset
- bufoffset
,
849 rules
->value
.stringv
, rules
->length
) == 0);
850 DEBUG_printf((" result=%d\n", result
));
853 case MIME_MAGIC_ISTRING
:
855 * Load the buffer if necessary...
858 if (bufoffset
< 0 || rules
->offset
< bufoffset
||
859 (rules
->offset
+ rules
->length
) > (bufoffset
+ buflength
))
862 * Reload file buffer...
865 cupsFileSeek(fp
, rules
->offset
);
866 buflength
= cupsFileRead(fp
, (char *)buffer
, sizeof(buffer
));
867 bufoffset
= rules
->offset
;
871 * Compare the buffer against the string. If the file is too
872 * short then don't compare - it can't match...
875 if ((rules
->offset
+ rules
->length
) > (bufoffset
+ buflength
))
878 result
= (strncasecmp((char *)buffer
+ rules
->offset
- bufoffset
,
879 rules
->value
.stringv
, rules
->length
) == 0);
882 case MIME_MAGIC_CHAR
:
884 * Load the buffer if necessary...
887 if (bufoffset
< 0 || rules
->offset
< bufoffset
)
890 * Reload file buffer...
893 cupsFileSeek(fp
, rules
->offset
);
894 buflength
= cupsFileRead(fp
, (char *)buffer
, sizeof(buffer
));
895 bufoffset
= rules
->offset
;
899 * Compare the character values; if the file is too short, it
906 result
= (buffer
[rules
->offset
- bufoffset
] == rules
->value
.charv
);
909 case MIME_MAGIC_SHORT
:
911 * Load the buffer if necessary...
914 if (bufoffset
< 0 || rules
->offset
< bufoffset
||
915 (rules
->offset
+ 2) > (bufoffset
+ buflength
))
918 * Reload file buffer...
921 cupsFileSeek(fp
, rules
->offset
);
922 buflength
= cupsFileRead(fp
, (char *)buffer
, sizeof(buffer
));
923 bufoffset
= rules
->offset
;
927 * Compare the short values; if the file is too short, it
935 bufptr
= buffer
+ rules
->offset
- bufoffset
;
936 shortv
= (bufptr
[0] << 8) | bufptr
[1];
937 result
= (shortv
== rules
->value
.shortv
);
941 case MIME_MAGIC_INT
:
943 * Load the buffer if necessary...
946 if (bufoffset
< 0 || rules
->offset
< bufoffset
||
947 (rules
->offset
+ 4) > (bufoffset
+ buflength
))
950 * Reload file buffer...
953 cupsFileSeek(fp
, rules
->offset
);
954 buflength
= cupsFileRead(fp
, (char *)buffer
, sizeof(buffer
));
955 bufoffset
= rules
->offset
;
959 * Compare the int values; if the file is too short, it
967 bufptr
= buffer
+ rules
->offset
- bufoffset
;
968 intv
= (((((bufptr
[0] << 8) | bufptr
[1]) << 8) | bufptr
[2]) << 8) |
970 result
= (intv
== rules
->value
.intv
);
974 case MIME_MAGIC_LOCALE
:
975 #if defined(WIN32) || defined(__EMX__) || defined(__APPLE__)
976 result
= (strcmp(rules
->value
.localev
, setlocale(LC_ALL
, "")) == 0);
978 result
= (strcmp(rules
->value
.localev
, setlocale(LC_MESSAGES
, "")) == 0);
979 #endif /* __APPLE__ */
982 case MIME_MAGIC_CONTAINS
:
984 * Load the buffer if necessary...
987 if (bufoffset
< 0 || rules
->offset
< bufoffset
||
988 (rules
->offset
+ rules
->region
) > (bufoffset
+ buflength
))
991 * Reload file buffer...
994 cupsFileSeek(fp
, rules
->offset
);
995 buflength
= cupsFileRead(fp
, (char *)buffer
, sizeof(buffer
));
996 bufoffset
= rules
->offset
;
1000 * Compare the buffer against the string. If the file is too
1001 * short then don't compare - it can't match...
1004 if ((rules
->offset
+ rules
->length
) > (bufoffset
+ buflength
))
1008 if (buflength
> rules
->region
)
1009 region
= rules
->region
- rules
->length
;
1011 region
= buflength
- rules
->length
;
1013 for (n
= 0; n
< region
; n
++)
1014 if ((result
= (memcmp(buffer
+ rules
->offset
- bufoffset
+ n
,
1015 rules
->value
.stringv
, rules
->length
) == 0)) != 0)
1021 if (rules
->child
!= NULL
)
1022 result
= checkrules(filename
, fp
, 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 now... */
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 matches
1156 * and 0 otherwise...
1159 return (*s
== *pat
);
1164 * End of "$Id: type.c 4613 2005-08-30 12:41:48Z mike $".