]>
git.ipfire.org Git - thirdparty/cups.git/blob - scheduler/type.c
2 * "$Id: type.c 7720 2008-07-11 22:46:21Z mike $"
4 * MIME typing routines for the Common UNIX Printing System (CUPS).
6 * Copyright 2007-2009 by Apple Inc.
7 * Copyright 1997-2006 by Easy Software Products, all rights reserved.
9 * These coded instructions, statements, and computer programs are the
10 * property of Apple Inc. and are protected by Federal copyright
11 * law. Distribution and use rights are outlined in the file "LICENSE.txt"
12 * which should have been included with this file. If this file is
13 * file is missing or damaged, see the license at "http://www.cups.org/".
17 * mimeAddType() - Add a MIME type to a database.
18 * mimeAddTypeRule() - Add a detection rule for a file type.
19 * mimeFileType() - Determine the type of a file.
20 * mimeType() - Lookup a file type.
21 * compare_types() - Compare two MIME super/type names.
22 * checkrules() - Check each rule in a list.
23 * patmatch() - Pattern matching...
27 * Include necessary headers...
35 #include <cups/string.h>
37 #include <cups/debug.h>
44 typedef struct _mime_filebuf_s
/**** File buffer for MIME typing ****/
46 cups_file_t
*fp
; /* File pointer */
47 int offset
, /* Offset in file */
48 length
; /* Length of buffered data */
49 unsigned char buffer
[MIME_MAX_BUFFER
];/* Buffered data */
57 static int compare_types(mime_type_t
*t0
, mime_type_t
*t1
);
58 static int checkrules(const char *filename
, _mime_filebuf_t
*fb
,
60 static int patmatch(const char *s
, const char *pat
);
68 static const char * const debug_ops
[] =
70 "NOP", /* No operation */
71 "AND", /* Logical AND of all children */
72 "OR", /* Logical OR of all children */
73 "MATCH", /* Filename match */
74 "ASCII", /* ASCII characters in range */
75 "PRINTABLE", /* Printable characters (32-255) */
76 "STRING", /* String matches */
77 "CHAR", /* Character/byte matches */
78 "SHORT", /* Short/16-bit word matches */
79 "INT", /* Integer/32-bit word matches */
80 "LOCALE", /* Current locale matches string */
81 "CONTAINS", /* File contains a string */
82 "ISTRING" /* Case-insensitive string matches */
88 * 'mimeAddType()' - Add a MIME type to a database.
91 mime_type_t
* /* O - New (or existing) MIME type */
92 mimeAddType(mime_t
*mime
, /* I - MIME database */
93 const char *super
, /* I - Super-type name */
94 const char *type
) /* I - Type name */
96 mime_type_t
*temp
; /* New MIME type */
100 * Range check input...
103 if (!mime
|| !super
|| !type
)
107 * See if the type already exists; if so, return the existing type...
110 if ((temp
= mimeType(mime
, super
, type
)) != NULL
)
114 * The type doesn't exist; add it...
118 mime
->types
= cupsArrayNew((cups_array_func_t
)compare_types
, NULL
);
123 if ((temp
= calloc(1, sizeof(mime_type_t
) - MIME_MAX_TYPE
+
124 strlen(type
) + 1)) == NULL
)
127 strlcpy(temp
->super
, super
, sizeof(temp
->super
));
128 strcpy(temp
->type
, type
); /* Safe: temp->type is allocated */
129 temp
->priority
= 100;
131 cupsArrayAdd(mime
->types
, temp
);
138 * 'mimeAddTypeRule()' - Add a detection rule for a file type.
141 int /* O - 0 on success, -1 on failure */
142 mimeAddTypeRule(mime_type_t
*mt
, /* I - Type to add to */
143 const char *rule
) /* I - Rule to add */
145 int num_values
, /* Number of values seen */
146 op
, /* Operation code */
147 logic
, /* Logic for next rule */
148 invert
; /* Invert following rule? */
149 char name
[255], /* Name in rule string */
150 value
[3][255], /* Value in rule string */
151 *ptr
, /* Position in name or value */
152 quote
; /* Quote character */
153 int length
[3]; /* Length of each parameter */
154 mime_magic_t
*temp
, /* New rule */
155 *current
; /* Current rule */
159 * Range check input...
166 * Find the last rule in the top-level of the rules tree.
169 for (current
= mt
->rules
; current
; current
= current
->next
)
174 * Parse the rules string. Most rules are either a file extension or a
175 * comparison function:
178 * function(parameters)
181 logic
= MIME_MAGIC_NOP
;
184 DEBUG_printf(("mimeAddTypeRule: %s/%s: %s", mt
->super
, mt
->type
, rule
));
186 while (*rule
!= '\0')
188 while (isspace(*rule
& 255))
193 DEBUG_puts("mimeAddTypeRule: New parenthesis group");
194 logic
= MIME_MAGIC_NOP
;
197 else if (*rule
== ')')
199 DEBUG_puts("mimeAddTypeRule: Close paren...");
200 if (current
== NULL
|| current
->parent
== NULL
)
203 current
= current
->parent
;
205 if (current
->parent
== NULL
)
206 logic
= MIME_MAGIC_OR
;
208 logic
= current
->parent
->op
;
212 else if (*rule
== '+' && current
!= NULL
)
214 if (logic
!= MIME_MAGIC_AND
&&
215 current
!= NULL
&& current
->prev
!= NULL
)
218 * OK, we have more than 1 rule in the current tree level... Make a
219 * new group tree and move the previous rule to it...
222 if ((temp
= calloc(1, sizeof(mime_magic_t
))) == NULL
)
225 temp
->op
= MIME_MAGIC_AND
;
226 temp
->child
= current
;
227 temp
->parent
= current
->parent
;
228 current
->prev
->next
= temp
;
229 temp
->prev
= current
->prev
;
231 current
->prev
= NULL
;
232 current
->parent
= temp
;
234 DEBUG_printf(("mimeAddTypeRule: Creating new AND group %p...", temp
));
236 else if (current
->parent
)
238 DEBUG_printf(("mimeAddTypeRule: Setting group %p op to AND...",
240 current
->parent
->op
= MIME_MAGIC_AND
;
243 logic
= MIME_MAGIC_AND
;
246 else if (*rule
== ',')
248 if (logic
!= MIME_MAGIC_OR
&& current
!= NULL
)
251 * OK, we have two possibilities; either this is the top-level rule or
252 * we have a bunch of AND rules at this level.
255 if (current
->parent
== NULL
)
258 * This is the top-level rule; we have to move *all* of the AND rules
259 * down a level, as AND has precedence over OR.
262 if ((temp
= calloc(1, sizeof(mime_magic_t
))) == NULL
)
265 DEBUG_printf(("mimeAddTypeRule: Creating new AND group %p inside OR "
268 while (current
->prev
!= NULL
)
270 current
->parent
= temp
;
271 current
= current
->prev
;
274 current
->parent
= temp
;
275 temp
->op
= MIME_MAGIC_AND
;
276 temp
->child
= current
;
278 mt
->rules
= current
= temp
;
283 * This isn't the top rule, so go up one level...
286 DEBUG_puts("mimeAddTypeRule: Going up one level");
287 current
= current
->parent
;
291 logic
= MIME_MAGIC_OR
;
294 else if (*rule
== '!')
296 DEBUG_puts("mimeAddTypeRule: NOT");
300 else if (isalnum(*rule
& 255))
303 * Read an extension name or a function...
307 while (isalnum(*rule
& 255) && (ptr
- name
) < (sizeof(name
) - 1))
315 * Read function parameters...
320 num_values
< (sizeof(value
) / sizeof(value
[0]));
323 ptr
= value
[num_values
];
325 while ((ptr
- value
[num_values
]) < (sizeof(value
[0]) - 1) &&
326 *rule
!= '\0' && *rule
!= ',' && *rule
!= ')')
328 if (isspace(*rule
& 255))
331 * Ignore whitespace...
337 else if (*rule
== '\"' || *rule
== '\'')
340 * Copy quoted strings literally...
345 while (*rule
!= '\0' && *rule
!= quote
&&
346 (ptr
- value
[num_values
]) < (sizeof(value
[0]) - 1))
354 else if (*rule
== '<')
358 while (*rule
!= '>' && *rule
!= '\0' &&
359 (ptr
- value
[num_values
]) < (sizeof(value
[0]) - 1))
361 if (isxdigit(rule
[0] & 255) && isxdigit(rule
[1] & 255))
364 *ptr
= (*rule
++ - '0') << 4;
366 *ptr
= (tolower(*rule
++) - 'a' + 10) << 4;
369 *ptr
++ |= *rule
++ - '0';
371 *ptr
++ |= tolower(*rule
++) - 'a' + 10;
387 length
[num_values
] = ptr
- value
[num_values
];
404 * Figure out the function...
407 if (!strcmp(name
, "match"))
408 op
= MIME_MAGIC_MATCH
;
409 else if (!strcmp(name
, "ascii"))
410 op
= MIME_MAGIC_ASCII
;
411 else if (!strcmp(name
, "printable"))
412 op
= MIME_MAGIC_PRINTABLE
;
413 else if (!strcmp(name
, "string"))
414 op
= MIME_MAGIC_STRING
;
415 else if (!strcmp(name
, "istring"))
416 op
= MIME_MAGIC_ISTRING
;
417 else if (!strcmp(name
, "char"))
418 op
= MIME_MAGIC_CHAR
;
419 else if (!strcmp(name
, "short"))
420 op
= MIME_MAGIC_SHORT
;
421 else if (!strcmp(name
, "int"))
423 else if (!strcmp(name
, "locale"))
424 op
= MIME_MAGIC_LOCALE
;
425 else if (!strcmp(name
, "contains"))
426 op
= MIME_MAGIC_CONTAINS
;
427 else if (!strcmp(name
, "priority") && num_values
== 1)
429 mt
->priority
= atoi(value
[0]);
438 * This is just a filename match on the extension...
441 snprintf(value
[0], sizeof(value
[0]), "*.%s", name
);
442 length
[0] = strlen(value
[0]);
443 op
= MIME_MAGIC_MATCH
;
447 * Add a rule for this operation.
450 if ((temp
= calloc(1, sizeof(mime_magic_t
))) == NULL
)
453 temp
->invert
= invert
;
456 temp
->parent
= current
->parent
;
457 current
->next
= temp
;
462 temp
->prev
= current
;
464 if (logic
== MIME_MAGIC_NOP
)
467 * Add parenthetical grouping...
470 DEBUG_printf(("mimeAddTypeRule: Making new OR group %p for "
471 "parenthesis...", temp
));
473 temp
->op
= MIME_MAGIC_OR
;
475 if ((temp
->child
= calloc(1, sizeof(mime_magic_t
))) == NULL
)
478 temp
->child
->parent
= temp
;
479 temp
->child
->invert
= temp
->invert
;
483 logic
= MIME_MAGIC_OR
;
486 DEBUG_printf(("mimeAddTypeRule: adding %p: %s, op=MIME_MAGIC_%s(%d), "
487 "logic=MIME_MAGIC_%s, invert=%d", temp
, name
, debug_ops
[op
],
488 op
, debug_ops
[logic
], invert
));
491 * Fill in data for the rule...
500 case MIME_MAGIC_MATCH
:
501 if (length
[0] > (sizeof(temp
->value
.matchv
) - 1))
503 strcpy(temp
->value
.matchv
, value
[0]);
505 case MIME_MAGIC_ASCII
:
506 case MIME_MAGIC_PRINTABLE
:
507 temp
->offset
= strtol(value
[0], NULL
, 0);
508 temp
->length
= strtol(value
[1], NULL
, 0);
509 if (temp
->length
> MIME_MAX_BUFFER
)
510 temp
->length
= MIME_MAX_BUFFER
;
512 case MIME_MAGIC_STRING
:
513 case MIME_MAGIC_ISTRING
:
514 temp
->offset
= strtol(value
[0], NULL
, 0);
515 if (length
[1] > sizeof(temp
->value
.stringv
))
517 temp
->length
= length
[1];
518 memcpy(temp
->value
.stringv
, value
[1], length
[1]);
520 case MIME_MAGIC_CHAR
:
521 temp
->offset
= strtol(value
[0], NULL
, 0);
523 temp
->value
.charv
= value
[1][0];
525 temp
->value
.charv
= (char)strtol(value
[1], NULL
, 0);
527 case MIME_MAGIC_SHORT
:
528 temp
->offset
= strtol(value
[0], NULL
, 0);
529 temp
->value
.shortv
= (short)strtol(value
[1], NULL
, 0);
531 case MIME_MAGIC_INT
:
532 temp
->offset
= strtol(value
[0], NULL
, 0);
533 temp
->value
.intv
= (int)strtol(value
[1], NULL
, 0);
535 case MIME_MAGIC_LOCALE
:
536 if (length
[0] > (sizeof(temp
->value
.localev
) - 1))
539 strcpy(temp
->value
.localev
, value
[0]);
541 case MIME_MAGIC_CONTAINS
:
542 temp
->offset
= strtol(value
[0], NULL
, 0);
543 temp
->region
= strtol(value
[1], NULL
, 0);
544 if (length
[2] > sizeof(temp
->value
.stringv
))
546 temp
->length
= length
[2];
547 memcpy(temp
->value
.stringv
, value
[2], length
[2]);
560 * 'mimeFileType()' - Determine the type of a file.
563 mime_type_t
* /* O - Type of file */
564 mimeFileType(mime_t
*mime
, /* I - MIME database */
565 const char *pathname
, /* I - Name of file to check on disk */
566 const char *filename
, /* I - Original filename or NULL */
567 int *compression
) /* O - Is the file compressed? */
569 _mime_filebuf_t fb
; /* File buffer */
570 const char *base
; /* Base filename of file */
571 mime_type_t
*type
, /* File type */
572 *best
; /* Best match */
575 DEBUG_printf(("mimeFileType(mime=%p, pathname=\"%s\", filename=\"%s\", "
576 "compression=%p)", mime
, pathname
, filename
, compression
));
579 * Range check input parameters...
582 if (!mime
|| !pathname
)
586 * Try to open the file...
589 if ((fb
.fp
= cupsFileOpen(pathname
, "r")) == NULL
)
596 * Figure out the base filename (without directory portion)...
601 if ((base
= strrchr(filename
, '/')) != NULL
)
606 else if ((base
= strrchr(pathname
, '/')) != NULL
)
612 * Then check it against all known types...
615 for (type
= (mime_type_t
*)cupsArrayFirst(mime
->types
), best
= NULL
;
617 type
= (mime_type_t
*)cupsArrayNext(mime
->types
))
618 if (checkrules(base
, &fb
, type
->rules
))
620 if (!best
|| type
->priority
> best
->priority
)
625 * Finally, close the file and return a match (if any)...
629 *compression
= cupsFileCompression(fb
.fp
);
631 cupsFileClose(fb
.fp
);
638 * 'mimeType()' - Lookup a file type.
641 mime_type_t
* /* O - Matching file type definition */
642 mimeType(mime_t
*mime
, /* I - MIME database */
643 const char *super
, /* I - Super-type name */
644 const char *type
) /* I - Type name */
646 mime_type_t key
; /* MIME type search key*/
650 * Range check input...
653 if (!mime
|| !super
|| !type
)
657 * Lookup the type in the array...
660 strlcpy(key
.super
, super
, sizeof(key
.super
));
661 strlcpy(key
.type
, type
, sizeof(key
.type
));
663 return ((mime_type_t
*)cupsArrayFind(mime
->types
, &key
));
668 * 'compare_types()' - Compare two MIME super/type names.
671 static int /* O - Result of comparison */
672 compare_types(mime_type_t
*t0
, /* I - First type */
673 mime_type_t
*t1
) /* I - Second type */
675 int i
; /* Result of comparison */
678 if ((i
= strcasecmp(t0
->super
, t1
->super
)) == 0)
679 i
= strcasecmp(t0
->type
, t1
->type
);
686 * 'checkrules()' - Check each rule in a list.
689 static int /* O - 1 if match, 0 if no match */
690 checkrules(const char *filename
, /* I - Filename */
691 _mime_filebuf_t
*fb
, /* I - File to check */
692 mime_magic_t
*rules
) /* I - Rules to check */
694 int n
; /* Looping var */
695 int region
; /* Region to look at */
696 int logic
, /* Logic to apply */
697 result
, /* Result of test */
698 intv
; /* Integer value */
699 short shortv
; /* Short value */
700 unsigned char *bufptr
; /* Pointer into buffer */
703 DEBUG_printf(("checkrules(filename=\"%s\", fb=%p, rules=%p)", filename
,
709 if (rules
->parent
== NULL
)
710 logic
= MIME_MAGIC_OR
;
712 logic
= rules
->parent
->op
;
716 while (rules
!= NULL
)
719 * Compute the result of this rule...
724 case MIME_MAGIC_MATCH
:
725 result
= patmatch(filename
, rules
->value
.matchv
);
728 case MIME_MAGIC_ASCII
:
730 * Load the buffer if necessary...
733 if (fb
->offset
< 0 || rules
->offset
< fb
->offset
||
734 (rules
->offset
+ rules
->length
) > (fb
->offset
+ fb
->length
))
737 * Reload file buffer...
740 cupsFileSeek(fb
->fp
, rules
->offset
);
741 fb
->length
= cupsFileRead(fb
->fp
, (char *)fb
->buffer
,
743 fb
->offset
= rules
->offset
;
747 * Test for ASCII printable characters plus standard control chars.
750 if ((rules
->offset
+ rules
->length
) > (fb
->offset
+ fb
->length
))
751 n
= fb
->offset
+ fb
->length
- rules
->offset
;
755 bufptr
= fb
->buffer
+ rules
->offset
- fb
->offset
;
757 if ((*bufptr
>= 32 && *bufptr
<= 126) ||
758 (*bufptr
>= 8 && *bufptr
<= 13) ||
759 *bufptr
== 26 || *bufptr
== 27)
770 case MIME_MAGIC_PRINTABLE
:
772 * Load the buffer if necessary...
775 if (fb
->offset
< 0 || rules
->offset
< fb
->offset
||
776 (rules
->offset
+ rules
->length
) > (fb
->offset
+ fb
->length
))
779 * Reload file buffer...
782 cupsFileSeek(fb
->fp
, rules
->offset
);
783 fb
->length
= cupsFileRead(fb
->fp
, (char *)fb
->buffer
,
785 fb
->offset
= rules
->offset
;
789 * Test for 8-bit printable characters plus standard control chars.
792 if ((rules
->offset
+ rules
->length
) > (fb
->offset
+ fb
->length
))
793 n
= fb
->offset
+ fb
->length
- rules
->offset
;
797 bufptr
= fb
->buffer
+ rules
->offset
- fb
->offset
;
800 if (*bufptr
>= 128 ||
801 (*bufptr
>= 32 && *bufptr
<= 126) ||
802 (*bufptr
>= 8 && *bufptr
<= 13) ||
803 *bufptr
== 26 || *bufptr
== 27)
814 case MIME_MAGIC_STRING
:
815 DEBUG_printf(("checkrules: string(%d, \"%s\")", rules
->offset
,
816 rules
->value
.stringv
));
819 * Load the buffer if necessary...
822 if (fb
->offset
< 0 || rules
->offset
< fb
->offset
||
823 (rules
->offset
+ rules
->length
) > (fb
->offset
+ fb
->length
))
826 * Reload file buffer...
829 cupsFileSeek(fb
->fp
, rules
->offset
);
830 fb
->length
= cupsFileRead(fb
->fp
, (char *)fb
->buffer
,
832 fb
->offset
= rules
->offset
;
834 DEBUG_printf(("checkrules: loaded %d byte fb->buffer at %d, starts "
835 "with \"%c%c%c%c\"...",
836 fb
->length
, fb
->offset
, fb
->buffer
[0], fb
->buffer
[1],
837 fb
->buffer
[2], fb
->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
) > (fb
->offset
+ fb
->length
))
848 result
= (memcmp(fb
->buffer
+ rules
->offset
- fb
->offset
,
849 rules
->value
.stringv
, rules
->length
) == 0);
850 DEBUG_printf(("checkrules: result=%d", result
));
853 case MIME_MAGIC_ISTRING
:
855 * Load the buffer if necessary...
858 if (fb
->offset
< 0 || rules
->offset
< fb
->offset
||
859 (rules
->offset
+ rules
->length
) > (fb
->offset
+ fb
->length
))
862 * Reload file buffer...
865 cupsFileSeek(fb
->fp
, rules
->offset
);
866 fb
->length
= cupsFileRead(fb
->fp
, (char *)fb
->buffer
,
868 fb
->offset
= rules
->offset
;
872 * Compare the buffer against the string. If the file is too
873 * short then don't compare - it can't match...
876 if ((rules
->offset
+ rules
->length
) > (fb
->offset
+ fb
->length
))
879 result
= (strncasecmp((char *)fb
->buffer
+ rules
->offset
-
881 rules
->value
.stringv
, rules
->length
) == 0);
884 case MIME_MAGIC_CHAR
:
886 * Load the buffer if necessary...
889 if (fb
->offset
< 0 || rules
->offset
< fb
->offset
)
892 * Reload file buffer...
895 cupsFileSeek(fb
->fp
, rules
->offset
);
896 fb
->length
= cupsFileRead(fb
->fp
, (char *)fb
->buffer
,
898 fb
->offset
= rules
->offset
;
902 * Compare the character values; if the file is too short, it
909 result
= (fb
->buffer
[rules
->offset
- fb
->offset
] ==
913 case MIME_MAGIC_SHORT
:
915 * Load the buffer if necessary...
918 if (fb
->offset
< 0 || rules
->offset
< fb
->offset
||
919 (rules
->offset
+ 2) > (fb
->offset
+ fb
->length
))
922 * Reload file buffer...
925 cupsFileSeek(fb
->fp
, rules
->offset
);
926 fb
->length
= cupsFileRead(fb
->fp
, (char *)fb
->buffer
,
928 fb
->offset
= rules
->offset
;
932 * Compare the short values; if the file is too short, it
940 bufptr
= fb
->buffer
+ rules
->offset
- fb
->offset
;
941 shortv
= (bufptr
[0] << 8) | bufptr
[1];
942 result
= (shortv
== rules
->value
.shortv
);
946 case MIME_MAGIC_INT
:
948 * Load the buffer if necessary...
951 if (fb
->offset
< 0 || rules
->offset
< fb
->offset
||
952 (rules
->offset
+ 4) > (fb
->offset
+ fb
->length
))
955 * Reload file buffer...
958 cupsFileSeek(fb
->fp
, rules
->offset
);
959 fb
->length
= cupsFileRead(fb
->fp
, (char *)fb
->buffer
,
961 fb
->offset
= rules
->offset
;
965 * Compare the int values; if the file is too short, it
973 bufptr
= fb
->buffer
+ rules
->offset
- fb
->offset
;
974 intv
= (((((bufptr
[0] << 8) | bufptr
[1]) << 8) |
975 bufptr
[2]) << 8) | bufptr
[3];
976 result
= (intv
== rules
->value
.intv
);
980 case MIME_MAGIC_LOCALE
:
981 #if defined(WIN32) || defined(__EMX__) || defined(__APPLE__)
982 result
= (strcmp(rules
->value
.localev
,
983 setlocale(LC_ALL
, "")) == 0);
985 result
= (strcmp(rules
->value
.localev
,
986 setlocale(LC_MESSAGES
, "")) == 0);
987 #endif /* __APPLE__ */
990 case MIME_MAGIC_CONTAINS
:
992 * Load the buffer if necessary...
995 if (fb
->offset
< 0 || rules
->offset
< fb
->offset
||
996 (rules
->offset
+ rules
->region
) > (fb
->offset
+ fb
->length
))
999 * Reload file buffer...
1002 cupsFileSeek(fb
->fp
, rules
->offset
);
1003 fb
->length
= cupsFileRead(fb
->fp
, (char *)fb
->buffer
,
1004 sizeof(fb
->buffer
));
1005 fb
->offset
= rules
->offset
;
1009 * Compare the buffer against the string. If the file is too
1010 * short then don't compare - it can't match...
1013 if ((rules
->offset
+ rules
->length
) > (fb
->offset
+ fb
->length
))
1017 if (fb
->length
> rules
->region
)
1018 region
= rules
->region
- rules
->length
;
1020 region
= fb
->length
- rules
->length
;
1022 for (n
= 0; n
< region
; n
++)
1023 if ((result
= (memcmp(fb
->buffer
+ rules
->offset
- fb
->offset
+ n
,
1024 rules
->value
.stringv
,
1025 rules
->length
) == 0)) != 0)
1031 if (rules
->child
!= NULL
)
1032 result
= checkrules(filename
, fb
, rules
->child
);
1039 * If the logic is inverted, invert the result...
1046 * OK, now if the current logic is OR and this result is true, the this
1047 * rule set is true. If the current logic is AND and this result is false,
1048 * the the rule set is false...
1051 DEBUG_printf(("checkrules: result of test %p (MIME_MAGIC_%s) is %d",
1052 rules
, debug_ops
[rules
->op
], result
));
1054 if ((result
&& logic
== MIME_MAGIC_OR
) ||
1055 (!result
&& logic
== MIME_MAGIC_AND
))
1059 * Otherwise the jury is still out on this one, so move to the next rule.
1062 rules
= rules
->next
;
1070 * 'patmatch()' - Pattern matching...
1073 static int /* O - 1 if match, 0 if no match */
1074 patmatch(const char *s
, /* I - String to match against */
1075 const char *pat
) /* I - Pattern to match against */
1078 * Range check the input...
1081 if (s
== NULL
|| pat
== NULL
)
1085 * Loop through the pattern and match strings, and stop if we come to a
1086 * point where the strings don't match or we find a complete match.
1089 while (*s
!= '\0' && *pat
!= '\0')
1094 * Wildcard - 0 or more characters...
1099 return (1); /* Last pattern char is *, so everything matches... */
1102 * Test all remaining combinations until we get to the end of the string.
1107 if (patmatch(s
, pat
))
1113 else if (*pat
== '?')
1116 * Wildcard - 1 character...
1123 else if (*pat
== '[')
1126 * Match a character from the input set [chars]...
1130 while (*pat
!= ']' && *pat
!= '\0')
1136 if (*pat
== ']' || *pat
== '\0')
1139 while (*pat
!= ']' && *pat
!= '\0')
1147 else if (*pat
== '\\')
1150 * Handle quoted characters...
1157 * Stop if the pattern and string don't match...
1165 * Done parsing the pattern and string; return 1 if the last character
1166 * matches and 0 otherwise...
1169 return (*s
== *pat
);
1174 * End of "$Id: type.c 7720 2008-07-11 22:46:21Z mike $".