home *** CD-ROM | disk | FTP | other *** search
- // ------------------------------- //
- // -------- Start of File -------- //
- // ------------------------------- //
- // ----------------------------------------------------------- //
- // C++ Source Code File Name: ffind.cpp
- // Compiler Used: MSVC40, DJGPP 2.7.2.1, GCC 2.7.2.1, HP CPP 10.24
- // Produced By: gaer@nhc.noaa.gov
- // File Creation Date: 03/09/1999
- // Date Last Modified: 03/26/1999
- // ----------------------------------------------------------- //
- // ------------- Program description and details ------------- //
- // ----------------------------------------------------------- //
- /*
- THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND.
- THE ENTIRE RISK OF THE QUALITY AND PERFORMANCE OF THIS SOFTWARE
- IS WITH YOU. SHOULD ANY ELEMENT OF THIS SOFTWARE PROVE DEFECTIVE,
- YOU WILL ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR, OR
- CORRECTION.
-
- This program is used to find and replace strings in a file.
- */
- // ----------------------------------------------------------- //
- #include <stdio.h>
- #include <string.h>
- #include <stdlib.h>
- #include <fstream.h>
- #include <iostream.h>
- #include "strutil.h"
- #include "ustring.h"
- #include "dllist.h"
-
- // Version number and program name
- const double FFindVersionNumber = 1031.102;
- const char *ProgramName = "ffind";
-
- // Program globals
- const int MAX_LINE = 1024; // Maximum characters per line
- char *open_file = 0; // Name of file currently opened
- unsigned num_files = 0; // Total number of files processed
- char *string_to_find = 0; // String to find in each line
- int find_string = 0; // Find specified string flag
- int find_all = 0; // Find all occurrences
- int check_case = 1; // Case sensitive/insensitive compare flag
- unsigned num_matches = 0; // Total number of matches found
- int cat_file = 0; // Concatenate file flag
- char *string_to_replace = 0; // String to replace
- char *string_to_insert = 0; // String to insert
- int replacing_string = 0; // Replace string flag
- int num_replaced = 0; // Number of strings replaced
- int replacing_line = 0; // Replace line flag
- int inserting_string = 0; // Insert line flag
- int append_lines = 1; // Append lines connected with a backslash
- int num_processed = 0; // Number of string processed per file
-
- void HelpMessage(const char *program_name, const double version_number)
- {
- char vbuffer[255];
- sprintf(vbuffer, "%.3f", version_number);
- cout << endl;
- cout << program_name << " program version "
- << vbuffer << endl;
- cout << "Usage: " << program_name << " [switches] iofile.txt " << endl;
- cout << "Switches: " << endl;
- cout << " -a = Do not append lines connected by a backslash"
- << endl;
- cout << " -c = Concatenate file to stdout." << endl;
- cout << " -f = Find first occurrence of specified string: "
- << "-f\"string\"" << endl;
- cout << " -F = Find all occurrences of specified string: "
- << "-F\"string\"" << endl;
- cout << " -i = Perform case insensitive compare." << endl;
- cout << endl;
- cout << " -R -W = Replace all occurrences of a string in a file."
- << endl;
- cout << " Usage: -R\"string\" -W\"replacement\"" << endl;
- cout << endl;
- cout << " -L -W = Replace entire line after the specifed string."
- << endl;
- cout << " Usage: -L\"string\" -W\"replacement\"" << endl;
- cout << endl;
- cout << " -I -W = Insert a line after the specifed string."
- << endl;
- cout << " Usage: -I\"string\" -W\"insert\"" << endl;
- cout << endl;
- exit(0);
- }
-
- int ProcessArgs(char *arg)
- {
- switch(arg[1]) {
- case 'a':
- append_lines = 0;
- break;
-
- case 'c':
- cat_file = 1;
- break;
-
- case 'f':
- if(arg[2] == '\0') {
- cerr << endl;
- cerr << "You must enter a string following the -f option." << endl;
- cerr << "Example usage: " << ProgramName << " -f\"string\"" << endl;
- cerr << endl;
- return 0;
- }
- find_string = 1;
- find_all = 0;
- replacing_line = 0;
- replacing_string = 0;
- inserting_string = 0;
- string_to_find = arg+2;
- break;
-
- case 'F':
- if(arg[2] == '\0') {
- cerr << endl;
- cerr << "You must enter a string following the -F option." << endl;
- cerr << "Example usage: " << ProgramName << " -F\"string\"" << endl;
- cerr << endl;
- return 0;
- }
- find_string = 1;
- find_all =1;
- replacing_line = 0;
- replacing_string = 0;
- inserting_string = 0;
- string_to_find = arg+2;
- break;
-
- case 'i':
- check_case = 0;
- break;
-
- case 'R':
- if(arg[2] == '\0') {
- cerr << endl;
- cerr << "You must enter a string following the -R option." << endl;
- cerr << "Example usage: " << ProgramName << " -R\"string\"" << endl;
- cerr << endl;
- return 0;
- }
- string_to_replace = arg+2;
- replacing_string = 1;
- replacing_line = 0;
- inserting_string = 0;
- find_string = 0;
- find_all = 0;
- break;
-
- case 'L':
- if(arg[2] == '\0') {
- cerr << endl;
- cerr << "You must enter a string following the -L option." << endl;
- cerr << "Example usage: " << ProgramName << " -L\"string\"" << endl;
- cerr << endl;
- return 0;
- }
- string_to_replace = arg+2;
- replacing_line = 1;
- replacing_string = 0;
- inserting_string = 0;
- find_string = 0;
- find_all = 0;
- break;
-
- case 'I':
- if(arg[2] == '\0') {
- cerr << endl;
- cerr << "You must enter a string following the -I option." << endl;
- cerr << "Example usage: " << ProgramName << " -I\"string\"" << endl;
- cerr << endl;
- return 0;
- }
- string_to_replace = arg+2;
- inserting_string = 1;
- replacing_line = 0;
- replacing_string = 0;
- find_string = 0;
- find_all = 0;
- break;
-
- case 'W':
- if(arg[2] == '\0') {
- cerr << endl;
- cerr << "You must enter a string following the -W option." << endl;
- cerr << "Example usage: " << ProgramName << " -W\"string\"" << endl;
- cerr << endl;
- return 0;
- }
-
- if(string_to_replace == 0) {
- cerr << endl;
- cerr << "The -W option must be used with the -R, -L, or -I option."
- << endl;
- cerr << "Usage: -R\"string\" -W\"replacement\"" << endl;
- cerr << endl;
- return 0;
- }
-
- string_to_insert = arg+2;
- break;
-
- default:
- cerr << endl;
- cerr << "Unknown switch " << arg << endl;
- cerr << "Exiting..." << endl;
- cerr << endl;
- return 0;
- }
- arg[0] = '\0';
- return 1; // All command line arguments were valid
- }
-
- int ProcessTextFile(fstream &iofile, ostream &stream)
- {
- char LineBuffer[MAX_LINE];
- char rawLineBuffer[MAX_LINE];
- UString LineData;
- UString appendLineBuffer;
- DLList<UString> list;
- int i, j, rv, offset = 0;
- unsigned long line_number = 0;
-
- while(!iofile.eof()) { // Read in the file line by line
-
- // Clear the buffers
- for(i = 0; i < MAX_LINE; i++) LineBuffer[i] = '\0';
- for(i = 0; i < MAX_LINE; i++) rawLineBuffer[i] = '\0';
- LineData.DeleteAt(0, LineData.length());
- offset = 0; // Reset string offset
-
- iofile.getline(rawLineBuffer, MAX_LINE);
- line_number++;
-
- // Filter each line of text
- for(i = 0, j = 0; i < MAX_LINE; i++) {
- if((rawLineBuffer[i] == '\r') || (rawLineBuffer[i] == '\n')) break;
- LineBuffer[j++] = rawLineBuffer[i];
- }
-
- // Detect backslashes used to mark the continuation of a line
- if((LineBuffer[strlen(LineBuffer)-1] == '\\') && (append_lines == 1)) {
- appendLineBuffer += LineBuffer;
- appendLineBuffer += '\n'; // Insert LF after the backslash
- continue; // Goto the top of loop and append next line
- }
- if(appendLineBuffer.length() > 0) { // Append the next line
- appendLineBuffer += LineBuffer;
- LineData = appendLineBuffer;
- appendLineBuffer.DeleteAt(0, appendLineBuffer.length());
- }
- else
- LineData = LineBuffer;
-
- // Routine to cat file
- // -----------------------------------------------------------
- if(cat_file) {
- if(!iofile.eof()) // Get rid of EOF marker
- stream << LineData << endl;
- else
- stream << LineData;
- }
-
- // Routine to find a string
- // -----------------------------------------------------------
- if(string_to_find != 0 && find_string != 0) {
- if(find_all) {
- while(1) {
- if(check_case)
- offset = LineData.Find(string_to_find, offset);
- else
- offset = LineData.IFind(string_to_find, offset);
- if(offset == UString::NoMatch) break;
- num_matches++; num_processed++;
- offset++;
- }
- }
- else {
- if(check_case)
- rv = LineData.Find(string_to_find);
- else
- rv = LineData.IFind(string_to_find);
- if(rv != UString::NoMatch) {
- num_matches++; num_processed++;
- cout << "Found a match on line #" << line_number << endl;
- }
- }
- }
-
- // Get rid of EOF marker
- if((strcmp(LineData.c_str(), "\0") == 0) && (iofile.eof())) break;
-
- // Routine to replace a string
- // -----------------------------------------------------------
- if(replacing_string) {
- while(1) {
- if(check_case)
- offset = LineData.Find(string_to_replace, offset);
- else
- offset = LineData.IFind(string_to_replace, offset);
- if(offset == UString::NoMatch) break;
- LineData.DeleteAt(offset, (strlen(string_to_replace)));
- LineData.InsertAt(offset, string_to_insert);
- num_replaced++; // Update global replacement counter
- num_processed++; // Record number of string processed for this file
- offset += strlen(string_to_insert);
- }
- list.StoreNode(LineData); // Store all the lines
- }
-
- // Routine to replace a line
- // -----------------------------------------------------------
- if(replacing_line) {
- if(check_case)
- offset = LineData.Find(string_to_replace, offset);
- else
- offset = LineData.IFind(string_to_replace, offset);
-
- if(offset != UString::NoMatch) {
- offset += strlen(string_to_replace);
- LineData.DeleteAt(offset, (LineData.length() - offset));
- LineData.InsertAt(offset, string_to_insert);
- num_replaced++; // Update global replacement counter
- num_processed++; // Record number of string processed for this file
- }
- list.StoreNode(LineData); // Store all the lines
- }
-
- // Routine to insert a line
- // -----------------------------------------------------------
- if(inserting_string) {
- if(check_case)
- offset = LineData.Find(string_to_replace, offset);
- else
- offset = LineData.IFind(string_to_replace, offset);
-
- if(offset != UString::NoMatch) {
- offset += strlen(string_to_replace);
- LineData.InsertAt(offset, string_to_insert);
- num_replaced++; // Update global replacement counter
- num_processed++; // Record number of string processed for this file
- }
- list.StoreNode(LineData); // Store all the lines
- }
- }
-
- // If any strings were replaced in the file, rewrite the file
- // -----------------------------------------------------------
- if(num_replaced > 0) {
- char *EndOfLineSequence;
- iofile.close();
- #if defined(__DOS__)
- // In DOS/Windows there are two file types, text and binary
- fstream iofile(open_file, ios::out|ios::trunc|ios::binary);
- EndOfLineSequence = "\r\n";
- #else
- // In UNIX there is only one file type
- fstream iofile(open_file, ios::out|ios::in|ios::trunc);
- EndOfLineSequence = "\n";
- #endif
-
- if(!iofile) {
- cerr << endl;
- cerr << "Cannot write to: " << open_file << endl;
- cerr << "Exiting..." << endl;
- cerr << endl;
- exit(0);
- }
-
- DNode<UString> *list_ptr = list.GetFront();
- while(!list.IsHeader(list_ptr)) {
- iofile.write(list_ptr->Data.c_str(), list_ptr->Data.length());
- iofile.write(EndOfLineSequence, strlen(EndOfLineSequence));
- list_ptr = list_ptr->GetNext();
- }
-
- iofile.close();
- }
-
- list.Clear();
- return 1;
- }
-
- // Program's main thread of execution.
- // -----------------------------------------------------------
- int main(int argc, // Number of strings in array argv.
- char *argv[], // Array of command-line argument strings.
- char *envp[]) // Array of environment variable strings.
- // NOTE: None of the MSVC compilers will expand wildcard characters
- // used in command-line arguments unless linked with the setargv.obj
- // library. All the UNIX compliers will expand wildcard characters
- // by default.
- {
- // If no arguments are given print usage message to the screen
- if(argc < 3) {
- HelpMessage(ProgramName, FFindVersionNumber);
- return 0;
- }
-
- // Process command ling arguments and files
- int narg;
- char *arg = argv[narg = 1];
- while (narg < argc) {
- if (arg[0] != '\0') {
- if (arg[0] == '-') { // Look for command line arguments
- if(!ProcessArgs(arg)) return 0; // Exit if argument is not valid
- }
- else {
- open_file = arg; // Update the open file name pointer
- #if defined(__DOS__)
- // In MS-DOS there are two file types, text and binary
- fstream iofile(open_file, ios::in|ios::nocreate|ios::binary);
- #else
- // In UNIX there is only one file type
- fstream iofile(open_file, ios::in|ios::nocreate);
- #endif
- if(!iofile) {
- cerr << endl;
- cerr << "Cannot open file: " << open_file << endl;
- cerr << "Exiting..." << endl;
- cerr << endl;
- return 0;
- }
- num_files++;
-
- // Echo the name of the file and search operation
- // -----------------------------------------------------------
- if(replacing_string == 1) {
- if(string_to_insert == 0) {
- cerr << endl;
- cerr << "The -R option must be used with the -W option." << endl;
- cerr << "Usage: -R\"string\" -W\"replacement\"" << endl;
- cerr << endl;
- return 0;
- }
- num_processed = 0; // Number of string processed for this file
- cout << endl;
- cout << "Opening file: " << open_file << endl;
- cout << "Replacing: " << string_to_replace << endl;
- cout << "With: " << string_to_insert << endl;
- }
-
- if(replacing_line) {
- if(string_to_insert == 0) {
- cerr << endl;
- cerr << "The -L option must be used with the -W option." << endl;
- cerr << "Usage: -L\"string\" -W\"replacement\"" << endl;
- return 0;
- }
- num_processed = 0; // Number of string processed for this file
- cout << endl;
- cout << "Opening file: " << open_file << endl;
- cout << "Replacing line after: " << string_to_replace << endl;
- cout << "With: " << string_to_insert << endl;
- }
-
- if(inserting_string ) {
- if(string_to_insert == 0) {
- cerr << endl;
- cerr << "The -I option must be used with the -W option." << endl;
- cerr << "Usage: -I\"string\" -W\"insert\"" << endl;
- cerr << endl;
- return 0;
- }
- num_processed = 0; // Number of string processed for this file
- cout << endl;
- cout << "Opening file: " << open_file << endl;
- cout << "Inserting: " << string_to_replace << endl;
- cout << "After: " << string_to_insert << endl;
- }
-
- if(find_string) {
- num_processed = 0; // Number of string processed for this file
- cout << endl;
- cout << "Opening file: " << open_file << endl;
- cout << "Seraching for: " << string_to_find << endl;
- }
-
- // Process the test file
- num_matches = 0; num_replaced = 0; num_processed = 0;
- ProcessTextFile(iofile, cout);
- if(num_files) iofile.close();
-
- // Report the total number of strings replaced/inserted
- // -----------------------------------------------------------
- if(replacing_string) {
- cout << "Replaced " << num_processed << " occurrence(s)." << endl;
- cout << endl;
- }
-
- if(replacing_line) {
- cout << "Replaced " << num_processed << " occurrence(s)." << endl;
- cout << endl;
- }
-
- if(inserting_string ) {
- cout << "Inserted " << num_processed << " line(s)." << endl;
- cout << endl;
- }
-
- if(find_string) {
- if(find_all) {
- cout << "Found " << num_processed << " matches" << endl;
- cout << endl;
- }
- if(num_matches == 0) { // Used by -f command if search fails
- cout << "No matches found." << endl;
- cout << endl;
- }
- }
- }
- arg = argv[++narg];
- }
- }
-
- if(num_files == 0) {
- cerr << endl;
- cerr << "You must enter a file name." << endl;
- cerr << "Exiting..." << endl;
- cerr << endl;
- return 0;
- }
-
- // Return the total number of strings replaced/inserted
- // -----------------------------------------------------------
- if(replacing_string) return num_replaced;
- if(replacing_line) return num_replaced;
- if(inserting_string ) return num_replaced;
- if(find_string) return num_matches;
-
- return 0;
- }
- // ----------------------------------------------------------- //
- // ------------------------------- //
- // --------- End of File --------- //
- // ------------------------------- //
-