Ordinarily, extensions to standard utilities are bad, but I think it's 
worth considering when the flag is easily understood and provides a 
substantial benefit.  I think case insenstive matching in sed qualifies.

The diff below actually implements this behavior two different ways.  
Option 1 is to add /i to substitution patterns.  Option 2 adds -i to the 
command line.

Index: compile.c
===================================================================
RCS file: /home/tedu/cvs/src/usr.bin/sed/compile.c,v
retrieving revision 1.31
diff -u -r1.31 compile.c
--- compile.c   27 Oct 2009 23:59:43 -0000      1.31
+++ compile.c   2 Feb 2010 05:11:31 -0000
@@ -57,11 +57,13 @@
        int     lh_ref;
 } *labels[LHSZ];
 
+static char     *get_restring(char *, char **);
 static char     *compile_addr(char *, struct s_addr *);
 static char     *compile_ccl(char **, char *);
 static char     *compile_delimited(char *, char *);
 static char     *compile_flags(char *, struct s_subst *);
 static char     *compile_re(char *, regex_t **);
+static void      compile_restring(char *, regex_t **, int flags);
 static char     *compile_subst(char *, struct s_subst *);
 static char     *compile_text(void);
 static char     *compile_tr(char *, char **);
@@ -142,6 +144,7 @@
 compile_stream(struct s_command **link)
 {
        char *p;
+       char *restring;
        static char *lbuf;      /* To avoid excessive malloc calls */
        static size_t bufsize;
        struct s_command *cmd, *cmd2, *stack;
@@ -305,12 +308,14 @@
                                err(COMPILE, "substitute pattern can not be"
                                    " delimited by newline or backslash");
                        cmd->u.s = xmalloc(sizeof(struct s_subst));
-                       p = compile_re(p, &cmd->u.s->re);
+                       p = get_restring(p, &restring);
                        if (p == NULL)
                                err(COMPILE, "unterminated substitute pattern");
                        --p;
                        p = compile_subst(p, cmd->u.s);
                        p = compile_flags(p, cmd->u.s);
+                       compile_restring(restring, &cmd->u.s->re, 
cmd->u.s->ignorecase ?
+                           REG_ICASE : 0);
                        EATSPACE();
                        if (*p == ';') {
                                p++;
@@ -418,27 +423,45 @@
  * Returns a pointer to the first character after the final delimiter
  * or NULL in the case of a non terminated regular expression.  The regexp
  * pointer is set to the compiled regular expression.
- * Cflags are passed to regcomp.
  */
-static char *
-compile_re(char *p, regex_t **repp)
+static void
+compile_restring(char *re, regex_t **repp, int flags)
 {
        int eval;
+
+       *repp = xmalloc(sizeof(regex_t));
+       if ((eval = regcomp(*repp, re, flags | (Eflag ? REG_EXTENDED : 0) |
+           (iflag ? REG_ICASE : 0))) != 0)
+               err(COMPILE, "RE error: %s", strregerror(eval, *repp));
+       if (maxnsub < (*repp)->re_nsub)
+               maxnsub = (*repp)->re_nsub;
+       free(re);
+}
+
+static char *
+get_restring(char *p, char **rep)
+{
        char *re;
 
        re = xmalloc(strlen(p) + 1); /* strlen(re) <= strlen(p) */
        p = compile_delimited(p, re);
        if (p && strlen(re) == 0) {
-               *repp = NULL;
+               *rep = NULL;
                free(re);
                return (p);
        }
-       *repp = xmalloc(sizeof(regex_t));
-       if (p && (eval = regcomp(*repp, re, Eflag ? REG_EXTENDED : 0)) != 0)
-               err(COMPILE, "RE error: %s", strregerror(eval, *repp));
-       if (maxnsub < (*repp)->re_nsub)
-               maxnsub = (*repp)->re_nsub;
-       free(re);
+       *rep = re;
+       return (p);
+}
+
+
+static char *
+compile_re(char *p, regex_t **repp)
+{
+       char *re;
+
+       p = get_restring(p, &re);
+       compile_restring(re, repp, 0);
        return (p);
 }
 
@@ -549,6 +572,9 @@
                                    " substitute flags");
                        gn = 1;
                        s->n = 0;
+                       break;
+               case 'i':
+                       s->ignorecase = 1;
                        break;
                case '\0':
                case '\n':
Index: defs.h
===================================================================
RCS file: /home/tedu/cvs/src/usr.bin/sed/defs.h,v
retrieving revision 1.4
diff -u -r1.4 defs.h
--- defs.h      16 Oct 2008 16:34:32 -0000      1.4
+++ defs.h      2 Feb 2010 04:50:22 -0000
@@ -60,6 +60,7 @@
 struct s_subst {
        int n;                                  /* Occurrence to subst. */
        int p;                                  /* True if p flag */
+       int ignorecase;
        char *wfile;                            /* NULL if no wfile */
        int wfd;                                /* Cached file descriptor */
        regex_t *re;                            /* Regular expression */
Index: extern.h
===================================================================
RCS file: /home/tedu/cvs/src/usr.bin/sed/extern.h,v
retrieving revision 1.6
diff -u -r1.6 extern.h
--- extern.h    7 Aug 2009 03:30:56 -0000       1.6
+++ extern.h    2 Feb 2010 05:10:35 -0000
@@ -41,7 +41,7 @@
 extern u_long linenum;
 extern int appendnum;
 extern int lastline;
-extern int Eflag, aflag, eflag, nflag;
+extern int Eflag, aflag, eflag, iflag, nflag;
 extern char *fname;
 
 void    cfclose(struct s_command *, struct s_command *);
Index: main.c
===================================================================
RCS file: /home/tedu/cvs/src/usr.bin/sed/main.c,v
retrieving revision 1.17
diff -u -r1.17 main.c
--- main.c      27 Oct 2009 23:59:43 -0000      1.17
+++ main.c      2 Feb 2010 05:18:03 -0000
@@ -78,7 +78,7 @@
  */
 static struct s_flist *files, **fl_nextp = &files;
 
-int Eflag, aflag, eflag, nflag;
+int Eflag, aflag, eflag, iflag, nflag;
 
 /*
  * Current file and line number; line numbers restart across compilation
@@ -97,7 +97,7 @@
        int c, fflag;
 
        fflag = 0;
-       while ((c = getopt(argc, argv, "Eae:f:nru")) != -1)
+       while ((c = getopt(argc, argv, "Eae:f:inru")) != -1)
                switch (c) {
                case 'E':
                case 'r':
@@ -114,6 +114,9 @@
                        fflag = 1;
                        add_compunit(CU_FILE, optarg);
                        break;
+               case 'i':
+                       iflag = 1;
+                       break;
                case 'n':
                        nflag = 1;
                        break;
@@ -123,8 +126,8 @@
                default:
                case '?':
                        (void)fprintf(stderr,
-                           "usage: sed [-aEnru] command [file ...]\n"
-                           "       sed [-aEnru] [-e command] [-f command_file] 
[file ...]\n");
+                           "usage: sed [-aEinru] command [file ...]\n"
+                           "       sed [-aEinru] [-e command] [-f 
command_file] [file ...]\n");
                        exit(1);
                }
        argc -= optind;
Index: sed.1
===================================================================
RCS file: /home/tedu/cvs/src/usr.bin/sed/sed.1,v
retrieving revision 1.35
diff -u -r1.35 sed.1
--- sed.1       10 Jan 2010 10:53:33 -0000      1.35
+++ sed.1       2 Feb 2010 05:17:35 -0000
@@ -40,7 +40,7 @@
 .Nd stream editor
 .Sh SYNOPSIS
 .Nm sed
-.Op Fl aEnru
+.Op Fl aEinru
 .Ar command
 .Op Ar
 .Nm sed
@@ -94,6 +94,8 @@
 .Ar command_file
 to the list of commands.
 The editing commands should each be listed on a separate line.
+.It Fl i
+Perform case insensitive matching.
 .It Fl r
 An alias for
 .Fl E ,
@@ -435,6 +437,8 @@
 .It g
 Make the substitution for all non-overlapping matches of the
 regular expression, not just the first one.
+.It i
+Perform case insensitive matching.
 .It p
 Write the pattern space to standard output if a replacement was made.
 If the replacement string is identical to that which it replaces, it
@@ -529,7 +533,7 @@
 specification.
 .Pp
 The flags
-.Op Fl aEru
+.Op Fl aEiru
 are extensions to that specification.
 .Pp
 The use of newlines to separate multiple commands on the command line

Reply via email to