Introduced perl script.
authorlxoliva <lxoliva@559672b5-ba27-0410-b829-e8f1faed8b1b>
Mon, 25 Jan 2010 12:23:10 +0000 (12:23 +0000)
committerlxoliva <lxoliva@559672b5-ba27-0410-b829-e8f1faed8b1b>
Mon, 25 Jan 2010 12:23:10 +0000 (12:23 +0000)
Improved awk and python scripts.  Awk still wins.
Dropped psed experiment.

git-svn-id: http://www.fsfla.org/svn/fsfla/software/linux-libre/scripts@5896 559672b5-ba27-0410-b829-e8f1faed8b1b

deblob-check
deblob-psed-disabled [deleted file]

index 2957ec602cc00c1833583c68ed817082f08fbe55..ed1ce37181b0ad2de5a850037ec11fd0d9f1bc31 100755 (executable)
@@ -1,6 +1,6 @@
 #! /bin/sh
 
-# deblob-check version 2010-01-23
+# deblob-check version 2010-01-24
 # Inspired in gNewSense's find-firmware script.
 # Written by Alexandre Oliva <lxoliva@fsfla.org>
 
 #              recommended, because the regular expressions we use
 #              invoke exponential behavior in the python engine.
 
+#    --use-perl: Choose the internal perl script.  This is not
+#              recommended, because our regular expressions exceed
+#              some limits hard-coded into perl.
+
 #    --save-script-input: Save the input that would have been fed to
 #              any of the engines above.
 
@@ -249,21 +253,6 @@ case ${LANG+set} in set) LANG=C; export LANG;; esac
 
 rm="rm -f"
 
-sed=`echo $0 | sed 's,\(/\?\)[^/]*$,\1deblob-psed,'`
-if test -f "$sed"; then
-  :
-elif test -f deblob-psed; then
-  sed=deblob-psed
-else
-  sed=false
-fi
-
-if $sed -e 'q' < /dev/null > /dev/null; then
-  :
-else
-  sed=sed
-fi
-
 for echo in 'echo' 'printf %s\n'; do
   case `$echo '\nx'` in 
   '\nx') break;;
@@ -391,14 +380,13 @@ set_cmd=set_eqscript_cmd
 # on our own, but, yuck.
 if (${AWK-gawk} --re-interval --version) > /dev/null 2>&1; then
   set_main_cmd=set_awk_main
+# Don't choose perl by default, we exceed some internal limits.
+elif (${PERL-perl} --version) > /dev/null 2>&1; then
+  set_main_cmd=set_perl_main
 # Don't choose python by default, it exhibits exponential behavior
 # (see http://swtch.com/~rsc/regexp/regexp1.html for details)
-# processing lines containing /* such as this:
-# Documentation/sysctl/*, swap/mm readaround
-# Try it: deblob-check --use-python linux-2.6.32/CREDITS
-# It hits even with our tiny testsuite:
-# AWK=false PYTHON=python deblob-check -t
-elif (${PYTHON-false} --version) > /dev/null 2>&1; then
+# processing some of our regular expressions.
+elif (${PYTHON-python} --version) > /dev/null 2>&1; then
   set_main_cmd=set_python_main
 # Sed takes GBs of RAM to compile all the huge regexps in the sed
 # script we generate with all known false positives and blobs in Linux.
@@ -415,6 +403,12 @@ case $1 in
   set_main_cmd=set_python_main;
   ;;
 
+--use-perl)
+  shift;
+  set_cmd=set_eqscript_cmd;
+  set_main_cmd=set_perl_main;
+  ;;
+       
 --use-awk)
   shift;
   set_cmd=set_eqscript_cmd;
@@ -439,19 +433,19 @@ esac
 
 case $1 in
 --version | -V)
-  sed -e '/^# '$name' version /,/^# Written by/ { s/^# //; p; }; d' < $0
+  ${SED-sed} -e '/^# '$name' version /,/^# Written by/ { s/^# //; p; }; d' < $0
   exit 0
   ;;
 
 -\? | -h)
-  sed -n -e '/^# usage:/,/# -h/ { /^# -/,/^$/{s/^# \(-.*\):.*/\1/p; d; }; s/^\(# \?\)\?//p; }' < $0 &&
+  ${SED-sed} -n -e '/^# usage:/,/# -h/ { /^# -/,/^$/{s/^# \(-.*\):.*/\1/p; d; }; s/^\(# \?\)\?//p; }' < $0 &&
   echo
   echo "run \`$name --help | more' for full usage"
   exit 0
   ;;
 
 --help | -H)
-  sed -n -e '/^# '$name' version /,/^[^#]/ s/^\(# \?\)\?//p' < $0
+  ${SED-sed} -n -e '/^# '$name' version /,/^[^#]/ s/^\(# \?\)\?//p' < $0
   exit 0
   ;;
 
@@ -700,9 +694,9 @@ set_except () {
   blobna 'request_ihex_firmware'
   blobna 'MODULE_FIRMWARE[     ]*[(][^\n;]*[)][        ]*[;]\([        \n]*MODULE_FIRMWARE[    ]*[(][^\n;]*[)][        ]*[;]\)*'
   blobna 'DEFAULT_FIRMWARE'
-  blobna '\(\.\|->\)firmware[  \n]*=[^=]'
+  blobna '\([.]\|->\)firmware[         \n]*=[^=]'
   blobna 'mod_firmware_load' # sound/
-  blobname '\.\(fw\|bin[0-9]*\|hex\|frm\|co[dx]\|cis\|dat\|elf\|xlx\|rfb\|ucode\|img\)["]'
+  blobname '[.]\(fw\|bin[0-9]*\|hex\|frm\|co[dx]\|cis\|dat\|elf\|xlx\|rfb\|ucode\|img\)["]'
 
   case $prefix$1 in
   */*linux*.tar* | */*kernel*.tar* | */*linux-*.*.*/*)
