Reading Text File and Appending

Pages: 123
Ok so that was one of the ways I tried when I was trying to figure out how to correct the errors, however, it is still disregarding the original stuff and only copying in the new lines.

1
2
3
for (string line; getline(in_config, line) && line.find("</settings>") == string::npos; vlines.push_back(line)) {

	

So that works except it duplicates everything from the original file and then does everything correctly from the newlines file. Here is the whole code so far:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
//

#include <fstream>
#include <iostream>
#include <string>
#include <cstdlib>
#include <set>
#include <vector>
#include <Windows.h>
using namespace std;

int main() {

    

    const string Dir{ "C:/synergyii/config/" },
        oldname = Dir + "clientconfig.xml",
        newname = Dir + "clientconfig.txt";

    if (rename(oldname.c_str(), newname.c_str()) != 0) {
        perror("Error renaming file");
        return 1;
    }

    ifstream in_config{ newname },
        in_newlines{ Dir + "newlines.txt" };
    ofstream out{ oldname };

    if (!in_config) {
        cerr << "Cannot open clientconfig.txt for reading\n";
        return 1;
    }
    if (!in_newlines) {
        cerr << "Cannot open client newlines.txt for reading\n";
        return 1;
    }
    if (!out) {
        cerr << "Cannot open clientconfig.xml for writing\n";
        return 1;
    }

    vector<string> vlines;
    set<string>    slines;

    for (string line; getline(in_config, line) && line.find("</settings>") == string::npos; vlines.push_back(line)) {
        const auto& result = slines.insert(line);
        if (result.second)
            vlines.push_back(line);
    }

    for (string line; getline(in_newlines, line); ) {
        const auto& result = slines.insert(line);
        if (result.second)
            vlines.push_back(line);
    }
    

    for (const auto& line : vlines)
       out << line << '\n';

    out << '\t' << "</settings>\n";
    out << "</config>\n";
}
BUT I figured it out. Had the extra vlines.push_back(line) in there and once I took it, the code is working!
I've been looking over this to make sure there are no other scenarios that might cause it to not work and I ran into a possible issue. There may be times where the clientconfig.xml is not formatted cleaning. It may have just long lines of the codes and settings. Typically there are all inside <> brackets. So I figured I would add a part in the program to clean up the config first then discard the old and start the new line addition. However, I am struggling with delimiters or at least I think I need to use a delimiter to split the lines at the ><. Here is what I have:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
//

#include <fstream>
#include <sstream>
#include <iostream>
#include <string>
#include <cstdlib>
#include <set>
#include <vector>
#include <stdio.h>
#include <Windows.h>
using namespace std;

int main() {
    
    // First Part to Clean Up Config

    const string Dir{ "C:/synergyii/config/" },
        oldname = Dir + "clientconfig.xml",
        newname = Dir + "clientconfig-old.xml";

    if (rename(oldname.c_str(), newname.c_str()) != 0) {
        perror("Error renaming file");
        return 1;
    }

    ifstream in_config1{ newname };
    ofstream out1{ oldname };

    if (!in_config1) {
        cerr << "Cannot open clientconfig-old.xml for reading\n";
        return 1;
    }

    if (!out1) {
        cerr << "Cannot open clientconfig.xml for writing\n";
        return 1;
    }

    set<string> line1;
          
    while (in_config1)
    {
        
        // this is where I want to seperate the lines at the middle of >< so each lines ends with > and starts with <
        // Might also have to seperate some lines where they are >// so that the previous line ends with > and the next ends with //

    }

    remove("clientconfig-old.xml");


    // Second part to Add New Lines

    const string Dir{ "C:/synergyii/config/" },
        oldname = Dir + "clientconfig.xml",
        newname = Dir + "clientconfig-old.xml";

    if (rename(oldname.c_str(), newname.c_str()) != 0) {
        perror("Error renaming file");
        return 1;
    }

    ifstream in_config{ newname },
        in_newlines{ Dir + "newlines.txt" };
    ofstream out{ oldname };

    if (!in_config) {
        cerr << "Cannot open clientconfig-old.xml for reading\n";
        return 1;
    }
    if (!in_newlines) {
        cerr << "Cannot open client newlines.txt for reading\n";
        return 1;
    }
    if (!out) {
        cerr << "Cannot open clientconfig.xml for writing\n";
        return 1;
    }

    vector<string> vlines;
    set<string>    slines;

    for (string line; getline(in_config, line) && line.find("</settings>") == string::npos; ) {
        const auto& result = slines.insert(line);
        if (result.second)
            vlines.push_back(line);
    }

    for (string line; getline(in_newlines, line); ) {
        const auto& result = slines.insert(line);
        if (result.second)
            vlines.push_back(line);
    }
    

    for (const auto& line : vlines)
       out << line << '\n';

    out << '\t' << "</settings>\n";
    out << "</config>\n";
}


In the while (in_config1) I tried to use a getline but would not work. I believe I tried getline(in_config1, line1, "><"); but knew that would not work cause I am not sure where to define the delimiter. I put a note in the code what I am trying to achieve at the point. I will continue to scour the web for more info but anything can help since you all have help so much already.

Thanks,
V
Tried:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
    while(getline(in_config1, line1))
    {
        stringstream ss(line1);

        while(getline(ss, line1, '<')){
        
            out1 << "<" << line1 << '\n';
        
        }

    }


    char dfilename[] = "C:\\SynergyII\\config\\clientconfig-old.xml";

    if (remove(dfilename) != 0)
        perror("File deletion failed");
    else
        cout << "File deleted successfully";

 


but it is removing the leading < and breaking the lines up at every < so this is not the right deal. Also can't delete the file. Saying permission denied.

I even tried some of the stuff I learned from the early codes in this topic with no luck:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
    vector<string> vlines1;
    set<string> slines1;

    for (string line1; getline(in_config1, line1.replace(line1.begin(), line1.end(), '><', '>_<'));) {

        const auto& result = slines1.insert(line1);
        if (result.second)
                    vlines1.push_back(line1);        

    }
    
    for (const auto& line1 : vlines1)
        out1 << line1 << '\n';


I know someone like seeplus is going to have the answer and then I'm going to feel really stupid because it'll all make sense after :(
Post a sample of the data you are trying to parse and indicate what part you want to extract.
I was able to achieve what I wanted to do. I’m working on the code a little more to do some rearranging now and will post what I used as soon as I get it nailed down tight.
OK so here is an example of what is in the clientconfig.xml that I am trying to edit:

<?xml version="1.0" encoding="UTF-8"?>
<config>
<settings>
<differentsettings>true</differentsettings>
<etc>true</etc>
<etc>false</etc>
</settings>

<services>
<variousserviceclasses>
<thoseclasssettings>
</variousserviceclasses>
<variousserviceclasses>
<thoseclasssettings>
</variousserviceclasses>
</services>
<initpart>
<initstuff>
</initpart>
</config>

what I want to do is move the part in bold that settings are to go in between </initpart> and </config>. At first I was trying to get the hang of add new lines which we did. But in the event the <settings> section is not at the end I wish to move it. The first part fixes the config to be line by line and works well. Just need to get over the rearranging part and I think I will be done. This is my code so far. I don't have anything in the rearrange part as what I tried did nothing so I am open to suggestions.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
//

#include <stdio.h>
#include <fstream>
#include <sstream>
#include <iostream>
#include <string>
#include <cstdlib>
#include <set>
#include <vector>
#include <Windows.h>
using namespace std;

void findAndReplaceAll(std::string& data, std::string toSearch, std::string replaceStr)
{
    // Get the first occurrence
    size_t pos = data.find(toSearch);
    // Repeat till end is reached
    while (pos != std::string::npos)
    {
        // Replace this occurrence of Sub String
        data.replace(pos, toSearch.size(), replaceStr);
        // Get the next occurrence from the current position
        pos = data.find(toSearch, pos + replaceStr.size());
    }
}

int main() {

    // First Part to Clean Up Config

    const string Dir{ "C:/synergyii/config/" },
        oldname1 = Dir + "clientconfig.xml",
        newname1 = Dir + "clientconfig-old.xml";

    //if (rename(oldname1.c_str(), newname1.c_str()) != 0) {
    //    perror("Error renaming file");
    //    return 1;
    //}

    ifstream in_config1{ oldname1 };
    ofstream out1{ Dir + "clientconfigtemp.txt" };

    if (!in_config1) {
        cerr << "Cannot open clientconfig-old.xml for reading\n";
        return 1;
    }

    if (!out1) {
        cerr << "Cannot open clientconfig.xml for writing\n";
        return 1;
    }

    string line1;

    while (getline(in_config1, line1)) {

        findAndReplaceAll(line1, "><", ">^<");

        stringstream ss(line1);

        while (getline(ss, line1, '^')) {

            out1 << line1 << '\n';
        }
    }

    &ifstream::close;
    &ofstream::close;

    // Second Part Reorder if Needed

    ifstream in_config2{ Dir + "clientconfigtemp.txt" };
    ofstream out2{ Dir + "clientconfigtemp2.txt" };

    if (!in_config2) {
        cerr << "Cannot open clientconfig-old.xml for reading\n";
        return 1;
    }

    if (!out2) {
        cerr << "Cannot open clientconfig.xml for writing\n";
        return 1;
    }

    &ifstream::close;
    &ofstream::close;


    // Third part to Add New Lines

    const string Dir{ "C:/synergyii/config/" },
        oldname = Dir + "clientconfig.xml",
        newname = Dir + "clientconfig-old.xml";

    if (rename(oldname.c_str(), newname.c_str()) != 0) {
        perror("Error renaming file");
        return 1;
    }

    ifstream in_config{ Dir + "clientconfigtemp.txt" },
        in_newlines{ Dir + "newlines.txt" };
        ofstream out{ oldname1 };

    if (!in_config) {
        cerr << "Cannot open clientconfigtemp.txt for reading\n";
        return 1;
    }
    if (!in_newlines) {
        cerr << "Cannot open client newlines.txt for reading\n";
        return 1;
    }
    if (!out) {
        cerr << "Cannot open clientconfig.xml for writing\n";
        return 1;
    }
    
    vector<string> vlines;
    set<string>    slines;

    for (string line; getline(in_config, line) && line.find("</settings>") == string::npos; ) {
        const auto& result = slines.insert(line);
        if (result.second)
            vlines.push_back(line);
    }

    for (string line; getline(in_newlines, line); ) {
        const auto& result = slines.insert(line);
        if (result.second)
            vlines.push_back(line);
    }
    

    for (const auto& line : vlines)
       out << line << '\n';

    out << '\t' << "</settings>\n";
    out << "</config>\n";
}


> what I want to do is move the part in bold that settings are to go in between </initpart> and </config>.
> ..
> Just need to get over the rearranging part

The rearranging part could be something like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
#include <iostream>
#include <string>
#include <cctype>
#include <vector>
#include <cassert>
#include <fstream>

// remove leading and trailing white space
std::string trim( std::string str )
{
    std::size_t pos = 0 ;
    while( pos < str.size() && std::isspace( static_cast<unsigned char>(str[pos]) ) ) ++pos ;

    while( !str.empty() && std::isspace( static_cast<unsigned char>( str.back() ) ) ) str.pop_back() ;

    return str.substr(pos) ;
}

// convert to all lower case
std::string to_lower( const std::string& str )
{
    std::string result ;
    for( unsigned char c : str ) result += std::tolower(c) ;
    return result ;
}

// return true if substr is a prefix of str; after ignoring white space and case
bool starts_with( const std::string& str, const std::string& substr )
{
    return to_lower( trim(str) ).find( to_lower( trim(substr) ) ) == 0 ;
}

// read lines from an input stream into a vector
std::vector<std::string> get_lines( std::istream& stm )
{
    std::vector<std::string> result ;

    std::string line ;
    while( std::getline( stm, line ) ) result.push_back(line) ;

    return result ;
}

// write lines from the vector to an output stream
std::ostream& put_lines( std::ostream& stm, const std::vector<std::string>& lines )
{
    for( const std::string& str : lines ) stm << str << '\n' ;
    return stm ;
}

// return the position of the first line with the given prefix. return lines.size() if not found
std::size_t find_prefix( const std::vector<std::string>& lines, const std::string& prefix )
{

    for( std::size_t pos = 0 ; pos < lines.size() ; ++pos )
        if( starts_with( lines[pos], prefix ) ) return pos ;

    return lines.size() ; // not found
}

// move lines in positions [from,to] to the position immediately before dest
std::vector<std::string> move_lines_forward( std::vector<std::string> lines, std::size_t from, std::size_t to, std::size_t dest )
{
    assert( from <= to && to <= dest ) ; // sanity check

    std::vector<std::string> result ;

    // move lines [0,from) to result
    for( std::size_t i = 0 ; i < from ; ++i ) result.push_back( std::move( lines[i] ) ) ;

    // move lines [to+1,dest) to result
    for( std::size_t i = to+1 ; i < dest ; ++i ) result.push_back( std::move( lines[i] ) ) ;

    // move lines in positions [from,to] to result
    for( std::size_t i = from ; i <= to ; ++i ) result.push_back( std::move( lines[i] ) ) ;

    // move lines [dest,end) to result
    for( std::size_t i = dest ; i < lines.size() ; ++i ) result.push_back( std::move( lines[i] ) ) ;

    assert( result.size() == lines.size() ) ; // sanity check

    return result ;
}


int main()
{
    const std::string test_file_name = "test_clientconfig.xml" ;

    {
        // for testing: create a test file and dump its contents
        std::ofstream(test_file_name) <<
R"(<?xml version="1.0" encoding="UTF-8"?>
<config>
    <settings>
        <differentsettings>true</differentsettings>
        <etc>true</etc>
        <etc>false</etc>
    </settings>
    <services>
        <variousserviceclasses>
            <thoseclasssettings>
        </variousserviceclasses>
        <variousserviceclasses>
            <thoseclasssettings>
        </variousserviceclasses>
    </services>
    <initpart>
        <initstuff>
    </initpart>
</config>
)" ;
      std::cout << "test file contains:\n------------------\n"
                << std::ifstream(test_file_name).rdbuf() << "-----------\n\n" ;
    }

    if( std::ifstream file{test_file_name} )
    {
        auto lines = get_lines(file) ; // read the lines into a vector
        const auto nlines = lines.size() ;

        // we want to move section <settings> to just before </config>
        const std::size_t from = find_prefix( lines, "<settings>" ) ; // locate the first line of the section
        const std::size_t to = find_prefix( lines, "</settings>" ) ; // locate the last line of the section
        const std::size_t dest = find_prefix( lines, "</config>" ) ; // locate the dest ination line

        if( from <= to && to <= dest && dest < nlines ) // sanity check
        {
            // create a new vector with the lines moved
            const auto moved_vec = move_lines_forward( std::move(lines), from, to, dest );

            if( moved_vec.size() == nlines ) // if things appear to be ok
            {
                file.close() ; // close the input file

                // and modify the original file (overwrite it)
                std::ofstream file_out(test_file_name) ;
                put_lines( file_out, moved_vec ) ;
            }
        }
    }

    // for testing: dump the contents of the file at the end
    std::cout << "\n\nafter the section move, the modified file contains:\n-------------------------\n"
              << std::ifstream(test_file_name).rdbuf() << "-----------\n" ;
}


http://coliru.stacked-crooked.com/a/4cb97b5a8b3623a7
So JL's suggestion is not working for me. It is not reordering the config and therefore produces a blank file at the end. I wasn't sure if the parts before the int main() were suppose to be in a void or something else so I just put them in before my int main().
is move the part in bold that settings are to go in between </initpart> and </config>


Consider:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
#include <fstream>
#include <iostream>
#include <string>
#include <vector>

int main()
{
	std::ifstream ifs("clientconfig.xml");

	if (!ifs.is_open())
		return (std::cout << "Cannot open file for input\n"), 1;

	std::vector<std::string> first;
	std::vector<std::string> sett;
	std::vector<std::string> last;

	for (std::string line; getline(ifs, line); first.push_back(line))
		if (line.find("<settings>") != std::string::npos) {
			sett.push_back(line);
			break;
		}

	for (std::string line; getline(ifs, line); sett.push_back(line))
		if (line.find("</settings>") != std::string::npos) {
			sett.push_back(line);
			break;
		}

	for (std::string line; getline(ifs, line); last.push_back(line));

	ifs.close();

	std::ofstream ofs("clientconfig.xml");

	if (!ofs.is_open())
		return ("Cannot open file for output\n"), 2;

	for (const auto& f : first)
		ofs << f << '\n';

	for (const auto& l : last) {
		if (l.find("</config") != std::string::npos)
			for (const auto& s : sett)
				ofs << s << '\n';

		ofs << l << '\n';
	}
}


before:

<?xml version="1.0" encoding="UTF-8"?>
<config>
<settings>
<differentsettings>true</differentsettings>
<etc>true</etc>
<etc>false</etc>
</settings>
<services>
<variousserviceclasses>
<thoseclasssettings>
</variousserviceclasses>
<variousserviceclasses>
<thoseclasssettings>
</variousserviceclasses>
</services>
<initpart>
<initstuff>
</initpart>
</config>


after:


<?xml version="1.0" encoding="UTF-8"?>
<config>
<services>
<variousserviceclasses>
<thoseclasssettings>
</variousserviceclasses>
<variousserviceclasses>
<thoseclasssettings>
</variousserviceclasses>
</services>
<initpart>
<initstuff>
</initpart>
<settings>
<differentsettings>true</differentsettings>
<etc>true</etc>
<etc>false</etc>
</settings>
</config>

Last edited on
Dropped that in seeplus and tried but no luck. I changed the file names to match what I have already but the output for that section is coming out blank therefore my final section only puts the newlines in the final product.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
//

#include <stdio.h>
#include <fstream>
#include <sstream>
#include <iostream>
#include <string>
#include <cctype>
#include <cstdlib>
#include <set>
#include <vector>
#include <cassert>
#include <Windows.h>
using namespace std;



void findAndReplaceAll(std::string& data, std::string toSearch, std::string replaceStr)
{
    // Get the first occurrence
    size_t pos = data.find(toSearch);
    // Repeat till end is reached
    while (pos != std::string::npos)
    {
        // Replace this occurrence of Sub String
        data.replace(pos, toSearch.size(), replaceStr);
        // Get the next occurrence from the current position
        pos = data.find(toSearch, pos + replaceStr.size());
    }
}

int main() {

    // First Part to Clean Up Config

    const string Dir{ "C:/synergyii/config/" },
        oldname1 = Dir + "clientconfig.xml",
        newname1 = Dir + "clientconfig-old.xml";

    if (rename(oldname1.c_str(), newname1.c_str()) != 0) {
        perror("Error renaming file 1");
        return 1;
    }

    ifstream in_config1{ newname1 };
    ofstream out1{ Dir + "clientconfigtemp.txt" };

    if (!in_config1) {
        cerr << "Cannot open clientconfig-old.xml for reading\n";
        return 1;
    }

    if (!out1) {
        cerr << "Cannot open clientconfigtemp.txt for writing\n";
        return 1;
    }

    string line1;

    while (getline(in_config1, line1)) {

        findAndReplaceAll(line1, "><", ">^<");

        stringstream ss(line1);

        while (getline(ss, line1, '^')) {

            out1 << line1 << '\n';
        }
    }

    &ifstream::close;
    &ofstream::close;

    // Second Part Reorder if Needed

    
        ifstream ifs( Dir + "clientconfigtemp.txt");

        if (!ifs.is_open())
            return (cout << "Cannot open file for input\n"), 1;

        vector<string> first;
        vector<string> sett;
        vector<string> last;

        for (string line; getline(ifs, line); first.push_back(line))
            if (line.find("<settings>") != string::npos) {
                sett.push_back(line);
                break;
            }

        for (string line; getline(ifs, line); sett.push_back(line))
            if (line.find("</settings>") != string::npos) {
                sett.push_back(line);
                break;
            }

        for (string line; getline(ifs, line); last.push_back(line));

        ifs.close();

        ofstream ofs( Dir + "clientconfigtemp2.txt");

        if (!ofs.is_open())
            return ("Cannot open file for output\n"), 2;

        for (const auto& f : first)
            ofs << f << '\n';

        for (const auto& l : last) {
            if (l.find("</config>") != string::npos)
                for (const auto& s : sett)
                    ofs << s << '\n';

            ofs << l << '\n';
        }
    
   
    ofs.close();

       // Third part to Add New Lines


    ifstream in_config{ Dir + "clientconfigtemp2.txt" },
        in_newlines{ Dir + "newlines.txt" };
        ofstream out{ oldname1 };

    if (!in_config) {
        cerr << "Cannot open clientconfigtemp2.txt for reading\n";
        return 1;
    }
    if (!in_newlines) {
        cerr << "Cannot open client newlines.txt for reading\n";
        return 1;
    }
    if (!out) {
        cerr << "Cannot open clientconfig.xml for writing\n";
        return 1;
    }
    
    vector<string> vlines;
    set<string>    slines;

    for (string line; getline(in_config, line) && line.find("</settings>") == string::npos; ) {
        const auto& result = slines.insert(line);
        if (result.second)
            vlines.push_back(line);
    }

    for (string line; getline(in_newlines, line); ) {
        const auto& result = slines.insert(line);
        if (result.second)
            vlines.push_back(line);
    }
    

    for (const auto& line : vlines)
       out << line << '\n';

    out << '\t' << "</settings>\n";
    out << "</config>\n";
}
1
2
 &ifstream::close;
 &ofstream::close;


?? Shouldn't this be:

1
2
in_config1.close();
out.close();

made that change too seeplus but I also had to add:

1
2
3
4
5
for (string line; getline(ifs, line); last.push_back(line))
            if (line.find("</config>") != string::npos) {
                last.push_back(line);
                break;
            }


where this was:
 
for (string line; getline(ifs, line); last.push_back(line))


Now it is working perfectly. Just time to clean it up now.
While cleaning it up I noticed one thing off. in the last part where it is adding the newlines, we managed to add in a way for it to prevent duplication. I noticed in testing that if the line is not the last line of the original and the first line of the new there may be duplication. Is there a way anyone can think of where it will check in the last section vector to make sure that the new line being added in the <settings> section does already exist? I'm thinking that it might need 2 or more vectors in the last section to work and I am looking into it and trying out some things but haven't found a solution yet. An example would be the line already exist in the settings section in a different spot or the newline being added might be set to true and an existing one set to false. This would result in undesirable behavior so really trying to find a way to make sure there are no duplicated settings even if one is set to true and the other to false.

Updated code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
//

#include <stdio.h>
#include <fstream>
#include <sstream>
#include <iostream>
#include <string>
#include <cctype>
#include <cstdlib>
#include <set>
#include <vector>
#include <cassert>
#include <Windows.h>
using namespace std;



void findAndReplaceAll(std::string& data, std::string toSearch, std::string replaceStr)
{
    // Get the first occurrence
    size_t pos = data.find(toSearch);
    // Repeat till end is reached
    while (pos != std::string::npos)
    {
        // Replace this occurrence of Sub String
        data.replace(pos, toSearch.size(), replaceStr);
        // Get the next occurrence from the current position
        pos = data.find(toSearch, pos + replaceStr.size());
    }
}

int main() {


    // First Part to Clean Up Config

    const string Dir{ "C:/synergyii/config/" },
        oldname1 = Dir + "clientconfig.xml",
        newname1 = Dir + "clientconfig-old.xml";

    if (rename(oldname1.c_str(), newname1.c_str()) != 0) {
        perror("Error renaming file 1");
        return 1;
    }

    ifstream in_config1{ newname1 };
    ofstream out1{ Dir + "clientconfigtemp.txt" };

    if (!in_config1) {
        cerr << "Cannot open clientconfig-old.xml for reading\n";
        return 1;
    }

    if (!out1) {
        cerr << "Cannot open clientconfigtemp.txt for writing\n";
        return 1;
    }

    string line1;

    while (getline(in_config1, line1)) {

        findAndReplaceAll(line1, "><", ">^<");

        stringstream ss(line1);

        while (getline(ss, line1, '^')) {

            out1 << line1 << '\n';
        }
    }

    in_config1.close();
    out1.close();

    // Second Part Reorder if Needed

    
        ifstream ifs( Dir + "clientconfigtemp.txt");

        if (!ifs.is_open())
            return (cout << "Cannot open file for input\n"), 1;

        vector<string> first;
        vector<string> sett;
        vector<string> last;

        for (string line; getline(ifs, line); first.push_back(line))
            if (line.find("<settings>") != string::npos) {
                sett.push_back(line);
                break;
            }

        for (string line; getline(ifs, line); sett.push_back(line))
            if (line.find("</settings>") != string::npos) {
                sett.push_back(line);
                break;
            }

        for (string line; getline(ifs, line); last.push_back(line))
            if (line.find("</config>") != string::npos) {
                last.push_back(line);
                break;
            }

        ifs.close();

        ofstream ofs( Dir + "clientconfigtemp2.txt");

        if (!ofs.is_open())
            return ("Cannot open file for output\n"), 2;

        for (const auto& f : first)
            ofs << f << '\n';

        for (const auto& l : last) {
            if (l.find("</config>") != string::npos)
                for (const auto& s : sett)
                    ofs << s << '\n';

            ofs << l << '\n';
        }
    
   
    ofs.close();

       // Third part to Add New Lines


    ifstream in_config{ Dir + "clientconfigtemp2.txt" },
        in_newlines{ Dir + "newlines.txt" };
        ofstream out{ oldname1 };

    if (!in_config) {
        cerr << "Cannot open clientconfigtemp2.txt for reading\n";
        return 1;
    }
    if (!in_newlines) {
        cerr << "Cannot open client newlines.txt for reading\n";
        return 1;
    }
    if (!out) {
        cerr << "Cannot open clientconfig.xml for writing\n";
        return 1;
    }
    
    vector<string> vlines;
    set<string>    slines;

    for (string line; getline(in_config, line) && line.find("</settings>") == string::npos; ) {
        const auto& result = slines.insert(line);
        if (result.second)
            vlines.push_back(line);
    }

    for (string line; getline(in_newlines, line); ) {
        const auto& result = slines.insert(line);
        if (result.second)
            vlines.push_back(line);
    }
    

    for (const auto& line : vlines)
       out << line << '\n';

    out << '\t' << "</settings>\n";
    out << "</config>\n";
}
Last edited on
So I got my code to break the third part into different vectors. I have it set to print the first vector since that will not change, but what I am struggling with is comparing vector 2 and 3 to each other to make sure the lines are not duplicated across each other and within each other. Preferably I would like it to drop the duplicated line in vector 2 in favor of the one in vector 3 and ignore whether or not one setting is true and the other is false and still go with the setting in vector 3.
Ok I figured out how to get my code to check for duplicated lines and all in the whole vector so I only went back down to 2 vectors which was pretty sweet.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
    for (string line31; getline(in_config, line31); vlines31.push_back(line31))
        if (line31.find("<settings>") != string::npos) {
            vlines31.push_back(line31);
            break;
        }

    for (const auto& v : vlines31)
        out << v << '\n';


    for (string line32; getline(in_config, line32) && line32.find("</settings>") == string::npos; ) {
        line32.erase(remove_if(line32.begin(), line32.end(), isSpace), line32.end());
        line32.erase(line32.find_last_not_of(" ") + 1);
        const auto& result = slines32.insert(line32);
        if (result.second)
            vlines32.push_back(line32);
    }

    for (string line32; getline(in_newlines, line32);) {
        line32.erase(remove_if(line32.begin(), line32.end(), isSpace), line32.end());
        const auto& result = slines32.insert(line32);
        if (result.second)
            vlines32.push_back(line32);
    }

    vlines32.erase(unique(vlines32.begin(), vlines32.end()), vlines32.end() );

    for (auto it = vlines32.cbegin(); it != vlines32.cend(); ++it)
        out << '\t' << '\t' << *it << '\n';


If anyone has any suggestions on where I can start looking to compare the setting lines by just the first part since there maybe time a setting was set to false and another gets added as true and thus cause big problems. Example:

<setting1>true</setting1>
<setting2>false</setting2>
<setting1>false</setting1>

I would like to remove one of those. Any suggestions would be greatly appreciated.

Thanks,
V
I would like to remove one of those


But which one?
Pages: 123