Changeset 1770 in MondoRescue for branches/stable/mindi-busybox/editors/sed.c


Ignore:
Timestamp:
Nov 6, 2007, 11:01:53 AM (16 years ago)
Author:
Bruno Cornec
Message:
  • Better output for mindi-busybox revision
  • Remove dummy file created on NFS - report from Arnaud Tiger <arnaud.tiger_at_hp.com>
  • strace useful for debug
  • fix new versions for pb (2.0.0 for mindi and 1.7.2 for mindi-busybox)
  • fix build process for mindi-busybox + options used in that version (dd for label-partitions-as-necessary)
  • fix typo in label-partitions-as-necessary which doesn't seem to work
  • Update to busybox 1.7.2
  • perl is now required at restore time to support uuid swap partitions (and will be used for many other thigs

in the future for sure)

  • next mindi version will be 2.0.0 due to all the changes made in it (udev may break working distros)
  • small optimization in mindi on keyboard handling (one single find instead of multiple)
  • better interaction for USB device when launching mindi manually
  • attempt to automatically guess block disk size for ramdisk
  • fix typos in bkphw
  • Fix the remaining problem with UUID support for swap partitions
  • Updates mondoarchive man page for USB support
  • Adds preliminary Hardware support to mindi (Proliant SSSTK)
  • Tries to add udev support also for rhel4
  • Fix UUID support which was still broken.
  • Be conservative in test for the start-nfs script
  • Update config file for mindi-busybox for 1.7.2 migration
  • Try to run around a busybox bug (1.2.2 pb on inexistant links)
  • Add build content for mindi-busybox in pb
  • Remove distributions content for mindi-busybox
  • Fix a warning on inexistant raidtab
  • Solve problem on tmpfs in restore init (Problem of inexistant symlink and busybox)
  • Create MONDO_CACHE and use it everywhere + creation at start
  • Really never try to eject a USB device
  • Fix a issue with &> usage (replaced with 1> and 2>)
  • Adds magic file to depllist in order to have file working + ldd which helps for debugging issues
  • tty modes correct to avoid sh error messages
  • Use ext3 normally and not ext2 instead
  • USB device should be corrected after reading (take 1st part)
  • Adds a mount_USB_here function derived from mount_CDROM_here
  • usb detection place before /dev detection in device name at restore time
  • Fix when restoring from USB: media is asked in interactive mode
  • Adds USB support for mondorestore
  • mount_cdrom => mount_media
  • elilo.efi is now searched throughout /boot/efi and not in a fixed place as there is no standard
  • untar-and-softlink => untar (+ interface change)
  • suppress useless softlinks creation/removal in boot process
  • avoids udevd messages on groups
  • Increase # of disks to 99 as in mindi at restore time (should be a conf file parameter)
  • skip existing big file creation
  • seems to work correctly for USB mindi boot
  • Adds group and tty link to udev conf
  • Always load usb-torage (even 2.6) to initiate USB bus discovery
  • Better printing of messages
  • Attempt to fix a bug in supporting OpenSusE 10.3 kernel for initramfs (mindi may now use multiple regex for kernel initrd detection)
  • Links were not correctly done as non relative for modules in mindi
  • exclusion of modules denied now works
  • Also create modules in their ordinary place, so that classical modprobe works + copy modules.dep
  • Fix bugs for DENY_MODS handling
  • Add device /dev/console for udev
  • ide-generic should now really be excluded
  • Fix a bug in major number for tty
  • If udev then adds modprobe/insmod to rootfs
  • tty0 is also cretaed with udev
  • ide-generic put rather in DENY_MODS
  • udevd remove from deplist s handled in mindi directly
  • better default for mindi when using --usb
  • Handles dynamically linked busybox (in case we want to use it soon ;-)
  • Adds fixed devices to create for udev
  • ide-generic should not be part of the initrd when using libata v2
  • support a dynamically linked udev (case on Ubuntu 7.10 and Mandriva 2008.0 so should be quite generic) This will give incitation to move to dyn. linked binaries in the initrd which will help for other tasks (ia6 4)
  • Improvement in udev support (do not use cl options not available in busybox)
  • Udev in mindi
    • auto creation of the right links at boot time with udev-links.conf(from Mandriva 2008.0)
    • rework startup of udev as current makes kernel crash (from Mandriva 2008.0)
    • add support for 64 bits udev
  • Try to render MyInsmod silent at boot time
  • Adds udev support (mandatory for newest distributions to avoid remapping of devices in a different way as on the original system)
  • We also need vaft format support for USB boot
  • Adds libusual support (Ubuntu 7.10 needs it for USB)
  • Improve Ubuntu/Debian keyboard detection and support
  • pbinit adapted to new pb (0.8.10). Filtering of docs done in it
  • Suppress some mondo warnings and errors on USB again
  • Tries to fix lack of files in deb mindi package
  • Verify should now work for USB devices
  • More log/mesages improvement for USB support
  • - Supress g_erase_tmpdir_and_scratchdir
  • Improve some log messages for USB support
  • Try to improve install in mindi to avoid issues with isolinux.cfg not installed vene if in the pkg :-(
  • Improve mindi-busybox build
  • In conformity with pb 0.8.9
  • Add support for Ubuntu 7.10 in build process
  • Add USB Key button to Menu UI (CD streamer removed)
  • Attempt to fix error messages on tmp/scratch files at the end by removing those dir at the latest possible.
  • Fix a bug linked to the size of the -E param which could be used (Arnaud Tiger/René Ribaud).
  • Integrate ~/.pbrc content into mondorescue.pb (required project-builder >= 0.8.7)
  • Put mondorescue in conformity with new pb filtering rules
  • Add USB support at restore time (no test done yet). New start-usb script PB varibale added where useful
  • Unmounting USB device before removal of temporary scratchdir
  • Stil refining USB copy back to mondo (one command was not executed)
  • No need to have the image subdor in the csratchdir when USB.
  • umount the USB partition before attempting to use it
  • Remove useless copy from mindi to mondo at end of USB handling

(risky merge, we are raising the limits of 2 diverging branches. The status of stable is not completely sure as such. Will need lots of tests, but it's not yet done :-()
(merge -r1692:1769 $SVN_M/branches/2.2.5)

File:
1 edited

Legend:

Unmodified
Added
Removed
  • branches/stable/mindi-busybox/editors/sed.c

    r902 r1770  
    1111 * MAINTAINER: Rob Landley <rob@landley.net>
    1212 *
    13  * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
     13 * Licensed under GPL version 2, see file LICENSE in this tarball for details.
    1414 */
    1515
     
    2222  the command line).  It calls get_address() and parse_cmd_args().  The
    2323  resulting sed_cmd_t structures are appended to a linked list
    24   (bbg.sed_cmd_head/bbg.sed_cmd_tail).
     24  (G.sed_cmd_head/G.sed_cmd_tail).
    2525
    2626  add_input_file() adds a FILE * to the list of input files.  We need to
     
    5959*/
    6060
    61 #include "busybox.h"
     61#include "libbb.h"
    6262#include "xregex.h"
    6363
    6464/* Each sed command turns into one of these structures. */
    6565typedef struct sed_cmd_s {
    66     /* Ordered by alignment requirements: currently 36 bytes on x86 */
    67 
    68     /* address storage */
    69     regex_t *beg_match; /* sed -e '/match/cmd' */
    70     regex_t *end_match; /* sed -e '/match/,/end_match/cmd' */
    71     regex_t *sub_match; /* For 's/sub_match/string/' */
    72     int beg_line;       /* 'sed 1p'   0 == apply commands to all lines */
    73     int end_line;       /* 'sed 1,3p' 0 == one line only. -1 = last line ($) */
    74 
    75     FILE *file;         /* File (sw) command writes to, -1 for none. */
    76     char *string;       /* Data string for (saicytb) commands. */
    77 
    78     unsigned short which_match;     /* (s) Which match to replace (0 for all) */
    79 
    80     /* Bitfields (gcc won't group them if we don't) */
    81     unsigned int invert:1;          /* the '!' after the address */
    82     unsigned int in_match:1;        /* Next line also included in match? */
    83     unsigned int no_newline:1;      /* Last line written by (sw) had no '\n' */
    84     unsigned int sub_p:1;           /* (s) print option */
    85 
    86     /* GENERAL FIELDS */
    87     char cmd;               /* The command char: abcdDgGhHilnNpPqrstwxy:={} */
    88     struct sed_cmd_s *next; /* Next command (linked list, NULL terminated) */
     66    /* Ordered by alignment requirements: currently 36 bytes on x86 */
     67    struct sed_cmd_s *next; /* Next command (linked list, NULL terminated) */
     68
     69    /* address storage */
     70    regex_t *beg_match;     /* sed -e '/match/cmd' */
     71    regex_t *end_match;     /* sed -e '/match/,/end_match/cmd' */
     72    regex_t *sub_match;     /* For 's/sub_match/string/' */
     73    int beg_line;           /* 'sed 1p'   0 == apply commands to all lines */
     74    int end_line;           /* 'sed 1,3p' 0 == one line only. -1 = last line ($) */
     75
     76    FILE *sw_file;          /* File (sw) command writes to, -1 for none. */
     77    char *string;           /* Data string for (saicytb) commands. */
     78
     79    unsigned short which_match; /* (s) Which match to replace (0 for all) */
     80
     81    /* Bitfields (gcc won't group them if we don't) */
     82    unsigned invert:1;      /* the '!' after the address */
     83    unsigned in_match:1;    /* Next line also included in match? */
     84    unsigned sub_p:1;       /* (s) print option */
     85
     86    char sw_last_char;      /* Last line written by (sw) had no '\n' */
     87
     88    /* GENERAL FIELDS */
     89    char cmd;               /* The command char: abcdDgGhHilnNpPqrstwxy:={} */
    8990} sed_cmd_t;
    9091
    91 static const char *const semicolon_whitespace = "; \n\r\t\v";
    92 
    93 struct sed_globals
    94 {
     92static const char semicolon_whitespace[] ALIGN1 = "; \n\r\t\v";
     93
     94struct globals {
    9595    /* options */
    96     int be_quiet, in_place, regex_type;
     96    int be_quiet, regex_type;
    9797    FILE *nonstdout;
    9898    char *outname, *hold_space;
    9999
    100100    /* List of input files */
    101     int input_file_count,current_input_file;
     101    int input_file_count, current_input_file;
    102102    FILE **input_file_list;
    103103
    104104    regmatch_t regmatch[10];
    105105    regex_t *previous_regex_ptr;
    106    
     106
    107107    /* linked list of sed commands */
    108108    sed_cmd_t sed_cmd_head, *sed_cmd_tail;
     
    118118        int len;    /* Space allocated */
    119119    } pipeline;
    120 } bbg;
    121 
    122 
    123 void sed_free_and_close_stuff(void);
     120};
     121#define G (*(struct globals*)&bb_common_bufsiz1)
     122void BUG_sed_globals_too_big(void);
     123#define INIT_G() do { \
     124    if (sizeof(struct globals) > COMMON_BUFSIZE) \
     125        BUG_sed_globals_too_big(); \
     126    G.sed_cmd_tail = &G.sed_cmd_head; \
     127} while (0)
     128
     129
    124130#if ENABLE_FEATURE_CLEAN_UP
    125 void sed_free_and_close_stuff(void)
    126 {
    127     sed_cmd_t *sed_cmd = bbg.sed_cmd_head.next;
    128 
    129     llist_free(bbg.append_head, free);
     131static void sed_free_and_close_stuff(void)
     132{
     133    sed_cmd_t *sed_cmd = G.sed_cmd_head.next;
     134
     135    llist_free(G.append_head, free);
    130136
    131137    while (sed_cmd) {
    132138        sed_cmd_t *sed_cmd_next = sed_cmd->next;
    133139
    134         if(sed_cmd->file)
    135             bb_xprint_and_close_file(sed_cmd->file);
     140        if (sed_cmd->sw_file)
     141            xprint_and_close_file(sed_cmd->sw_file);
    136142
    137143        if (sed_cmd->beg_match) {
     
    152158    }
    153159
    154     if(bbg.hold_space) free(bbg.hold_space);
    155 
    156     while(bbg.current_input_file<bbg.input_file_count)
    157         fclose(bbg.input_file_list[bbg.current_input_file++]);
    158 }
     160    if (G.hold_space) free(G.hold_space);
     161
     162    while (G.current_input_file < G.input_file_count)
     163        fclose(G.input_file_list[G.current_input_file++]);
     164}
     165#else
     166void sed_free_and_close_stuff(void);
    159167#endif
    160168
     
    163171static void cleanup_outname(void)
    164172{
    165   if(bbg.outname) unlink(bbg.outname);
     173    if (G.outname) unlink(G.outname);
    166174}
    167175
    168176/* strdup, replacing "\n" with '\n', and "\delimiter" with 'delimiter' */
    169177
    170 static void parse_escapes(char *dest, char *string, int len, char from, char to)
    171 {
    172     int i=0;
    173 
    174     while(i<len) {
    175         if(string[i] == '\\') {
    176             if(!to || string[i+1] == from) {
    177                 *(dest++) = to ? to : string[i+1];
    178                 i+=2;
     178static void parse_escapes(char *dest, const char *string, int len, char from, char to)
     179{
     180    int i = 0;
     181
     182    while (i < len) {
     183        if (string[i] == '\\') {
     184            if (!to || string[i+1] == from) {
     185                *dest++ = to ? to : string[i+1];
     186                i += 2;
    179187                continue;
    180             } else *(dest++)=string[i++];
    181         }
    182         *(dest++) = string[i++];
    183     }
    184     *dest=0;
    185 }
    186 
    187 static char *copy_parsing_escapes(char *string, int len)
    188 {
    189     char *dest=xmalloc(len+1);
    190 
    191     parse_escapes(dest,string,len,'n','\n');
     188            }
     189            *dest++ = string[i++];
     190        }
     191        *dest++ = string[i++];
     192    }
     193    *dest = 0;
     194}
     195
     196static char *copy_parsing_escapes(const char *string, int len)
     197{
     198    char *dest = xmalloc(len + 1);
     199
     200    parse_escapes(dest, string, len, 'n', '\n');
    192201    return dest;
    193202}
     
    200209 * a backslash ('\').  A negative delimiter disables square bracket checking.
    201210 */
    202 static int index_of_next_unescaped_regexp_delim(int delimiter, char *str)
     211static int index_of_next_unescaped_regexp_delim(int delimiter, const char *str)
    203212{
    204213    int bracket = -1;
     
    209218    if (delimiter < 0) {
    210219        bracket--;
    211         delimiter *= -1;
     220        delimiter = -delimiter;
    212221    }
    213222
     
    228237
    229238    /* if we make it to here, we've hit the end of the string */
    230     bb_error_msg_and_die("unmatched '%c'",delimiter);
     239    bb_error_msg_and_die("unmatched '%c'", delimiter);
    231240}
    232241
     
    234243 *  Returns the index of the third delimiter
    235244 */
    236 static int parse_regex_delim(char *cmdstr, char **match, char **replace)
    237 {
    238     char *cmdstr_ptr = cmdstr;
     245static int parse_regex_delim(const char *cmdstr, char **match, char **replace)
     246{
     247    const char *cmdstr_ptr = cmdstr;
    239248    char delimiter;
    240249    int idx = 0;
     
    244253    if (*cmdstr == '\0')
    245254        bb_error_msg_and_die("bad format in substitution expression");
    246     delimiter = *(cmdstr_ptr++);
     255    delimiter = *cmdstr_ptr++;
    247256
    248257    /* save the match string */
     
    261270 * returns the index in the string just past where the address ends.
    262271 */
    263 static int get_address(char *my_str, int *linenum, regex_t ** regex)
    264 {
    265     char *pos = my_str;
     272static int get_address(const char *my_str, int *linenum, regex_t ** regex)
     273{
     274    const char *pos = my_str;
    266275
    267276    if (isdigit(*my_str)) {
    268         *linenum = strtol(my_str, &pos, 10);
     277        *linenum = strtol(my_str, (char**)&pos, 10);
    269278        /* endstr shouldnt ever equal NULL */
    270279    } else if (*my_str == '$') {
     
    276285        char *temp;
    277286
    278         if (*my_str == '\\') delimiter = *(++pos);
    279         else delimiter = '/';
     287        delimiter = '/';
     288        if (*my_str == '\\') delimiter = *++pos;
    280289        next = index_of_next_unescaped_regexp_delim(delimiter, ++pos);
    281         temp = copy_parsing_escapes(pos,next);
    282         *regex = (regex_t *) xmalloc(sizeof(regex_t));
    283         xregcomp(*regex, temp, bbg.regex_type|REG_NEWLINE);
     290        temp = copy_parsing_escapes(pos, next);
     291        *regex = xmalloc(sizeof(regex_t));
     292        xregcomp(*regex, temp, G.regex_type|REG_NEWLINE);
    284293        free(temp);
    285294        /* Move position to next character after last delimiter */
     
    290299
    291300/* Grab a filename.  Whitespace at start is skipped, then goes to EOL. */
    292 static int parse_file_cmd(sed_cmd_t *sed_cmd, char *filecmdstr, char **retval)
    293 {
    294     int start = 0, idx, hack=0;
     301static int parse_file_cmd(sed_cmd_t *sed_cmd, const char *filecmdstr, char **retval)
     302{
     303    int start = 0, idx, hack = 0;
    295304
    296305    /* Skip whitespace, then grab filename to end of line */
    297     while (isspace(filecmdstr[start])) start++;
    298     idx=start;
    299     while(filecmdstr[idx] && filecmdstr[idx]!='\n') idx++;
     306    while (isspace(filecmdstr[start]))
     307        start++;
     308    idx = start;
     309    while (filecmdstr[idx] && filecmdstr[idx] != '\n')
     310        idx++;
     311
    300312    /* If lines glued together, put backslash back. */
    301     if(filecmdstr[idx]=='\n') hack=1;
    302     if(idx==start) bb_error_msg_and_die("Empty filename");
    303     *retval = bb_xstrndup(filecmdstr+start, idx-start+hack+1);
    304     if(hack) *(idx+*retval)='\\';
     313    if (filecmdstr[idx] == '\n')
     314        hack = 1;
     315    if (idx == start)
     316        bb_error_msg_and_die("empty filename");
     317    *retval = xstrndup(filecmdstr+start, idx-start+hack+1);
     318    if (hack)
     319        (*retval)[idx] = '\\';
    305320
    306321    return idx;
    307322}
    308323
    309 static int parse_subst_cmd(sed_cmd_t *sed_cmd, char *substr)
    310 {
    311     int cflags = bbg.regex_type;
     324static int parse_subst_cmd(sed_cmd_t *sed_cmd, const char *substr)
     325{
     326    int cflags = G.regex_type;
    312327    char *match;
    313     int idx = 0;
     328    int idx;
    314329
    315330    /*
     
    328343    /* process the flags */
    329344
    330     sed_cmd->which_match=1;
     345    sed_cmd->which_match = 1;
    331346    while (substr[++idx]) {
    332347        /* Parse match number */
    333         if(isdigit(substr[idx])) {
    334             if(match[0]!='^') {
     348        if (isdigit(substr[idx])) {
     349            if (match[0] != '^') {
    335350                /* Match 0 treated as all, multiple matches we take the last one. */
    336                 char *pos=substr+idx;
    337                 sed_cmd->which_match=(unsigned short)strtol(substr+idx,&pos,10);
    338                 idx=pos-substr;
     351                const char *pos = substr + idx;
     352/* FIXME: error check? */
     353                sed_cmd->which_match = (unsigned short)strtol(substr+idx, (char**) &pos, 10);
     354                idx = pos - substr;
    339355            }
    340356            continue;
    341357        }
    342358        /* Skip spaces */
    343         if(isspace(substr[idx])) continue;
     359        if (isspace(substr[idx])) continue;
    344360
    345361        switch (substr[idx]) {
    346             /* Replace all occurrences */
    347             case 'g':
    348                 if (match[0] != '^') sed_cmd->which_match = 0;
    349                 break;
    350             /* Print pattern space */
    351             case 'p':
    352                 sed_cmd->sub_p = 1;
    353                 break;
    354             /* Write to file */
    355             case 'w':
    356             {
    357                 char *temp;
    358                 idx+=parse_file_cmd(sed_cmd,substr+idx,&temp);
    359 
    360                 break;
    361             }
    362             /* Ignore case (gnu exension) */
    363             case 'I':
    364                 cflags |= REG_ICASE;
    365                 break;
    366             /* Comment */
    367             case '#':
    368                 while(substr[++idx]);
    369                 /* Fall through */
    370             /* End of command */
    371             case ';':
    372             case '}':
    373                 goto out;
    374             default:
    375                 bb_error_msg_and_die("bad option in substitution expression");
     362        /* Replace all occurrences */
     363        case 'g':
     364            if (match[0] != '^') sed_cmd->which_match = 0;
     365            break;
     366        /* Print pattern space */
     367        case 'p':
     368            sed_cmd->sub_p = 1;
     369            break;
     370        /* Write to file */
     371        case 'w':
     372        {
     373            char *temp;
     374            idx += parse_file_cmd(sed_cmd, substr+idx, &temp);
     375            break;
     376        }
     377        /* Ignore case (gnu exension) */
     378        case 'I':
     379            cflags |= REG_ICASE;
     380            break;
     381        /* Comment */
     382        case '#':
     383            while (substr[++idx]) /*skip all*/;
     384            /* Fall through */
     385        /* End of command */
     386        case ';':
     387        case '}':
     388            goto out;
     389        default:
     390            bb_error_msg_and_die("bad option in substitution expression");
    376391        }
    377392    }
     
    380395    if (*match != '\0') {
    381396        /* If match is empty, we use last regex used at runtime */
    382         sed_cmd->sub_match = (regex_t *) xmalloc(sizeof(regex_t));
     397        sed_cmd->sub_match = xmalloc(sizeof(regex_t));
    383398        xregcomp(sed_cmd->sub_match, match, cflags);
    384399    }
     
    391406 *  Process the commands arguments
    392407 */
    393 static char *parse_cmd_args(sed_cmd_t *sed_cmd, char *cmdstr)
     408static const char *parse_cmd_args(sed_cmd_t *sed_cmd, const char *cmdstr)
    394409{
    395410    /* handle (s)ubstitution command */
    396     if (sed_cmd->cmd == 's') cmdstr += parse_subst_cmd(sed_cmd, cmdstr);
     411    if (sed_cmd->cmd == 's')
     412        cmdstr += parse_subst_cmd(sed_cmd, cmdstr);
    397413    /* handle edit cmds: (a)ppend, (i)nsert, and (c)hange */
    398414    else if (strchr("aic", sed_cmd->cmd)) {
     
    400416            bb_error_msg_and_die
    401417                ("only a beginning address can be specified for edit commands");
    402         for(;;) {
    403             if(*cmdstr=='\n' || *cmdstr=='\\') {
     418        for (;;) {
     419            if (*cmdstr == '\n' || *cmdstr == '\\') {
    404420                cmdstr++;
    405421                break;
    406             } else if(isspace(*cmdstr)) cmdstr++;
    407             else break;
    408         }
    409         sed_cmd->string = bb_xstrdup(cmdstr);
    410         parse_escapes(sed_cmd->string,sed_cmd->string,strlen(cmdstr),0,0);
     422            } else if (isspace(*cmdstr))
     423                cmdstr++;
     424            else
     425                break;
     426        }
     427        sed_cmd->string = xstrdup(cmdstr);
     428        parse_escapes(sed_cmd->string, sed_cmd->string, strlen(cmdstr), 0, 0);
    411429        cmdstr += strlen(cmdstr);
    412430    /* handle file cmds: (r)ead */
    413     } else if(strchr("rw", sed_cmd->cmd)) {
     431    } else if (strchr("rw", sed_cmd->cmd)) {
    414432        if (sed_cmd->end_line || sed_cmd->end_match)
    415             bb_error_msg_and_die("Command only uses one address");
     433            bb_error_msg_and_die("command only uses one address");
    416434        cmdstr += parse_file_cmd(sed_cmd, cmdstr, &sed_cmd->string);
    417         if(sed_cmd->cmd=='w')
    418             sed_cmd->file=bb_xfopen(sed_cmd->string,"w");
     435        if (sed_cmd->cmd == 'w') {
     436            sed_cmd->sw_file = xfopen(sed_cmd->string, "w");
     437            sed_cmd->sw_last_char = '\n';
     438        }
    419439    /* handle branch commands */
    420440    } else if (strchr(":btT", sed_cmd->cmd)) {
    421441        int length;
    422442
    423         while(isspace(*cmdstr)) cmdstr++;
     443        cmdstr = skip_whitespace(cmdstr);
    424444        length = strcspn(cmdstr, semicolon_whitespace);
    425445        if (length) {
    426             sed_cmd->string = bb_xstrndup(cmdstr, length);
     446            sed_cmd->string = xstrndup(cmdstr, length);
    427447            cmdstr += length;
    428448        }
     
    431451    else if (sed_cmd->cmd == 'y') {
    432452        char *match, *replace;
    433         int i=cmdstr[0];
    434 
    435         cmdstr+=parse_regex_delim(cmdstr, &match, &replace)+1;
     453        int i = cmdstr[0];
     454
     455        cmdstr += parse_regex_delim(cmdstr, &match, &replace)+1;
    436456        /* \n already parsed, but \delimiter needs unescaping. */
    437         parse_escapes(match,match,strlen(match),i,i);
    438         parse_escapes(replace,replace,strlen(replace),i,i);
     457        parse_escapes(match, match, strlen(match), i, i);
     458        parse_escapes(replace, replace, strlen(replace), i, i);
    439459
    440460        sed_cmd->string = xzalloc((strlen(match) + 1) * 2);
    441461        for (i = 0; match[i] && replace[i]; i++) {
    442             sed_cmd->string[i * 2] = match[i];
    443             sed_cmd->string[(i * 2) + 1] = replace[i];
     462            sed_cmd->string[i*2] = match[i];
     463            sed_cmd->string[i*2+1] = replace[i];
    444464        }
    445465        free(match);
     
    450470     */
    451471    else if (strchr("dDgGhHlnNpPqx={}", sed_cmd->cmd) == 0) {
    452         bb_error_msg_and_die("Unsupported command %c", sed_cmd->cmd);
     472        bb_error_msg_and_die("unsupported command %c", sed_cmd->cmd);
    453473    }
    454474
    455475    /* give back whatever's left over */
    456     return (cmdstr);
     476    return cmdstr;
    457477}
    458478
     
    460480/* Parse address+command sets, skipping comment lines. */
    461481
    462 static void add_cmd(char *cmdstr)
     482static void add_cmd(const char *cmdstr)
    463483{
    464484    sed_cmd_t *sed_cmd;
     
    466486
    467487    /* Append this line to any unfinished line from last time. */
    468     if (bbg.add_cmd_line) {
    469         cmdstr = bb_xasprintf("%s\n%s", bbg.add_cmd_line, cmdstr);
    470         free(bbg.add_cmd_line);
    471         bbg.add_cmd_line = cmdstr;
     488    if (G.add_cmd_line) {
     489        char *tp = xasprintf("%s\n%s", G.add_cmd_line, cmdstr);
     490        free(G.add_cmd_line);
     491        cmdstr = G.add_cmd_line = tp;
    472492    }
    473493
    474494    /* If this line ends with backslash, request next line. */
    475     temp=strlen(cmdstr);
    476     if(temp && cmdstr[temp-1]=='\\') {
    477         if (!bbg.add_cmd_line) bbg.add_cmd_line = bb_xstrdup(cmdstr);
    478         bbg.add_cmd_line[temp-1] = 0;
     495    temp = strlen(cmdstr);
     496    if (temp && cmdstr[--temp] == '\\') {
     497        if (!G.add_cmd_line)
     498            G.add_cmd_line = xstrdup(cmdstr);
     499        G.add_cmd_line[temp] = '\0';
    479500        return;
    480501    }
    481502
    482503    /* Loop parsing all commands in this line. */
    483     while(*cmdstr) {
     504    while (*cmdstr) {
    484505        /* Skip leading whitespace and semicolons */
    485506        cmdstr += strspn(cmdstr, semicolon_whitespace);
    486507
    487508        /* If no more commands, exit. */
    488         if(!*cmdstr) break;
     509        if (!*cmdstr) break;
    489510
    490511        /* if this is a comment, jump past it and keep going */
    491512        if (*cmdstr == '#') {
    492513            /* "#n" is the same as using -n on the command line */
    493             if (cmdstr[1] == 'n') bbg.be_quiet++;
    494             if(!(cmdstr=strpbrk(cmdstr, "\n\r"))) break;
     514            if (cmdstr[1] == 'n')
     515                G.be_quiet++;
     516            cmdstr = strpbrk(cmdstr, "\n\r");
     517            if (!cmdstr) break;
    495518            continue;
    496519        }
     
    513536            cmdstr++;
    514537            idx = get_address(cmdstr, &sed_cmd->end_line, &sed_cmd->end_match);
    515             if (!idx) bb_error_msg_and_die("no address after comma\n");
     538            if (!idx)
     539                bb_error_msg_and_die("no address after comma");
    516540            cmdstr += idx;
    517541        }
    518542
    519543        /* skip whitespace before the command */
    520         while (isspace(*cmdstr)) cmdstr++;
     544        cmdstr = skip_whitespace(cmdstr);
    521545
    522546        /* Check for inversion flag */
     
    526550
    527551            /* skip whitespace before the command */
    528             while (isspace(*cmdstr)) cmdstr++;
     552            cmdstr = skip_whitespace(cmdstr);
    529553        }
    530554
    531555        /* last part (mandatory) will be a command */
    532         if (!*cmdstr) bb_error_msg_and_die("missing command");
     556        if (!*cmdstr)
     557            bb_error_msg_and_die("missing command");
    533558        sed_cmd->cmd = *(cmdstr++);
    534559        cmdstr = parse_cmd_args(sed_cmd, cmdstr);
    535560
    536561        /* Add the command to the command array */
    537         bbg.sed_cmd_tail->next = sed_cmd;
    538         bbg.sed_cmd_tail = bbg.sed_cmd_tail->next;
     562        G.sed_cmd_tail->next = sed_cmd;
     563        G.sed_cmd_tail = G.sed_cmd_tail->next;
    539564    }
    540565
    541566    /* If we glued multiple lines together, free the memory. */
    542     free(bbg.add_cmd_line);
    543     bbg.add_cmd_line = NULL;
     567    free(G.add_cmd_line);
     568    G.add_cmd_line = NULL;
    544569}
    545570
     
    550575static void pipe_putc(char c)
    551576{
    552     if(bbg.pipeline.idx==bbg.pipeline.len) {
    553         bbg.pipeline.buf = xrealloc(bbg.pipeline.buf,
    554                                 bbg.pipeline.len + PIPE_GROW);
    555         bbg.pipeline.len+=PIPE_GROW;
    556     }
    557     bbg.pipeline.buf[bbg.pipeline.idx++] = c;
     577    if (G.pipeline.idx == G.pipeline.len) {
     578        G.pipeline.buf = xrealloc(G.pipeline.buf,
     579                G.pipeline.len + PIPE_GROW);
     580        G.pipeline.len += PIPE_GROW;
     581    }
     582    G.pipeline.buf[G.pipeline.idx++] = c;
    558583}
    559584
     
    565590    for (i = 0; replace[i]; i++) {
    566591        /* if we find a backreference (\1, \2, etc.) print the backref'ed * text */
    567         if (replace[i] == '\\' && replace[i+1]>='0' && replace[i+1]<='9') {
    568             int backref=replace[++i]-'0';
    569 
    570             /* print out the text held in bbg.regmatch[backref] */
    571             if(bbg.regmatch[backref].rm_so != -1)
    572                 for (j = bbg.regmatch[backref].rm_so;
    573                     j < bbg.regmatch[backref].rm_eo; j++) pipe_putc(line[j]);
    574         }
    575 
    576         /* if we find a backslash escaped character, print the character */
    577         else if (replace[i] == '\\') pipe_putc(replace[++i]);
    578 
     592        if (replace[i] == '\\') {
     593            unsigned backref = replace[++i] - '0';
     594            if (backref <= 9) {
     595                /* print out the text held in G.regmatch[backref] */
     596                if (G.regmatch[backref].rm_so != -1) {
     597                    j = G.regmatch[backref].rm_so;
     598                    while (j < G.regmatch[backref].rm_eo)
     599                        pipe_putc(line[j++]);
     600                }
     601                continue;
     602            }
     603            /* I _think_ it is impossible to get '\' to be
     604             * the last char in replace string. Thus we dont check
     605             * for replace[i] == NUL. (counterexample anyone?) */
     606            /* if we find a backslash escaped character, print the character */
     607            pipe_putc(replace[i]);
     608            continue;
     609        }
    579610        /* if we find an unescaped '&' print out the whole matched text. */
    580         else if (replace[i] == '&')
    581             for (j = bbg.regmatch[0].rm_so; j < bbg.regmatch[0].rm_eo; j++)
    582                 pipe_putc(line[j]);
     611        if (replace[i] == '&') {
     612            j = G.regmatch[0].rm_so;
     613            while (j < G.regmatch[0].rm_eo)
     614                pipe_putc(line[j++]);
     615            continue;
     616        }
    583617        /* Otherwise just output the character. */
    584         else pipe_putc(replace[i]);
     618        pipe_putc(replace[i]);
    585619    }
    586620}
     
    590624    char *oldline = *line;
    591625    int altered = 0;
    592     int match_count=0;
     626    int match_count = 0;
    593627    regex_t *current_regex;
    594628
    595629    /* Handle empty regex. */
    596630    if (sed_cmd->sub_match == NULL) {
    597         current_regex = bbg.previous_regex_ptr;
    598         if(!current_regex)
    599             bb_error_msg_and_die("No previous regexp.");
    600     } else bbg.previous_regex_ptr = current_regex = sed_cmd->sub_match;
     631        current_regex = G.previous_regex_ptr;
     632        if (!current_regex)
     633            bb_error_msg_and_die("no previous regexp");
     634    } else
     635        G.previous_regex_ptr = current_regex = sed_cmd->sub_match;
    601636
    602637    /* Find the first match */
    603     if(REG_NOMATCH==regexec(current_regex, oldline, 10, bbg.regmatch, 0))
     638    if (REG_NOMATCH == regexec(current_regex, oldline, 10, G.regmatch, 0))
    604639        return 0;
    605640
    606641    /* Initialize temporary output buffer. */
    607     bbg.pipeline.buf=xmalloc(PIPE_GROW);
    608     bbg.pipeline.len=PIPE_GROW;
    609     bbg.pipeline.idx=0;
     642    G.pipeline.buf = xmalloc(PIPE_GROW);
     643    G.pipeline.len = PIPE_GROW;
     644    G.pipeline.idx = 0;
    610645
    611646    /* Now loop through, substituting for matches */
     
    617652           The match_count check is so not to break
    618653           echo "hi" | busybox sed 's/^/!/g' */
    619         if(!bbg.regmatch[0].rm_so && !bbg.regmatch[0].rm_eo && match_count) {
    620             pipe_putc(*(oldline++));
     654        if (!G.regmatch[0].rm_so && !G.regmatch[0].rm_eo && match_count) {
     655            pipe_putc(*oldline++);
    621656            continue;
    622657        }
     
    626661        /* If we aren't interested in this match, output old line to
    627662           end of match and continue */
    628         if(sed_cmd->which_match && sed_cmd->which_match!=match_count) {
    629             for(i=0;i<bbg.regmatch[0].rm_eo;i++)
    630                 pipe_putc(*(oldline++));
     663        if (sed_cmd->which_match && sed_cmd->which_match != match_count) {
     664            for (i = 0; i < G.regmatch[0].rm_eo; i++)
     665                pipe_putc(*oldline++);
    631666            continue;
    632667        }
    633668
    634669        /* print everything before the match */
    635         for (i = 0; i < bbg.regmatch[0].rm_so; i++) pipe_putc(oldline[i]);
     670        for (i = 0; i < G.regmatch[0].rm_so; i++)
     671            pipe_putc(oldline[i]);
    636672
    637673        /* then print the substitution string */
     
    639675
    640676        /* advance past the match */
    641         oldline += bbg.regmatch[0].rm_eo;
     677        oldline += G.regmatch[0].rm_eo;
    642678        /* flag that something has changed */
    643679        altered++;
     
    645681        /* if we're not doing this globally, get out now */
    646682        if (sed_cmd->which_match) break;
    647     } while (*oldline && (regexec(current_regex, oldline, 10, bbg.regmatch, 0) != REG_NOMATCH));
     683    } while (*oldline && (regexec(current_regex, oldline, 10, G.regmatch, 0) != REG_NOMATCH));
    648684
    649685    /* Copy rest of string into output pipeline */
    650686
    651     while(*oldline) pipe_putc(*(oldline++));
     687    while (*oldline)
     688        pipe_putc(*oldline++);
    652689    pipe_putc(0);
    653690
    654691    free(*line);
    655     *line = bbg.pipeline.buf;
     692    *line = G.pipeline.buf;
    656693    return altered;
    657694}
     
    662699    sed_cmd_t *sed_cmd;
    663700
    664     for (sed_cmd = bbg.sed_cmd_head.next; sed_cmd; sed_cmd = sed_cmd->next) {
    665         if ((sed_cmd->cmd == ':') && (sed_cmd->string) && (strcmp(sed_cmd->string, label) == 0)) {
    666             return (sed_cmd);
    667         }
    668     }
    669     bb_error_msg_and_die("Can't find label for jump to `%s'", label);
     701    for (sed_cmd = G.sed_cmd_head.next; sed_cmd; sed_cmd = sed_cmd->next) {
     702        if (sed_cmd->cmd == ':' && sed_cmd->string && !strcmp(sed_cmd->string, label)) {
     703            return sed_cmd;
     704        }
     705    }
     706    bb_error_msg_and_die("can't find label for jump to '%s'", label);
    670707}
    671708
    672709static void append(char *s)
    673710{
    674     llist_add_to_end(&bbg.append_head, bb_xstrdup(s));
     711    llist_add_to_end(&G.append_head, xstrdup(s));
    675712}
    676713
     
    680717
    681718    /* Output appended lines. */
    682     while((data = (char *)llist_pop(&bbg.append_head))) {
    683         fprintf(bbg.nonstdout,"%s\n",data);
     719    while ((data = (char *)llist_pop(&G.append_head))) {
     720        fprintf(G.nonstdout, "%s\n", data);
    684721        free(data);
    685722    }
     
    688725static void add_input_file(FILE *file)
    689726{
    690     bbg.input_file_list=xrealloc(bbg.input_file_list,
    691             (bbg.input_file_count + 1) * sizeof(FILE *));
    692     bbg.input_file_list[bbg.input_file_count++] = file;
    693 }
    694 
    695 /* Get next line of input from bbg.input_file_list, flushing append buffer and
     727    G.input_file_list = xrealloc(G.input_file_list,
     728            (G.input_file_count + 1) * sizeof(FILE *));
     729    G.input_file_list[G.input_file_count++] = file;
     730}
     731
     732/* Get next line of input from G.input_file_list, flushing append buffer and
    696733 * noting if we ran out of files without a newline on the last line we read.
    697734 */
    698 static char *get_next_line(int *no_newline)
    699 {
    700     char *temp=NULL;
     735enum {
     736    NO_EOL_CHAR = 1,
     737    LAST_IS_NUL = 2,
     738};
     739static char *get_next_line(char *gets_char)
     740{
     741    char *temp = NULL;
    701742    int len;
     743    char gc;
    702744
    703745    flush_append();
    704     while (bbg.current_input_file<bbg.input_file_count) {
    705         temp = bb_get_chunk_from_file(bbg.input_file_list[bbg.current_input_file],&len);
     746
     747    /* will be returned if last line in the file
     748     * doesn't end with either '\n' or '\0' */
     749    gc = NO_EOL_CHAR;
     750    while (G.current_input_file < G.input_file_count) {
     751        FILE *fp = G.input_file_list[G.current_input_file];
     752        /* Read line up to a newline or NUL byte, inclusive,
     753         * return malloc'ed char[]. length of the chunk read
     754         * is stored in len. NULL if EOF/error */
     755        temp = bb_get_chunk_from_file(fp, &len);
    706756        if (temp) {
    707             *no_newline = !(len && temp[len-1]=='\n');
    708             if (!*no_newline) temp[len-1] = 0;
     757            /* len > 0 here, it's ok to do temp[len-1] */
     758            char c = temp[len-1];
     759            if (c == '\n' || c == '\0') {
     760                temp[len-1] = '\0';
     761                gc = c;
     762                if (c == '\0') {
     763                    int ch = fgetc(fp);
     764                    if (ch != EOF)
     765                        ungetc(ch, fp);
     766                    else
     767                        gc = LAST_IS_NUL;
     768                }
     769            }
     770            /* else we put NO_EOL_CHAR into *gets_char */
    709771            break;
    710         // Close this file and advance to next one
    711         } else fclose(bbg.input_file_list[bbg.current_input_file++]);
    712     }
    713 
     772
     773        /* NB: I had the idea of peeking next file(s) and returning
     774         * NO_EOL_CHAR only if it is the *last* non-empty
     775         * input file. But there is a case where this won't work:
     776         * file1: "a woo\nb woo"
     777         * file2: "c no\nd no"
     778         * sed -ne 's/woo/bang/p' input1 input2 => "a bang\nb bang"
     779         * (note: *no* newline after "b bang"!) */
     780        }
     781        /* Close this file and advance to next one */
     782        fclose(fp);
     783        G.current_input_file++;
     784    }
     785    *gets_char = gc;
    714786    return temp;
    715787}
    716788
    717 /* Output line of text.  missing_newline means the last line output did not
    718    end with a newline.  no_newline means this line does not end with a
    719    newline. */
    720 
    721 static int puts_maybe_newline(char *s, FILE *file, int missing_newline, int no_newline)
    722 {
    723     if(missing_newline) fputc('\n',file);
    724     fputs(s,file);
    725     if(!no_newline) fputc('\n',file);
    726 
    727     if(ferror(file)) {
    728         bb_default_error_retval = 4;  /* It's what gnu sed exits with... */
     789/* Output line of text. */
     790/* Note:
     791 * The tricks with NO_EOL_CHAR and last_puts_char are there to emulate gnu sed.
     792 * Without them, we had this:
     793 * echo -n thingy >z1
     794 * echo -n again >z2
     795 * >znull
     796 * sed "s/i/z/" z1 z2 znull | hexdump -vC
     797 * output:
     798 * gnu sed 4.1.5:
     799 * 00000000  74 68 7a 6e 67 79 0a 61  67 61 7a 6e              |thzngy.agazn|
     800 * bbox:
     801 * 00000000  74 68 7a 6e 67 79 61 67  61 7a 6e                 |thzngyagazn|
     802 */
     803static void puts_maybe_newline(char *s, FILE *file, char *last_puts_char, char last_gets_char)
     804{
     805    char lpc = *last_puts_char;
     806
     807    /* Need to insert a '\n' between two files because first file's
     808     * last line wasn't terminated? */
     809    if (lpc != '\n' && lpc != '\0') {
     810        fputc('\n', file);
     811        lpc = '\n';
     812    }
     813    fputs(s, file);
     814
     815    /* 'x' - just something which is not '\n', '\0' or NO_EOL_CHAR */
     816    if (s[0])
     817        lpc = 'x';
     818
     819    /* had trailing '\0' and it was last char of file? */
     820    if (last_gets_char == LAST_IS_NUL) {
     821        fputc('\0', file);
     822        lpc = 'x'; /* */
     823    } else
     824    /* had trailing '\n' or '\0'? */
     825    if (last_gets_char != NO_EOL_CHAR) {
     826        fputc(last_gets_char, file);
     827        lpc = last_gets_char;
     828    }
     829
     830    if (ferror(file)) {
     831        xfunc_error_retval = 4;  /* It's what gnu sed exits with... */
    729832        bb_error_msg_and_die(bb_msg_write_error);
    730833    }
    731 
    732     return no_newline;
    733 }
    734 
    735 #define sed_puts(s,n) missing_newline=puts_maybe_newline(s,bbg.nonstdout,missing_newline,n)
     834    *last_puts_char = lpc;
     835}
     836
     837#define sed_puts(s, n) (puts_maybe_newline(s, G.nonstdout, &last_puts_char, n))
     838
     839static int beg_match(sed_cmd_t *sed_cmd, const char *pattern_space)
     840{
     841    int retval = sed_cmd->beg_match && !regexec(sed_cmd->beg_match, pattern_space, 0, NULL, 0);
     842    if (retval)
     843        G.previous_regex_ptr = sed_cmd->beg_match;
     844    return retval;
     845}
    736846
    737847/* Process all the lines in all the files */
     
    740850{
    741851    char *pattern_space, *next_line;
    742     int linenum = 0, missing_newline=0;
    743     int no_newline,next_no_newline=0;
     852    int linenum = 0;
     853    char last_puts_char = '\n';
     854    char last_gets_char, next_gets_char;
     855    sed_cmd_t *sed_cmd;
     856    int substituted;
    744857
    745858    /* Prime the pump */
    746     next_line = get_next_line(&next_no_newline);
     859    next_line = get_next_line(&next_gets_char);
    747860
    748861    /* go through every line in each file */
    749     for(;;) {
    750         sed_cmd_t *sed_cmd;
    751         int substituted=0;
    752 
    753         /* Advance to next line.  Stop if out of lines. */
    754         if(!(pattern_space=next_line)) break;
    755         no_newline=next_no_newline;
    756 
    757         /* Read one line in advance so we can act on the last line,
    758         * the '$' address */
    759         next_line = get_next_line(&next_no_newline);
    760         linenum++;
     862again:
     863    substituted = 0;
     864
     865    /* Advance to next line.  Stop if out of lines. */
     866    pattern_space = next_line;
     867    if (!pattern_space) return;
     868    last_gets_char = next_gets_char;
     869
     870    /* Read one line in advance so we can act on the last line,
     871    * the '$' address */
     872    next_line = get_next_line(&next_gets_char);
     873    linenum++;
    761874restart:
    762         /* for every line, go through all the commands */
    763         for (sed_cmd = bbg.sed_cmd_head.next; sed_cmd; sed_cmd = sed_cmd->next)
    764         {
    765             int old_matched, matched;
    766 
    767             old_matched = sed_cmd->in_match;
    768 
    769             /* Determine if this command matches this line: */
    770 
    771             /* Are we continuing a previous multi-line match? */
    772 
    773             sed_cmd->in_match = sed_cmd->in_match
    774 
     875    /* for every line, go through all the commands */
     876    for (sed_cmd = G.sed_cmd_head.next; sed_cmd; sed_cmd = sed_cmd->next) {
     877        int old_matched, matched;
     878
     879        old_matched = sed_cmd->in_match;
     880
     881        /* Determine if this command matches this line: */
     882
     883        /* Are we continuing a previous multi-line match? */
     884        sed_cmd->in_match = sed_cmd->in_match
    775885            /* Or is no range necessary? */
    776                 || (!sed_cmd->beg_line && !sed_cmd->end_line
    777                     && !sed_cmd->beg_match && !sed_cmd->end_match)
    778 
     886            || (!sed_cmd->beg_line && !sed_cmd->end_line
     887                && !sed_cmd->beg_match && !sed_cmd->end_match)
    779888            /* Or did we match the start of a numerical range? */
    780                 || (sed_cmd->beg_line > 0 && (sed_cmd->beg_line == linenum))
    781 
     889            || (sed_cmd->beg_line > 0 && (sed_cmd->beg_line == linenum))
    782890            /* Or does this line match our begin address regex? */
    783                     || (sed_cmd->beg_match &&
    784                     !regexec(sed_cmd->beg_match, pattern_space, 0, NULL, 0))
    785 
     891            || (beg_match(sed_cmd, pattern_space))
    786892            /* Or did we match last line of input? */
    787                 || (sed_cmd->beg_line == -1 && next_line == NULL);
    788 
    789             /* Snapshot the value */
    790 
    791             matched = sed_cmd->in_match;
    792 
    793             /* Is this line the end of the current match? */
    794 
    795             if(matched) {
    796                 sed_cmd->in_match = !(
    797                     /* has the ending line come, or is this a single address command? */
    798                     (sed_cmd->end_line ?
    799                         sed_cmd->end_line==-1 ?
    800                             !next_line
    801                             : sed_cmd->end_line<=linenum
    802                         : !sed_cmd->end_match)
    803                     /* or does this line matches our last address regex */
    804                     || (sed_cmd->end_match && old_matched && (regexec(sed_cmd->end_match, pattern_space, 0, NULL, 0) == 0))
    805                 );
    806             }
    807 
    808             /* Skip blocks of commands we didn't match. */
    809             if (sed_cmd->cmd == '{') {
    810                 if(sed_cmd->invert ? matched : !matched)
    811                     while(sed_cmd && sed_cmd->cmd!='}') sed_cmd=sed_cmd->next;
    812                 if(!sed_cmd) bb_error_msg_and_die("Unterminated {");
    813                 continue;
    814             }
    815 
    816             /* Okay, so did this line match? */
    817             if (sed_cmd->invert ? !matched : matched) {
    818                 /* Update last used regex in case a blank substitute BRE is found */
    819                 if (sed_cmd->beg_match) {
    820                     bbg.previous_regex_ptr = sed_cmd->beg_match;
     893            || (sed_cmd->beg_line == -1 && next_line == NULL);
     894
     895        /* Snapshot the value */
     896
     897        matched = sed_cmd->in_match;
     898
     899        /* Is this line the end of the current match? */
     900
     901        if (matched) {
     902            sed_cmd->in_match = !(
     903                /* has the ending line come, or is this a single address command? */
     904                (sed_cmd->end_line ?
     905                    sed_cmd->end_line == -1 ?
     906                        !next_line
     907                        : (sed_cmd->end_line <= linenum)
     908                    : !sed_cmd->end_match
     909                )
     910                /* or does this line matches our last address regex */
     911                || (sed_cmd->end_match && old_matched
     912                     && (regexec(sed_cmd->end_match,
     913                                 pattern_space, 0, NULL, 0) == 0))
     914            );
     915        }
     916
     917        /* Skip blocks of commands we didn't match. */
     918        if (sed_cmd->cmd == '{') {
     919            if (sed_cmd->invert ? matched : !matched) {
     920                while (sed_cmd->cmd != '}') {
     921                    sed_cmd = sed_cmd->next;
     922                    if (!sed_cmd)
     923                        bb_error_msg_and_die("unterminated {");
    821924                }
    822 
    823                 /* actual sedding */
    824                 switch (sed_cmd->cmd) {
    825 
    826                     /* Print line number */
    827                     case '=':
    828                         fprintf(bbg.nonstdout,"%d\n", linenum);
    829                         break;
    830 
    831                     /* Write the current pattern space up to the first newline */
    832                     case 'P':
    833                     {
    834                         char *tmp = strchr(pattern_space, '\n');
    835 
    836                         if (tmp) {
    837                             *tmp = '\0';
    838                             sed_puts(pattern_space,1);
    839                             *tmp = '\n';
     925            }
     926            continue;
     927        }
     928
     929        /* Okay, so did this line match? */
     930        if (sed_cmd->invert ? !matched : matched) {
     931            /* Update last used regex in case a blank substitute BRE is found */
     932            if (sed_cmd->beg_match) {
     933                G.previous_regex_ptr = sed_cmd->beg_match;
     934            }
     935
     936            /* actual sedding */
     937            switch (sed_cmd->cmd) {
     938
     939            /* Print line number */
     940            case '=':
     941                fprintf(G.nonstdout, "%d\n", linenum);
     942                break;
     943
     944            /* Write the current pattern space up to the first newline */
     945            case 'P':
     946            {
     947                char *tmp = strchr(pattern_space, '\n');
     948
     949                if (tmp) {
     950                    *tmp = '\0';
     951                    /* TODO: explain why '\n' below */
     952                    sed_puts(pattern_space, '\n');
     953                    *tmp = '\n';
     954                    break;
     955                }
     956                /* Fall Through */
     957            }
     958
     959            /* Write the current pattern space to output */
     960            case 'p':
     961                /* NB: we print this _before_ the last line
     962                 * (of current file) is printed. Even if
     963                 * that line is nonterminated, we print
     964                 * '\n' here (gnu sed does the same) */
     965                sed_puts(pattern_space, '\n');
     966                break;
     967            /* Delete up through first newline */
     968            case 'D':
     969            {
     970                char *tmp = strchr(pattern_space, '\n');
     971
     972                if (tmp) {
     973                    tmp = xstrdup(tmp+1);
     974                    free(pattern_space);
     975                    pattern_space = tmp;
     976                    goto restart;
     977                }
     978            }
     979            /* discard this line. */
     980            case 'd':
     981                goto discard_line;
     982
     983            /* Substitute with regex */
     984            case 's':
     985                if (!do_subst_command(sed_cmd, &pattern_space))
     986                    break;
     987                substituted |= 1;
     988
     989                /* handle p option */
     990                if (sed_cmd->sub_p)
     991                    sed_puts(pattern_space, last_gets_char);
     992                /* handle w option */
     993                if (sed_cmd->sw_file)
     994                    puts_maybe_newline(
     995                        pattern_space, sed_cmd->sw_file,
     996                        &sed_cmd->sw_last_char, last_gets_char);
     997                break;
     998
     999            /* Append line to linked list to be printed later */
     1000            case 'a':
     1001                append(sed_cmd->string);
     1002                break;
     1003
     1004            /* Insert text before this line */
     1005            case 'i':
     1006                sed_puts(sed_cmd->string, '\n');
     1007                break;
     1008
     1009            /* Cut and paste text (replace) */
     1010            case 'c':
     1011                /* Only triggers on last line of a matching range. */
     1012                if (!sed_cmd->in_match)
     1013                    sed_puts(sed_cmd->string, NO_EOL_CHAR);
     1014                goto discard_line;
     1015
     1016            /* Read file, append contents to output */
     1017            case 'r':
     1018            {
     1019                FILE *rfile;
     1020
     1021                rfile = fopen(sed_cmd->string, "r");
     1022                if (rfile) {
     1023                    char *line;
     1024
     1025                    while ((line = xmalloc_getline(rfile))
     1026                            != NULL)
     1027                        append(line);
     1028                    xprint_and_close_file(rfile);
     1029                }
     1030
     1031                break;
     1032            }
     1033
     1034            /* Write pattern space to file. */
     1035            case 'w':
     1036                puts_maybe_newline(
     1037                    pattern_space, sed_cmd->sw_file,
     1038                    &sed_cmd->sw_last_char, last_gets_char);
     1039                break;
     1040
     1041            /* Read next line from input */
     1042            case 'n':
     1043                if (!G.be_quiet)
     1044                    sed_puts(pattern_space, last_gets_char);
     1045                if (next_line) {
     1046                    free(pattern_space);
     1047                    pattern_space = next_line;
     1048                    last_gets_char = next_gets_char;
     1049                    next_line = get_next_line(&next_gets_char);
     1050                    linenum++;
     1051                    break;
     1052                }
     1053                /* fall through */
     1054
     1055            /* Quit.  End of script, end of input. */
     1056            case 'q':
     1057                /* Exit the outer while loop */
     1058                free(next_line);
     1059                next_line = NULL;
     1060                goto discard_commands;
     1061
     1062            /* Append the next line to the current line */
     1063            case 'N':
     1064            {
     1065                int len;
     1066                /* If no next line, jump to end of script and exit. */
     1067                if (next_line == NULL) {
     1068                    /* Jump to end of script and exit */
     1069                    free(next_line);
     1070                    next_line = NULL;
     1071                    goto discard_line;
     1072                /* append next_line, read new next_line. */
     1073                }
     1074                len = strlen(pattern_space);
     1075                pattern_space = realloc(pattern_space, len + strlen(next_line) + 2);
     1076                pattern_space[len] = '\n';
     1077                strcpy(pattern_space + len+1, next_line);
     1078                last_gets_char = next_gets_char;
     1079                next_line = get_next_line(&next_gets_char);
     1080                linenum++;
     1081                break;
     1082            }
     1083
     1084            /* Test/branch if substitution occurred */
     1085            case 't':
     1086                if (!substituted) break;
     1087                substituted = 0;
     1088                /* Fall through */
     1089            /* Test/branch if substitution didn't occur */
     1090            case 'T':
     1091                if (substituted) break;
     1092                /* Fall through */
     1093            /* Branch to label */
     1094            case 'b':
     1095                if (!sed_cmd->string) goto discard_commands;
     1096                else sed_cmd = branch_to(sed_cmd->string);
     1097                break;
     1098            /* Transliterate characters */
     1099            case 'y':
     1100            {
     1101                int i, j;
     1102
     1103                for (i = 0; pattern_space[i]; i++) {
     1104                    for (j = 0; sed_cmd->string[j]; j += 2) {
     1105                        if (pattern_space[i] == sed_cmd->string[j]) {
     1106                            pattern_space[i] = sed_cmd->string[j + 1];
    8401107                            break;
    8411108                        }
    842                         /* Fall Through */
    843                     }
    844 
    845                     /* Write the current pattern space to output */
    846                     case 'p':
    847                         sed_puts(pattern_space,no_newline);
    848                         break;
    849                     /* Delete up through first newline */
    850                     case 'D':
    851                     {
    852                         char *tmp = strchr(pattern_space,'\n');
    853 
    854                         if(tmp) {
    855                             tmp=bb_xstrdup(tmp+1);
    856                             free(pattern_space);
    857                             pattern_space=tmp;
    858                             goto restart;
    859                         }
    860                     }
    861                     /* discard this line. */
    862                     case 'd':
    863                         goto discard_line;
    864 
    865                     /* Substitute with regex */
    866                     case 's':
    867                         if(do_subst_command(sed_cmd, &pattern_space)) {
    868                             substituted|=1;
    869 
    870                             /* handle p option */
    871                             if(sed_cmd->sub_p)
    872                                 sed_puts(pattern_space,no_newline);
    873                             /* handle w option */
    874                             if(sed_cmd->file)
    875                                 sed_cmd->no_newline=puts_maybe_newline(pattern_space, sed_cmd->file, sed_cmd->no_newline, no_newline);
    876 
    877                         }
    878                         break;
    879 
    880                     /* Append line to linked list to be printed later */
    881                     case 'a':
    882                     {
    883                         append(sed_cmd->string);
    884                         break;
    885                     }
    886 
    887                     /* Insert text before this line */
    888                     case 'i':
    889                         sed_puts(sed_cmd->string,1);
    890                         break;
    891 
    892                     /* Cut and paste text (replace) */
    893                     case 'c':
    894                         /* Only triggers on last line of a matching range. */
    895                         if (!sed_cmd->in_match) sed_puts(sed_cmd->string,0);
    896                         goto discard_line;
    897 
    898                     /* Read file, append contents to output */
    899                     case 'r':
    900                     {
    901                         FILE *rfile;
    902 
    903                         rfile = fopen(sed_cmd->string, "r");
    904                         if (rfile) {
    905                             char *line;
    906 
    907                             while ((line = bb_get_chomped_line_from_file(rfile))
    908                                     != NULL)
    909                                 append(line);
    910                             bb_xprint_and_close_file(rfile);
    911                         }
    912 
    913                         break;
    914                     }
    915 
    916                     /* Write pattern space to file. */
    917                     case 'w':
    918                         sed_cmd->no_newline=puts_maybe_newline(pattern_space,sed_cmd->file, sed_cmd->no_newline,no_newline);
    919                         break;
    920 
    921                     /* Read next line from input */
    922                     case 'n':
    923                         if (!bbg.be_quiet)
    924                             sed_puts(pattern_space,no_newline);
    925                         if (next_line) {
    926                             free(pattern_space);
    927                             pattern_space = next_line;
    928                             no_newline=next_no_newline;
    929                             next_line = get_next_line(&next_no_newline);
    930                             linenum++;
    931                             break;
    932                         }
    933                         /* fall through */
    934 
    935                     /* Quit.  End of script, end of input. */
    936                     case 'q':
    937                         /* Exit the outer while loop */
    938                         free(next_line);
    939                         next_line = NULL;
    940                         goto discard_commands;
    941 
    942                     /* Append the next line to the current line */
    943                     case 'N':
    944                     {
    945                         /* If no next line, jump to end of script and exit. */
    946                         if (next_line == NULL) {
    947                             /* Jump to end of script and exit */
    948                             free(next_line);
    949                             next_line = NULL;
    950                             goto discard_line;
    951                         /* append next_line, read new next_line. */
    952                         } else {
    953                             int len=strlen(pattern_space);
    954 
    955                             pattern_space = realloc(pattern_space, len + strlen(next_line) + 2);
    956                             pattern_space[len]='\n';
    957                             strcpy(pattern_space+len+1, next_line);
    958                             no_newline=next_no_newline;
    959                             next_line = get_next_line(&next_no_newline);
    960                             linenum++;
    961                         }
    962                         break;
    963                     }
    964 
    965                     /* Test/branch if substitution occurred */
    966                     case 't':
    967                         if(!substituted) break;
    968                         substituted=0;
    969                         /* Fall through */
    970                     /* Test/branch if substitution didn't occur */
    971                     case 'T':
    972                         if (substituted) break;
    973                         /* Fall through */
    974                     /* Branch to label */
    975                     case 'b':
    976                         if (!sed_cmd->string) goto discard_commands;
    977                         else sed_cmd = branch_to(sed_cmd->string);
    978                         break;
    979                     /* Transliterate characters */
    980                     case 'y':
    981                     {
    982                         int i;
    983 
    984                         for (i = 0; pattern_space[i]; i++) {
    985                             int j;
    986 
    987                             for (j = 0; sed_cmd->string[j]; j += 2) {
    988                                 if (pattern_space[i] == sed_cmd->string[j]) {
    989                                     pattern_space[i] = sed_cmd->string[j + 1];
    990                                     break;
    991                                 }
    992                             }
    993                         }
    994 
    995                         break;
    996                     }
    997                     case 'g':   /* Replace pattern space with hold space */
    998                         free(pattern_space);
    999                         pattern_space = bb_xstrdup(bbg.hold_space ? bbg.hold_space : "");
    1000                         break;
    1001                     case 'G':   /* Append newline and hold space to pattern space */
    1002                     {
    1003                         int pattern_space_size = 2;
    1004                         int hold_space_size = 0;
    1005 
    1006                         if (pattern_space)
    1007                             pattern_space_size += strlen(pattern_space);
    1008                         if (bbg.hold_space)
    1009                             hold_space_size = strlen(bbg.hold_space);
    1010                         pattern_space = xrealloc(pattern_space,
    1011                                 pattern_space_size + hold_space_size);
    1012                         if (pattern_space_size == 2) pattern_space[0]=0;
    1013                         strcat(pattern_space, "\n");
    1014                         if (bbg.hold_space)
    1015                             strcat(pattern_space, bbg.hold_space);
    1016                         no_newline=0;
    1017 
    1018                         break;
    1019                     }
    1020                     case 'h':   /* Replace hold space with pattern space */
    1021                         free(bbg.hold_space);
    1022                         bbg.hold_space = bb_xstrdup(pattern_space);
    1023                         break;
    1024                     case 'H':   /* Append newline and pattern space to hold space */
    1025                     {
    1026                         int hold_space_size = 2;
    1027                         int pattern_space_size = 0;
    1028 
    1029                         if (bbg.hold_space)
    1030                             hold_space_size += strlen(bbg.hold_space);
    1031                         if (pattern_space)
    1032                             pattern_space_size = strlen(pattern_space);
    1033                         bbg.hold_space = xrealloc(bbg.hold_space,
    1034                                             hold_space_size + pattern_space_size);
    1035 
    1036                         if (hold_space_size == 2) *bbg.hold_space=0;
    1037                         strcat(bbg.hold_space, "\n");
    1038                         if (pattern_space) strcat(bbg.hold_space, pattern_space);
    1039 
    1040                         break;
    1041                     }
    1042                     case 'x': /* Exchange hold and pattern space */
    1043                     {
    1044                         char *tmp = pattern_space;
    1045                         pattern_space = bbg.hold_space ? : xzalloc(1);
    1046                         no_newline=0;
    1047                         bbg.hold_space = tmp;
    1048                         break;
    10491109                    }
    10501110                }
    1051             }
    1052         }
    1053 
    1054         /*
    1055          * exit point from sedding...
    1056          */
    1057 discard_commands:
    1058         /* we will print the line unless we were told to be quiet ('-n')
    1059            or if the line was suppressed (ala 'd'elete) */
    1060         if (!bbg.be_quiet) sed_puts(pattern_space,no_newline);
    1061 
    1062         /* Delete and such jump here. */
    1063 discard_line:
    1064         flush_append();
    1065         free(pattern_space);
    1066     }
     1111
     1112                break;
     1113            }
     1114            case 'g':   /* Replace pattern space with hold space */
     1115                free(pattern_space);
     1116                pattern_space = xstrdup(G.hold_space ? G.hold_space : "");
     1117                break;
     1118            case 'G':   /* Append newline and hold space to pattern space */
     1119            {
     1120                int pattern_space_size = 2;
     1121                int hold_space_size = 0;
     1122
     1123                if (pattern_space)
     1124                    pattern_space_size += strlen(pattern_space);
     1125                if (G.hold_space)
     1126                    hold_space_size = strlen(G.hold_space);
     1127                pattern_space = xrealloc(pattern_space,
     1128                        pattern_space_size + hold_space_size);
     1129                if (pattern_space_size == 2)
     1130                    pattern_space[0] = 0;
     1131                strcat(pattern_space, "\n");
     1132                if (G.hold_space)
     1133                    strcat(pattern_space, G.hold_space);
     1134                last_gets_char = '\n';
     1135
     1136                break;
     1137            }
     1138            case 'h':   /* Replace hold space with pattern space */
     1139                free(G.hold_space);
     1140                G.hold_space = xstrdup(pattern_space);
     1141                break;
     1142            case 'H':   /* Append newline and pattern space to hold space */
     1143            {
     1144                int hold_space_size = 2;
     1145                int pattern_space_size = 0;
     1146
     1147                if (G.hold_space)
     1148                    hold_space_size += strlen(G.hold_space);
     1149                if (pattern_space)
     1150                    pattern_space_size = strlen(pattern_space);
     1151                G.hold_space = xrealloc(G.hold_space,
     1152                        hold_space_size + pattern_space_size);
     1153
     1154                if (hold_space_size == 2)
     1155                    *G.hold_space = 0;
     1156                strcat(G.hold_space, "\n");
     1157                if (pattern_space)
     1158                    strcat(G.hold_space, pattern_space);
     1159
     1160                break;
     1161            }
     1162            case 'x': /* Exchange hold and pattern space */
     1163            {
     1164                char *tmp = pattern_space;
     1165                pattern_space = G.hold_space ? : xzalloc(1);
     1166                last_gets_char = '\n';
     1167                G.hold_space = tmp;
     1168                break;
     1169            }
     1170            }
     1171        }
     1172    }
     1173
     1174    /*
     1175     * exit point from sedding...
     1176     */
     1177 discard_commands:
     1178    /* we will print the line unless we were told to be quiet ('-n')
     1179       or if the line was suppressed (ala 'd'elete) */
     1180    if (!G.be_quiet)
     1181        sed_puts(pattern_space, last_gets_char);
     1182
     1183    /* Delete and such jump here. */
     1184 discard_line:
     1185    flush_append();
     1186    free(pattern_space);
     1187
     1188    goto again;
    10671189}
    10681190
    10691191/* It is possible to have a command line argument with embedded
    1070    newlines.  This counts as multiple command lines. */
     1192 * newlines.  This counts as multiple command lines.
     1193 * However, newline can be escaped: 's/e/z\<newline>z/'
     1194 * We check for this.
     1195 */
    10711196
    10721197static void add_cmd_block(char *cmdstr)
    10731198{
    1074     int go=1;
    1075     char *temp=bb_xstrdup(cmdstr),*temp2=temp;
    1076 
    1077     while(go) {
    1078         int len=strcspn(temp2,"\n");
    1079         if(!temp2[len]) go=0;
    1080         else temp2[len]=0;
    1081         add_cmd(temp2);
    1082         temp2+=len+1;
    1083     }
    1084     free(temp);
    1085 }
    1086 
     1199    char *sv, *eol;
     1200
     1201    cmdstr = sv = xstrdup(cmdstr);
     1202    do {
     1203        eol = strchr(cmdstr, '\n');
     1204 next:
     1205        if (eol) {
     1206            /* Count preceding slashes */
     1207            int slashes = 0;
     1208            char *sl = eol;
     1209
     1210            while (sl != cmdstr && *--sl == '\\')
     1211                slashes++;
     1212            /* Odd number of preceding slashes - newline is escaped */
     1213            if (slashes & 1) {
     1214                strcpy(eol-1, eol);
     1215                eol = strchr(eol, '\n');
     1216                goto next;
     1217            }
     1218            *eol = '\0';
     1219        }
     1220        add_cmd(cmdstr);
     1221        cmdstr = eol + 1;
     1222    } while (eol);
     1223    free(sv);
     1224}
     1225
     1226int sed_main(int argc, char **argv);
    10871227int sed_main(int argc, char **argv)
    10881228{
    1089     int status = EXIT_SUCCESS, opt, getpat = 1;
    1090 
    1091     bbg.sed_cmd_tail=&bbg.sed_cmd_head;
     1229    enum {
     1230        OPT_in_place = 1 << 0,
     1231    };
     1232    unsigned opt;
     1233    llist_t *opt_e, *opt_f;
     1234    int status = EXIT_SUCCESS;
     1235
     1236    INIT_G();
    10921237
    10931238    /* destroy command strings on exit */
     
    10951240
    10961241    /* Lie to autoconf when it starts asking stupid questions. */
    1097     if(argc==2 && !strcmp(argv[1],"--version")) {
    1098         printf("This is not GNU sed version 4.0\n");
    1099         exit(0);
     1242    if (argc == 2 && !strcmp(argv[1], "--version")) {
     1243        puts("This is not GNU sed version 4.0");
     1244        return 0;
    11001245    }
    11011246
    11021247    /* do normal option parsing */
    1103     while ((opt = getopt(argc, argv, "irne:f:")) > 0) {
    1104         switch (opt) {
    1105         case 'i':
    1106             bbg.in_place++;
    1107             atexit(cleanup_outname);
    1108             break;
    1109         case 'r':
    1110             bbg.regex_type|=REG_EXTENDED;
    1111             break;
    1112         case 'n':
    1113             bbg.be_quiet++;
    1114             break;
    1115         case 'e':
    1116             add_cmd_block(optarg);
    1117             getpat=0;
    1118             break;
    1119         case 'f':
    1120         {
    1121             FILE *cmdfile;
    1122             char *line;
    1123 
    1124             cmdfile = bb_xfopen(optarg, "r");
    1125 
    1126             while ((line = bb_get_chomped_line_from_file(cmdfile)) != NULL) {
    1127                 add_cmd(line);
    1128                 getpat=0;
    1129                 free(line);
    1130             }
    1131             bb_xprint_and_close_file(cmdfile);
    1132 
    1133             break;
    1134         }
    1135         default:
     1248    opt_e = opt_f = NULL;
     1249    opt_complementary = "e::f::" /* can occur multiple times */
     1250                        "nn"; /* count -n */
     1251    opt = getopt32(argv, "irne:f:", &opt_e, &opt_f,
     1252                &G.be_quiet); /* counter for -n */
     1253    argc -= optind;
     1254    argv += optind;
     1255    if (opt & OPT_in_place) { // -i
     1256        atexit(cleanup_outname);
     1257    }
     1258    if (opt & 0x2) G.regex_type |= REG_EXTENDED; // -r
     1259    //if (opt & 0x4) G.be_quiet++; // -n
     1260    while (opt_e) { // -e
     1261        add_cmd_block(opt_e->data);
     1262        opt_e = opt_e->link;
     1263        /* we leak opt_e here... */
     1264    }
     1265    while (opt_f) { // -f
     1266        char *line;
     1267        FILE *cmdfile;
     1268        cmdfile = xfopen(opt_f->data, "r");
     1269        while ((line = xmalloc_getline(cmdfile)) != NULL) {
     1270            add_cmd(line);
     1271            free(line);
     1272        }
     1273        fclose(cmdfile);
     1274        opt_f = opt_f->link;
     1275        /* we leak opt_f here... */
     1276    }
     1277    /* if we didn't get a pattern from -e or -f, use argv[0] */
     1278    if (!(opt & 0x18)) {
     1279        if (!argc)
    11361280            bb_show_usage();
    1137         }
    1138     }
    1139 
    1140     /* if we didn't get a pattern from -e or -f, use argv[optind] */
    1141     if(getpat) {
    1142         if (argv[optind] == NULL)
    1143             bb_show_usage();
    1144         else
    1145             add_cmd_block(argv[optind++]);
     1281        add_cmd_block(*argv++);
     1282        argc--;
    11461283    }
    11471284    /* Flush any unfinished commands. */
     
    11491286
    11501287    /* By default, we write to stdout */
    1151     bbg.nonstdout=stdout;
    1152 
    1153     /* argv[(optind)..(argc-1)] should be names of file to process. If no
     1288    G.nonstdout = stdout;
     1289
     1290    /* argv[0..(argc-1)] should be names of file to process. If no
    11541291     * files were specified or '-' was specified, take input from stdin.
    11551292     * Otherwise, we process all the files specified. */
    1156     if (argv[optind] == NULL) {
    1157         if(bbg.in_place) bb_error_msg_and_die(bb_msg_requires_arg, "-i");
     1293    if (argv[0] == NULL) {
     1294        if (opt & OPT_in_place)
     1295            bb_error_msg_and_die(bb_msg_requires_arg, "-i");
    11581296        add_input_file(stdin);
    11591297        process_files();
     
    11621300        FILE *file;
    11631301
    1164         for (i = optind; i < argc; i++) {
    1165             if(!strcmp(argv[i], "-") && !bbg.in_place) {
     1302        for (i = 0; i < argc; i++) {
     1303            struct stat statbuf;
     1304            int nonstdoutfd;
     1305
     1306            if (LONE_DASH(argv[i]) && !(opt & OPT_in_place)) {
    11661307                add_input_file(stdin);
    11671308                process_files();
    1168             } else {
    1169                 file = bb_wfopen(argv[i], "r");
    1170                 if (file) {
    1171                     if(bbg.in_place) {
    1172                         struct stat statbuf;
    1173                         int nonstdoutfd;
    1174 
    1175                         bbg.outname=bb_xstrndup(argv[i],strlen(argv[i])+6);
    1176                         strcat(bbg.outname,"XXXXXX");
    1177                         if(-1==(nonstdoutfd=mkstemp(bbg.outname)))
    1178                             bb_error_msg_and_die("no temp file");
    1179                         bbg.nonstdout=fdopen(nonstdoutfd,"w");
    1180 
    1181                         /* Set permissions of output file */
    1182 
    1183                         fstat(fileno(file),&statbuf);
    1184                         fchmod(nonstdoutfd,statbuf.st_mode);
    1185                         add_input_file(file);
    1186                         process_files();
    1187                         fclose(bbg.nonstdout);
    1188 
    1189                         bbg.nonstdout=stdout;
    1190                         unlink(argv[i]);
    1191                         rename(bbg.outname,argv[i]);
    1192                         free(bbg.outname);
    1193                         bbg.outname=0;
    1194                     } else add_input_file(file);
    1195                 } else {
    1196                     status = EXIT_FAILURE;
    1197                 }
    1198             }
    1199         }
    1200         if(bbg.input_file_count>bbg.current_input_file) process_files();
     1309                continue;
     1310            }
     1311            file = fopen_or_warn(argv[i], "r");
     1312            if (!file) {
     1313                status = EXIT_FAILURE;
     1314                continue;
     1315            }
     1316            if (!(opt & OPT_in_place)) {
     1317                add_input_file(file);
     1318                continue;
     1319            }
     1320
     1321            G.outname = xasprintf("%sXXXXXX", argv[i]);
     1322            nonstdoutfd = mkstemp(G.outname);
     1323            if (-1 == nonstdoutfd)
     1324                bb_perror_msg_and_die("cannot create temp file %s", G.outname);
     1325            G.nonstdout = fdopen(nonstdoutfd, "w");
     1326
     1327            /* Set permissions of output file */
     1328
     1329            fstat(fileno(file), &statbuf);
     1330            fchmod(nonstdoutfd, statbuf.st_mode);
     1331            add_input_file(file);
     1332            process_files();
     1333            fclose(G.nonstdout);
     1334
     1335            G.nonstdout = stdout;
     1336            /* unlink(argv[i]); */
     1337            // FIXME: error check / message?
     1338            rename(G.outname, argv[i]);
     1339            free(G.outname);
     1340            G.outname = 0;
     1341        }
     1342        if (G.input_file_count > G.current_input_file)
     1343            process_files();
    12011344    }
    12021345
Note: See TracChangeset for help on using the changeset viewer.