1 /* $NetBSD: list.c,v 1.24 2008/12/07 19:21:00 christos Exp $ */
4 * Copyright (c) 1980, 1993
5 * The Regents of the University of California. All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the University nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 #include <sys/cdefs.h>
35 static char sccsid
[] = "@(#)list.c 8.4 (Berkeley) 5/1/95";
37 __RCSID("$NetBSD: list.c,v 1.24 2008/12/07 19:21:00 christos Exp $");
52 * Mail -- a mail program
54 * Message list handling.
58 * Token values returned by the scanner used for argument lists.
59 * Also, sizes of scanner-related things.
62 TEOL
, /* End of the command line */
63 TNUMBER
, /* A message number or range of numbers */
64 TDASH
, /* A simple dash */
65 TSTRING
, /* A string (possibly containing '-') */
75 TXOR
, /* A logical '^' */
77 TERROR
/* A lexical error */
80 #define REGDEP 2 /* Maximum regret depth. */
81 #define STRINGLEN 1024 /* Maximum length of string token */
83 static int lexnumber
; /* Number of TNUMBER from scan() */
84 static char lexstring
[STRINGLEN
]; /* String from TSTRING, scan() */
85 static int regretp
; /* Pointer to TOS of regret tokens */
86 static int regretstack
[REGDEP
]; /* Stack of regretted tokens */
87 static char *string_stack
[REGDEP
]; /* Stack of regretted strings */
88 static int numberstack
[REGDEP
]; /* Stack of regretted numbers */
91 * Scan out the list of string arguments, shell style
95 getrawlist(const char line
[], char **argv
, int argc
)
100 char linebuf
[LINESIZE
];
108 if (argn
>= argc
- 1) {
110 "Too many elements in the list; excess discarded.\n");
115 while ((c
= *cp
) != '\0') {
117 if (quotec
!= '\0') {
120 else if (quotec
!= '\'' && c
== '\\')
126 case '0': case '1': case '2': case '3':
127 case '4': case '5': case '6': case '7':
129 if (*cp
>= '0' && *cp
<= '7')
130 c
= c
* 8 + *cp
++ - '0';
131 if (*cp
>= '0' && *cp
<= '7')
132 c
= c
* 8 + *cp
++ - '0';
160 /* null doesn't show up anyway */
161 else if ((c
>= 'A' && c
<= '_') ||
162 (c
>= 'a' && c
<= 'z'))
170 } else if (c
== '"' || c
== '\'')
178 argv
[argn
++] = savestr(linebuf
);
185 * Mark all messages that the user wanted from the command
186 * line in the message structure. Return 0 on success, -1
191 * Bit values for colon modifiers.
193 #define CMBOX 0x001 /* Unread messages */
194 #define CMDELETED 0x002 /* Deleted messages */
195 #define CMMODIFY 0x004 /* Unread messages */
196 #define CMNEW 0x008 /* New messages */
197 #define CMOLD 0x010 /* Old messages */
198 #define CMPRESERVE 0x020 /* Unread messages */
199 #define CMREAD 0x040 /* Read messages */
200 #define CMSAVED 0x080 /* Saved messages */
201 #define CMTAGGED 0x100 /* Tagged messages */
202 #define CMUNREAD 0x200 /* Unread messages */
203 #define CMNEGATE 0x400 /* Negate the match */
204 #define CMMASK 0x7ff /* Mask the valid bits */
207 * The following table describes the letters which can follow
208 * the colon and gives the corresponding modifier bit.
211 static const struct coltab
{
212 char co_char
; /* What to find past : */
213 int co_bit
; /* Associated modifier bit */
214 int co_mask
; /* m_status bits to mask */
215 int co_equal
; /* ... must equal this */
217 { '!', CMNEGATE
, 0, 0 },
218 { 'd', CMDELETED
, MDELETED
, MDELETED
},
219 { 'e', CMMODIFY
, MMODIFY
, MMODIFY
},
220 { 'm', CMBOX
, MBOX
, MBOX
},
221 { 'n', CMNEW
, MNEW
, MNEW
},
222 { 'o', CMOLD
, MNEW
, 0 },
223 { 'p', CMPRESERVE
, MPRESERVE
, MPRESERVE
},
224 { 'r', CMREAD
, MREAD
, MREAD
},
225 { 's', CMSAVED
, MSAVED
, MSAVED
},
226 { 't', CMTAGGED
, MTAGGED
, MTAGGED
},
227 { 'u', CMUNREAD
, MREAD
|MNEW
, 0 },
231 static int lastcolmod
;
234 ignore_message(int m_flag
, int colmod
)
237 const struct coltab
*colp
;
239 ignore_msg
= !(colmod
& CMNEGATE
);
240 colmod
&= (~CMNEGATE
& CMMASK
);
242 for (colp
= &coltab
[0]; colp
->co_char
; colp
++)
243 if (colp
->co_bit
& colmod
&&
244 (m_flag
& colp
->co_mask
) == colp
->co_equal
)
250 * Turn the character after a colon modifier into a bit
256 const struct coltab
*colp
;
260 for (colp
= &coltab
[0]; colp
->co_char
; colp
++)
261 if (colp
->co_char
== col
)
267 get_colmod(int colmod
, char *cp
)
269 if ((cp
[0] == '\0') ||
270 (cp
[0] == '!' && cp
[1] == '\0'))
271 colmod
|= lastcolmod
;
273 for (/*EMPTY*/; *cp
; cp
++) {
275 if ((colresult
= evalcol(*cp
)) == 0) {
276 (void)printf("Unknown colon modifier \"%s\"\n", lexstring
);
279 if (colresult
== CMNEGATE
)
288 syntax_error(const char *msg
)
290 (void)printf("Syntax error: %s\n", msg
);
295 * scan out a single lexical item and return its token number,
296 * updating the string pointer passed **p. Also, store the value
297 * of the number or string scanned in lexnumber or lexstring as
298 * appropriate. In any event, store the scanned `thing' in lexstring.
303 static const struct lex
{
305 enum token_e l_token
;
320 const struct lex
*lp
;
326 (void)strcpy(lexstring
, string_stack
[regretp
]);
327 lexnumber
= numberstack
[regretp
];
328 return regretstack
[regretp
--];
335 * strip away leading white space.
340 * If no characters remain, we are at end of line,
349 * If the leading character is a digit, scan
350 * the number and convert it on the fly.
351 * Return TNUMBER when done.
353 c
= (unsigned char)*cp
++;
357 lexnumber
= lexnumber
* 10 + c
- '0';
359 c
= (unsigned char)*cp
++;
367 * Check for single character tokens; return such
370 for (lp
= &singles
[0]; lp
->l_char
!= 0; lp
++)
371 if (c
== lp
->l_char
) {
379 * We've got a string! Copy all the characters
380 * of the string into lexstring, until we see
381 * a null, space, or tab.
382 * Respect quoting and quoted pairs.
392 if (c
== '\\' && (*cp
== quotec
|| *cp
== '\\'))
404 c
= '\0'; /* end of token! */
410 if (cp2
- lexstring
< STRINGLEN
- 1)
414 if (quotec
&& c
== 0) {
415 (void)fprintf(stderr
, "Missing %c\n", quotec
);
424 * Unscan the named token by pushing it onto the regret stack.
429 if (++regretp
>= REGDEP
)
430 errx(1, "Too many regrets");
431 regretstack
[regretp
] = token
;
432 lexstring
[sizeof(lexstring
) - 1] = '\0';
433 string_stack
[regretp
] = savestr(lexstring
);
434 numberstack
[regretp
] = lexnumber
;
438 * Reset all the scanner global variables.
446 #define DELIM " \t," /* list of string delimiters */
448 is_substr(const char *big
, const char *little
)
451 if ((cp
= strstr(big
, little
)) == NULL
)
454 return strchr(DELIM
, cp
[strlen(little
)]) != 0 &&
455 (cp
== big
|| strchr(DELIM
, cp
[-1]) != 0);
461 * Look for (compiled regex) pattern in a line.
464 * 0 if no match found.
468 regexcmp(void *pattern
, char *line
, size_t len
)
470 regmatch_t pmatch
[1];
487 pmatch
[0].rm_eo
= line
[len
- 1] == '\n' ? len
- 1 : len
;
489 eflags
= REG_STARTEND
;
492 switch ((rval
= regexec(preg
, line
, 0, pmp
, eflags
))) {
498 char errbuf
[LINESIZE
];
499 (void)regerror(rval
, preg
, errbuf
, sizeof(errbuf
));
500 (void)printf("regexec failed: '%s': %s\n", line
, errbuf
);
506 * Look for (string) pattern in line.
507 * Return 1 if match found.
510 substrcmp(void *pattern
, char *line
, size_t len
)
519 if (line
[len
- 1] == '\n') {
520 line
[len
- 1] = '\0';
524 cp
= salloc(len
+ 1);
525 (void)strlcpy(cp
, line
, len
+ 1);
529 return strcasestr(line
, substr
) != NULL
;
533 * Look for NULL line. Used to find non-existent fields.
534 * Return 1 if match found.
537 hasfieldcmp(void *pattern __unused
, char *line
, size_t len __unused
)
548 * Determine the compare function and its argument based on the
549 * "regex-search" variable.
552 get_cmpfn(void **pattern
, char *str
)
553 )(void *, char *, size_t)
564 if ((val
= value(ENAME_REGEX_SEARCH
)) != NULL
) {
568 if (is_substr(val
, "icase"))
570 if (is_substr(val
, "extended"))
571 cflags
|= REG_EXTENDED
;
573 * NOTE: regcomp() will fail if "nospec" and
574 * "extended" are used together.
576 if (is_substr(val
, "nospec"))
577 cflags
|= REG_NOSPEC
;
579 if ((e
= regcomp(&preg
, str
, cflags
)) != 0) {
580 char errbuf
[LINESIZE
];
581 (void)regerror(e
, &preg
, errbuf
, sizeof(errbuf
));
582 (void)printf("regcomp failed: '%s': %s\n", str
, errbuf
);
594 * Free any memory allocated by get_cmpfn()
597 free_cmparg(void *pattern
)
599 if (pattern
== &preg
)
604 * Check the message body for the pattern.
607 matchbody(int (*cmpfn
)(void *, char *, size_t),
608 void *pattern
, struct message
*mp
, char const *fieldname __unused
)
616 fieldname
= fieldname
;
619 * Get a temporary file.
625 (void)sasprintf(&tempname
, "%s/mail.RbXXXXXXXXXX", tmpdir
);
627 if ((fd
= mkstemp(tempname
)) != -1) {
628 (void)unlink(tempname
);
629 if ((fp
= Fdopen(fd
, "w+")) == NULL
)
633 warn("%s", tempname
);
639 * Pump the (decoded) message body into the temp file.
643 struct mime_info
*mip
;
646 mip
= value(ENAME_MIME_DECODE_MSG
) ? mime_decode_open(mp
)
649 retval
= mime_sendmessage(mp
, fp
, ignoreall
, NULL
, mip
);
650 mime_decode_close(mip
);
653 if (sendmessage(mp
, fp
, ignoreall
, NULL
, NULL
) == -1)
656 warn("matchbody: mesg=%d", get_msgnum(mp
));
661 * XXX - should we read the entire body into a buffer so we
662 * can search across lines?
666 while ((line
= fgetln(fp
, &len
)) != NULL
&& len
> 0) {
667 gotmatch
= cmpfn(pattern
, line
, len
);
677 * Check the "To:", "Cc:", and "Bcc" fields for the pattern.
680 matchto(int (*cmpfn
)(void *, char *, size_t),
681 void *pattern
, struct message
*mp
, char const *fieldname __unused
)
683 static const char *to_fields
[] = { "to", "cc", "bcc", 0 };
688 fieldname
= fieldname
;
691 for (to
= to_fields
; *to
; to
++) {
693 field
= hfield(*to
, mp
);
694 gotmatch
= cmpfn(pattern
, field
, 0);
702 * Check a field for the pattern.
705 matchfield(int (*cmpfn
)(void *, char *, size_t),
706 void *pattern
, struct message
*mp
, char const *fieldname
)
711 fieldname
= fieldname
;
713 field
= hfield(fieldname
, mp
);
714 return cmpfn(pattern
, field
, 0);
718 * Check the headline for the pattern.
721 matchfrom(int (*cmpfn
)(void *, char *, size_t),
722 void *pattern
, struct message
*mp
, char const *fieldname __unused
)
724 char headline
[LINESIZE
];
728 fieldname
= fieldname
;
730 (void)readline(setinput(mp
), headline
, (int)sizeof(headline
), 0);
731 field
= savestr(headline
);
732 if (strncmp(field
, "From ", 5) != 0)
735 return cmpfn(pattern
, field
+ 5, 0);
739 * Check the sender for the pattern.
742 matchsender(int (*cmpfn
)(void *, char *, size_t),
743 void *pattern
, struct message
*mp
, char const *fieldname __unused
)
748 fieldname
= fieldname
;
750 field
= nameof(mp
, 0);
751 return cmpfn(pattern
, field
, 0);
755 * Interpret 'str' and check each message (1 thru 'msgCount') for a match.
756 * The 'str' has the format: [/[[x]:]y with the following meanings:
758 * y pattern 'y' is compared against the senders address.
759 * /y pattern 'y' is compared with the subject field. If 'y' is empty,
760 * the last search 'str' is used.
761 * /:y pattern 'y' is compared with the subject field.
762 * /x:y pattern 'y' is compared with the specified header field 'x' or
763 * the message body if 'x' == "body".
765 * The last two forms require "searchheaders" to be defined.
768 match_string(int *markarray
, char *str
, int msgCount
)
772 int (*matchfn
)(int (*)(void *, char *, size_t),
773 void *, struct message
*, char const *);
774 int (*cmpfn
)(void *, char *, size_t);
776 char const *fieldname
;
779 matchfn
= matchsender
;
783 static char lastscan
[STRINGLEN
];
790 (void)strlcpy(lastscan
, str
, sizeof(lastscan
));
792 if (value(ENAME_SEARCHHEADERS
) == NULL
||
793 (cp
= strchr(str
, ':')) == NULL
) {
794 matchfn
= matchfield
;
795 fieldname
= "subject";
799 static const struct matchtbl_s
{
802 char const *fieldname
;
803 int (*matchfn
)(int (*)(void *, char *, size_t),
804 void *, struct message
*, char const *);
806 #define X(a) a, sizeof(a) - 1
807 #define X_NULL NULL, 0
808 { X(":"), "subject", matchfield
},
809 { X("body:"), NULL
, matchbody
},
810 { X("from:"), NULL
, matchfrom
},
811 { X("to:"), NULL
, matchto
},
812 { X_NULL
, NULL
, matchfield
}
816 const struct matchtbl_s
*mtp
;
819 * Check for special cases!
820 * These checks are case sensitive so the true fields
821 * can be grabbed as mentioned in the manpage.
825 for (mtp
= matchtbl
; mtp
->key
; mtp
++) {
826 if (len
== mtp
->len
&&
827 strncmp(str
, mtp
->key
, len
) == 0)
830 matchfn
= mtp
->matchfn
;
832 fieldname
= mtp
->fieldname
;
836 (void)strlcpy(p
, str
, len
);
843 cmpfn
= get_cmpfn(&cmparg
, str
);
848 for (i
= 1; i
<= msgCount
; i
++) {
851 rval
= matchfn(cmpfn
, cmparg
, mp
, fieldname
);
855 markarray
[i
- 1] = 1;
859 free_cmparg(cmparg
); /* free any memory allocated by get_cmpfn() */
866 * Return the message number corresponding to the passed meta character.
869 metamess(int meta
, int f
)
878 * First 'good' message left.
880 for (mp
= get_message(1); mp
; mp
= next_message(mp
))
881 if ((mp
->m_flag
& MDELETED
) == f
)
882 return get_msgnum(mp
);
883 (void)printf("No applicable messages\n");
888 * Last 'good message left.
890 for (mp
= get_message(get_msgCount()); mp
; mp
= prev_message(mp
))
891 if ((mp
->m_flag
& MDELETED
) == f
)
892 return get_msgnum(mp
);
893 (void)printf("No applicable messages\n");
901 (void)printf("No applicable messages\n");
905 if ((dot
->m_flag
& MDELETED
) != f
) {
906 (void)printf("%d: Inappropriate message\n", m
);
912 (void)printf("Unknown metachar (%c)\n", c
);
918 * Check the passed message number for legality and proper flags.
919 * If f is MDELETED, then either kind will do. Otherwise, the message
920 * has to be undeleted.
923 check(int mesg
, int f
)
927 if ((mp
= get_message(mesg
)) == NULL
) {
928 (void)printf("%d: Invalid message number\n", mesg
);
931 if (f
!= MDELETED
&& (mp
->m_flag
& MDELETED
) != 0) {
932 (void)printf("%d: Inappropriate message\n", mesg
);
940 markall_core(int *markarray
, char **bufp
, int f
, int level
)
947 } logic_op
; /* binary logic operation */
948 int logic_invert
; /* invert the result */
949 int *tmparray
; /* temporarly array with result */
950 int msgCount
; /* tmparray length and message count */
951 int beg
; /* first value of a range */
952 int colmod
; /* the colon-modifier for this group */
953 int got_not
; /* for syntax checking of '!' */
954 int got_one
; /* we have a message spec, valid or not */
955 int got_bin
; /* we have a pending binary operation */
962 msgCount
= get_msgCount();
963 tmparray
= csalloc((size_t)msgCount
, sizeof(*tmparray
));
970 while ((tok
= scan(bufp
)) != TEOL
) {
975 * Do some syntax checking.
990 return syntax_error("missing left operand");
994 return syntax_error("end of range missing");
999 * The main tok switch.
1004 case TERROR
: /* trapped above */
1006 assert(/*CONSTCOND*/0);
1010 if (got_one
) { /* a possible logical xor */
1012 t
= scan(bufp
); /* peek ahead */
1014 lexstring
[0] = '^'; /* restore lexstring */
1015 lexstring
[1] = '\0';
1016 if (t
!= TDASH
&& t
!= TEOL
&& t
!= TCLOSE
) {
1017 /* convert tok to TXOR and put
1018 * it back on the stack so we
1019 * can handle it consistently */
1028 lexnumber
= metamess(lexstring
[0], f
);
1029 if (lexnumber
== -1)
1033 if (check(lexnumber
, f
))
1038 if (lexnumber
< beg
) {
1039 (void)printf("invalid range: %d-%d\n", beg
, lexnumber
);
1042 for (i
= beg
; i
<= lexnumber
; i
++)
1043 tmparray
[i
- 1] = 1;
1048 beg
= lexnumber
; /* start of a range */
1055 tmparray
[beg
- 1] = 1;
1061 for (mp
= prev_message(dot
); mp
; mp
= prev_message(mp
)) {
1062 if ((mp
->m_flag
& MDELETED
) == 0)
1066 (void)printf("Referencing before 1\n");
1069 lexnumber
= get_msgnum(mp
);
1073 for (mp
= next_message(dot
); mp
; mp
= next_message(mp
)) {
1074 if ((mp
->m_flag
& MDELETED
) == 0)
1078 (void)printf("Referencing beyond EOF\n");
1081 lexnumber
= get_msgnum(mp
);
1085 if (lexstring
[0] == ':') { /* colon modifier! */
1086 colmod
= get_colmod(colmod
, lexstring
+ 1);
1092 if (match_string(tmparray
, lexstring
, msgCount
) == -1)
1098 for (i
= 1; i
<= msgCount
; i
++)
1099 tmparray
[i
- 1] = 1;
1107 if (markall_core(tmparray
, bufp
, f
, level
+ 1) == -1)
1113 return syntax_error("extra ')'");
1117 /*********************
1118 * Logical operations.
1122 logic_invert
= ! logic_invert
;
1126 * Binary operations.
1130 return syntax_error("'!' precedes '&'");
1137 return syntax_error("'!' precedes '|'");
1144 return syntax_error("'!' precedes logical '^'");
1151 * Do the logic operations.
1154 for (i
= 0; i
< msgCount
; i
++)
1155 tmparray
[i
] = ! tmparray
[i
];
1159 for (i
= 0; i
< msgCount
; i
++)
1160 markarray
[i
] &= tmparray
[i
];
1164 for (i
= 0; i
< msgCount
; i
++)
1165 markarray
[i
] |= tmparray
[i
];
1169 for (i
= 0; i
< msgCount
; i
++)
1170 markarray
[i
] ^= tmparray
[i
];
1175 * Clear the temporary array and reset the logic
1178 for (i
= 0; i
< msgCount
; i
++)
1188 return syntax_error("end of range missing");
1191 return syntax_error("missing ')'");
1195 return syntax_error("trailing '!'");
1198 return syntax_error("missing right operand");
1202 * If we have colon-modifiers but no messages
1203 * specifiec, then assume '*' was given.
1206 for (i
= 1; i
<= msgCount
; i
++)
1207 markarray
[i
- 1] = 1;
1209 for (i
= 1; i
<= msgCount
; i
++) {
1211 if ((mp
= get_message(i
)) != NULL
&&
1212 ignore_message(mp
->m_flag
, colmod
))
1213 markarray
[i
- 1] = 0;
1220 markall(char buf
[], int f
)
1228 msgCount
= get_msgCount();
1231 * Clear all the previous message marks.
1233 for (i
= 1; i
<= msgCount
; i
++)
1234 if ((mp
= get_message(i
)) != NULL
)
1235 mp
->m_flag
&= ~MMARK
;
1237 buf
= skip_WSP(buf
);
1242 markarray
= csalloc((size_t)msgCount
, sizeof(*markarray
));
1243 if (markall_core(markarray
, &buf
, f
, 0) == -1)
1247 * Transfer the markarray values to the messages.
1250 for (i
= 1; i
<= msgCount
; i
++) {
1251 if (markarray
[i
- 1] &&
1252 (mp
= get_message(i
)) != NULL
&&
1253 (f
== MDELETED
|| (mp
->m_flag
& MDELETED
) == 0)) {
1254 mp
->m_flag
|= MMARK
;
1260 (void)printf("No applicable messages.\n");
1267 * Convert the user string of message numbers and
1268 * store the numbers into vector.
1270 * Returns the count of messages picked up or -1 on error.
1273 getmsglist(char *buf
, int *vector
, int flags
)
1278 if (get_msgCount() == 0) {
1282 if (markall(buf
, flags
) < 0)
1285 for (mp
= get_message(1); mp
; mp
= next_message(mp
))
1286 if (mp
->m_flag
& MMARK
)
1287 *ip
++ = get_msgnum(mp
);
1289 return (int)(ip
- vector
);
1293 * Find the first message whose flags & m == f and return
1294 * its message number.
1301 if (get_msgCount() == 0)
1305 for (mp
= dot
; mp
; mp
= next_message(mp
))
1306 if ((mp
->m_flag
& m
) == f
)
1307 return get_msgnum(mp
);
1308 for (mp
= prev_message(dot
); mp
; mp
= prev_message(mp
))
1309 if ((mp
->m_flag
& m
) == f
)
1310 return get_msgnum(mp
);
1315 * Show all headers without paging. (-H flag)
1319 show_headers_and_exit(int flags
)
1323 /* We are exiting anyway, so use the default signal handler. */
1324 if (signal(SIGINT
, SIG_DFL
) == SIG_IGN
)
1325 (void)signal(SIGINT
, SIG_IGN
);
1328 for (mp
= get_message(1); mp
; mp
= next_message(mp
))
1329 if (flags
== 0 || !ignore_message(mp
->m_flag
, flags
))
1330 printhead(get_msgnum(mp
));
1337 * A hack so -H can have an optional modifier as -H[:flags].
1339 * This depends a bit on the internals of getopt(). In particular,
1340 * for flags expecting an argument, argv[optind-1] must contain the
1341 * optarg and optarg must point to a substring of argv[optind-1] not a
1345 get_Hflag(char **argv
)
1351 if (optarg
== NULL
) /* We had an error, just get the flags. */
1354 if (*optarg
!= ':' || optarg
== argv
[optind
- 1]) {
1357 if (optarg
!= argv
[optind
]) {
1358 static char temparg
[LINESIZE
];
1363 optlen
= strlen(optarg
);
1364 arglen
= strlen(argv
[optind
]);
1365 p
= argv
[optind
] + arglen
- optlen
;
1366 optlen
= MIN(optlen
, sizeof(temparg
) - 1);
1368 (void)memmove(temparg
+ 1, p
, optlen
+ 1);
1369 argv
[optind
] = temparg
;
1373 flags
= get_colmod(flags
, optarg
+ 1);