@@ -956,16 +950,16 @@ set_except () {
     accept '[  ]-[ ]move[ ]firmware[ ]loading[ ]to[ ]request_firmware[(][)]' drivers/staging/slicoss/README
     accept 'config[ ]FIRMWARE_IN_KERNEL.*let[ ]firmware[ ]be[ ]loaded[ ]from[ ]userspace\.' drivers/base/Kconfig
     accept '[   ]*and[ ]request_firmware[(][)][ ]in[ ]the[ ]source' drivers/base/Kconfig
-    accept 'static[ ]int[\n]_request_firmware[(]const[ ]struct[ ]firmware[ ][*][*]firmware_p,[ ]const[ ]char[ ][*]name,[^{]*[\n][{][\n]\([^}]\|[^\n}][}]*\)*[\n][}][\n]' drivers/base/firmware_class.c
-    accept 'static[ ]int[\n]request_firmware_work_func[(]void[ ][*]arg[)][\n][{][\n]\([^}]\|[^\n}][}]*\)*ret[ ]=[ ]_request_firmware[(]\([^}]\|[^\n}][}]*\)*[\n][}][\n]' drivers/base/firmware_class.c
-    accept '[/][*][*][\n][ ][*][ ]request_firmware:[ ]-[ ]send[ ]firmware[ ][^{]*[\n][{][\n]\([^}]\|[^\n}][}]*\)*[\n][}][\n]' drivers/base/firmware_class.c
-    accept '[/][*][*][\n][ ][*][ ]request_firmware_nowait:[ ]asynchronous[ ]version[^{]*[\n][{][\n]\([^}]\|[^\n}][}]*\)*[\n][}][\n]' drivers/base/firmware_class.c
+    accept 'static[ ]int[\n]_request_firmware[(]const[ ]struct[ ]firmware[ ][*][*]firmware_p,[ ]const[ ]char[ ][*]name,[^{]*[\n][{][\n]\([\n]*[^\n}][}]*\)*[\n]\+[}][\n]' drivers/base/firmware_class.c
+    accept 'static[ ]int[\n]request_firmware_work_func[(]void[ ][*]arg[)][\n][{][\n]\([\n]*[^\n}][}]*\)*ret[ ]=[ ]_request_firmware[(]\([\n]*[^\n}][}]*\)*[\n]\+[}][\n]' drivers/base/firmware_class.c
+    accept '[/][*][*][\n][ ][*][ ]request_firmware:[ ]-[ ]send[ ]firmware[ ][^{]*[\n][{][\n]\([\n]*[^\n}][}]*\)*[\n]\+[}][\n]' drivers/base/firmware_class.c
+    accept '[/][*][*][\n][ ][*][ ]request_firmware_nowait:[ ]asynchronous[ ]version[^{]*[\n][{][\n]\([\n]*[^\n}][}]*\)*[\n]\+[}][\n]' drivers/base/firmware_class.c
     accept 'EXPORT_SYMBOL[(]request_firmware\(_nowait\)\?[)][;]' drivers/base/firmware_class.c
     accept 'int[ ]request_firmware\(_nowait\)\?[(][^;]*[)][;]' include/linux/firmware.h
     accept 'static[ ]inline[ ]int[ ]request_firmware\(_nowait\)\?[(][^{]*[)][\n][{][\n][       ]return[ ]-EINVAL[;][\n][}]' include/linux/firmware.h
-    accept 'static[ ]inline[ ]int[\n]\(maybe_\)\?reject_firmware\(_nowait\)\?[(][^{;]*[)][\n][{][\n]\([^}]\|[^\n}][}]*\)*[\n][}]' include/linux/firmware.h
+    accept 'static[ ]inline[ ]int[\n]\(maybe_\)\?reject_firmware\(_nowait\)\?[(][^{;]*[)][\n][{][\n]\([\n]*[^\n}][}]*\)*[\n]\+[}]' include/linux/firmware.h
 
-    accept 'static[ ]inline[ ]int[ ]request_ihex_firmware\?[(][^{]*[)][\n][{][\n]\([^}]\|[^\n}][}]*\)*[\n][}][\n]' include/linux/ihex.h
+    accept 'static[ ]inline[ ]int[ ]request_ihex_firmware\?[(][^{]*[)][\n][{][\n]\([\n]*[^\n}][}]*\)*[\n]\+[}][\n]' include/linux/ihex.h
     ocomment '[/][*][ ]Optional[ ]firmware\([^\n]*[\n][ ][*]\)*[^\n]*[ ]MODULE_FIRMWARE[(][)]'
     oprepline '#define[ ]MODULE_FIRMWARE[(]_firmware[)]' include/linux/module.h
     accept '[ ][*][ ]Sample[ ]code[ ]on[ ]how[ ]to[ ]use[ ]request_firmware[(][)][ ]from[ ]drivers\.' samples/firmware_class/firmware_sample_driver.c
@@ -1010,7 +1004,7 @@ set_except () {
     blob '\(#\(ifdef[ ]AMB_NEW_MICROCODE\|else\|endif\)[\n]#\(define\|include\)[ ]UCODE2\?[(][^\n]*[\n]\)\+\([\n]*static[ ]\(u32\|region\)[ ]__devinitdata[ ]ucode_\(start\|\(regions\|data\)\[\]\)[ ]=[^;]*[;]\)*' drivers/atm/ambassador.c
 
     blobname '\(pca\|sba\)200e\(_ecd\)\?\.\(data\|bin[12]\?\)' 'drivers/atm/\(Makefile\|fore200e\(_mkfirm\)\?\.c\)'
-    blobna '[/][*][/]*\([*]*[^*/][^*/]*[/]*\)*[*]*PCA-200E[ ]firmware[ ][*][/]' drivers/atm/fore200e_mkfirm.c
+    blobna '[/][*][/]*\([*]*[^*/][/]*\)*[*]*PCA-200E[ ]firmware[ ][*][/]' drivers/atm/fore200e_mkfirm.c
     blobna '_fore200e_\(pca\|sba\)_fw_\(data\|size\)' drivers/atm/fore200e.c
     blob '#ifdef[ ]CONFIG_ATM_FORE200E_\(PCA\|SBA\)\([\n]extern[ ]const[ ]unsigned[ ]\(char\|int\)[ ]*_fore200e_\(pca\|sba\)_fw_\(data\[\]\|size\)[;]\)\+[\n]#endif\([\n]\+#ifdef[ ]CONFIG_ATM_FORE200E_\(PCA\|SBA\)\([\n]extern[ ]const[ ]unsigned[ ]\(char\|int\)[ ]*_fore200e_\(pca\|sba\)_fw_\(data\[\]\|size\)[;]\)\+[\n]#endif\)*' drivers/atm/fore200e.c
 
@@ -1031,15 +1025,15 @@ set_except () {
     blobname 'intelliport2\.bin' drivers/char/ip2/ip2main.c
 
     blob 'static[ ]unsigned[ ]char[ ]warp_g[24]00_t2\?gzs\?a\?f\?\[\][ ]=[ ][{][^{};]*[}][;]\([\n][\n]*static[ ]unsigned[ ]char[ ]warp_g[24]00_t2\?gzs\?a\?f\?\[\][ ]=[ ][{][^{};]*[}][;]\)*' drivers/gpu/drm/mga/mga_ucode.h
-    blob '\(#define[ ]WARP_UCODE_\(SIZE\|INSTALL\)[(][ ]*which\([^\n]*\\[      ]*[\n]\)*[^\n]*\|static[ ]const[ ]unsigned[ ]int[ ]mga_warp_g[24]00_microcode_size[ ]=[^;]*[;]\|static[ ]int[ ]mga_warp_install_g[24]00_microcode[(][^{]*[)][\n][{][\n]\([^}]\|[^\n}][}]*\)*[\n][}]\)\([\n][\n]*\(#define[ ]WARP_UCODE_\(SIZE\|INSTALL\)[(][ ]*which\([^\n]*\\[         ]*[\n]\)*[^\n]*\|static[ ]const[ ]unsigned[ ]int[ ]mga_warp_g[24]00_microcode_size[ ]=[^;]*[;]\|static[ ]int[ ]mga_warp_install_g[24]00_microcode[(][^{]*[)][\n][{][\n]\([^}]\|[^\n}][}]*\)*[\n][}]\)\)*' drivers/gpu/drm/mga/mga_warp.c
+    blob '\(#define[ ]WARP_UCODE_\(SIZE\|INSTALL\)[(][ ]*which\([^\n]*\\[      ]*[\n]\)*[^\n]*\|static[ ]const[ ]unsigned[ ]int[ ]mga_warp_g[24]00_microcode_size[ ]=[^;]*[;]\|static[ ]int[ ]mga_warp_install_g[24]00_microcode[(][^{]*[)][\n][{][\n]\([\n]*[^\n}][}]*\)*[\n]\+[}]\)\([\n][\n]*\(#define[ ]WARP_UCODE_\(SIZE\|INSTALL\)[(][ ]*which\([^\n]*\\[        ]*[\n]\)*[^\n]*\|static[ ]const[ ]unsigned[ ]int[ ]mga_warp_g[24]00_microcode_size[ ]=[^;]*[;]\|static[ ]int[ ]mga_warp_install_g[24]00_microcode[(][^{]*[)][\n][{][\n]\([\n]*[^\n}][}]*\)*[\n]\+[}]\)\)*' drivers/gpu/drm/mga/mga_warp.c
     blobna '\(case[ ]MGA_CARD_TYPE_G[^:]*:[    \n]*\)\+return[ ][^;]*mga_warp[^;]*microcode[^;]*[;]\([         \n]*\(case[ ]MGA_CARD_TYPE_G[^:]*:[     \n]*\)\+return[ ][^;]*mga_warp[^;]*microcode[^;]*[;][   ]*\)*' drivers/gpu/drm/mga/mga_warp.c
 
     blob 'static[ ]u32[ ]r128_cce_microcode\[\][ ]=[ ][{][^;]*[}][;]' drivers/gpu/drm/r128/r128_cce.c
-    blob 'static[ ]void[ ]r128_cce_load_microcode[(][^{]*[)][\n][{][\n]\([^}]\|[^\n}][}]*\)*[\n][}]' drivers/gpu/drm/r128/r128_cce.c
+    blob 'static[ ]void[ ]r128_cce_load_microcode[(][^{]*[)][\n][{][\n]\([\n]*[^\n}][}]*\)*[\n]\+[}]' drivers/gpu/drm/r128/r128_cce.c
     # blobna 'R128_WRITE[(]R128_PM4_MICROCODE_DATA[HL],[\n      ]*r128_cce_microcode\[i[ ][*][ ]2\([ ][+][ ]1\)\?\][)]\([;][\n         ]*R128_WRITE[(]R128_PM4_MICROCODE_DATA[HL],[\n   ]*r128_cce_microcode\[i[ ][*][ ]2\([ ][+][ ]1\)\?\][)]\)*' drivers/gpu/drm/r128/r128_cce.c
 
     blob 'static[ ]const[ ]u32[ ]R[SV0-9]*[05]_\(c\|pf\)p_microcode\[\]\(\[[23]\]\)\?[ ]=[ ][{][^;]*[}][;]\([\n][\n]*static[ ]const[ ]u32[ ]R[SV0-9]*[05]_\(c\|pf\)p_microcode\[\]\(\[[23]\]\)\?[ ]=[ ][{][^;]*[}][;]\)*' 'drivers/gpu/drm/radeon/\(radeon\|r600\)_microcode\.h'
-    blob 'static[ ]void[ ]r\(adeon\|[167]00\)_cp_load_microcode[(][^{]*[)][\n][{][\n]\([^}]\|[^\n}][}]*\)*cp_microcode\([^}]\|[^\n}][}]*\)*[\n][}]' 'drivers/gpu/drm/radeon/r\(\(adeon\|600\)_cp\|100\)\.c'
+    blob 'static[ ]void[ ]r\(adeon\|[167]00\)_cp_load_microcode[(][^{]*[)][\n][{][\n]\([\n]*[^\n}][}]*\)*cp_microcode\([\n]*[^\n}][}]*\)*[\n]\+[}]' 'drivers/gpu/drm/radeon/r\(\(adeon\|600\)_cp\|100\)\.c'
     # blobna 'RADEON_WRITE[(]R\(ADEON\|600\)_CP_\(ME_RAM\|PFP_UCODE\)_DATA[HL]\?,[\n    ]*R[SV0-9]*[05]_\(c\|pf\)p_microcode\[i\]\(\[[012]\]\)\?[)]\([;][\n    ]*RADEON_WRITE[(]R\(ADEON\|600\)_CP_\(ME_RAM\|PFP_UCODE\)_DATA[HL]\?,[\n         ]*R[SV0-9]*[05]_\(c\|pf\)p_microcode\[i\]\(\[[012]\]\)\?[)]\)*' 'drivers/gpu/drm/radeon/\(radeon\|r600\)_cp\.c'
 
     blob 'sub[ ]\(sp887[0x]\|tda1004\(5\|6\(lifeview\)\?\)\|av7110\|dec\(2\(00\|54\)0t\|3000s\)\|opera1\|vp7041\|dibusb\|nxt200[24]cx\(23\(1xx\|855\)\|18\)\|pvrusb2\|or51\(211\|132_\(qam\|vsb\)\)\|bluebird\|mpc718\)[ ]*[{]\([^}]*\|[^\n}][}]*\)[\n][}]\([\n][\n]*sub[ ]\(sp887[0x]\|tda1004\(5\|6\(lifeview\)\?\)\|av7110\|dec\(2\(00\|54\)0t\|3000s\)\|opera1\|vp7041\|dibusb\|nxt200[24]cx\(23\(1xx\|855\)\|18\)\|pvrusb2\|or51\(211\|132_\(qam\|vsb\)\)\|bluebird\|mpc718\)[ ]*[{]\([^}]*\|[^\n}][}]*\)[\n][}]\)*' Documentation/dvb/get_dvb_firmware
@@ -1053,7 +1047,7 @@ set_except () {
     blobna '[\n][      ]scriptlen[ ]=[ ]sizeof[(]script[)][^;]*[;][\n][        ]for[^{]*scriptlen[^{]*[{][^}]*[^\n     }]' drivers/media/dvb/dvb-usb/af9005-fe.c
 
     accept 'struct[ ]\(sp8870\|tda1004x\)_config[\n][{][^}]*[(][*]request_firmware[)][^}]*[\n][}][;]' 'drivers/media/dvb/frontends/\(sp8870\|tda1004x\)\.h'
-    blob '[/][*][/]*\([*]*[^*/][^*/]*[/]*\)*[*]*get_dvb_firmware[/]*\([*]*[^*/][^*/]*[/]*\)*[*]*[*][/]\([\n]\(#define[ ]\(\([^\n       ]*_DEFAULT\|NONFREE\)_FIRMWARE\|["][^"]*["]\)[ ]\([^\n]\|[\\][\n]\)*\|[/][*][(]DEBLOBBED[)][*][/]\)\)*' 'drivers/media/dvb/frontends/\(nxt200x\|or51211\|sp887[0x]\|tda1004[8x]\)\.c'
+    blob '[/][*][/]*\([*]*[^*/][/]*\)*[*]*get_dvb_firmware[/]*\([*]*[^*/][/]*\)*[*]*[*][/]\([\n]\(#define[ ]\(\([^\n   ]*_DEFAULT\|NONFREE\)_FIRMWARE\|["][^"]*["]\)[ ]\([^\n]\|[\\][\n]\)*\|[/][*][(]DEBLOBBED[)][*][/]\)\)*' 'drivers/media/dvb/frontends/\(nxt200x\|or51211\|sp887[0x]\|tda1004[8x]\)\.c'
     blobname 'dvb-fe-sp8870\.fw' drivers/media/dvb/frontends/sp8870.c
     blobname 'dvb-fe-tda1004[56]\.fw' drivers/media/dvb/frontends/tda1004x.c
 
@@ -1074,21 +1068,21 @@ set_except () {
 
     blob 'static[ ]u32[ ]tigon2\?Fw\(Text\|Rodata\|Data\)\[[(]MAX_\(TEXT\|RODATA\|DATA\)_LEN[/]4[)][ ][+][ ]1\][ ]__devinitdata[ ]=[ ][{][^}]*[}][;]\([\n]static[ ]u32[ ]tigon2\?Fw\(Text\|Rodata\|Data\)\[[(]MAX_\(TEXT\|RODATA\|DATA\)_LEN[/]4[)][ ][+][ ]1\][ ]__devinitdata[ ]=[ ][{][^}]*[}][;]\)*' drivers/net/acenic_firwmare.h
     blob '#define[ ]tigon2\?Fw[^ ]*\(Addr\|Len\)[ ]0x[^\n]*\([\n]#define[ ]tigon2\?Fw[^ ]*\(Addr\|Len\)[ ]0x[^\n]*\)\+' drivers/net/acenic_firmware.h
-    blob '\([/][*][/]*\([*]*[^*/][^*/]*[/]*\)*[*]*Do[ ]not[ ]try[ ]to[ ]clear[/]*\([*]*[^*/][^*/]*[/]*\)*[*]*[*][/][\n][       ]\)\?ace_clear[^;]*[;][\n]\([^}]*[{][^}]*ace_copy[^}]*tigon2\?Fw[^}]*[}]\)*[\n]\+[      ]return[ ]0[;][\n][}]' drivers/net/acenic.c
+    blob '\([/][*][/]*\([*]*[^*/][/]*\)*[*]*Do[ ]not[ ]try[ ]to[ ]clear[/]*\([*]*[^*/][/]*\)*[*]*[*][/][\n][   ]\)\?ace_clear[^;]*[;][\n]\([^}]*[{][^}]*ace_copy[^}]*tigon2\?Fw[^}]*[}]\)*[\n]\+[      ]return[ ]0[;][\n][}]' drivers/net/acenic.c
     blob 'if[ ][(]\(ACE_IS_TIGON_I[(]ap[)]\|ap->version[ ]==[ ]2\)[)][\n][     ][      ]writel[(]tigon2\?FwStartAddr,[ ][&]regs->Pc[)][;]\([\n][       ]if[ ][(]\(ACE_IS_TIGON_I[(]ap[)]\|ap->version[ ]==[ ]2\)[)][\n][       ][      ]writel[(]tigon2\?FwStartAddr,[ ][&]regs->Pc[)][;]\)*' drivers/net/acenic.c
 
     blob '#include[ ]["]starfire_firmware\.h["]' drivers/net/starfire.c
-    blob '[/][*][/]*\([*]*[^*/][^*/]*[/]*\)*[*]*Load[ ]Rx[/]Tx[ ]firmware[/]*\([*]*[^*/][^*/]*[/]*\)*[*]*[*][/]\([\n][ ]for[ ][(][^)]*FIRMWARE_[RT]X_SIZE[^)]*[)][\n][ ][      ]writel[^;]*firmware_[rt]x[^;]*[;]\)\+' drivers/net/starfire.c
+    blob '[/][*][/]*\([*]*[^*/][/]*\)*[*]*Load[ ]Rx[/]Tx[ ]firmware[/]*\([*]*[^*/][/]*\)*[*]*[*][/]\([\n][     ]for[ ][(][^)]*FIRMWARE_[RT]X_SIZE[^)]*[)][\n][ ][      ]writel[^;]*firmware_[rt]x[^;]*[;]\)\+' drivers/net/starfire.c
 
     blob 'static[ ]\(u8\|const[ ]u32\|struct[ ]fw_info\)[ ]bnx2_\(\(COM\|CP\|[RT]XP\|TPAT\)_b0[69]Fw\(Text\|Data\|Rodata\)\|\(xi_\)\?rv2p_proc[12]\|\(com\|cp\|[rt]xp\|tpat\)_fw_0[69]\)\(\[[^]};]*\]\)*[ ]=[ ][{][^}]*[}][;]\([\n][\n]*static[ ]\(u8\|const[ ]u32\|struct[ ]fw_info\)[ ]bnx2_\(\(COM\|CP\|[RT]XP\|TPAT\)_b0[69]Fw\(Text\|Data\|Rodata\)\|\(xi_\)\?rv2p_proc[12]\|\(com\|cp\|[rt]xp\|tpat\)_fw_0[69]\)\(\[[^]};]*\]\)*[ ]=[ ][{][^}]*[}][;]\)*' 'drivers/net/bnx2_fw2\?.h'
     blob '#include[ ]["]bnx2_fw\.h["][\n][\n]*#include[ ]["]bnx2_fw2\.h["]' drivers/net/bnx2.c
-    blob 'static[ ]void[\n]load_rv2p_fw[(][^{]*[)][\n][{][\n]\([^}]\|[^\n}][}]*\)*[\n][}]' drivers/net/bnx2.c
-    blob 'static[ ]int[\n]bnx2_init_cpus[(][^{]*[)][\n][{][\n]\([^}]\|[^\n}][}]*\)*[\n][}]' drivers/net/bnx2.c
+    blob 'static[ ]void[\n]load_rv2p_fw[(][^{]*[)][\n][{][\n]\([\n]*[^\n}][}]*\)*[\n]\+[}]' drivers/net/bnx2.c
+    blob 'static[ ]int[\n]bnx2_init_cpus[(][^{]*[)][\n][{][\n]\([\n]*[^\n}][}]*\)*[\n]\+[}]' drivers/net/bnx2.c
 
     # init_data_e1h? might actually be just data, but it doesn't
     # really matter.
     blob 'static[ ]const[ ]u32[ ]\(init\?\|[tucx]sem_\(int_table\|pram\)\)_data_e1h\?\[\][ ]=[ ][{][^}]*[}][;]\([\n][\n]*static[ ]const[ ]u32[ ]\(init\?\|[tucx]sem_\(int_table\|pram\)\)_data_e1h\?\[\][ ]=[ ][{][^}]*[}][;]\)*' drivers/net/bnx2x_init_values.h
-    blob 'static[ ]\(void[ ]\|const[ ]u32[ ][*]\)bnx2x_\(sel_blob\|init_wr_wb\|init_block\)[(][^{]*[)][\n][{][\n]\([^}]\|[^\n}][}]*\)*[\n][}]\([\n][\n]*static[ ]\(void[ ]\|const[ ]u32[ ][*]\)bnx2x_\(sel_blob\|init_wr_wb\|init_block\)[(][^{]*[)][\n][{][\n]\([^}]\|[^\n}][}]*\)*[\n][}]\)*' 'drivers/net/bnx2x_init\(_ops\)\?\.h'
+    blob 'static[ ]\(void[ ]\|const[ ]u32[ ][*]\)bnx2x_\(sel_blob\|init_wr_wb\|init_block\)[(][^{]*[)][\n][{][\n]\([\n]*[^\n}][}]*\)*[\n]\+[}]\([\n][\n]*static[ ]\(void[ ]\|const[ ]u32[ ][*]\)bnx2x_\(sel_blob\|init_wr_wb\|init_block\)[(][^{]*[)][\n][{][\n]\([\n]*[^\n}][}]*\)*[\n]\+[}]\)*' 'drivers/net/bnx2x_init\(_ops\)\?\.h'
 
     blobname 'sun[/]cassini\.bin' drivers/net/cassini.c
 
@@ -1096,12 +1090,12 @@ set_except () {
     blobna 'for[ ][(][^\n]*ARRAY_SIZE[(]\(sr\|twinax\)_edc[)][^\n]*[)][\n][^;]*mdio_write[^;]*[;]' drivers/net/cxgb3/ael1002.c
     blobname '\(cxgb3[/]\)\?t3\(fw\|\(%c\|.\)_p\(rotocol_\)\?sram\)-\(%d\|[0-9]*\)\.\(%d\|[0-9]*\)\.\(%d\|[0-9]*\)\.bin' drivers/net/cxgb3/cxgb3_main.c
 
-    blob '\([/][*][*]*[*][/][\n]*\)*\([/][*][/]*\([*]*[^*/][^*/]*[/]*\)*[*]*Micro[ ]code[/]*\([*]*[^*/][^*/]*[/]*\)*[*]*8086:[/]*\([*]*[^*/][^*/]*[/]*\)*[*]*[*][/]\([\n]*[/][*][/]*\([*]*[^*/][^*/]*[/]*\)*[*]*[*][/]\)*\|#define[ ][ ]*D10\(1M\(_B\)\?\|1S\|2_E\)_\(CPUSAVER_\(TIMER\|BUNDLE\|MIN_SIZE\)_DWORD\|RCVBUNDLE_UCODE\)[   ]\(\\[\n]\|[^\n]\)*\)\([\n]*[/][*][/]*\([*]*[^*/][^*/]*[/]*\|[*]*[*][/][\n]*[/][*]\)*[*]*Micro[ ]code[/]*\([*]*[^*/][^*/]*[/]*\)*[*]*8086:[/]*\([*]*[^*/][^*/]*[/]*\)*[*]*[*][/]\([\n]*[/][*][/]*\([*]*[^*/][^*/]*[/]*\)*[*]*[*][/]\)*\|[\n][\n]*#define[ ][ ]*D10\(1M\(_B\)\?\|1S\|2_E\)_\(CPUSAVER_\(TIMER\|BUNDLE\|MIN_SIZE\)_DWORD\|RCVBUNDLE_UCODE\)[      ]\(\\[\n]\|[^\n]\)*\)*' drivers/net/e100.c
-    blobna '\([/][*][/]*\([*]*[^*/][^*/]*[/]*\)*[*]*[*][/][\n]*[       ][      ]\)\(ucode\[opts->\(timer\|bundle\|min_size\)_dword\][ ].=[ ][^;]*[;][\n][\n]*[ ][      ]\)*[^}]*UCODE_SIZE[^}]*cb_ucode[^}]*return[;][\n][     ][}]' drivers/net/e100.c
+    blob '\([/][*][*]*[*][/][\n]*\)*\([/][*][/]*\([*]*[^*/][/]*\)*[*]*Micro[ ]code[/]*\([*]*[^*/][/]*\)*[*]*8086:[/]*\([*]*[^*/][/]*\)*[*]*[*][/]\([\n]*[/][*][/]*\([*]*[^*/][/]*\)*[*]*[*][/]\)*\|#define[ ][ ]*D10\(1M\(_B\)\?\|1S\|2_E\)_\(CPUSAVER_\(TIMER\|BUNDLE\|MIN_SIZE\)_DWORD\|RCVBUNDLE_UCODE\)[   ]\(\\[\n]\|[^\n]\)*\)\([\n]*[/][*][/]*\([*]*[^*/][^*/]*[/]*\|[*]*[*][/][\n]*[/][*]\)*[*]*Micro[ ]code[/]*\([*]*[^*/][/]*\)*[*]*8086:[/]*\([*]*[^*/][/]*\)*[*]*[*][/]\([\n]*[/][*][/]*\([*]*[^*/][/]*\)*[*]*[*][/]\)*\|[\n][\n]*#define[ ][ ]*D10\(1M\(_B\)\?\|1S\|2_E\)_\(CPUSAVER_\(TIMER\|BUNDLE\|MIN_SIZE\)_DWORD\|RCVBUNDLE_UCODE\)[        ]\(\\[\n]\|[^\n]\)*\)*' drivers/net/e100.c
+    blobna '\([/][*][/]*\([*]*[^*/][/]*\)*[*]*[*][/][\n]*[     ][      ]\)\(ucode\[opts->\(timer\|bundle\|min_size\)_dword\][ ].=[ ][^;]*[;][\n][\n]*[ ][      ]\)*[^}]*UCODE_SIZE[^}]*cb_ucode[^}]*return[;][\n][     ][}]' drivers/net/e100.c
 
     blob 'static[ ]unsigned[ ]char[ ]__devinitdata[ ]lanai4_\(code\|data\)\[[0-9]*\][ ]=[ ][{][^;]*[}][;]' drivers/net/myri_code.h
     blob '#include[ ]["]myri_code\.h["]' drivers/net/myri_sbus.c
-    blobna '\([/][*][/]*\([*]*[^*/][^*/]*[/]*\)*[*]*[*][/][\n   ]*\)\?for[ ][(][^\n]*sizeof[(]lanai4_\(code\|data\)[^\n]*[)][\n][^\n]*sbus_writeb[^;]*lanai4_\(code\|data\)[^;]*lanai4_code_off[^;]*[;]\([\n    ]*\([/][*][/]*\([*]*[^*/][^*/]*[/]*\)*[*]*[*][/][\n     ]*\)\?for[ ][(][^\n]*sizeof[(]lanai4_\(code\|data\)[^\n]*[)][\n][^\n]*sbus_writeb[^;]*lanai4_\(code\|data\)[^;]*lanai4_\(code\|data\)_off[^;]*[;]\)*' drivers/net/myri_sbus.c
+    blobna '\([/][*][/]*\([*]*[^*/][/]*\)*[*]*[*][/][\n         ]*\)\?for[ ][(][^\n]*sizeof[(]lanai4_\(code\|data\)[^\n]*[)][\n][^\n]*sbus_writeb[^;]*lanai4_\(code\|data\)[^;]*lanai4_code_off[^;]*[;]\([\n    ]*\([/][*][/]*\([*]*[^*/][/]*\)*[*]*[*][/][\n   ]*\)\?for[ ][(][^\n]*sizeof[(]lanai4_\(code\|data\)[^\n]*[)][\n][^\n]*sbus_writeb[^;]*lanai4_\(code\|data\)[^;]*lanai4_\(code\|data\)_off[^;]*[;]\)*' drivers/net/myri_sbus.c
 
     blob 'static[ ]u32[ ]s_firmLoad\[\][ ]=[ ][{][^;]*[}][;]' drivers/net/tehuti_fw.h
     blob 'bdx_tx_push_desc_safe[^;]*s_firmLoad[^;]*[;]' drivers/net/tehuti.c
@@ -1109,14 +1103,14 @@ set_except () {
 
     blob '[ ][*][ ]Firmware[ ]is:[\n][ ][*][   ]Derived[ ]from[ ]proprietary[^/]*notice[ ]is[ ]accompanying[ ]it\.[\n][ ][*][/]' drivers/net/tg3.c
     blob 'Derived[ ]from[ ]proprietary[ ]unpublished[ ]source[ ]code' drivers/net/tg3.c
-    blob '\(static[ ]const[ ]\)\?u32[ ]tg3\(Tso5\?\)\?Fw\(Text\|Rodata\|Data\)\[[^{]*\][ ]=[ ][{][^}]*[}][;]\([\n][\n]*\(static[ ]const[ ]u32[ ]tg3\(Tso5\?\)\?Fw\(Text\|Rodata\|Data\)\[[^{]*\][ ]=[ ][{][^}]*[}][;]\|#if[ ]0\([ ][/][*][/]*\([*]*[^*/][^*/]*[/]*\)*[*]*[*][/]\)\?[\n]\(static[ ]const[ ]\)\?u32[ ]tg3\(Tso5\?\)\?Fw\(Text\|Rodata\|Data\)\[[^{]*\][ ]=[ ][{][^}]*[}][;][\n]#endif\)\)*' drivers/net/tg3.c
+    blob '\(static[ ]const[ ]\)\?u32[ ]tg3\(Tso5\?\)\?Fw\(Text\|Rodata\|Data\)\[[^{]*\][ ]=[ ][{][^}]*[}][;]\([\n][\n]*\(static[ ]const[ ]u32[ ]tg3\(Tso5\?\)\?Fw\(Text\|Rodata\|Data\)\[[^{]*\][ ]=[ ][{][^}]*[}][;]\|#if[ ]0\([ ][/][*][/]*\([*]*[^*/][/]*\)*[*]*[*][/]\)\?[\n]\(static[ ]const[ ]\)\?u32[ ]tg3\(Tso5\?\)\?Fw\(Text\|Rodata\|Data\)\[[^{]*\][ ]=[ ][{][^}]*[}][;][\n]#endif\)\)*' drivers/net/tg3.c
 
     blob 'static[ ]const[ ]u8[ ]typhoon_firmware_image\[\][ ]=[ ][{][^}]*[}][;]' drivers/net/typhoon-firmware.h
 
     blobna 'licensed[^\n]*strictly[ ]for[ ]use[^\n]*[\n]*[^\n]*COPS[ ]LocalTalk' 'drivers/net/appletalk/cops_\(ff\|lt\)drv\.h'
     blob 'static[ ]const[ ]unsigned[ ]char[ ]ffdrv_code\[\][ ]=[ ][{][^}]*[}][;]' drivers/net/appletalk/cops_ffdrv.h
     blob 'static[ ]const[ ]unsgined[ ]char[ ]ltdrv_code\[\][ ]=[ ][{][^}]*[}][;]' drivers/net/appletalk/cops_ltdrv.h
-    blob '#include[ ]["]cops_\(lt\|ff\)drv\.h["][      ]*\([/][*][/]*\([*]*[^*/][^*/]*[/]*\)*[*]*Firmware[/]*\([*]*[^*/][^*/]*[/]*\)*[*]*[*][/]\)\?\([\n][\n]*#include[ ]["]cops_\(lt\|ff\)drv\.h["][  ]*\([/][*][/]*\([*]*[^*/][^*/]*[/]*\)*[*]*Firmware[/]*\([*]*[^*/][^*/]*[/]*\)*[*]*[*][/]\)\?\)*' drivers/net/appletalk/cops.c
+    blob '#include[ ]["]cops_\(lt\|ff\)drv\.h["][      ]*\([/][*][/]*\([*]*[^*/][/]*\)*[*]*Firmware[/]*\([*]*[^*/][/]*\)*[*]*[*][/]\)\?\([\n][\n]*#include[ ]["]cops_\(lt\|ff\)drv\.h["][      ]*\([/][*][/]*\([*]*[^*/][/]*\)*[*]*Firmware[/]*\([*]*[^*/][/]*\)*[*]*[*][/]\)\?\)*' drivers/net/appletalk/cops.c
 
     blob 'static[ ]unsigned[ ]char[ ]bits_1200\[\][ ]*=[ ][{][^}]*[}][;]' drivers/net/hamradio/yam1200.h
     blob 'static[ ]unsigned[ ]char[ ]bits_9600\[\][ ]*=[ ][{][^}]*[}][;]' drivers/net/hamradio/yam9600.h
@@ -1128,7 +1122,7 @@ set_except () {
 
     blob 'static[ ]const[ ]u8[ ]microcode\[\][ ]=[ ][{][^}]*[}][ ]*[;]' drivers/net/tokenring/3c359_microcode.h
     blob '#include[ ]["]3c359_microcode\.h["]' drivers/net/tokenring/3c359.c
-    blobna 'start[ ]=[ ][(]0xFFFF[ ]-[ ][(]mc_size[)][^;]*[;][\n       ]*[/][*][/]*\([*]*[^*/][^*/]*[/]*\)*[*]*[*][/][\n       ]*printk[(]KERN_INFO[ ]["]3C359:[ ]Uploading[ ]Microcode:[ ]["][)][;][\n        ]*for[ ][(][^{]*\(mc_size[^{]*[)][ ][{][^}]*writeb[(]microcode\[\|[)][ ][{][^}]*writeb[(]microcode\[mc_size\)[^}]*[}]\([\n][    ]*printk[^\n]*[;][\n    ]*for[ ][(][^{]*\(mc_size[^{]*[)][ ][{][^}]*writeb[(]microcode\[\|[)][ ][{][^}]*writeb[(]microcode\[mc_size\)[^}]*[}]\)*' drivers/net/tokenring/3c359.c
+    blobna 'start[ ]=[ ][(]0xFFFF[ ]-[ ][(]mc_size[)][^;]*[;][\n       ]*[/][*][/]*\([*]*[^*/][/]*\)*[*]*[*][/][\n     ]*printk[(]KERN_INFO[ ]["]3C359:[ ]Uploading[ ]Microcode:[ ]["][)][;][\n        ]*for[ ][(][^{]*\(mc_size[^{]*[)][ ][{][^}]*writeb[(]microcode\[\|[)][ ][{][^}]*writeb[(]microcode\[mc_size\)[^}]*[}]\([\n][    ]*printk[^\n]*[;][\n    ]*for[ ][(][^{]*\(mc_size[^{]*[)][ ][{][^}]*writeb[(]microcode\[\|[)][ ][{][^}]*writeb[(]microcode\[mc_size\)[^}]*[}]\)*' drivers/net/tokenring/3c359.c
 
     blobname 'tr_smctr\.bin' drivers/net/tokenring/smctr.c
 
@@ -1141,7 +1135,7 @@ set_except () {
     blob 'unsigned[ ]short[ ]sbus_risc_code01\[\][ ]__devinitdata[ ]=[ ][{][^}]*[}][;]' drivers/scsi/qlogicpti_asm.c
     blob '#include[ ]["]qlogicpti_asm\.c["]' drivers/scsi/qlogicpti.c
 
-    blob '\([/][*][ ]Microcode[/]*\([*]*[^*/][^*/]*[/]*\)*[*]*[*][/][\n]*\)\?static[ ]\(u\(nsigned[ ]\)\?char\|unsigned[ ]short\|ADV_DCNT\)[ ]_\(asc_mcode\|adv_asc3\(550\|8C\(08\|16\)00\)\)_\(buf\[\][ ]=[ ][{][^}]*[}]\|size[ ]=[ ]sizeof[^;]*\|chksum[ ]=[ ]0x[^;]*\)[;]\([        ]*[/][*][/]*\([*]*[^*/][^*/]*[/]*\)*[*]*[*][/]\)\?\([\n][\n]*\([/][*][ ]Microcode[/]*\([*]*[^*/][^*/]*[/]*\)*[*]*[*][/][\n]*\)\?static[ ]\(u\(nsigned[ ]\)\?char\|unsigned[ ]short\|ADV_DCNT\)[ ]_\(asc_mcode\|adv_asc3\(550\|8C\(08\|16\)00\)\)_\(buf\[\][ ]=[ ][{][^}]*[}]\|size[ ]=[ ]sizeof[^;]*\|chksum[ ]=[ ]0x[^;]*\)[;]\([      ]*[/][*][/]*\([*]*[^*/][^*/]*[/]*\)*[*]*[*][/]\)\?\)*' drivers/scsi/advansys.c
+    blob '\([/][*][ ]Microcode[/]*\([*]*[^*/][/]*\)*[*]*[*][/][\n]*\)\?static[ ]\(u\(nsigned[ ]\)\?char\|unsigned[ ]short\|ADV_DCNT\)[ ]_\(asc_mcode\|adv_asc3\(550\|8C\(08\|16\)00\)\)_\(buf\[\][ ]=[ ][{][^}]*[}]\|size[ ]=[ ]sizeof[^;]*\|chksum[ ]=[ ]0x[^;]*\)[;]\([      ]*[/][*][/]*\([*]*[^*/][/]*\)*[*]*[*][/]\)\?\([\n][\n]*\([/][*][ ]Microcode[/]*\([*]*[^*/][/]*\)*[*]*[*][/][\n]*\)\?static[ ]\(u\(nsigned[ ]\)\?char\|unsigned[ ]short\|ADV_DCNT\)[ ]_\(asc_mcode\|adv_asc3\(550\|8C\(08\|16\)00\)\)_\(buf\[\][ ]=[ ][{][^}]*[}]\|size[ ]=[ ]sizeof[^;]*\|chksum[ ]=[ ]0x[^;]*\)[;]\([  ]*[/][*][/]*\([*]*[^*/][/]*\)*[*]*[*][/]\)\?\)*' drivers/scsi/advansys.c
 
     blob '\(#ifdef[ ]UNIQUE_FW_NAME[\n]\)\?static[ ]unsigned[ ]short[ ]\(risc\|fw12\(80e\|160\)i\)_code01\[\][ ]=[ ][{]\([\n]#else[\n]static[ ]unsigned[ ]short[ ]risc_code01\[\][ ]=[ ][{][\n]#endif[\n]\)\?[^}]*[}][;]\([\n][\n]*\(#ifdef[ ]UNIQUE_FW_NAME[\n]\)\?static[ ]unsigned[ ]short[ ]\(risc_code\|fw12\(80e\|160\)i\)_length01[ ]=[ ][^;]*[;]\([\n]#else[\n]static[ ]unsigned[ ]short[ ]risc_code_length01[ ]=[ ][^;]*[;][\n]#endif\)\?\)\?' 'drivers/scsi/ql1\(04\|2\(8\|16\)\)0_fw\.h'
 
@@ -1152,7 +1146,7 @@ set_except () {
     blobname 'keyspan[/]\(mpr\|usa\(18x\|19\(q[iw]\|w\)\?\|28\(x\(a\|b\)\?\)\?\|49w\(lc\)\?\)\)\.fw' drivers/usb/serial/keyspan.c
 
     accept '[  ][      ]fw_name[ ]=[ ]["]keyspan_pda[/]\(keyspan_pda\|xircom_pgs\)\.fw["][;]' drivers/usb/serial/keyspan_pda.c
-    blobna 'fw_name[ ]=[ ]\([^}]\|[^\n}][}]*\)*\([/][*]KEYSPAN_PDA[*][/]\)\?request_ihex_firmware' drivers/usb/serial/keyspan_pda.c
+    blobna 'fw_name[ ]=[ ]\([\n]*[^\n}][}]*\)*\([/][*]KEYSPAN_PDA[*][/]\)\?request_ihex_firmware' drivers/usb/serial/keyspan_pda.c
     accept '[  ]if[ ][(][/][*]KEYSPAN_PDA[*][/]request_ihex_firmware' drivers/usb/serial/keyspan_pda.c
 
     blobname 'edgeport[/]\(boot\|down\)2\?\.fw' drivers/usb/serial/io_edgeport.c
@@ -1215,8 +1209,8 @@ set_except () {
     blobname 'cyzfirm\.bin' drivers/char/cyclades.c
 
     accept 'MODULE_FIRMWARE[(]["]dsp56k[/]bootstrap\.bin["][)][;]' drivers/char/dsp56k.c
-    blobna 'const[ ]char[ ]fw_name\[\][ ]=[ ]["]dsp56k[/]bootstrap\.bin["][;]\([^}]\|[^\n}][}]*\)*request_firmware\([^}]\|[^\n}][}]*\)*[\n][   ]err[ ]=[ ]request_firmware[(][&]fw,[ ]fw_name,[ ]' drivers/char/dsp56k.c
-    accept '[  ]const[ ]char[ ]fw_name\[\][ ]=[ ]["]dsp56k[/]bootstrap\.bin["][;]\([^}]\|[^\n}][}]*\)*[\n][    ]err[ ]=[ ]request_firmware[(][&]fw,[ ]fw_name,[ ]' drivers/char/dsp56k.c
+    blobna 'const[ ]char[ ]fw_name\[\][ ]=[ ]["]dsp56k[/]bootstrap\.bin["][;]\([\n]*[^\n}][}]*\)*request_firmware\([\n]*[^\n}][}]*\)*[\n]\+[   ]err[ ]=[ ]request_firmware[(][&]fw,[ ]fw_name,[ ]' drivers/char/dsp56k.c
+    accept '[  ]const[ ]char[ ]fw_name\[\][ ]=[ ]["]dsp56k[/]bootstrap\.bin["][;]\([\n]*[^\n}][}]*\)*[\n]\+[   ]err[ ]=[ ]request_firmware[(][&]fw,[ ]fw_name,[ ]' drivers/char/dsp56k.c
 
     blobname 'isi\(6\(08\|\(08\|16\)em\)\|46\(08\|16\)\)\.bin' drivers/char/isicom.c
 
@@ -1237,10 +1231,10 @@ set_except () {
     blobname 'dvb-fe-xc5000-1\.1\.fw' drivers/media/common/tuners/xc5000.c
 
     blobname '4210\(100[12]\|%4X\)\.sb' drivers/net/irda/irda-usb.c
-    blobna '[/][*][    \n*]*[ ]Known[ ]firmware[/]*\([*]*[^*/][^*/]*[/]*\)*[*]*\(STIR421x\|4210\(100[12]\|%4X\)\.sb\)[/]*\([*]*[^*/][^*/]*[/]*\)*[*]*[*][/]' drivers/net/irda/irda-usb.c
+    blobna '[/][*][    \n*]*[ ]Known[ ]firmware[/]*\([*]*[^*/][/]*\)*[*]*\(STIR421x\|4210\(100[12]\|%4X\)\.sb\)[/]*\([*]*[^*/][/]*\)*[*]*[*][/]' drivers/net/irda/irda-usb.c
 
     blobname 'myri10ge_\(rss_\)\?ethp\?_z8e\.dat' drivers/net/myri10ge.c
-    blobna 'If[ ]the[ ]driver[ ]can[ ]neither[ ]enable[ ]ECRC[/]*\([*]*[^*/][^*/]*[/]*\)*[*]*myri10ge_\(rss_\)\?ethp\?_z8e\.dat[/]*\([*]*[^*/][^*/]*[/]*\)*[*]*[*][/]' drivers/net/myri10ge.c
+    blobna 'If[ ]the[ ]driver[ ]can[ ]neither[ ]enable[ ]ECRC[/]*\([*]*[^*/][/]*\)*[*]*myri10ge_\(rss_\)\?ethp\?_z8e\.dat[/]*\([*]*[^*/][/]*\)*[*]*[*][/]' drivers/net/myri10ge.c
 
     blobname 'spider_fw\.bin' drivers/net/spider_net.h
 
@@ -1261,7 +1255,7 @@ set_except () {
     blobna 'if[ ][(]IPW2100_FW_MAJOR[^{]*[{][^}]*[     ][}]' 'drivers/net/wireless/\(ipw2x00/\)\?ipw2100\.c'
     blobname '["]["][ ]x[ ]["]\.fw["]' 'drivers/net/wireless/\(ipw2x00/\)\?ipw2100\.c'
 
-    accept '[/][*][ ]Call[ ]this[ ]function[ ]from[ ]process[ ]context[/]*\([*]*[^*/][^*/]*[/]*\)*[*]*request_firmware' 'drivers/net/wireless/\(ipw2x00/\)\?ipw2200.c'
+    accept '[/][*][ ]Call[ ]this[ ]function[ ]from[ ]process[ ]context[/]*\([*]*[^*/][/]*\)*[*]*request_firmware' 'drivers/net/wireless/\(ipw2x00/\)\?ipw2200.c'
     blobname 'ipw2200-\(i\?bss\|sniffer\)\.fw' 'drivers/net/wireless/\(ipw2x00/\)\?ipw2200.c'
     accept '[  ][      ]IPW_ERROR[(]["]%s[ ]request_firmware[ ]failed' 'drivers/net/wireless/\(ipw2x00/\)\?ipw2200.c'
 
@@ -1279,7 +1273,7 @@ set_except () {
     blobname 'sd\(8385\|868[68]\)\(_helper\)\?\.bin' drivers/net/wireless/libertas/if_sdio.c
     accept '[  ]*card->firmware[ ]=[ ]\(if_sdio\|lbs_fw\)' drivers/net/wireless/libertas/if_sdio.c
     blobname 'usb8388\(-5\.126\.0\.p5\)\?\.bin' drivers/net/wireless/libertas/if_usb.c
-    blob '[/][*][/]*\([*]*[^*/][^*/]*[/]*\)*[*]*usb8388\(-5\.126\.0\.p5\)\?\.bin[/]*\([*]*[^*/][^*/]*[/]*\)*[*]*[*][/]' drivers/net/wireless/libertas/if_usb.c
+    blob '[/][*][/]*\([*]*[^*/][/]*\)*[*]*usb8388\(-5\.126\.0\.p5\)\?\.bin[/]*\([*]*[^*/][/]*\)*[*]*[*][/]' drivers/net/wireless/libertas/if_usb.c
     accept '[  ][      ]lbs_pr_err[(]["]request_firmware\([(][)]\)\?[ ]failed' 'drivers/net/wireless/if_\(spi\|usb\)\.c'
     blobna 'o\.[ ]Copy[ ]the[ ]firmware[ ]image[^\n]*usb8388\([^\n]\|[\n][     ]*[^    \n]\)*' drivers/net/wireless/libertas/README
     blobna '\[fw_name=usb8388[^]]*\]' drivers/net/wireless/libertas/README
@@ -1291,7 +1285,7 @@ set_except () {
     blobname 'lbtf_usb\.bin' drivers/net/wireless/libertas_tf/if_usb.c
 
     blobname 'isl38\(86\|87\|90\)\(usb\(_bare\)\?\)\?' 'drivers/net/wireless/p54/p54\(pci\.c\|usb\.[ch]\)'
-    blob '[/][*][ ]for[ ]isl3886[ ]register[ ]definitions[/]*\([*]*[^*/][^*/]*[/]*\)*[*]*[*][/]' drivers/net/wireless/p54/p54usb.h
+    blob '[/][*][ ]for[ ]isl3886[ ]register[ ]definitions[/]*\([*]*[^*/][/]*\)*[*]*[*][/]' drivers/net/wireless/p54/p54usb.h
     blobna 'If[ ]you[ ]enable[ ]this\([^\n]\|[\n][     ]*[^    \n]\)*isl3890\([^\n]\|[\n][     ]*[^    \n]\)*' drivers/net/wireless/Kconfig
 
     blobname 'isl38\(77\|86\|90\)' drivers/net/wireless/prism54/islpci_dev.c
@@ -1387,7 +1381,7 @@ set_except () {
 
     blobname 'aica_firmware\.bin' sound/sh/aica.c
 
-    accept '[ ][*][/]*\([*]*[^*/][^*/]*[/]*\)*[*]*Caution:[ ]This[ ]API[/]*\([*]*[^*/][^*/]*[/]*\)*[*]*request_firmware.' sound/sound_firmware.c
+    accept '[ ][*][/]*\([*]*[^*/][/]*\)*[*]*Caution:[ ]This[ ]API[/]*\([*]*[^*/][/]*\)*[*]*request_firmware.' sound/sound_firmware.c
     accept 'static[ ]int[ ]do_mod_firmware_load[(]' sound/sound_firmware.c
     accept 'int[ ]mod_firmware_load[(]' sound/sound_firmware.c
     accept '[  ]r[ ]=[ ]do_mod_firmware_load[(]' sound/sound_firmware.c
@@ -1443,7 +1437,7 @@ set_except () {
 
     blobname 'dvb-fe-nxt2002\.fw' drivers/media/dvb/frontends/nxt200x.c
 
-    blob '[/][*][\n][ ][*][ ]This[ ]driver[ ]needs[ ]two[ ]external[ ]firmware[ ]files[/]*\([*]*[^*/][^*/]*[/]*\)*[*]*dvb-fe-or51132-\(vsb\|qam\)\.fw[/]*\([*]*[^*/][^*/]*[/]*\)*[*]*[*][/]' drivers/media/dvb/frontends/or51132.c
+    blob '[/][*][\n][ ][*][ ]This[ ]driver[ ]needs[ ]two[ ]external[ ]firmware[ ]files[/]*\([*]*[^*/][/]*\)*[*]*dvb-fe-or51132-\(vsb\|qam\)\.fw[/]*\([*]*[^*/][/]*\)*[*]*[*][/]' drivers/media/dvb/frontends/or51132.c
     blobname 'dvb-fe-or51132-\(vsb\|qam\)\.fw' drivers/media/dvb/frontends/or51132.c
 
     blobname 'dvb-fe-or51211\.fw' drivers/media/dvb/frontends/or51211.c
@@ -1633,7 +1627,7 @@ set_except () {
     # These are regarded as ok
     initnc 'static[ ]const[ ]u8[ ]SN9C102_\(Y\|UV\)_QTABLE[01]\[64\][ ]=[ ][{]'
     initnc '[  ]static[ ]\(const[ ]\)\?u8[ ]jpeg_header\[589\][ ]=[ ][{]' media/video/sn9c102/sn9c102_core.c
-    accept '[  ]\{1,2\}err[ ]=[ ]sn9c102_write_const_regs[(]cam\(,[    \n]\+[{]0x[0-9a-fA-F][0-9a-fA-F],[ ]0x[0-9a-fA-F][0-9a-fA-F][}]\)*[)][;]'
+    accept '[  ][      ]\?err[ ]=[ ]sn9c102_write_const_regs[(]cam\(,[         \n]\+[{]0x[0-9a-fA-F][0-9a-fA-F],[ ]0x[0-9a-fA-F][0-9a-fA-F][}]\)*[)][;]'
 
     # too lax?
     defsnc 'static[ ]yyconst[ ]\(flex_int\(16\|32\)_t\|\(\(short[ ]\)\?int\)\)[ ]yy_[^[]*\[[][0-9]*\][ ]='
@@ -2083,7 +2077,7 @@ set_except () {
     defsnc 'static[ ]struct[ ]nand_ecclayout[ ]onenand_oob_128[ ]=' drivers/mtd/onenand/onenand_base.c
     blobname 'bnx2x-e1h\?-\([0-9.%d]*\.fw\)\?' drivers/net/bnx2x_main.c
     blob '#define[ ]BCM_5710_FW_\(\(MAJOR\|MINOR\|REVISION\|ENGINEERING\)_VERSION\|COMPILE_FLAGS\)[    ]*[0-9]\+\([\n]#define[ ]BCM_5710_FW_\(\(MAJOR\|MINOR\|REVISION\|ENGINEERING\)_VERSION\|COMPILE_FLAGS\)[        ]*[0-9]\+\)*' drivers/net/bnx2x_hsi.h
-    blob 'static[ ]int[ ]__devinit[ ]bnx2x_check_firmware[(]struct[ ]bnx2x[ ][*]bp[)][\n][{]\([^}]\|[^\n}][}]*\)*[\n][}]' drivers/net/bnx2x_main.c
+    blob 'static[ ]int[ ]__devinit[ ]bnx2x_check_firmware[(]struct[ ]bnx2x[ ][*]bp[)][\n][{]\([\n]*[^\n}][}]*\)*[\n]\+[}]' drivers/net/bnx2x_main.c
     blobna 'if[ ][(][(]fw_ver\[[0-3]\][ ]!=[ ]BCM_5710_FW_\(MAJOR\|MINOR\|REVISION\|ENGINEERING\)_VERSION[)]\([ ][|][|][\n][   ]*[(]fw_ver\[[0-3]\][ ]!=[ ]BCM_5710_FW_\(MAJOR\|MINOR\|REVISION\|ENGINEERING\)_VERSION[)]\)*[)][ ][{][^{}]*[}]' drivers/net/bnx2x_main.c
     blobna 'sprintf[(]fw_file_name[ ][+][ ]offset,[ ]["]%d[.]%d[.]%d[.]%d[.]fw["]\(,[\n][      ]*BCM_5710_FW_\(MAJOR\|MINOR\|REVISION\|ENGINEERING\)_VERSION\)*[)][;]' drivers/net/bnx2x_main.c
     blob 'rc[ ]=[ ]bnx2x_check_firmware[(]bp[)][;]' drivers/net/bnx2x_main.c
@@ -2132,11 +2126,11 @@ set_except () {
     defsnc '[  ][}][ ]common_modes\[17\][ ]=' drivers/gpu/drm/radeon/radeon_connectors.c
     defsnc '[  ][      ]*\(static[ ]\)\?struct[ ]phy_reg[ ]phy_reg_init\(_0\)\?\[\][ ]=' drivers/net/r8169.c
     accept '[  ][      ]*struct[ ]phy_reg[ ]phy_reg_init_1\[\][ ]=[ ][{][^;]*0x8300[^;]*[}][;]' drivers/net/r8169.c
-    blob 'static[ ]void[ ]rtl8168d_[12]_hw_phy_config[(]void[ ]__iomem[ ][*]ioaddr[)][\n][{][\n]\([^}]*\|[^\n}][}]*\)*[\n][}]' drivers/net/r8169.c
+    blob 'static[ ]void[ ]rtl8168d_[12]_hw_phy_config[(]void[ ]__iomem[ ][*]ioaddr[)][\n][{][\n]\([\n]*[^\n}][}]*\)*[\n]\+[}]' drivers/net/r8169.c
     blobna 'rtl8168d_[12]_hw_phy_config[(]ioaddr[)][;]' drivers/net/r8169.c
     blobna 'static[ ]struct[ ]phy_reg_init_[12]\[\][ ]=[ ][{][\n       {}0-9a-fx]*0x06,[ ]0xf8f9[\n    {}0-9a-fx]*[}][;]' drivers/net/r8169.c
     # This loads firmware to be flashed from filename provided through ethtool.
-    accept 'int[ ]be_load_fw[(][^\n;{]*[)][ \n][{]\([^}]*\|[^\n}][}]*\)*ETHTOOL_FLASH_MAX_FILENAME\([^}]*\|[^\n}][}]*\)*be_cmd_get_fw_ver\([^}]*\|[^\n}][}]*\)*request_firmware\([^}]*\|[^\n}][}]*\)*[\n][}]' drivers/net/benet/be_main.c
+    accept 'int[ ]be_load_fw[(][^\n;{]*[)][ \n][{]\([\n]*[^\n}][}]*\)*ETHTOOL_FLASH_MAX_FILENAME\([\n]*[^\n}][}]*\)*be_cmd_get_fw_ver\([\n]*[^\n}][}]*\)*request_firmware\([\n]*[^\n}][}]*\)*[\n]\+[}]' drivers/net/benet/be_main.c
     defsnc '[  ]u8[ ]init_hash_seed\[\][ ]=' drivers/net/qlge/qlge_main.c
     defsnc 'static[ ]const[ ]u_int32_t[ ]ar9287\(Common\|Modes\(_\([tr]x_gain\)\)\?\)_9287_1_[01]\[\]\[[236]\][ ]=' drivers/net/wireless/ath9k/initvals.h
     defsnc 'static[ ]const[ ]u_int32_t[ ]ar9271\(Common\|Modes\)_9271_1_0\[\]\[[26]\][ ]=' drivers/net/wireless/ath9k/initvals.h
@@ -2180,7 +2174,7 @@ set_except () {
     defsnc 'static[ ]struct[ ]nand_ecclayout[ ]hwecc4_2048[ ]__initconst[ ]=' drivers/mtd/nand/davinci_nand.c
     defsnc 'static[ ]const[ ]u16[ ]wm8974_reg\[WM8974_CACHEREGNUM\][ ]=' sound/soc/codecs/wm8974.c
     defsnc 'static[ ]const[ ]u16[ ]ak4642_reg\[AK4642_CACHEREGNUM\][ ]=' sound/soc/codecs/ak4642.c
-    accept 'int[ ]snd_hda_load_patch[(][^\n;{]*[)][ \n][{]\([^}]*\|[^\n}][}]*\)*hda_codec\([^}]*\|[^\n}][}]*\)*request_firmware\([^}]*\|[^\n}][}]*\)*[\n][}]' sound/pci/hda/hda_hwdep.c
+    accept 'int[ ]snd_hda_load_patch[(][^\n;{]*[)][ \n][{]\([\n]*[^\n}][}]*\)*hda_codec\([\n]*[^\n}][}]*\)*request_firmware\([\n]*[^\n}][}]*\)*[\n]\+[}]' sound/pci/hda/hda_hwdep.c
     accept '[ ][ ][ ]Bit[ 0-7]*' Documentation/input/sentelic.txt
     accept 'The[ ]hd-audio[ ]driver[ ]reads[ ]the[ ]file[ ]via[ ]request_firmware[(][)]\.' Documentation/sound/alsa/HD-Audio.txt
     blob 'SD8688[ ]firmware:[\n]*\([/]lib[/]firmware[^\n]*[\n]*\)*The[ ]images[^:]*:[\n]*[^\n]*[/]linux-firmware[^\n]*' Documentation/btmrvl.txt
@@ -2188,7 +2182,7 @@ set_except () {
     defsnc 'static[ ]int[ ]zoom2_batt_table\[\][ ]=' arch/arm/mach-omap2/board-zoom2.c
     defsnc 'static[ ]struct[ ]ad714x_platf\(or\|ro\)m_data[ ]ad714[27]_platf\(or\|ro\)m_data[ ]=' arch/blackfin/mach-bf537/boards/stamp.c
     blob 'static[ ]const[ ]u8[ ]lgs8g75_initdat\[\][ ]=[ ][{][^;]*[}][;]' drivers/media/dvb/frontends/lgs8gxx.c
-    blob 'static[ ]int[ ]lgs8g75_init_data[(][^\n;{]*[)][ \n][{]\([^}]*\|[^\n}][}]*\)*lgs8g75_initdat\([^}]*\|[^\n}][}]*\)*[\n][}]' drivers/media/dvb/frontends/lgs8gxx.c
+    blob 'static[ ]int[ ]lgs8g75_init_data[(][^\n;{]*[)][ \n][{]\([\n]*[^\n}][}]*\)*lgs8g75_initdat\([\n]*[^\n}][}]*\)*[\n]\+[}]' drivers/media/dvb/frontends/lgs8gxx.c
     defsc 'static[ ]struct[ ]idxdata[ ]tbl_common_[a-e]\[\][ ]=' 'drivers/media/video/gspca/gl860/gl860-\(mi2020\|mi1320\|ov9655\|ov2640\)\.c'
     defsnc 'static[ ]struct[ ]validx[ ]tbl_\(commm\?on\|init_\(at_startup\|post_alt\)\|sensor_settings_common_[ab]\|big_[abc]\|640\|800\)\[\][ ]=' 'drivers/media/video/gspca/gl860/gl860-\(mi2020\|mi1320\|ov9655\|ov2640\).c'
     defsnc 'static[ ]u8[ ][*]tbl_\(640\|800\)\[\][ ]=' 'drivers/media/video/gspca/gl860/gl860-\(mi1320\|ov9655\).c'
@@ -2582,7 +2576,7 @@ set_except () {
 constx="[0-9][0-9a-fA-FxX]*"
 # Regular expression that matches a separator between consecutive
 # literal constants.
-sepx="\\([,:{}         \\nLlUu\"\'\\\\]\\+[xX\$]\\?\\|[        \\n]*[.][a-zA-Z][a-zA-Z0-9]*[   ]\\+[\$]\\?\\)"
+sepx="\\([     \\n]*\\(\\([    \\n]\\|[,:{}LlUu\"\'\\\\][,:{}  \\nLlUu\"\'\\\\]*\\)[xX\$]\\?\\|[.][a-zA-Z][a-zA-Z0-9]*[        ]\\+[\$]\\?\\)\\)"
 
 # Regular expression that matches a continuation of a blob, after an
 # initial constant.  *, \+ and \? can be safely appended to it without
@@ -2609,22 +2603,22 @@ bol="\\(^\\|[\\n]\\)"
 eol="\\([\\n]\\|\$\\)"
 
 # Regular expression that matches a C-style comment.
-comment="\\([/][*][/]*\\([*]*[^*/][^*/]*[/]*\\)*[*]*[*][/]\\|[/][/][^\\n]*[\\n]\\)"
+comment="\\([/]\\([*][/]*\\([*]*[^*/][/]*\\)*[*]\\+[/]\\|[/][^\\n]*[\\n]\\)\\)"
 
 # Regular expression that matches comments typically used in assembly.
 asmcomment="\\($comment\\|[;#][^\\n]*[\\n]\\)"
 
 # Regular expression that matches a braced initializer containing at
 # least one blob.
-initblob="[^\\n]*=\\([         \\n\\\\]*\\|$comment\\)*[{]\\([^;]*\\|$comment\\)*$blobseq\\([^;]*\\|$comment\\)*[}]\\?\\([     \\n\\\\]*\\|$comment\\)[;]\\?"
+initblob="[^\\n=]*=\\([        \\n\\\\]\\|$comment\\)*[{]\\([^;]\\|$comment\\)*$blobseq\\([^;]\\|$comment\\)*[}]\\?\\([        \\n\\\\]*\\|$comment\\)[;]\\?"
 
 # Regular expression that matches a C (possibly multi-line) #define
 # that contains a blob.
-defineblob='[  ]*#[    ]*define[       ]\+\([^\n]*\\[\n]\)*[^\n]*'"$blobseq"'\([^\n]*\\[\n]\)*'
+defineblob='[  ]*#[    ]*define[       ][^\n]*\([\\][\n][^\n]*\)*'"$blobseq"'\([^\n]*\\[\n]\)*'
 
 # Regular expression that matches an assembly label followed by a blob
 # without any intervening label.
-asmblob="[a-zA-Z_.][^\\n:;#/   ]*[ ]*:\\([^:{}]*\\|$asmcomment\\)*$blobseq\\([^:]*\\|$asmcomment\\)*"
+asmblob="[a-zA-Z_.][^\\n:;#/   ]*:\\([^:{}]\\|$asmcomment\\)*$blobseq\\([^:]*\\|$asmcomment\\)*"
 
 # Set up the sed script that will go through the (processed) input,
 # looking for sequences of blobs and printing whatever was requested.
@@ -2639,11 +2633,11 @@ asmblob="[a-zA-Z_.][^\\n:;#/    ]*[ ]*:\\([^:{}]*\\|$asmcomment\\)*$blobseq\\([^:]
 # $4 is the action for every complete input pattern.
 
 set_sed_main () {
-  falsepos=`sed -n 's,^[+]\^*,,p' < "$regex_name" |
-    sed -n -e 's,[$]$,\\\\([\\\\n]\\\\|$\\\\),' \
+  falsepos=`${SED-sed} -n 's,^[+]\^*,,p' < "$regex_name" |
+    ${SED-sed} -n -e 's,[$]$,\\\\([\\\\n]\\\\|$\\\\),' \
        -e '1h; 1!H; ${g;s,[\n],\\\\|,g;s,^\(..*\)$,\\\\(\1\\\\),;p;}'`
-  blobs=`sed -n 's,^[-],,p' < "$regex_name" |
-    sed -n -e 's,[$]$,\\\\([\\\\n]\\\\|$\\\\),' \
+  blobs=`${SED-sed} -n 's,^[-],,p' < "$regex_name" |
+    ${SED-sed} -n -e 's,[$]$,\\\\([\\\\n]\\\\|$\\\\),' \
        -e '1h; 1!H; ${g;s,[\n],\\\\|,g;s,^\(..*\)$,\\\\(\1\\\\),;p;}'`
 
   # Regular expression that matches one or more blobs without
@@ -3213,7 +3207,7 @@ b list_both
 
 " > "$scriptname"
 
-  scriptcmd='$sed -n -f "$scriptname"'
+  scriptcmd='${SED-sed} -n -f "$scriptname"'
 
   sedunbreak='
 : restart
@@ -3225,7 +3219,7 @@ b list_both
 }
 p
 '
-  scriptcmd2='$sed -n -e "$sedunbreak"'
+  scriptcmd2='${SED-sed} -n -e "$sedunbreak"'
 }
 
 set_flex_main () {
@@ -3237,7 +3231,7 @@ s,[-]$, { blob (); },
 '     
 
   echo '%%' > "$scriptname"
-  sed "$adjust_rx" < "$regex_name" >> "$scriptname"
+  ${SED-sed} "$adjust_rx" < "$regex_name" >> "$scriptname"
   echo '\n|. { unmatched (); }
 %%
 int falsepos () {}
@@ -3288,25 +3282,25 @@ $@ = 1
 EOF
 
   if test "X$DEBLOB_CHECK_PYTHON_REGEX" = Xdebug; then
-    sed -e "$adjust_rx" \
+    ${SED-sed} -e "$adjust_rx" \
        -e 's,\([^-+]*\)\(.*\),re.compile (r'"'\\2'"'),g' \
        < "$regex_name" >> "$scriptname"
   fi
 
-  sed -n 's,^[+],,p' < "$regex_name" |
-    sed -n -e "$adjust_rx" -e 's,\^,,' \
+  ${SED-sed} -n 's,^[+],,p' < "$regex_name" |
+    ${SED-sed} -n -e "$adjust_rx" -e 's,\^,,' \
        -e '1h; 1!H; $ { g; s,[\n],|,g; '"\
 s,^\\(.*\\)\$,falsepos = r'(?P<falsepos>\\1)',;\
 "' p;}' >> "$scriptname"
 
-  sed -n 's,^[-],,p' < "$regex_name" |
-    sed -n -e "$adjust_rx" \
+  ${SED-sed} -n 's,^[-],,p' < "$regex_name" |
+    ${SED-sed} -n -e "$adjust_rx" \
        -e '1h; 1!H; $ { g; s,[\n],|,g; '"\
 s,^\\(.*\\)\$,blob = r'(?P<blob>\\1)',;\
 "' p;}' >> "$scriptname"
 
   echo "\\($initblob\\|$defineblob\\|$asmblob\\)" | 
-    sed -e "$adjust_rx" \
+    ${SED-sed} -e "$adjust_rx" \
         -e "s,^\\(.*\\)\$,cblob = r'(?P<cblob>\\1)'," >> "$scriptname"
 
   cat >> "$scriptname" <<\EOF
@@ -3314,18 +3308,16 @@ s,^\\(.*\\)\$,blob = r'(?P<blob>\\1)',;\
 if no_falsepos or falsepos is None:
     falsepos = r'(?!)'
 
-# Use non-greedy operator to skip partial line before blob, to avoid
-# skipping blobs when more than one appears in the same line.
-rx = '^%s|[^\n]*?%s' % (falsepos, blob)
+rx = '^%s|%s' % (falsepos, blob)
 
 if with_context:
     rx += '|^' + cblob
 
-rxc = re.compile(rx, re.M | re.S)
+rxc = re.compile('(?<=.)(?:%s)' % rx, re.M | re.S)
 
 filenames = None
 
-s = ''
+s = '\n'
 
 for line in sys.stdin:
     # Read into s all lines between begin and end.  An empty line, without
@@ -3333,7 +3325,7 @@ for line in sys.stdin:
     if line[:3] == ';/*' and line[-4:] == '*/;\n':
         if line[3:9] == 'begin ':
             nextfilenames = (line[9:-4], filenames)
-            if s == '':
+            if s == '\n':
                 filenames = nextfilenames
                 del nextfilenames
                 continue
@@ -3345,7 +3337,7 @@ for line in sys.stdin:
             s += line
             continue
     else:
-       assert filenames != None
+        assert filenames != None
         s += line
         continue
         
@@ -3353,7 +3345,7 @@ for line in sys.stdin:
             print 'looking for matches'
             sfilenames = filenames
             while filenames != None:
-               if filenames[0] == name_to_list:
+                if filenames[0] == name_to_list:
                     print name_to_list
                     assert filenames[1] == None
                 else:
@@ -3365,53 +3357,56 @@ for line in sys.stdin:
     if s[-1] == '\n':
         s = s[:-1]
 
-    pp = p = pend = 0
+    pp = 1
+    p = pend = 0
     match = rxc.search (s, p)
     while match != None:
         firstmatch = match
         blobs = falses = 0
-        while match != None:
+        while 1:
             if verbose:
                 print 'found match'
             what = match.lastgroup
 
             if what == 'cblob':
-               if verbose: print 'match is a blob context'
-               pend = match.end()
+                if verbose: print 'match is a blob context'
+                pend = s.find ('\n', match.end()) + 1
+                if pend == 0:
+                    pend = len(s)
                 p = match.start() + 1
-                match = rxc.search (s, p)
-                continue
-
-            blob_p = what == 'blob'
-            assert blob_p or what == 'falsepos'
-
-            if blob_p:
-               if verbose: print 'match is a blob'
-                blobs += 1
             else:
-               if verbose: print 'match is a false positive'
-                falses += 1
+                blob_p = what == 'blob'
+                assert blob_p or what == 'falsepos'
+
+                if blob_p:
+                    if verbose: print 'match is a blob'
+                    blobs += 1
+                else:
+                    if verbose: print 'match is a false positive'
+                    falses += 1
             
-            assert match.end(what) == match.end()
-            if blob_p and replace_blob or not blob_p and replace_falsepos:
-                s = s[:match.start(what)] + replacement + s[match.end():]
-                p = match.start(what) + len(replacement)
-            else:
-                p = match.end()
+                if blob_p and replace_blob or not blob_p and replace_falsepos:
+                    s = s[:match.start(what)] + replacement + s[match.end(what):]
+                    p = match.start(what) + len(replacement)
+                    if pend > match.start(what):
+                        pend += p - match.end(what)
+                else:
+                    p = match.end(what)
 
-            match = rxc.match (s, p)
-        
-        if print_nomatch:
-            sys.stdout.write (s[pp:firstmatch.start()])
-        pp = firstmatch.start()
+                if p > pend:
+                    pend = s.find ('\n', p) + 1
+                    if (pend == 0):
+                        pend = len(s)
 
-       if (p < pend):
-           p = pend
+            match = rxc.search (s, p)
+            if match == None or match.start () >= pend:
+                break
 
-        p = s.find ('\n', p)
-        if p == -1:
-            p = len(s)
-        p += 1
+        if print_nomatch:
+            sys.stdout.write (s[pp:firstmatch.start() + 1])
+            pp = firstmatch.start() + 1
+        else:
+            pp = s.rfind ('\n', 0, firstmatch.start () + 1) + 1
 
         if print_blob and blobs or print_falsepos and falses:
             if not print_nomatch:
@@ -3424,12 +3419,12 @@ for line in sys.stdin:
                         assert filenames[1] != None
                     filenames = filenames[1]
                 filenames = sfilenames
-            sys.stdout.write (s[pp:p])
-            pp = p
+            sys.stdout.write (s[pp:pend])
+            pp = pend
 
         if list_blob and blobs or list_falsepos and falses:
             while filenames != None:
-               if filenames[0] == name_to_list:
+                if filenames[0] == name_to_list:
                     print name_to_list
                     assert filenames[1] == None
                 else:
@@ -3438,15 +3433,13 @@ for line in sys.stdin:
                 filenames = filenames[1]
             exit (1)
 
-        match = rxc.search (s, p)
-
     if print_nomatch:
         sys.stdout.write(s[pp:])
 
     if verbose:
         print 'no further matches'
 
-    s = ''
+    s = '\n'
     filenames = nextfilenames
     del nextfilenames
 
@@ -3458,6 +3451,208 @@ EOF
   scriptcmd="${PYTHON-python} "'"$scriptname"'
 }
 
+set_perl_main () {
+  adjust_rx='
+s,\\(,\\(?:,g;
+s,\\\([{(|)}?+]\),\1,g;
+'
+
+  # Add $ before arguments
+  set `echo "$@" | sed 's,\(^\|= *\),&$,g'`
+
+  cat >> "$scriptname" <<\EOF
+#! /usr/bin/perl
+
+use strict;
+use warnings;
+
+# Should we replace blobs and false positives with replacement?
+my $replace_blob = 0;
+my $replace_falsepos = 0;
+my $replacement = '/*(DEBLOBBED)*/';
+
+# Should we print lines containing blobs, false positives, and neither?
+my $print_blob = 0;
+my $with_context = 0;
+my $print_falsepos = 0;
+my $print_nomatch = 0;
+
+# Should we print name_to_list and exit if we find blobs or false positives?
+my $list_blob = 0;
+my $list_falsepos = 0;
+
+# Should we forget everything we know about false positives?
+my $falsepos;
+my $no_falsepos = 0;
+
+EOF
+
+  cat >> "$scriptname" <<EOF
+my \$name_to_list = '$input';
+
+my \$verbose = $vp;
+
+# Which of the defaults above should we override?
+$@ = 1;
+
+EOF
+
+  ${SED-sed} -n 's,^[+],,p' < "$regex_name" |
+    ${SED-sed} -n -e "$adjust_rx" -e 's,\^,,' \
+       -e '1h; 1!H; $ { g; s,[\n],|,g; '"\
+s,^\\(.*\\)\$,\$falsepos = qr'(?<falsepos>\\1)'ms;,;\
+"' p;}' >> "$scriptname"
+
+  ${SED-sed} -n 's,^[-],,p' < "$regex_name" |
+    ${SED-sed} -n -e "$adjust_rx" \
+       -e '1h; 1!H; $ { g; s,[\n],|,g; '"\
+s,^\\(.*\\)\$,my \$blob = qr'(?<blob>\\1)'ms;,;\
+"' p;}' >> "$scriptname"
+
+  echo "\\($initblob\\|$defineblob\\|$asmblob\\)" | 
+    ${SED-sed} -e "$adjust_rx" \
+        -e "s,^\\(.*\\)\$,my \$cblob = qr'(?<cblob>\\1)'ms if \$with_context;," >> "$scriptname"
+
+  cat >> "$scriptname" <<\EOF
+
+$falsepos = qr/(?<falsepos>(?!))/ if $no_falsepos || ! defined $falsepos;
+
+my $rx = qr/^$falsepos|$blob/ms;
+
+$rx = qr/$rx|^$cblob/ms if $with_context;
+
+my @filenames;
+my $nfilenames = 0;
+my $nextnfilenames;
+
+my $s = '';
+
+while (<STDIN>) {
+    # Read into s all lines between begin and end.  An empty line, without
+    # even the '\n', flags the end of the input.
+    if (m:^[;][/][*](begin|end) (.*)[*][/][;]$:) {
+       if ($1 eq 'begin') {
+           print "entering $2\n" if $verbose;
+           $filenames[$nfilenames] = $2;
+           $nextnfilenames = $nfilenames + 1;
+           if ($s eq '') {
+               $nfilenames = $nextnfilenames;
+               next;
+           }
+       } else {
+           $nextnfilenames = $nfilenames - 1;
+           print "processing $filenames[$nextnfilenames]\n" if $verbose;
+       }
+    } else {
+       $s .= $_;
+       next;
+    }
+       
+    if ($verbose) {
+       print "looking for matches in\n";
+       for (my $i = $nfilenames; --$i > 0; ) {
+           print $filenames[$i], " within\n";
+       }
+       print $filenames[0], "\n";
+    }
+
+    $s =~ s/[\n]$//;
+
+    my $pp = my $p = 0;
+
+    my $matchfound = substr ($s, $p) =~ /$rx/o;
+    while ($matchfound) {
+       print "found first match\n" if $verbose;
+       my $firstmatchstart = $-[0] + $p;
+       my $blobs = my $falses = 0;
+       my $matchstart = $-[0] + $p;
+       my $pend = -1;
+       my $blob_p;
+       do {{
+           my $matchend = $+[0] + $p;
+           print "found match $matchstart..$matchend\n" if $verbose;
+           print "$&" if $verbose > 1;
+
+           if (defined $+{'cblob'}) {
+               print "match is a blob context\n" if ($verbose);
+               $pend = index ($s, "\n", $matchend) + 1;
+               $pend = length $s if !$pend;
+           }
+
+           if (defined $+{'falsepos'}) {
+               print "match is a false positive\n" if ($verbose);
+               # $matchend -= $+[0] - $+[1];
+               $blob_p = 0;
+               $falses++;
+           } elsif (defined $+{'blob'}) {
+               $blob_p = 1;
+               $blobs++;
+               print "match is a blob at $matchstart\n" if ($verbose);
+           } else {
+               $p = $matchstart;
+               print "searching up to $pend\n" if $verbose;
+               next;
+           }
+
+           if ($blob_p ? $replace_blob : $replace_falsepos) {
+               substr ($s, $matchstart, $matchend - $matchstart,
+                       $replacement);
+               $p = $matchstart + length $replacement;
+               $pend += $p - $matchend if $pend >= $matchstart;
+           } else {
+               $p = $matchend;
+           }
+
+           $pend = index ($s, "\n", $p) + 1 if $p >= $pend;
+           $pend = length $s if !$pend;
+           print "searching up to $pend\n" if $verbose;
+           $p--;
+       }} while (($matchfound = (substr ($s, $p) =~ /(?<=.)$rx/mso))
+                 && ($matchstart = $-[0] + $p) < $pend);
+
+       print "last match before $pend\n" if $verbose;
+
+       if ($print_nomatch) {
+           print substr ($s, $pp, $firstmatchstart - $pp);
+           $pp = $firstmatchstart;
+       } elsif (($print_blob || $print_falsepos) && $firstmatchstart > 0) {
+           $pp = rindex ($s, "\n", $firstmatchstart - 1) + 1;
+       }
+
+       if (($print_blob && $blobs) || ($print_falsepos && $falses)) {
+           if (!$print_nomatch) {
+               for (my $i = $nfilenames; $i-- > 0;) {
+                   print "::: ", $filenames[$i], " :::\n";
+               }
+           }
+
+           print substr ($s, $pp, $pend - $pp);
+           $pp = $pend;
+       }
+
+       if (($list_blob && $blobs) || ($list_falsepos && $falses)) {
+           for (my $i = $nfilenames; --$i > 0;) {
+               print $filenames[$i], " within ";
+           }
+           print $filenames[0], "\n";
+           exit (1);
+       }
+    }
+
+    print substr ($s, $pp) if $print_nomatch;
+       
+    print "no further matches\n" if $verbose;
+
+    $s = '';
+    $nfilenames = $nextnfilenames;
+}
+
+exit (0);
+EOF
+
+  scriptcmd="${PERL-perl} "'"$scriptname"'
+}
+
 set_awk_main () {
   adjust_rx='
 s,[$]$,([\\n]|$),;
@@ -3468,22 +3663,22 @@ s,\\\([{(|)}?+]\),\1,g;
   case " = $@ = " in
   *" = no_falsepos = "*) falsepos='$.^';;
   *) falsepos=`
-    sed -n 's,^[+],,p' < "$regex_name" |
-    sed -n -e "$adjust_rx" -e 's,\^,,' \
+    ${SED-sed} -n 's,^[+],,p' < "$regex_name" |
+    ${SED-sed} -n -e "$adjust_rx" -e 's,\^,,' \
        -e '1h; 1!H; $ { g; s,[\n],|,g; p;}'
     `
      case $falsepos in "") falsepos='$.^';; esac;;
   esac
 
   blob=`
-    sed -n 's,^[-],,p' < "$regex_name" |
-    sed -n -e "$adjust_rx" \
+    ${SED-sed} -n 's,^[-],,p' < "$regex_name" |
+    ${SED-sed} -n -e "$adjust_rx" \
        -e '1h; 1!H; $ { g; s,[\n],|,g; p;}'`
 
   case " = $@ = " in
   *" = with_context = "*) cblob=`
     $echo "\\($initblob\\|$defineblob\\|$asmblob\\)" | 
-    sed -e "$adjust_rx"
+    ${SED-sed} -e "$adjust_rx"
    `;;
   *) cblob='$.^';;
   esac
@@ -3521,26 +3716,26 @@ BEGIN {
     verbose = $vp;
 
     nfilenames = 0;
-    s = "";
+    s = "\n";
 
     # Which of the defaults above should we override?
     $@ = 1;
 
     # requires GNU awk RS extension:
-$xrs    RS = "[;][/][*](begin|end) [^\n]*[*][/][;][\n]";
+$xrs   RS = "[;][/][*](begin|end) [^\n]*[*][/][;][\n]";
 }
 # requires GNU awk RS extension:
 $xrs { s = s \$0; }
 # does not require GNU awk RS extension:
 $nrs !/^[;][/][*].*[*][/][;]$/ {
-$nrs     s = s \$0 "\n";
-$nrs     next;
+$nrs    s = s \$0 "\n";
+$nrs    next;
 $nrs }
 $eormatch /^[;][/][*]begin .*[*][/][;]$eornl$/ {
     filenames[nfilenames] = substr($eor, 10, length ($eor) - 12 - $eornlsz);
     if (verbose) print "entering " nfilenames ": " filenames[nfilenames];
     nextnfilenames = nfilenames + 1;
-    if (s == "") {
+    if (s == "\n") {
        nfilenames = nextnfilenames;
        next;
     }
@@ -3553,92 +3748,97 @@ $eormatch /^[;][/][*]end .*[*][/][;]$eornl$/ {
 {
     if (verbose) {
        print "looking for matches";
-       for (i = nfilenames; --i >= 0;)
+       for (i = nfilenames; --i > 0;)
            print filenames[i] " within";
-        print filenames[0]
+       print filenames[0]
     }
 
     s = substr (s, 1, length (s) - 1)
 
-    pp = p = pend = 1;
+    pp = 2;
+    p = pend = 1;
     if (verbose > 1) print "searching starting at", substr (s, p, 10)
-    while (match (substr (s, p),
-                 /(^|[\n])($falsepos)|(^|[\n])($cblob)|$blob/)) {
+    matchfound = match (substr (s, p),
+                       /[\n]($falsepos)|[\n]($cblob)|.($blob)/);
+    while (matchfound) {
        blobs = falses = 0;
-       firstmatchstart = RSTART + p - 1;
-       if (substr (s, firstmatchstart, 1) == "\n")
-           firstmatchstart++;
+       firstmatchstart = RSTART + p;
        for (;;) {
            matchstart = RSTART + p - 1;
            matchlen = RLENGTH;
-           if (substr (s, matchstart, 1) == "\n") {
-               matchstart++;
-               matchlen--;
-           }
-           if (verbose)
+           if (verbose) {
                print "found match", matchstart, matchlen;
-           if (verbose > 1)
-               print substr (s, matchstart, matchlen);
-           if (match (substr (s, matchstart, matchlen), /^($falsepos)$/) == 1) {
+               if (verbose > 1)
+                   print substr (s, matchstart + 1, matchlen - 1);
+           }
+
+           cblob_p = 0;
+
+           if (match (substr (s, matchstart, matchlen), /^[\n]($falsepos)/) == 1) {
                if (verbose) print "match is a false positive";
                blob_p = 0;
                falses++;
-           } else if (match (substr (s, matchstart, matchlen), /^($cblob)$/) == 1) {
+           } else if (match (substr (s, matchstart, matchlen), /^[\n]($cblob)$/) == 1) {
                if (verbose) print "match is a blob context";
-               pend = p + matchlen;
+               pend = index (substr (s, matchstart + matchlen), "\n");
+               if (pend)
+                   pend += matchstart + matchlen;
+               else
+                   pend = length (s);
                p = matchstart + 1;
-               if (verbose) print "search after cblob starting at", p;
-               match (substr (s, p, matchlen - 1), /^($falsepos)|^($cblob)|[^\n]*($blob)/);
-               continue;
+               if (verbose) print "range is:", substr (s, p, pend - p);
+               cblob_p = 1;
            } else {
                if (verbose) print "match is a blob";
                blob_p = 1;
                blobs++;
            }
 
-           if (blob_p ? replace_blob : replace_falsepos) {
-               s = substr (s, 1, matchstart - 1)       \\
-                   replacement                         \\
-                   substr (s, matchstart + matchlen);
-               p = matchstart + length (replacement);
-           } else
-               p = matchstart + matchlen;
-           i = index (substr (s, p), "\n");
-           if (!i)
-               i = length (s)
-           p--;
-           if (!match (substr (s, p),
-                       /[\n]($falsepos)|[\n]($cblob)|$blob/) \\
-               || (RSTART > i && p + RSTART >= pend))
+           if (!cblob_p) {
+               if (blob_p ? replace_blob : replace_falsepos) {
+                   s = substr (s, 1, matchstart)               \\
+                       replacement                             \\
+                       substr (s, matchstart + matchlen);
+                   p = matchstart + length (replacement) - 1;
+                   pend += (p + 2 - matchstart - matchlen);
+               } else
+                   p = matchstart + matchlen - 1;
+
+               if (p > pend) {
+                   i = index (substr (s, p), "\n");
+                   if (i)
+                       pend = p + i;
+                   else
+                       pend = length (s)
+               }
+           }
+           
+           if (verbose) print "search until", pend;
+
+           if (!(matchfound = match (substr (s, p),
+                                     /[\n]($falsepos)|[\n]($cblob)|.($blob)/)) ||
+               p + RSTART >= pend)
                break;
        }
 
        if (print_nomatch)
            printf "%s", substr (s, pp, firstmatchstart - pp);
-        else if (print_blob || print_falsepos) {
+       else if (print_blob || print_falsepos) {
            lastline = substr (s, pp, firstmatchstart - pp);
            sub (/.*[\n]/, "", lastline);
+           if (verbose) print "lastline: " lastline "\\\\n"
            firstmatchstart -= length (lastline);
-        }
+       }
        pp = firstmatchstart;
 
-       if (p < pend)
-           p = pend;
-
-       i = index (substr (s, p), "\n");
-       if (i)
-           p += i;
-       else
-           p = length (s);
-
-       if (verbose) print "match set range:", pp, p
+       if (verbose) print "match set range:", pp, pend
 
        if ((print_blob && blobs) || (print_falsepos && falses)) {
            if (!print_nomatch)
-               for (i = nfilenames; i--;)
+               for (i = nfilenames; i-- > 0;)
                    print "::: " filenames[i] " :::";
-           printf "%s", substr (s, pp, p - pp);
-           pp = p;
+           printf "%s", substr (s, pp, pend - pp);
+           pp = pend;
        }
 
        if ((list_blob && blobs) || (list_falsepos && falses)) {
@@ -3655,7 +3855,7 @@ $eormatch /^[;][/][*]end .*[*][/][;]$eornl$/ {
     if (verbose)
        print "no further matches";
 
-    s = "";
+    s = "\n";
     nfilenames = nextnfilenames;
     next;
 }
@@ -3673,7 +3873,7 @@ s,[-]$, { blob (); },
 '     
 
   echo '%%' > "$scriptname"
-  sed "$adjust_rx" < "$regex_name" >> "$scriptname"
+  ${SED-sed} "$adjust_rx" < "$regex_name" >> "$scriptname"
   echo '\n|. { unmatched (); }
 %%
 int falsepos () {}
@@ -3777,7 +3977,7 @@ check () {
   set_except "$input"
 
   # Check that all regular expressions match our requirements.
-  sed -n '
+  ${SED-sed} -n '
 s,^\(-\^\?\|[+]\^\),,
 h
 s,[$]$,,
@@ -3845,7 +4045,7 @@ BAD regular expression:
        s/\$/*\\/;/
       }
       s/^[ $s]//"
-    cmd='sed "$sedpatch"'
+    cmd='${SED-sed} "$sedpatch"'
     ;;
   *)
     cmd='cat'
diff --git a/deblob-psed-disabled b/deblob-psed-disabled
deleted file mode 100755 (executable)
index 594fa43..0000000
+++ /dev/null
@@ -1,2004 +0,0 @@
-#!/usr/bin/perl
-    eval 'exec /usr/bin/perl -S $0 ${1+"$@"}'
-       if $running_under_some_shell;
-my $startperl;
-my $perlpath;
-($startperl = <<'/../') =~ s/\s*\z//;
-#!/usr/bin/perl
-/../
-($perlpath = <<'/../') =~ s/\s*\z//;
-/usr/bin/perl
-/../
-
-$0 =~ s/^.*?(\w+)[\.\w]*$/$1/;
-
-# (p)sed - a stream editor
-# History:  Aug 12 2000: Original version.
-#           Mar 25 2002: Rearrange generated Perl program.
-#           Jul 23 2007: Fix bug in regex stripping (M.Thorland)
-
-use strict;
-use integer;
-use Symbol;
-
-=head1 NAME
-
-psed - a stream editor
-
-=head1 SYNOPSIS
-
-   psed [-an] script [file ...]
-   psed [-an] [-e script] [-f script-file] [file ...]
-
-   s2p  [-an] [-e script] [-f script-file]
-
-=head1 DESCRIPTION
-
-A stream editor reads the input stream consisting of the specified files
-(or standard input, if none are given), processes is line by line by
-applying a script consisting of edit commands, and writes resulting lines
-to standard output. The filename `C<->' may be used to read standard input.
-
-The edit script is composed from arguments of B<-e> options and
-script-files, in the given order. A single script argument may be specified
-as the first parameter.
-
-If this program is invoked with the name F<s2p>, it will act as a
-sed-to-Perl translator. See L<"sed Script Translation">.
-
-B<sed> returns an exit code of 0 on success or >0 if an error occurred.
-
-=head1 OPTIONS
-
-=over 4
-
-=item B<-a>
-
-A file specified as argument to the B<w> edit command is by default
-opened before input processing starts. Using B<-a>, opening of such
-files is delayed until the first line is actually written to the file.
-
-=item B<-e> I<script>
-
-The editing commands defined by I<script> are appended to the script.
-Multiple commands must be separated by newlines.
-
-=item B<-f> I<script-file>
-
-Editing commands from the specified I<script-file> are read and appended
-to the script.
-
-=item B<-n>
-
-By default, a line is written to standard output after the editing script
-has been applied to it. The B<-n> option suppresses automatic printing.
-
-=back
-
-=head1 COMMANDS
-
-B<sed> command syntax is defined as
-
-Z<> Z<> Z<> Z<>[I<address>[B<,>I<address>]][B<!>]I<function>[I<argument>]
-
-with whitespace being permitted before or after addresses, and between
-the function character and the argument. The I<address>es and the
-address inverter (C<!>) are used to restrict the application of a
-command to the selected line(s) of input.
-
-Each command must be on a line of its own, except where noted in
-the synopses below.
-
-The edit cycle performed on each input line consist of reading the line
-(without its trailing newline character) into the I<pattern space>,
-applying the applicable commands of the edit script, writing the final
-contents of the pattern space and a newline to the standard output.
-A I<hold space> is provided for saving the contents of the
-pattern space for later use.
-
-=head2 Addresses
-
-A sed address is either a line number or a pattern, which may be combined
-arbitrarily to construct ranges. Lines are numbered across all input files.
-
-Any address may be followed by an exclamation mark (`C<!>'), selecting
-all lines not matching that address.
-
-=over 4
-
-=item I<number>
-
-The line with the given number is selected.
-
-=item B<$>
-
-A dollar sign (C<$>) is the line number of the last line of the input stream.
-
-=item B</>I<regular expression>B</>
-
-A pattern address is a basic regular expression (see 
-L<"Basic Regular Expressions">), between the delimiting character C</>.
-Any other character except C<\> or newline may be used to delimit a
-pattern address when the initial delimiter is prefixed with a
-backslash (`C<\>').
-
-=back
-
-If no address is given, the command selects every line.
-
-If one address is given, it selects the line (or lines) matching the
-address.
-
-Two addresses select a range that begins whenever the first address
-matches, and ends (including that line) when the second address matches.
-If the first (second) address is a matching pattern, the second 
-address is not applied to the very same line to determine the end of
-the range. Likewise, if the second address is a matching pattern, the
-first address is not applied to the very same line to determine the
-begin of another range. If both addresses are line numbers,
-and the second line number is less than the first line number, then
-only the first line is selected.
-
-
-=head2 Functions
-
-The maximum permitted number of addresses is indicated with each
-function synopsis below.
-
-The argument I<text> consists of one or more lines following the command.
-Embedded newlines in I<text> must be preceded with a backslash.  Other
-backslashes in I<text> are deleted and the following character is taken
-literally.
-
-=over 4
-
-=cut
-
-my %ComTab;
-my %GenKey;
-#--------------------------------------------------------------------------
-$ComTab{'a'}=[ 1, 'txt', \&Emit,       '{ push( @Q, <<'."'TheEnd' ) }\n" ]; #ok
-
-=item [1addr]B<a\> I<text>
-
-Write I<text> (which must start on the line following the command)
-to standard output immediately before reading the next line
-of input, either by executing the B<N> function or by beginning a new cycle.
-
-=cut
-
-#--------------------------------------------------------------------------
-$ComTab{'b'}=[ 2, 'str', \&Branch,     '{ goto XXX; }'                   ]; #ok
-
-=item [2addr]B<b> [I<label>]
-
-Branch to the B<:> function with the specified I<label>. If no label
-is given, branch to the end of the script.
-
-=cut
-
-#--------------------------------------------------------------------------
-$ComTab{'c'}=[ 2, 'txt', \&Change,     <<'-X-'                           ]; #ok
-{ print <<'TheEnd'; } $doPrint = 0; goto EOS;
--X-
-### continue OK => next CYCLE;
-
-=item [2addr]B<c\> I<text>
-
-The line, or range of lines, selected by the address is deleted. 
-The I<text> (which must start on the line following the command)
-is written to standard output. With an address range, this occurs at
-the end of the range.
-
-=cut
-
-#--------------------------------------------------------------------------
-$ComTab{'d'}=[ 2, '',    \&Emit,       <<'-X-'                           ]; #ok
-{ $doPrint = 0;
-  goto EOS;
-}
--X-
-### continue OK => next CYCLE;
-
-=item [2addr]B<d>
-
-Deletes the pattern space and starts the next cycle.
-
-=cut
-
-#--------------------------------------------------------------------------
-$ComTab{'D'}=[ 2, '',    \&Emit,       <<'-X-'                           ]; #ok
-{ s/^.*\n?//;
-  if(length($_)){ goto BOS } else { goto EOS }
-}
--X-
-### continue OK => next CYCLE;
-
-=item [2addr]B<D>
-
-Deletes the pattern space through the first embedded newline or to the end.
-If the pattern space becomes empty, a new cycle is started, otherwise
-execution of the script is restarted.
-
-=cut
-
-#--------------------------------------------------------------------------
-$ComTab{'g'}=[ 2, '',    \&Emit,       '{ $_ = $Hold };'                 ]; #ok
-
-=item [2addr]B<g>
-
-Replace the contents of the pattern space with the hold space.
-
-=cut
-
-#--------------------------------------------------------------------------
-$ComTab{'G'}=[ 2, '',    \&Emit,       '{ $_ .= "\n"; $_ .= $Hold };'    ]; #ok
-
-=item [2addr]B<G>
-
-Append a newline and the contents of the hold space to the pattern space.
-
-=cut
-
-#--------------------------------------------------------------------------
-$ComTab{'h'}=[ 2, '',    \&Emit,       '{ $Hold = $_ }'                  ]; #ok
-
-=item [2addr]B<h>
-
-Replace the contents of the hold space with the pattern space.
-
-=cut
-
-#--------------------------------------------------------------------------
-$ComTab{'H'}=[ 2, '',    \&Emit,       '{ $Hold .= "\n"; $Hold .= $_; }' ]; #ok
-
-=item [2addr]B<H>
-
-Append a newline and the contents of the pattern space to the hold space.
-
-=cut
-
-#--------------------------------------------------------------------------
-$ComTab{'i'}=[ 1, 'txt', \&Emit,       '{ print <<'."'TheEnd' }\n"       ]; #ok
-
-=item [1addr]B<i\> I<text>
-
-Write the I<text> (which must start on the line following the command)
-to standard output.
-
-=cut
-
-#--------------------------------------------------------------------------
-$ComTab{'l'}=[ 2, '',    \&Emit,       '{ _l() }'                        ]; #okUTF8
-
-=item [2addr]B<l>
-
-Print the contents of the pattern space: non-printable characters are
-shown in C-style escaped form; long lines are split and have a trailing
-`C<\>' at the point of the split; the true end of a line is marked with
-a `C<$>'. Escapes are: `\a', `\t', `\n', `\f', `\r', `\e' for
-BEL, HT, LF, FF, CR, ESC, respectively, and `\' followed by a three-digit
-octal number for all other non-printable characters.
-
-=cut
-
-#--------------------------------------------------------------------------
-$ComTab{'n'}=[ 2, '',    \&Emit,       <<'-X-'                           ]; #ok
-{ print $_, "\n" if $doPrint;
-  printQ() if @Q;
-  $CondReg = 0;
-  last CYCLE unless getsARGV();
-  chomp();
-}
--X-
-
-=item [2addr]B<n>
-
-If automatic printing is enabled, write the pattern space to the standard
-output. Replace the pattern space with the next line of input. If
-there is no more input, processing is terminated.
-
-=cut
-
-#--------------------------------------------------------------------------
-$ComTab{'N'}=[ 2, '',    \&Emit,       <<'-X-'                           ]; #ok
-{ printQ() if @Q;
-  $CondReg = 0;
-  last CYCLE unless getsARGV( $h );
-  chomp( $h );
-  $_ .= "\n$h";
-}
--X-
-
-=item [2addr]B<N>
-
-Append a newline and the next line of input to the pattern space. If
-there is no more input, processing is terminated.
-
-=cut
-
-#--------------------------------------------------------------------------
-$ComTab{'p'}=[ 2, '',    \&Emit,       '{ print $_, "\n"; }'             ]; #ok
-
-=item [2addr]B<p>
-
-Print the pattern space to the standard output. (Use the B<-n> option
-to suppress automatic printing at the end of a cycle if you want to
-avoid double printing of lines.)
-
-=cut
-
-#--------------------------------------------------------------------------
-$ComTab{'P'}=[ 2, '',    \&Emit,       <<'-X-'                           ]; #ok
-{ if( /^(.*)/ ){ print $1, "\n"; } }
--X-
-
-=item [2addr]B<P>
-
-Prints the pattern space through the first embedded newline or to the end.
-
-=cut
-
-#--------------------------------------------------------------------------
-$ComTab{'q'}=[ 1, 'str',    \&Emit,       <<'-X-'                           ]; #ok
-{ print $_, "\n" if $doPrint;
-  $exitstatus = '-X-';
-  last CYCLE;
-}
--X-
-
-=item [1addr]B<q>
-
-Branch to the end of the script and quit without starting a new cycle.
-
-=cut
-
-#--------------------------------------------------------------------------
-$ComTab{'r'}=[ 1, 'str', \&Emit,       "{ _r( '-X-' ) }"                 ]; #ok
-
-=item [1addr]B<r> I<file>
-
-Copy the contents of the I<file> to standard output immediately before
-the next attempt to read a line of input. Any error encountered while
-reading I<file> is silently ignored.
-
-=cut
-
-#--------------------------------------------------------------------------
-$ComTab{'s'}=[ 2, 'sub', \&Emit,       ''                                ]; #ok
-
-=item [2addr]B<s/>I<regular expression>B</>I<replacement>B</>I<flags>
-
-Substitute the I<replacement> string for the first substring in
-the pattern space that matches the I<regular expression>.
-Any character other than backslash or newline can be used instead of a 
-slash to delimit the regular expression and the replacement.
-To use the delimiter as a literal character within the regular expression
-and the replacement, precede the character by a backslash (`C<\>').
-
-Literal newlines may be embedded in the replacement string by
-preceding a newline with a backslash.
-
-Within the replacement, an ampersand (`C<&>') is replaced by the string
-matching the regular expression. The strings `C<\1>' through `C<\9>' are
-replaced by the corresponding subpattern (see L<"Basic Regular Expressions">).
-To get a literal `C<&>' or `C<\>' in the replacement text, precede it
-by a backslash.
-
-The following I<flags> modify the behaviour of the B<s> command:
-
-=over 8
-
-=item B<g>
-
-The replacement is performed for all matching, non-overlapping substrings
-of the pattern space.
-
-=item B<1>..B<9>
-
-Replace only the n-th matching substring of the pattern space.
-
-=item B<p>
-
-If the substitution was made, print the new value of the pattern space.
-
-=item B<w> I<file>
-
-If the substitution was made, write the new value of the pattern space
-to the specified file.
-
-=back
-
-=cut
-
-#--------------------------------------------------------------------------
-$ComTab{'t'}=[ 2, 'str', \&Branch,     '{ goto XXX if _t() }'            ]; #ok
-
-=item [2addr]B<t> [I<label>]
-
-Branch to the B<:> function with the specified I<label> if any B<s>
-substitutions have been made since the most recent reading of an input line
-or execution of a B<t> function. If no label is given, branch to the end of
-the script. 
-
-
-=cut
-
-#--------------------------------------------------------------------------
-$ComTab{'w'}=[ 2, 'str', \&Write,      "{ _w( '-X-' ) }"                 ]; #ok
-
-=item [2addr]B<w> I<file>
-
-The contents of the pattern space are written to the I<file>.
-
-=cut
-
-#--------------------------------------------------------------------------
-$ComTab{'x'}=[ 2, '',    \&Emit,       '{ ($Hold, $_) = ($_, $Hold) }'   ]; #ok
-
-=item [2addr]B<x>
-
-Swap the contents of the pattern space and the hold space.
-
-=cut
-
-#--------------------------------------------------------------------------
-$ComTab{'y'}=[ 2, 'tra', \&Emit,       ''                                ]; #ok
-=item [2addr]B<y>B</>I<string1>B</>I<string2>B</>
-
-In the pattern space, replace all characters occuring in I<string1> by the
-character at the corresponding position in I<string2>. It is possible
-to use any character (other than a backslash or newline) instead of a
-slash to delimit the strings.  Within I<string1> and I<string2>, a
-backslash followed by any character other than a newline is that literal
-character, and a backslash followed by an `n' is replaced by a newline
-character.
-
-=cut
-
-#--------------------------------------------------------------------------
-$ComTab{'='}=[ 1, '',    \&Emit,       '{ print "$.\n" }'                ]; #ok
-
-=item [1addr]B<=>
-
-Prints the current line number on the standard output.
-
-=cut
-
-#--------------------------------------------------------------------------
-$ComTab{':'}=[ 0, 'str', \&Label,      ''                                ]; #ok
-=item [0addr]B<:> [I<label>]
-
-The command specifies the position of the I<label>. It has no other effect.
-
-=cut
-
-#--------------------------------------------------------------------------
-$ComTab{'{'}=[ 2, '',    \&BeginBlock, '{'                               ]; #ok
-$ComTab{'}'}=[ 0, '',    \&EndBlock,   ';}'                              ]; #ok
-# ';' to avoid warning on empty {}-block
-
-=item [2addr]B<{> [I<command>]
-
-=item [0addr]B<}>
-
-These two commands begin and end a command list. The first command may
-be given on the same line as the opening B<{> command. The commands
-within the list are jointly selected by the address(es) given on the
-B<{> command (but may still have individual addresses).
-
-=cut
-
-#--------------------------------------------------------------------------
-$ComTab{'#'}=[ 0, 'str', \&Comment,    ''                                ]; #ok
-
-=item [0addr]B<#> [I<comment>]
-
-The entire line is ignored (treated as a comment). If, however, the first
-two characters in the script are `C<#n>', automatic printing of output is
-suppressed, as if the B<-n> option were given on the command line.
-
-=back
-
-=cut
-
-use vars qw{ $isEOF $Hold %wFiles @Q $CondReg $doPrint };
-
-my $useDEBUG    = exists( $ENV{PSEDDEBUG} );
-my $useEXTBRE   = $ENV{PSEDEXTBRE} || '';
-$useEXTBRE =~ s/[^<>wWyB]//g; # gawk RE's handle these
-
-my $doAutoPrint = 1;          # automatic printing of pattern space (-n => 0)
-my $doOpenWrite = 1;          # open w command output files at start (-a => 0)
-my $svOpenWrite = 0;          # save $doOpenWrite
-
-# lower case $0 below as a VMSism.  The VMS build procedure creates the
-# s2p file traditionally in upper case on the disk.  When VMS is in a
-# case preserved or case sensitive mode, $0 will be returned in the exact
-# case which will be on the disk, and that is not predictable at this time.
-
-my $doGenerate  = lc($0) eq 's2p';
-
-# Collected and compiled script
-#
-my( @Commands, %Defined, @BlockStack, %Label, $labNum, $Code, $Func );
-$Code = '';
-
-##################
-#  Compile Time
-#
-# Labels
-# 
-# Error handling
-#
-sub Warn($;$){
-    my( $msg, $loc ) = @_;
-    $loc ||= '';
-    $loc .= ': ' if length( $loc );
-    warn( "$0: $loc$msg\n" );
-}
-
-$labNum = 0;
-sub newLabel(){
-    return 'L_'.++$labNum;
-}
-
-# safeHere: create safe here delimiter and  modify opcode and argument
-#
-sub safeHere($$){
-    my( $codref, $argref ) = @_;
-    my $eod = 'EOD000';
-    while( $$argref =~ /^$eod$/m ){
-        $eod++;
-    }
-    $$codref =~ s/TheEnd/$eod/e;
-    $$argref .= "$eod\n"; 
-}
-
-# Emit: create address logic and emit command
-#
-sub Emit($$$$$$){
-    my( $addr1, $addr2, $negated, $opcode, $arg, $fl ) = @_;
-    my $cond = '';
-    if( defined( $addr1 ) ){
-        if( defined( $addr2 ) ){
-           $addr1 .= $addr2 =~ /^\d+$/ ? "..$addr2" : "...$addr2";
-        } else {
-           $addr1 .= ' == $.' if $addr1 =~ /^\d+$/;
-       }
-       $cond = $negated ? "unless( $addr1 )\n" : "if( $addr1 )\n";
-    }
-
-    if( $opcode eq '' ){
-       $Code .= "$cond$arg\n";
-
-    } elsif( $opcode =~ s/-X-/$arg/e ){
-       $Code .= "$cond$opcode\n";
-
-    } elsif( $opcode =~ /TheEnd/ ){
-       safeHere( \$opcode, \$arg );
-       $Code .= "$cond$opcode$arg";
-
-    } else {
-       $Code .= "$cond$opcode\n";
-    }
-    0;
-}
-
-# Write (w command, w flag): store pathname
-#
-sub Write($$$$$$){
-    my( $addr1, $addr2, $negated, $opcode, $path, $fl ) = @_;
-    $wFiles{$path} = '';
-    Emit( $addr1, $addr2, $negated, $opcode, $path, $fl );
-}
-
-
-# Label (: command): label definition
-#
-sub Label($$$$$$){
-    my( $addr1, $addr2, $negated, $opcode, $lab, $fl ) = @_;
-    my $rc = 0;
-    $lab =~ s/\s+//;
-    if( length( $lab ) ){
-       my $h;
-       if( ! exists( $Label{$lab} ) ){
-           $h = $Label{$lab}{name} = newLabel();
-        } else {
-           $h = $Label{$lab}{name};
-           if( exists( $Label{$lab}{defined} ) ){
-               my $dl = $Label{$lab}{defined};
-               Warn( "duplicate label $lab (first defined at $dl)", $fl );
-               $rc = 1;
-           }
-       }
-        $Label{$lab}{defined} = $fl;
-       $Code .= "$h:;\n";
-    }
-    $rc;
-}
-
-# BeginBlock ({ command): push block start
-#
-sub BeginBlock($$$$$$){
-    my( $addr1, $addr2, $negated, $opcode, $arg, $fl ) = @_;
-    push( @BlockStack, [ $fl, $addr1, $addr2, $negated ] );
-    Emit( $addr1, $addr2, $negated, $opcode, $arg, $fl );
-}
-
-# EndBlock (} command): check proper nesting
-#
-sub EndBlock($$$$$$){
-    my( $addr1, $addr2, $negated, $opcode, $arg, $fl ) = @_;
-    my $rc;
-    my $jcom = pop( @BlockStack );
-    if( defined( $jcom ) ){
-       $rc = Emit( $addr1, $addr2, $negated, $opcode, $arg, $fl );
-    } else {
-       Warn( "unexpected `}'", $fl );
-       $rc = 1;
-    }
-    $rc;
-}
-
-# Branch (t, b commands): check or create label, substitute default
-#
-sub Branch($$$$$$){
-    my( $addr1, $addr2, $negated, $opcode, $lab, $fl ) = @_;
-    $lab =~ s/\s+//; # no spaces at end
-    my $h;
-    if( length( $lab ) ){
-       if( ! exists( $Label{$lab} ) ){
-           $h = $Label{$lab}{name} = newLabel();
-        } else {
-           $h = $Label{$lab}{name};
-       }
-       push( @{$Label{$lab}{used}}, $fl );
-    } else {
-       $h = 'EOS';
-    }
-    $opcode =~ s/XXX/$h/e;
-    Emit( $addr1, $addr2, $negated, $opcode, '', $fl );
-}
-
-# Change (c command): is special due to range end watching
-#
-sub Change($$$$$$){
-    my( $addr1, $addr2, $negated, $opcode, $arg, $fl ) = @_;
-    my $kwd = $negated ? 'unless' : 'if';
-    if( defined( $addr2 ) ){
-        $addr1 .= $addr2 =~ /^\d+$/ ? "..$addr2" : "...$addr2";
-       if( ! $negated ){
-           $addr1  = '$icnt = ('.$addr1.')';
-           $opcode = 'if( $icnt =~ /E0$/ )' . $opcode;
-       }
-    } else {
-       $addr1 .= ' == $.' if $addr1 =~ /^\d+$/;
-    }
-    safeHere( \$opcode, \$arg );
-    $Code .= "$kwd( $addr1 ){\n  $opcode$arg}\n";
-    0;
-}
-
-
-# Comment (# command): A no-op. Who would've thought that!
-#
-sub Comment($$$$$$){
-    my( $addr1, $addr2, $negated, $opcode, $arg, $fl ) = @_;
-### $Code .= "# $arg\n";
-    0;
-}
-
-# stripRegex from the current command. If we're in the first
-# part of s///, trailing spaces have to be kept as the initial
-# part of the replacement string.
-#
-sub stripRegex($$;$){
-    my( $del, $sref, $sub ) = @_;
-    my $regex = $del;
-    print "stripRegex:$del:$$sref:\n" if $useDEBUG;
-    while( $$sref =~ s{^(.*?)(\\*)\Q$del\E(\s*)}{}s ){
-        my ($lead, $sl, $rest) = ($1, $2, $3);
-       $regex .= $lead.$sl.$del;
-       if( !($lead =~ /(?:^|[^\\])\[^?\]?[^]]*$/) && length( $sl ) % 2 == 0 ){
-            if( $sub && (length( $rest ) > 0) ){
-                $$sref = $rest . $$sref;
-           }
-           return $regex;
-       }
-       $regex .= $rest;
-    }
-    undef();
-}
-
-# stripTrans: take a <del> terminated string from y command
-#   honoring and cleaning up of \-escaped <del>'s
-#
-sub stripTrans($$){
-    my( $del, $sref ) = @_;
-    my $t = '';
-    print "stripTrans:$del:$$sref:\n" if $useDEBUG;
-    while( $$sref =~ s{^(.*?)(\\*)\Q$del\E}{}s ){
-        my $sl = $2;
-       $t .= $1;
-       if( length( $sl ) % 2 == 0 ){
-           $t .= $sl;
-           $t =~ s/\\\\/\\/g;
-           return $t;
-       }
-       chop( $sl );
-       $t .= $sl.$del.$3;
-    }
-    undef();
-}
-
-# makey - construct Perl y/// from sed y///
-#
-sub makey($$$){
-    my( $fr, $to, $fl ) = @_;
-    my $error = 0;
-
-    # Ensure that any '-' is up front.
-    # Diagnose duplicate contradicting mappings
-    my %tr;
-    for( my $i = 0; $i < length($fr); $i++ ){
-       my $fc = substr($fr,$i,1);
-       my $tc = substr($to,$i,1);
-       if( exists( $tr{$fc} ) && $tr{$fc} ne $tc ){
-           Warn( "ambiguous translation for character `$fc' in `y' command",
-                 $fl );
-           $error++;
-       }
-       $tr{$fc} = $tc;
-    }
-    $fr = $to = '';
-    if( exists( $tr{'-'} ) ){
-       ( $fr, $to ) = ( '-', $tr{'-'} );
-       delete( $tr{'-'} );
-    } else {
-       $fr = $to = '';
-    }
-    # might just as well sort it...
-    for my $fc ( sort keys( %tr ) ){
-       $fr .= $fc;
-       $to .= $tr{$fc};
-    }
-    # make embedded delimiters and newlines safe
-    $fr =~ s/([{}])/\$1/g;
-    $to =~ s/([{}])/\$1/g;
-    $fr =~ s/\n/\\n/g;
-    $to =~ s/\n/\\n/g;
-    return $error ? undef() : "{ y{$fr}{$to}; }";
-}
-
-######
-# makes - construct Perl s/// from sed s///
-#
-sub makes($$$$$$$){
-    my( $regex, $subst, $path, $global, $print, $nmatch, $fl ) = @_;
-
-    # make embedded newlines safe
-    $regex =~ s/\n/\\n/g;
-    $subst =~ s/\n/\\n/g;
-    my $code;
-    # n-th occurrence
-    #
-    if( length( $nmatch ) ){
-       $code = <<TheEnd;
-{ \$n = $nmatch;
-  while( --\$n && ( \$s = m ${regex}g ) ){}
-  \$s = ( substr( \$_, pos() ) =~ s ${regex}${subst}s ) if \$s;
-  \$CondReg ||= \$s;
-TheEnd
-    } else {
-        $code = <<TheEnd;
-{ \$s = s ${regex}${subst}s${global};
-  \$CondReg ||= \$s;
-TheEnd
-    }
-    if( $print ){
-        $code .= '  print $_, "\n" if $s;'."\n";
-    }
-    if( defined( $path ) ){
-        $wFiles{$path} = '';
-       $code .= " _w( '$path' ) if \$s;\n";
-        $GenKey{'w'} = 1;
-    }
-    $code .= "}";
-}
-
-=head1 BASIC REGULAR EXPRESSIONS
-
-A I<Basic Regular Expression> (BRE), as defined in POSIX 1003.2, consists
-of I<atoms>, for matching parts of a string, and I<bounds>, specifying
-repetitions of a preceding atom.
-
-=head2 Atoms
-
-The possible atoms of a BRE are: B<.>, matching any single character;
-B<^> and B<$>, matching the null string at the beginning or end
-of a string, respectively; a I<bracket expressions>, enclosed
-in B<[> and B<]> (see below); and any single character with no
-other significance (matching that character). A B<\> before one
-of: B<.>, B<^>, B<$>, B<[>, B<*>, B<\>, matching the character
-after the backslash. A sequence of atoms enclosed in B<\(> and B<\)>
-becomes an atom and establishes the target for a I<backreference>,
-consisting of the substring that actually matches the enclosed atoms.
-Finally, B<\> followed by one of the digits B<0> through B<9> is a
-backreference.
-
-A B<^> that is not first, or a B<$> that is not last does not have
-a special significance and need not be preceded by a backslash to
-become literal. The same is true for a B<]>, that does not terminate
-a bracket expression.
-
-An unescaped backslash cannot be last in a BRE.
-
-=head2 Bounds
-
-The BRE bounds are: B<*>, specifying 0 or more matches of the preceding
-atom; B<\{>I<count>B<\}>, specifying that many repetitions;
-B<\{>I<minimum>B<,\}>, giving a lower limit; and
-B<\{>I<minimum>B<,>I<maximum>B<\}> finally defines a lower and upper
-bound. 
-
-A bound appearing as the first item in a BRE is taken literally.
-
-=head2 Bracket Expressions
-
-A I<bracket expression> is a list of characters, character ranges
-and character classes enclosed in B<[> and B<]> and matches any
-single character from the represented set of characters.
-
-A character range is written as two characters separated by B<-> and
-represents all characters (according to the character collating sequence)
-that are not less than the first and not greater than the second.
-(Ranges are very collating-sequence-dependent, and portable programs
-should avoid relying on them.)
-
-A character class is one of the class names
-
-   alnum     digit     punct
-   alpha     graph     space
-   blank     lower     upper
-   cntrl     print     xdigit
-
-enclosed in B<[:> and B<:]> and represents the set of characters
-as defined in ctype(3).
-
-If the first character after B<[> is B<^>, the sense of matching is
-inverted.
-
-To include a literal `C<^>', place it anywhere else but first. To
-include a literal 'C<]>' place it first or immediately after an
-initial B<^>. To include a literal `C<->' make it the first (or
-second after B<^>) or last character, or the second endpoint of
-a range.
-
-The special bracket expression constructs C<[[:E<lt>:]]> and C<[[:E<gt>:]]> 
-match the null string at the beginning and end of a word respectively.
-(Note that neither is identical to Perl's `\b' atom.)
-
-=head2 Additional Atoms
-
-Since some sed implementations provide additional regular expression
-atoms (not defined in POSIX 1003.2), B<psed> is capable of translating
-the following backslash escapes:
-
-=over 4
-
-=item B<\E<lt>> This is the same as C<[[:E<gt>:]]>.
-
-=item B<\E<gt>> This is the same as C<[[:E<lt>:]]>.
-
-=item B<\w> This is an abbreviation for C<[[:alnum:]_]>.
-
-=item B<\W> This is an abbreviation for C<[^[:alnum:]_]>.
-
-=item B<\y> Match the empty string at a word boundary.
-
-=item B<\B> Match the empty string between any two either word or non-word characters.
-
-=back
-
-To enable this feature, the environment variable PSEDEXTBRE must be set
-to a string containing the requested characters, e.g.:
-C<PSEDEXTBRE='E<lt>E<gt>wW'>.
-
-=cut
-
-#####
-# bre2p - convert BRE to Perl RE
-#
-sub peek(\$$){
-    my( $pref, $ic ) = @_;
-    $ic < length($$pref)-1 ? substr( $$pref, $ic+1, 1 ) : '';
-}
-
-sub bre2p($$$){
-    my( $del, $pat, $fl ) = @_;
-    my $led = $del;
-    $led =~ tr/{([</})]>/;
-    $led = '' if $led eq $del;
-
-    $pat = substr( $pat, 1, length($pat) - 2 );
-    my $res = '';
-    my $bracklev = 0;
-    my $backref  = 0;
-    my $parlev = 0;
-    for( my $ic = 0; $ic < length( $pat ); $ic++ ){
-        my $c = substr( $pat, $ic, 1 );
-        if( $c eq '\\' ){
-           ### backslash escapes
-            my $nc = peek($pat,$ic);
-            if( $nc eq '' ){
-                Warn( "`\\' cannot be last in pattern", $fl );
-                return undef();
-            }
-           $ic++;
-            if( $nc eq $del ){ ## \<pattern del> => \<pattern del>
-                $res .= "\\$del";
-
-           } elsif( $nc =~ /([[.*\\n])/ ){
-               ## check for \-escaped magics and \n:
-               ## \[ \. \* \\ \n stay as they are
-                $res .= '\\'.$nc;
-
-            } elsif( $nc eq '(' ){ ## \( => (
-                $parlev++;
-                $res .= '(';
-
-            } elsif( $nc eq ')' ){ ## \) => )
-                $parlev--;
-               $backref++;
-                if( $parlev < 0 ){
-                    Warn( "unmatched `\\)'", $fl );
-                    return undef();
-                }
-                $res .= ')';
-
-            } elsif( $nc eq '{' ){ ## repetition factor \{<i>[,[<j>]]\}
-                my $endpos = index( $pat, '\\}', $ic );
-                if( $endpos < 0 ){
-                    Warn( "unmatched `\\{'", $fl );
-                    return undef();
-                }
-                my $rep = substr( $pat, $ic+1, $endpos-($ic+1) );
-                $ic = $endpos + 1;
-
-               if( $res =~ /^\^?$/ ){
-                   $res .= "\\{$rep\}";
-                } elsif( $rep =~ /^(\d+)(,?)(\d*)?$/ ){
-                    my $min = $1;
-                    my $com = $2 || '';
-                    my $max = $3;
-                    if( length( $max ) ){
-                        if( $max < $min ){
-                            Warn( "maximum less than minimum in `\\{$rep\\}'",
-                                 $fl );
-                            return undef();
-                        }
-                    } else {
-                        $max = '';
-                    }
-                   # simplify some
-                   if( $min == 0 && $max eq '1' ){
-                       $res .= '?';
-                   } elsif( $min == 1 && "$com$max" eq ',' ){
-                       $res .= '+';
-                   } elsif( $min == 0 && "$com$max" eq ',' ){
-                       $res .= '*';
-                   } else {
-                       $res .= "{$min$com$max}";
-                   }
-                } else {
-                    Warn( "invalid repeat clause `\\{$rep\\}'", $fl );
-                    return undef();
-                }
-
-            } elsif( $nc =~ /^[1-9]$/ ){
-               ## \1 .. \9 => \1 .. \9, but check for a following digit
-               if( $nc > $backref ){
-                    Warn( "invalid backreference ($nc)", $fl );
-                    return undef();
-               }
-                $res .= "\\$nc";
-               if( peek($pat,$ic) =~ /[0-9]/ ){
-                   $res .= '(?:)';
-               }
-
-            } elsif( $useEXTBRE && ( $nc =~ /[$useEXTBRE]/ ) ){
-               ## extensions - at most <>wWyB - not in POSIX
-                if(      $nc eq '<' ){ ## \< => \b(?=\w), be precise
-                    $res .= '\\b(?<=\\W)';
-                } elsif( $nc eq '>' ){ ## \> => \b(?=\W), be precise
-                    $res .= '\\b(?=\\W)';
-                } elsif( $nc eq 'y' ){ ## \y => \b
-                    $res .= '\\b';
-                } else {               ## \B, \w, \W remain the same
-                    $res .= "\\$nc";
-                } 
-           } elsif( $nc eq $led ){
-               ## \<closing bracketing-delimiter> - keep '\'
-               $res .= "\\$nc";
-
-            } else { ## \ <char> => <char> ("as if `\' were not present")
-                $res .= $nc;
-            }
-
-        } elsif( $c eq '.' ){ ## . => .
-            $res .= $c;
-
-       } elsif( $c eq '*' ){ ## * => * but \* if there's nothing preceding it
-           if( $res =~ /^\^?$/ ){
-                $res .= '\\*';
-            } elsif( substr( $res, -1, 1 ) ne '*' ){
-               $res .= $c;
-           }
-
-        } elsif( $c eq '[' ){
-           ## parse []: [^...] [^]...] [-...]
-           my $add = '[';
-           if( peek($pat,$ic) eq '^' ){
-               $ic++;
-               $add .= '^';
-           }
-           my $nc = peek($pat,$ic);
-           if( $nc eq ']' || $nc eq '-' ){
-               $add .= $nc;
-                $ic++;
-           }
-           # check that [ is not trailing
-           if( $ic >= length( $pat ) - 1 ){
-               Warn( "unmatched `['", $fl );
-               return undef();
-           }
-           # look for [:...:] and x-y
-           my $rstr = substr( $pat, $ic+1 );
-           if( $rstr =~ /^((?:\[:\(\w+|[><]\):\]|[^]-](?:-[^]])?)*)/ ){
-               my $cnt = $1;
-               $ic += length( $cnt );
-               $cnt =~ s/([\/\$])/\\$1/g; # `/', `$' are magic in Perl []
-               # try some simplifications
-               my $red = $cnt;
-               if( $red =~ s/0-9// ){
-                   $cnt = $red.'\d';
-                   if( $red =~ s/A-Z// && $red =~ s/a-z// && $red =~ s/_// ){
-                       $cnt = $red.'\w';
-                    }
-               }
-               $add .= $cnt;
-
-               # POSIX 1003.2 has this (optional) for begin/end word
-               $add = '\\b(?=\\W)'  if $add eq '[[:<:]]';
-               $add = '\\b(?<=\\W)' if $add eq '[[:>:]]';
-
-           }
-
-           ## may have a trailing `-' before `]'
-           if( $ic < length($pat) - 1 &&
-                substr( $pat, $ic+1 ) =~ /^(-?])/ ){
-               $ic += length( $1 );
-               $add .= $1;
-               # another simplification
-               $add =~ s/^\[(\^?)(\\[dw])]$/ $1 eq '^' ? uc($2) : $2 /e;
-               $res .= $add;
-           } else {
-               Warn( "unmatched `['", $fl );
-               return undef();
-           }
-
-        } elsif( $c eq $led ){ ## unescaped <closing bracketing-delimiter>
-            $res .= "\\$c";
-
-        } elsif( $c eq ']' ){ ## unmatched ] is not magic
-            $res .= ']';
-
-        } elsif( $c =~ /[|+?{}()@#\/]/ ){ ## not magic in BRE, but in Perl: \-quote
-            $res .= "\\$c";
-
-        } elsif( $c eq '^' ){ ## not magic unless 1st, but in Perl: \-quote
-            $res .= length( $res ) ? '\\^' : '^';
-
-        } elsif( $c eq '$' ){ ## not magic unless last, but in Perl: \-quote
-            $res .= $ic == length( $pat ) - 1 ? '$' : '\\$';
-
-        } else {
-            $res .= $c;
-        }
-    }
-
-    if( $parlev ){
-       Warn( "unmatched `\\('", $fl );
-       return undef();
-    }
-
-    # final cleanup: eliminate raw HTs
-    $res =~ s/\t/\\t/g;
-    return $del . $res . ( $led ? $led : $del );
-}
-
-
-#####
-# sub2p - convert sed substitution to Perl substitution
-#
-sub sub2p($$$){
-    my( $del, $subst, $fl ) = @_;
-    my $led = $del;
-    $led =~ tr/{([</})]>/;
-    $led = '' if $led eq $del;
-
-    $subst = substr( $subst, 1, length($subst) - 2 );
-    my $res = '';
-    for( my $ic = 0; $ic < length( $subst ); $ic++ ){
-        my $c = substr( $subst, $ic, 1 );
-        if( $c eq '\\' ){
-           ### backslash escapes
-            my $nc = peek($subst,$ic);
-            if( $nc eq '' ){
-                Warn( "`\\' cannot be last in substitution", $fl );
-                return undef();
-            }
-           $ic++;
-           if( $nc =~ /[\\$del$led]/ ){ ## \ and delimiter
-               $res .= '\\' . $nc;
-            } elsif( $nc =~ /[1-9]/ ){ ## \1 - \9 => ${1} - ${9}
-                $res .= '${' . $nc . '}';
-           } else { ## everything else (includes &): omit \
-               $res .= $nc;
-           }
-        } elsif( $c eq '&' ){ ## & => $&
-            $res .= '$&';
-       } elsif( $c =~ /[\$\@$led]/ ){ ## magic in Perl's substitution string
-           $res .= '\\' . $c;
-        } else {
-           $res .= $c;
-       }
-    }
-
-    # final cleanup: eliminate raw HTs
-    $res =~ s/\t/\\t/g;
-    return ( $led ? $del : $led ) . $res . ( $led ? $led : $del );
-}
-
-
-sub Parse(){
-    my $error = 0;
-    my( $pdef, $pfil, $plin );
-    for( my $icom = 0; $icom < @Commands; $icom++ ){
-       my $cmd = $Commands[$icom];
-       print "Parse:$cmd:\n" if $useDEBUG;
-       $cmd =~ s/^\s+//;
-       next unless length( $cmd );
-       my $scom = $icom;
-       if( exists( $Defined{$icom} ) ){
-           $pdef = $Defined{$icom};
-           if( $pdef =~ /^ #(\d+)/ ){
-               $pfil = 'expression #';
-               $plin = $1;
-           } else {
-               $pfil = "$pdef l.";
-               $plin = 1;
-            }
-        } else {
-           $plin++;
-        }
-        my $fl = "$pfil$plin";
-
-        # insert command as comment in gnerated code
-       #
-       $Code .= "# $cmd\n" if $doGenerate;
-
-       # The Address(es)
-       #
-       my( $negated, $naddr, $addr1, $addr2 );
-       $naddr = 0;
-       if(      $cmd =~ s/^(\d+)\s*// ){
-           $addr1 = "$1"; $naddr++;
-       } elsif( $cmd =~ s/^\$\s*// ){
-           $addr1 = 'eofARGV()'; $naddr++;
-       } elsif( $cmd =~ s{^(/)}{} || $cmd =~ s{^\\(.)}{} ){
-           my $del = $1;
-           my $regex = stripRegex( $del, \$cmd );
-           if( defined( $regex ) ){
-               $addr1 = 'm '.bre2p( $del, $regex, $fl ).'s';
-               $naddr++;
-           } else {
-               Warn( "malformed regex, 1st address", $fl );
-               $error++;
-               next;
-           }
-        }
-        if( defined( $addr1 ) && $cmd =~ s/,\s*// ){
-           if(      $cmd =~ s/^(\d+)\s*// ){
-               $addr2 = "$1"; $naddr++;
-           } elsif( $cmd =~ s/^\$\s*// ){
-               $addr2 = 'eofARGV()'; $naddr++;
-           } elsif( $cmd =~ s{^(/)}{} || $cmd =~ s{^\\(.)}{} ){
-               my $del = $1;
-               my $regex = stripRegex( $del, \$cmd );
-               if( defined( $regex ) ){
-                   $addr2 = 'm '. bre2p( $del, $regex, $fl ).'s';
-                   $naddr++;
-               } else {
-                   Warn( "malformed regex, 2nd address", $fl );
-                   $error++;
-                   next;
-               }
-            } else {
-               Warn( "invalid address after `,'", $fl );
-               $error++;
-               next;
-            }
-        }
-
-        # address modifier `!'
-        #
-        $negated = $cmd =~ s/^!\s*//;
-       if( defined( $addr1 ) ){
-           print "Parse: addr1=$addr1" if $useDEBUG;
-           if( defined( $addr2 ) ){
-               print ", addr2=$addr2 " if $useDEBUG;
-               # both numeric and addr1 > addr2 => eliminate addr2
-               undef( $addr2 ) if $addr1 =~ /^\d+$/ &&
-                                   $addr2 =~ /^\d+$/ && $addr1 > $addr2;
-           }
-       }
-       print 'negated' if $useDEBUG && $negated;
-       print " command:$cmd\n" if $useDEBUG;
-
-       # The Command
-       #
-        if( $cmd !~ s/^([:#={}abcdDgGhHilnNpPqrstwxy])\s*// ){
-           my $h = substr( $cmd, 0, 1 );
-           Warn( "unknown command `$h'", $fl );
-           $error++;
-           next;
-       }
-        my $key = $1;
-
-       my $tabref = $ComTab{$key};
-       $GenKey{$key} = 1;
-       if( $naddr > $tabref->[0] ){
-           Warn( "excess address(es)", $fl );
-           $error++;
-           next;
-       }
-
-       my $arg = '';
-       if(      $tabref->[1] eq 'str' ){
-           # take remainder - don't care if it is empty
-           $arg = $cmd;
-            $cmd = '';
-
-       } elsif( $tabref->[1] eq 'txt' ){
-           # multi-line text
-           my $goon = $cmd =~ /(.*)\\$/;
-           if( length( $1 ) ){
-               Warn( "extra characters after command ($cmd)", $fl );
-               $error++;
-           }
-           while( $goon ){
-               $icom++;
-               if( $icom > $#Commands ){
-                   Warn( "unexpected end of script", $fl );
-                   $error++;
-                   last;
-               }
-               $cmd = $Commands[$icom];
-               $Code .= "# $cmd\n" if $doGenerate;
-               $goon = $cmd =~ s/\\$//;
-               $cmd =~ s/\\(.)/$1/g;
-               $arg .= "\n" if length( $arg );
-               $arg .= $cmd;
-           }
-           $arg .= "\n" if length( $arg );
-           $cmd = '';
-
-       } elsif( $tabref->[1] eq 'sub' ){
-           # s///
-           if( ! length( $cmd ) ){
-               Warn( "`s' command requires argument", $fl );
-               $error++;
-               next;
-           }
-           if( $cmd =~ s{^([^\\\n])}{} ){
-               my $del = $1;
-               my $regex = stripRegex( $del, \$cmd, "s" );
-               if( ! defined( $regex ) ){
-                   Warn( "malformed regular expression", $fl );
-                   $error++;
-                   next;
-               }
-               $regex = bre2p( $del, $regex, $fl );
-
-               # a trailing \ indicates embedded NL (in replacement string)
-               while( $cmd =~ s/(?<!\\)\\$/\n/ ){
-                   $icom++;
-                   if( $icom > $#Commands ){
-                       Warn( "unexpected end of script", $fl );
-                       $error++;
-                       last;
-                   }
-                   $cmd .= $Commands[$icom];
-                   $Code .= "# $Commands[$icom]\n" if $doGenerate;
-               }
-
-               my $subst = stripRegex( $del, \$cmd );
-               if( ! defined( $regex ) ){
-                   Warn( "malformed substitution expression", $fl );
-                   $error++;
-                   next;
-               }
-               $subst = sub2p( $del, $subst, $fl );
-
-               # parse s/// modifier: g|p|0-9|w <file>
-               my( $global, $nmatch, $print, $write ) =
-                 ( '',      '',      0,      undef );
-               while( $cmd =~ s/^([gp0-9])// ){
-                   $1 eq 'g' ? ( $global = 'g' ) :
-                   $1 eq 'p' ? ( $print  = $1  ) : ( $nmatch .= $1 );
-                }
-               $write = $1 if $cmd =~ s/w\s*(.*)$//;
-               ### $nmatch =~ s/^(\d)\1*$/$1/; ### may be dangerous?
-               if( $global && length( $nmatch ) || length( $nmatch ) > 1 ){
-                   Warn( "conflicting flags `$global$nmatch'", $fl );
-                   $error++;
-                   next;
-               }
-
-               $arg = makes( $regex, $subst,
-                             $write, $global, $print, $nmatch, $fl );
-               if( ! defined( $arg ) ){
-                   $error++;
-                   next;
-               }
-
-            } else {
-               Warn( "improper delimiter in s command", $fl );
-               $error++;
-               next;
-            }
-
-       } elsif( $tabref->[1] eq 'tra' ){
-           # y///
-           # a trailing \ indicates embedded newline
-           while( $cmd =~ s/(?<!\\)\\$/\n/ ){
-               $icom++;
-               if( $icom > $#Commands ){
-                   Warn( "unexpected end of script", $fl );
-                   $error++;
-                   last;
-               }
-               $cmd .= $Commands[$icom];
-                $Code .= "# $Commands[$icom]\n" if $doGenerate;
-           }
-           if( ! length( $cmd ) ){
-               Warn( "`y' command requires argument", $fl );
-               $error++;
-               next;
-           }
-           my $d = substr( $cmd, 0, 1 ); $cmd = substr( $cmd, 1 );
-           if( $d eq '\\' ){
-               Warn( "`\\' not valid as delimiter in `y' command", $fl );
-               $error++;
-               next;
-           }
-           my $fr = stripTrans( $d, \$cmd );
-           if( ! defined( $fr ) || ! length( $cmd ) ){
-               Warn( "malformed `y' command argument", $fl );
-               $error++;
-               next;
-           }
-           my $to = stripTrans( $d, \$cmd );
-           if( ! defined( $to ) ){
-               Warn( "malformed `y' command argument", $fl );
-               $error++;
-               next;
-           }
-           if( length($fr) != length($to) ){
-               Warn( "string lengths in `y' command differ", $fl );
-               $error++;
-               next;
-           }
-           if( ! defined( $arg = makey( $fr, $to, $fl ) ) ){
-               $error++;
-               next;
-           }
-
-       }
-
-       # $cmd must be now empty - exception is {
-       if( $cmd !~ /^\s*$/ ){
-           if( $key eq '{' ){
-               # dirty hack to process command on '{' line
-               $Commands[$icom--] = $cmd;
-           } else {
-               Warn( "extra characters after command ($cmd)", $fl );
-               $error++;
-               next;
-           }
-       }
-
-       # Make Code
-        #
-       if( &{$tabref->[2]}( $addr1, $addr2, $negated,
-                             $tabref->[3], $arg, $fl ) ){
-           $error++;
-       }
-    }
-
-    while( @BlockStack ){
-       my $bl = pop( @BlockStack );
-       Warn( "start of unterminated `{'", $bl );
-        $error++;
-    }
-
-    for my $lab ( keys( %Label ) ){
-       if( ! exists( $Label{$lab}{defined} ) ){
-           for my $used ( @{$Label{$lab}{used}} ){
-               Warn( "undefined label `$lab'", $used );
-               $error++;
-           }
-       }
-    }
-
-    exit( 1 ) if $error;
-}
-
-
-##############
-#### MAIN ####
-##############
-
-sub usage(){
-    print STDERR "Usage: sed [-an] command [file...]\n";
-    print STDERR "           [-an] [-e command] [-f script-file] [file...]\n";
-}
-
-###################
-# Here we go again...
-#
-my $expr = 0;
-while( @ARGV && $ARGV[0] =~ /^-(.)(.*)$/ ){
-    my $opt = $1;
-    my $arg = $2;
-    shift( @ARGV );
-    if(      $opt eq 'e' ){
-        if( length( $arg ) ){
-           push( @Commands, split( "\n", $arg ) );
-        } elsif( @ARGV ){
-           push( @Commands, shift( @ARGV ) ); 
-        } else {
-            Warn( "option -e requires an argument" );
-            usage();
-            exit( 1 );
-        }
-       $expr++;
-        $Defined{$#Commands} = " #$expr";
-       next;
-    }
-    if( $opt eq 'f' ){
-        my $path;
-        if( length( $arg ) ){
-           $path = $arg;
-        } elsif( @ARGV ){
-           $path = shift( @ARGV ); 
-        } else {
-            Warn( "option -f requires an argument" );
-            usage();
-            exit( 1 );
-        }
-       my $fst = $#Commands + 1;
-        open( SCRIPT, "<$path" ) || die( "$0: $path: could not open ($!)\n" );
-        my $cmd;
-        while( defined( $cmd = <SCRIPT> ) ){
-            chomp( $cmd );
-            push( @Commands, $cmd );
-        }
-        close( SCRIPT );
-       if( $#Commands >= $fst ){
-           $Defined{$fst} = "$path";
-       }
-       next;
-    }
-    if( $opt eq '-' && $arg eq '' ){
-       last;
-    }
-    if( $opt eq 'h' || $opt eq '?' ){
-        usage();
-        exit( 0 );
-    }
-    if( $opt eq 'n' ){
-       $doAutoPrint = 0;
-    } elsif( $opt eq 'a' ){
-       $doOpenWrite = 0;
-    } else {
-        Warn( "illegal option `$opt'" );
-        usage();
-        exit( 1 );
-    }
-    if( length( $arg ) ){
-       unshift( @ARGV, "-$arg" );
-    }
-}
-
-# A singleton command may be the 1st argument when there are no options.
-#
-if( @Commands == 0 ){
-    if( @ARGV == 0 ){
-        Warn( "no script command given" );
-        usage();
-        exit( 1 );
-    }
-    push( @Commands, split( "\n", shift( @ARGV ) ) );
-    $Defined{0} = ' #1';
-}
-
-print STDERR "Files: @ARGV\n" if $useDEBUG;
-
-# generate leading code
-#
-$Func = <<'[TheEnd]';
-
-# openARGV: open 1st input file
-#
-sub openARGV(){
-    unshift( @ARGV, '-' ) unless @ARGV;
-    my $file = shift( @ARGV );
-    open( ARG, "<$file" )
-    || die( "$0: can't open $file for reading ($!)\n" );
-    $isEOF = 0;
-}
-
-# getsARGV: Read another input line into argument (default: $_).
-#           Move on to next input file, and reset EOF flag $isEOF.
-sub getsARGV(;\$){
-    my $argref = @_ ? shift() : \$_; 
-    while( $isEOF || ! defined( $$argref = <ARG> ) ){
-       close( ARG );
-       return 0 unless @ARGV;
-       my $file = shift( @ARGV );
-       open( ARG, "<$file" )
-       || die( "$0: can't open $file for reading ($!)\n" );
-       $isEOF = 0;
-    }
-    1;
-}
-
-# eofARGV: end-of-file test
-#
-sub eofARGV(){
-    return @ARGV == 0 && ( $isEOF = eof( ARG ) );
-}
-
-# makeHandle: Generates another file handle for some file (given by its path)
-#             to be written due to a w command or an s command's w flag.
-sub makeHandle($){
-    my( $path ) = @_;
-    my $handle;
-    if( ! exists( $wFiles{$path} ) || $wFiles{$path} eq '' ){
-        $handle = $wFiles{$path} = gensym();
-       if( $doOpenWrite ){
-           if( ! open( $handle, ">$path" ) ){
-               die( "$0: can't open $path for writing: ($!)\n" );
-           }
-       }
-    } else {
-        $handle = $wFiles{$path};
-    }
-    return $handle;
-}
-
-# printQ: Print queued output which is either a string or a reference
-#         to a pathname.
-sub printQ(){
-    for my $q ( @Q ){
-       if( ref( $q ) ){
-            # flush open w files so that reading this file gets it all
-           if( exists( $wFiles{$$q} ) && $wFiles{$$q} ne '' ){
-               open( $wFiles{$$q}, ">>$$q" );
-           }
-            # copy file to stdout: slow, but safe
-           if( open( RF, "<$$q" ) ){
-               while( defined( my $line = <RF> ) ){
-                   print $line;
-               }
-               close( RF );
-           }
-       } else {
-           print $q;
-       }
-    }
-    undef( @Q );
-}
-
-[TheEnd]
-
-# generate the sed loop
-#
-$Code .= <<'[TheEnd]';
-sub openARGV();
-sub getsARGV(;\$);
-sub eofARGV();
-sub printQ();
-
-# Run: the sed loop reading input and applying the script
-#
-sub Run(){
-    my( $h, $icnt, $s, $n );
-    # hack (not unbreakable :-/) to avoid // matching an empty string
-    my $z = "\000"; $z =~ /$z/;
-    my $exitstatus = 0;
-    # Initialize.
-    openARGV();
-    $Hold    = '';
-    $CondReg = 0;
-    $doPrint = $doAutoPrint;
-CYCLE:
-    while( getsARGV() ){
-       chomp();
-       $CondReg = 0;   # cleared on t
-BOS:;
-[TheEnd]
-
-    # parse - avoid opening files when doing s2p
-    #
-    ( $svOpenWrite, $doOpenWrite ) = (  $doOpenWrite, $svOpenWrite )
-      if $doGenerate;
-    Parse();
-    ( $svOpenWrite, $doOpenWrite ) = (  $doOpenWrite, $svOpenWrite )
-      if $doGenerate;
-
-    # append trailing code
-    #
-    $Code .= <<'[TheEnd]';
-EOS:    if( $doPrint ){
-            print $_, "\n";
-        } else {
-           $doPrint = $doAutoPrint;
-       }
-        printQ() if @Q;
-    }
-
-    exit( $exitstatus );
-}
-[TheEnd]
-
-
-# append optional functions, prepend prototypes
-#
-my $Proto = "# prototypes\n";
-if( $GenKey{'l'} ){
-    $Proto .= "sub _l();\n";
-    $Func .= <<'[TheEnd]';
-# _l: l command processing
-#
-sub _l(){        
-    my $h = $_;
-    my $mcpl = 70;
-    # transform non printing chars into escape notation
-    $h =~ s/\\/\\\\/g;
-    if( $h =~ /[^[:print:]]/ ){
-       $h =~ s/\a/\\a/g;
-       $h =~ s/\f/\\f/g;
-       $h =~ s/\n/\\n/g;
-       $h =~ s/\t/\\t/g;
-       $h =~ s/\r/\\r/g;
-       $h =~ s/\e/\\e/g;
-        $h =~ s/([^[:print:]])/sprintf("\\%03o", ord($1))/ge;
-    }
-    # split into lines of length $mcpl
-    while( length( $h ) > $mcpl ){
-       my $l = substr( $h, 0, $mcpl-1 );
-       $h = substr( $h, $mcpl );
-       # remove incomplete \-escape from end of line
-       if( $l =~ s/(?<!\\)(\\[0-7]{0,2})$// ){
-           $h = $1 . $h;
-       }
-       print $l, "\\\n";
-    }
-    print "$h\$\n";
-}
-
-[TheEnd]
-}
-
-if( $GenKey{'r'} ){
-    $Proto .= "sub _r(\$);\n";
-    $Func .= <<'[TheEnd]';
-# _r: r command processing: Save a reference to the pathname.
-#
-sub _r($){
-    my $path = shift();
-    push( @Q, \$path );
-}
-
-[TheEnd]
-}
-
-if( $GenKey{'t'} ){
-    $Proto .= "sub _t();\n";
-    $Func .= <<'[TheEnd]';
-# _t: t command - condition register test/reset
-#
-sub _t(){
-    my $res = $CondReg;
-    $CondReg = 0;
-    $res;
-}
-
-[TheEnd]
-}
-
-if( $GenKey{'w'} ){
-    $Proto .= "sub _w(\$);\n";
-    $Func .= <<'[TheEnd]';
-# _w: w command and s command's w flag - write to file 
-#
-sub _w($){
-    my $path   = shift();
-    my $handle = $wFiles{$path};
-    if( ! $doOpenWrite && ! defined( fileno( $handle ) ) ){
-       open( $handle, ">$path" )
-       || die( "$0: $path: cannot open ($!)\n" );
-    }
-    print $handle $_, "\n";
-}
-
-[TheEnd]
-}
-
-$Code = $Proto . $Code;
-
-# magic "#n" - same as -n option
-#
-$doAutoPrint = 0 if substr( $Commands[0], 0, 2 ) eq '#n';
-
-# eval code - check for errors
-#
-print "Code:\n$Code$Func" if $useDEBUG;
-eval $Code . $Func;
-if( $@ ){
-    print "Code:\n$Code$Func";
-    die( "$0: internal error - generated incorrect Perl code: $@\n" );
-}
-
-if( $doGenerate ){
-
-    # write full Perl program
-    #
-    # bang line, declarations, prototypes
-    print <<TheEnd;
-#!$perlpath -w
-eval 'exec $perlpath -S \$0 \${1+"\$@"}'
-  if 0;
-\$0 =~ s/^.*?(\\w+)\[\\.\\w+\]*\$/\$1/;
-
-use strict;
-use Symbol;
-use vars qw{ \$isEOF \$Hold \%wFiles \@Q \$CondReg
-            \$doAutoPrint \$doOpenWrite \$doPrint };
-\$doAutoPrint = $doAutoPrint;
-\$doOpenWrite = $doOpenWrite;
-TheEnd
-
-    my $wf = "'" . join( "', '",  keys( %wFiles ) ) . "'";
-    if( $wf ne "''" ){
-       print <<TheEnd;
-sub makeHandle(\$);
-for my \$p ( $wf ){
-   exit( 1 ) unless makeHandle( \$p );
-}
-TheEnd
-   }
-
-   print $Code;
-   print "Run();\n";
-   print $Func;
-   exit( 0 );
-
-} else {
-
-    # execute: make handles (and optionally open) all w files; run!
-    for my $p ( keys( %wFiles ) ){
-        exit( 1 ) unless makeHandle( $p );
-    }
-    Run();
-}
-
-
-=head1 ENVIRONMENT
-
-The environment variable C<PSEDEXTBRE> may be set to extend BREs.
-See L<"Additional Atoms">.
-
-=head1 DIAGNOSTICS
-
-=over 4
-
-=item ambiguous translation for character `%s' in `y' command
-
-The indicated character appears twice, with different translations.
-
-=item `[' cannot be last in pattern
-
-A `[' in a BRE indicates the beginning of a I<bracket expression>.
-
-=item `\' cannot be last in pattern
-
-A `\' in a BRE is used to make the subsequent character literal.
-
-=item `\' cannot be last in substitution
-
-A `\' in a subsitution string is used to make the subsequent character literal.
-
-=item conflicting flags `%s'
-
-In an B<s> command, either the `g' flag and an n-th occurrence flag, or
-multiple n-th occurrence flags are specified. Note that only the digits
-`1' through `9' are permitted.
-
-=item duplicate label %s (first defined at %s)
-
-=item excess address(es)
-
-The command has more than the permitted number of addresses.
-
-=item extra characters after command (%s)
-
-=item illegal option `%s'
-
-=item improper delimiter in s command
-
-The BRE and substitution may not be delimited with `\' or newline.
-
-=item invalid address after `,'
-
-=item invalid backreference (%s)
-
-The specified backreference number exceeds the number of backreferences
-in the BRE.
-
-=item invalid repeat clause `\{%s\}'
-
-The repeat clause does not contain a valid integer value, or pair of
-values.
-
-=item malformed regex, 1st address
-
-=item malformed regex, 2nd address
-
-=item malformed regular expression
-
-=item malformed substitution expression
-
-=item malformed `y' command argument
-
-The first or second string of a B<y> command  is syntactically incorrect.
-
-=item maximum less than minimum in `\{%s\}'
-
-=item no script command given
-
-There must be at least one B<-e> or one B<-f> option specifying a
-script or script file.
-
-=item `\' not valid as delimiter in `y' command
-
-=item option -e requires an argument
-
-=item option -f requires an argument
-
-=item `s' command requires argument
-
-=item start of unterminated `{'
-
-=item string lengths in `y' command differ
-
-The translation table strings in a B<y> command must have equal lengths.
-
-=item undefined label `%s'
-
-=item unexpected `}'
-
-A B<}> command without a preceding B<{> command was encountered.
-
-=item unexpected end of script
-
-The end of the script was reached although a text line after a
-B<a>, B<c> or B<i> command indicated another line.
-
-=item unknown command `%s'
-
-=item unterminated `['
-
-A BRE contains an unterminated bracket expression.
-
-=item unterminated `\('
-
-A BRE contains an unterminated backreference.
-
-=item `\{' without closing `\}'
-
-A BRE contains an unterminated bounds specification.
-
-=item `\)' without preceding `\('
-
-=item `y' command requires argument
-
-=back
-
-=head1 EXAMPLE
-
-The basic material for the preceding section was generated by running
-the sed script
-
-   #no autoprint
-   s/^.*Warn( *"\([^"]*\)".*$/\1/
-   t process
-   b
-   :process
-   s/$!/%s/g
-   s/$[_[:alnum:]]\{1,\}/%s/g
-   s/\\\\/\\/g
-   s/^/=item /
-   p
-
-on the program's own text, and piping the output into C<sort -u>.
-
-
-=head1 SED SCRIPT TRANSLATION
-
-If this program is invoked with the name F<s2p> it will act as a
-sed-to-Perl translator. After option processing (all other
-arguments are ignored), a Perl program is printed on standard
-output, which will process the input stream (as read from all
-arguments) in the way defined by the sed script and the option setting
-used for the translation.
-
-=head1 SEE ALSO
-
-perl(1), re_format(7)
-
-=head1 BUGS
-
-The B<l> command will show escape characters (ESC) as `C<\e>', but
-a vertical tab (VT) in octal.
-
-Trailing spaces are truncated from labels in B<:>, B<t> and B<b> commands.
-
-The meaning of an empty regular expression (`C<//>'), as defined by B<sed>,
-is "the last pattern used, at run time". This deviates from the Perl
-interpretation, which will re-use the "last last successfully executed
-regular expression". Since keeping track of pattern usage would create
-terribly cluttered code, and differences would only appear in obscure
-context (where other B<sed> implementations appear to deviate, too),
-the Perl semantics was adopted. Note that common usage of this feature,
-such as in C</abc/s//xyz/>, will work as expected.
-
-Collating elements (of bracket expressions in BREs) are not implemented.
-
-=head1 STANDARDS
-
-This B<sed> implementation conforms to the IEEE Std1003.2-1992 ("POSIX.2")
-definition of B<sed>, and is compatible with the I<OpenBSD>
-implementation, except where otherwise noted (see L<"BUGS">).
-
-=head1 AUTHOR
-
-This Perl implementation of I<sed> was written by Wolfgang Laun,
-I<Wolfgang.Laun@alcatel.at>.
-
-=head1 COPYRIGHT and LICENSE
-
-This program is free and open software. You may use, modify,
-distribute, and sell this program (and any modified variants) in any
-way you wish, provided you do not restrict others from doing the same.
-
-=cut
-