/*_ replace.d 2003-11-05 Modified by: Adam Harper */ /*_ replace.d 2003-11-01 Modified by: Charles Hixson */ /*_ replace.c Mon Nov 21 1988 Modified by: Walter Bright */ import std.file; import std.stream; import std.c.stdio; // the replacing string and the string being replaced char[] newstr, oldstr; // the input and output files File filIn, filOut; uint strcount; int main( char[][] args ) { int i; uint len; char[] sourcename, backupname; if( args.length < 2 ) { std.c.stdio.printf( "Usage:\n\treplace filename(s)\n" ); return 1; }; std.c.stdio.printf( "String to be replaced? (terminate with a CR)\n" ); oldstr = std.stream.stdin.readLine(); std.c.stdio.printf( "Replacement string? (terminate with a CR)\n" ); newstr = std.stream.stdin.readLine(); strcount = 0; for( i = 1; i < args.length; i++ ) { char[] tempname; sourcename = args[i]; std.c.stdio.printf( "File <<%.*s>>\n", sourcename ); tempname = sourcename ~ ".tmp"; backupname = sourcename ~ ".bak"; try { filOut = new File(); filOut.create( tempname, FileMode.Out ); } catch( FileError fe ) { std.c.stdio.printf( "cannot create/write to <<%.*s>>\n", tempname ); continue; }; try { filIn = new File( sourcename, FileMode.In ); } catch( FileError fe ) { std.c.stdio.printf( "cannot open <<%.*s>> for reading\n", sourcename ); }; //std.c.stdio.printf( "%.*s\n", backupname ); //continue; strcount = doReplace(); filOut.close(); filIn.close(); if( strcount > 0 ) { try { std.file.remove( backupname ); /* Delete any existing backup. */ } catch( FileError fe ) { // }; try { std.file.rename( sourcename, backupname ); std.file.rename( tempname, sourcename ); } catch( FileError fe ) { std.c.stdio.printf( "File rename error with file <<%.*s>>\n", sourcename ); // I think that in this case an abort is the correct answer // as some manual recovery work may need to be done char[] tmp = "File rename error with file <<" ~ sourcename ~ ">>"; throw new FileError( tmp ); }; } else { std.c.stdio.printf( "No changes\n" ); try { std.file.remove( tempname ); } catch( FileError fe ) { std.c.stdio.printf( "could not delete file <<" ~ tempname ~ ">>\nmanual cleanup needed!\n" ); }; }; backupname = ""; tempname = ""; std.c.stdio.printf( "%d strings replaced in <<%.*s>>", strcount, sourcename ); strcount = 0; }; return 0; }; /* The parameters are the global values: * filIn : The file of original data * filOut : The temporary data file * oldstr : The data to be replaced * newstr : The data replacing the old data * * N.B.: String data values must be contained within one line * of the data std.file. * N.B.: This implementation decides to conserve memory at a cost * in execution time (unless readLine and writeLine have a buffered * implementation). */ uint doReplace( ) { uint cnt = 0; char[] wrk1, wrk2; while( filIn.eof() == false ) { wrk1 = filIn.readLine(); cnt += replaceInLine( wrk1, oldstr, newstr, wrk2 ); filOut.writeLine( wrk2 ); }; return cnt; }; /* Replace occurrences of from[] with to[] in s[]. * Closely based on the routine from phobos/string.d * inpLine is the data string for replacements (input line) * old is the pattern to be matched * to is the pattern that old is to be changed to * outLine is the revised data string (output line) * returned value is the count of replacements */ uint replaceInLine( char[] inpLine, char[] old, char[] to, out char[] outLine ) { char[] p; // the revised line int cnt = 0; // the count of replacements int i = 0; int istart = 0; // where the match starts if( old.length < 1 ){ return 0; }; while( istart < inpLine.length ) { i = find( inpLine[ istart..inpLine.length ], old ); if( i == -1 ) { p ~= inpLine[ istart..inpLine.length ]; break; }; p ~= inpLine[ istart..(istart + i) ]; p ~= to; istart += i + old.length; cnt++; }; outLine = p; return cnt; };