write a c++program to convert a text file to html file - c++

I am a beginner of c++ and find this question and code online, was trying to make it ok to read not only the file he gave but also any txt file but it shows some problem and I have no idea how to fix
the text file is just like regular text file, not an HTML format txt file
#include <iostream>
#include <fstream>
#include <map>
using namespace std;
istream findParagraph(istream& is, string& word)
{
cout << "<br>" << endl;
}
int main(int argc, char* argv[])
{
argv[1] = "The Republic, by Plato.txt";
ifstream infile(argv[1]);
char ch = 0;
ofstream out("title.html");
out << "<html>" << endl
<< "<head>" << endl
<< "<title>" << argv[1] << "</title>" << endl
<< "</head>" << endl
<< "<body>" << endl;
typedef map<string, unsigned> dictionary_type;
dictionary_type words;
string word;
while (findParagraph(infile, word))
++words[word];
out << "</body>" << endl << "</html>";
} //end main
1>C:\Users\User\source\repos\txt2html\txt2html\txt2html.cpp(15,40): error C2440: '=': cannot convert from 'const char [27]' to 'char *'

You want a basic program that converts a textfile to a minimum html file. You can pass the filename of the text file as parameter to your program.
If the name of your executable program would be "convert", then you can invoke your program with "convert input.txt"
The first parameter that you enter on the command line will appear in argv[1], the 2nd in argv[2] and so on. argv[0] contains the name of the program itself.
So please adapt the handling of the argv parameter. By the way, you could also give the name of the output html file as additional parameter and user argv[2] as output file name. argc would then be 3.
After opening all files and checking for errors, we will first write initial header information to the output html file.
Then we use the std::getline() function to read the source file line by line, until it is completely read.
For each line we read, we will output the plain text to the html file and add a line break "< br >".
At the end, we write the closing tags and that's it.
Please see the attached skelleton example program, which you can use to develop your ideas further.
#include <iostream>
#include <sstream>
#include <string>
#include <fstream>
int main(int argc, char *argv[])
{
// Filename is parameter
// Check if program has been invoked with on parameter
if (argc == 2) {
// Parameter is filename. Try to open the input text file
std::ifstream textFile(argv[1]);
// File could be opened
if (textFile) {
// Now open the output file. Becuase, if this cannot be opened then no need to do further steps
std::ofstream htmlFile("title.html");
if (htmlFile) {
// All files are open. Start to build the output
// Start writing the header
htmlFile << "<html>" << '\n' << "<head>" << '\n' <<"<title>" << argv[1] << "</title>" << '\n' << "</head>" <<
"<body>" << '\n';
// Write the body
// Frist read a complete line
std::string line{};
while (std::getline(textFile, line)) {
// Write the line and append a <br>
htmlFile << line << "<br>" << '\n';
}
// End of body
htmlFile << "</body>" << '\n' << "</html>" << '\n';
}
else {
// Error. HTML file could not be opend
std::cerr << "Could not open output HTML file 'title.html'\n";
}
}
else {
// Error. input text file could not be opend
std::cerr << "Could not open input text file '" << argv[1] << "'\n";
}
}
else {
// // Error, program has not been invoked correctly
std::cerr << "Nof Filename given. Invoke this program ("<< argv[0] << ") with 'file name' as parameter\n";
}
return 0;
}

Related

Why is Appended content not showing up on reading from a file in C++?

Please look at this code first, then I will ask my question.
#include <bits/stdc++.h>
#include <fstream>
using std::cout;
using std::cin;
using std::endl;
int main() {
std::ofstream out_file ("outfile.txt"); /* creates a outfile.txt */
if (!out_file) { // checks files existence
std::cerr << "Error bruh!" << endl;
return (1);
}
int num = 100;
double total = 456.78;
std::string name = "atik";
out_file << num << "\n" // writing to the file
<< total << "\n"
<< name << endl;
/* Reading from file, because i want to! - */
std::ifstream in_file("outfile.txt"); // will open outfile for reading.
char c;
while (in_file.get(c)) {
cout << c;
}
/*
Output (as expected) -
100
456.78
atik
Right Now My **output.txt** file is - (as expected)
100
456.78
atik
*/
/* Appending the file that we just created - */
std::ofstream out_file2 ("outfile.txt", std::ios::app);
cout << "\nEnter something to write in file : " << endl;
std::string line;
getline(cin, line);
out_file2 << line; // writes to out_file2
/* Reading from file again - */
std::ifstream in_file2("outfile.txt"); // will open outfile.txt for reading.
if( !in_file2 ) {
std::cerr << "File didn't open. Error encountered." << endl;
}
char ch;
cout << endl;
while( in_file2.get(ch) ) {
cout << ch;
}
/*
Output (unexpected? why?)-
100
456.78
atik
*/
in_file.close();
in_file.close();
out_file.close();
out_file2.close();
return 0;
}
Now, my outfile..txt is - (as expected):
100
456.78
atik
Hello there
Then why is the output for in_file2 not showing Hello there? Why does it truncate the Hello there? Can someone please explain?
out_file2<<line;
doesn't flush (the use of std::endl in the prior code does), so if there's less than a full block of data read from std::cin, the data written to out_file2 is likely stuck in your user-mode buffers (and not visible when you open the file for read independently). Those buffers make I/O efficient by reducing the number of system calls when you're performing many smallish writes, in exchange for any buffered data not being visible outside of that file handle until the buffer is flushed (implicitly by filling, or explicitly by manual flushing or closing the file handle).
Simply changing that line to:
out_file2 << line << std::flush;
(or just .close()ing out_file2 once you're done with it) will cause it to flush properly and you should see the new data on opening it again for read.

reading non-text file in c++

I open the mp3 file by mistake with notepad++ ( Open with ) and show the entire file in text inside the notepad it was so cool.
since I am learning c++ again, I told myself let write a program that opens any file inside the console and display their content on the console so I begin my code like this :
int readAndWrite() {
string filename(R"(path\to\a\file)");
ifstream file(filename);
string line;
if (!file.is_open()) {
cerr << "Could not open the file - '"
<< filename << "'" << endl;
return EXIT_FAILURE;
}
while (getline(file, line)){
cout << line;
}
return EXIT_SUCCESS;
}
but it only shows 3 or 4 lines of the file and then exits the program I check my notepad++ again and find out about 700,000 line is in there.
I told myself maybe there is a character inside the file so I start writing the above code with the below changes. instead of displaying the file let's wrote inside a text file.
int readAndWrite() {
string filename(R"(path\to\a\file)");
string filename2(R"(path\to\a\file\copy)");
ifstream file(filename);
ofstream copy(filename2);
string line;
if (!file.is_open()) {
cerr << "Could not open the file - '"
<< filename << "'" << endl;
return EXIT_FAILURE;
}
while (getline(file, line)){
copy << line;
}
return EXIT_SUCCESS;
}
and again the same results. next try I give up on reading the file line by line so I start copying with this function.
void copyStringNewFile(ifstream& file, ofstream& copy)
{
copy << file.rdbuf();
}
and their results did not change a bit.
At this point, I told myself the problem is from file maybe and it is kinda is because when I use a simple text file all of the above codes work.
Like all other non-text files, mp3 files don't contain lines so you shouldn't use std::getline. Use istream::read and ostream::write. You can use istream::gcount to check how many characters that was actually read.
Since you are dealing with non-text files, also open the files in binary mode.
You should also test if opening both files works - that is, both the input and the output file.
Example:
#include <cerrno>
#include <cstring>
#include <fstream>
#include <iostream>
int readAndWrite() {
std::string filename(R"(path\to\a\file)");
std::string filename2(R"(path\to\a\file_copy)");
std::ifstream file(filename, std::ios::binary);
if(!file) {
std::cerr << '\'' << filename << "': " << std::strerror(errno) << '\n';
return EXIT_FAILURE;
}
std::ofstream copy(filename2, std::ios::binary);
if(!copy) {
std::cerr << '\'' << filename2 << "': " << std::strerror(errno) << '\n';
return EXIT_FAILURE;
}
char buf[1024];
while(file) {
file.read(buf, sizeof(buf));
// write as many characters as was read above
if(!copy.write(buf, file.gcount())) {
// write failed, perhaps filesystem is full?
std::cerr << '\'' << filename2 << "': " << std::strerror(errno) << '\n';
return EXIT_FAILURE;
}
}
return EXIT_SUCCESS;
}
int main() {
return readAndWrite();
}

LLVM YAML API cannot read in yaml file "error: not a sequence"

This question is a continuation of my previous question.
error: implicit instantiation of undefined template 'llvm::yaml::MissingTrait
I am working on a project which uses the LLVM YAML I/O library. This is the documentation/tutorial that I am following:
https://www.llvm.org/docs/YamlIO.html
I have created a small program that would read in a yaml file into objects in memory. Then it would print those objects. Finally it would write the objects out into a different output file.
First it parses the command line arguments. Then it creates the input reader. Then it creates the YAML Input object, which is used to read the *.yaml file in, and parse it. It is in the parsing step that I am having an error. Supposing if parsing the input from the *.yaml file was successful, the data will get stored into the DocType myDoc;. Then it prints all the Person objects stored in that std::vector. An overloaded operator<<() prints each element. Then it creates the output writer, creates the YAML Output, and writes myDoc into the file output_file.yaml.
The goal of this program is to demonstrate reading and writing a *.yaml file with LLVM YAML I/O. It successfully writes the output file, but it cannot read the input file.
Now suppose that instead of filling myDoc with elements from the yin, I would be manually adding elements instead. So I activate the code that push_back each element, and I disable the code that reads the input from the yin into memory.
DocType myDoc;
///*
myDoc.push_back(Person("Tom", 8));
myDoc.push_back(Person("Dan", 7));
myDoc.push_back(Person("Ken"));
//*/
/* Reading input into the memory */
/*
yin >> myDoc;
if (error_code errc = yin.error()) {
errs() << "error parsing YAML input from file " << InputFile << '\n';
errs() << errc.message() << '\n';
return EXIT_FAILURE;
} else {
outs() << "parsing YAML input from file " << InputFile << '\n';
}
*/
In that case, the programs works fine. The myDoc is initialized with those elements, and then it prints each element to the stdout. Then in creates the output writer, creates the YAML Output, and writes the myDoc into the output_file.yaml.
Here is what the output file looks like when it is written:
---
- name: Tom
hat-size: 8
- name: Dan
hat-size: 7
- name: Ken
...
I copy the output file into the input file, for testing the input functionality of the program.
cp output_file.yaml input_file.yaml
Then I deactivate the code which manually fills the myDoc, and I activate the code which fills the myDoc from the yin.
DocType myDoc;
/*
myDoc.push_back(Person("Tom", 8));
myDoc.push_back(Person("Dan", 7));
myDoc.push_back(Person("Ken"));
*/
/* Reading input into the memory */
///*
yin >> myDoc;
if (error_code errc = yin.error()) {
errs() << "error parsing YAML input from file " << InputFile << '\n';
errs() << errc.message() << '\n';
return EXIT_FAILURE;
} else {
outs() << "parsing YAML input from file " << InputFile << '\n';
}
//*/
After that the code no longer works. If I try to provide that same input_file.yaml to the application, I get a bug. LLVM YAML I/O fails to parse the *.yaml file and prints an error! It's weird because this is the exact format that this same LLVM YAML I/O was outputting into the file.
./yaml_project --input-file=input_file2.yaml --output-file=output_file.yaml
opening input file input_file2.yaml
reading input file input_file2.yaml
input_file2.yaml:1:1: error: not a sequence
-
^
error parsing YAML input from file input_file2.yaml
Invalid argument
I cannot find why is it refusing to accept well formatted YAML code from the input file. If anyone knows how to fix this bug, please help me.
Here is the full listing of my code:
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/YAMLTraits.h"
#include "llvm/Support/YAMLParser.h"
#include "llvm/Support/ErrorOr.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/CommandLine.h"
#include <cstdlib> /* for EXIT_FAILURE */
#include <string> /* for std::string */
#include <vector> /* for std::vector */
#include <system_error> /* for std::error_code */
using std::string;
using std::vector;
using std::error_code;
using llvm::outs;
using llvm::errs;
using llvm::raw_ostream;
using llvm::raw_fd_ostream;
using llvm::ErrorOr;
using llvm::MemoryBuffer;
using llvm::yaml::ScalarEnumerationTraits;
using llvm::yaml::MappingTraits;
using llvm::yaml::IO;
using llvm::yaml::Input;
using llvm::yaml::Output;
using llvm::cl::opt;
using llvm::cl::desc;
using llvm::cl::ValueRequired;
using llvm::cl::OptionCategory;
using llvm::cl::ParseCommandLineOptions;
/* Command line options description: */
// Apply a custom category to all command-line options so that they are the
// only ones displayed.
// The category tells the CommonOptionsParser how to parse the argc and argv.
OptionCategory yamlCategory("yaml_project options");
opt<string> InputFile("input-file", desc("The input YAML file"), ValueRequired);
opt<string> OutputFile("output-file", desc("The output YAML file"), ValueRequired);
struct Person {
string name;
int hatSize;
Person(string name = "", int hatSize = 0)
: name(name), hatSize(hatSize) {}
};
raw_ostream& operator<<(raw_ostream& os, const Person& person) {
os << "{ " << person.name;
if (person.hatSize)
os << " , " << person.hatSize;
os << " }";
return os;
}
template <>
struct MappingTraits<Person> {
static void mapping(IO& io, Person& info) {
io.mapRequired("name", info.name);
io.mapOptional("hat-size", info.hatSize, 0);
}
};
typedef vector<Person> DocType;
LLVM_YAML_IS_SEQUENCE_VECTOR(Person)
int main(int argc, const char **argv) {
/* Command line parsing: */
ParseCommandLineOptions(argc, argv);
if (InputFile.empty()) {
errs() << "No input file specified\n";
return EXIT_FAILURE;
}
if (OutputFile.empty()) {
errs() << "No output file specified\n";
return EXIT_FAILURE;
}
/* Create the input reader */
auto reader = MemoryBuffer::getFile(InputFile, true);
if (error_code errc = reader.getError()) {
errs() << "error opening input file " << InputFile << '\n';
errs() << errc.message() << '\n';
// MemoryBuffer does not need to be closed
return EXIT_FAILURE;
} else {
outs() << "opening input file " << InputFile << '\n';
}
/* Create the YAML Input */
// dereference once to strip away the llvm::ErrorOr
// dereference twice to strip away the std::unique_ptr
Input yin(**reader);
if (error_code errc = yin.error()) {
errs() << "error reading input file " << InputFile << '\n';
outs() << errc.message() << '\n';
// MemoryBuffer does not need to be closed
return EXIT_FAILURE;
} else {
outs() << "reading input file " << InputFile << '\n';
}
DocType myDoc;
/*
myDoc.push_back(Person("Tom", 8));
myDoc.push_back(Person("Dan", 7));
myDoc.push_back(Person("Ken"));
*/
/* Reading input into the memory */
///*
yin >> myDoc;
if (error_code errc = yin.error()) {
errs() << "error parsing YAML input from file " << InputFile << '\n';
errs() << errc.message() << '\n';
return EXIT_FAILURE;
} else {
outs() << "parsing YAML input from file " << InputFile << '\n';
}
//*/
for (const Person& element : myDoc)
outs() << element << '\n';
/* Create the output writer */
error_code errc;
raw_fd_ostream writer(OutputFile, errc);
if (errc) {
errs() << "error opening output file " << OutputFile << '\n';
errs() << errc.message() << '\n';
writer.close();
return EXIT_FAILURE;
} else {
outs() << "opening output file " << OutputFile << '\n';
}
/* Create the YAML Output */
Output yout(writer);
/* Writing output into file */
yout << myDoc;
outs() << "writing YAML output into file " << OutputFile << '\n';
writer.close();
return EXIT_SUCCESS;
}
The problem is in the line
auto reader = MemoryBuffer::getFile(InputFile, true);
with llvm-12 change the line to
auto reader = MemoryBuffer::getFile(InputFile);
it should work.

Nicolai Josuttis says in his book that the open member function doesn't clear the state flags. That's not what I found in VS2010. Is this a MS issue?

Nicolai Josuttis in page 547 of his book "The C++ Standard Library" says the following in relation to the code below :
Note that after the processing of a file, clear() must be called to clear the state flags that are set at end-of-file. This is required because the stream object is used for multiple files. The member function open() does not clear the state flags. open() never clears any state flags. Thus, if a stream was not in a good state, after closing and reopening it you still have to call clear() to get to a good state. This is also the case, if you open a different file.
// header files for file I/O
#include <fstream>
#include <iostream>
using namespace std;
/* for all file names passed as command-line arguments
* - open, print contents, and close file
*/
int main (int argc, char* argv[])
{
ifstream file;
// for all command-line arguments
for (int i=1; i<argc; ++i) {
// open file
file.open(argv[i]);
// write file contents to cout
char c;
while (file.get(c)) {
cout.put(c);
}
// clear eofbit and failbit set due to end-of-file
file.clear();
// close file
file.close();
}
}
My code below works without a problem in VS2010. Note that after the file "data.txt" is created, it's read twice without clearing the input stream flags.
#include <iostream>
#include <fstream>
#include <string>
int main()
{
// Create file "data.txt" for writing, write 4 lines into the file and close the file.
std::ofstream out("data.txt");
out << "Line 1" << '\n' << "Line 2" << '\n' << "Line 3" << '\n' << "Line 4" << '\n';
out.close();
// Open the file "data.txt" for reading and write file contents to cout
std::ifstream in("data.txt");
std::string s;
while( std::getline(in, s) ) std::cout << s << '\n';
std::cout << '\n';
std::cout << std::boolalpha << "ifstream.eof() before close - " << in.eof() << '\n';
// Close the file without clearing its flags
in.close();
std::cout << std::boolalpha << "ifstream.eof() after close - " << in.eof() << '\n';
// Open the file "data.txt" again for reading
in.open("data.txt");
std::cout << std::boolalpha << "ifstream.good() after open - " << in.good() << '\n';
std::cout << '\n';
// Read and print the file contents
while( std::getline(in, s) ) std::cout << s << '\n';
std::cout << '\n';
}
Ouput
That was changed for C++11. The C++98 rule (as correctly described by Josuttis) was clearly wrong, so I wouldn't be surprised if implementations didn't honor it.

Reading and appending from/to a file with std::fstream

I'm wondering why the following piece of code doesn't work, looks pretty straight-forward, am I making a mistake?
The result of this is: file created but empty, if I manually add lines those lines are showed with this code, but nothing else happens.
#include <fstream>
#include <iostream>
#include <string>
using namespace std;
int main(){
fstream mfile("text.txt", ios_base::in | ios_base::out | ios_base::app);
mfile.seekg(ios_base::beg);
string line;
while( getline(mfile,line) ){
std::cout << line << "\n";
}
mfile.seekg(ios_base::end);
mfile << "Line 1\n";
mfile << "Line 2\n";
mfile << "---------------------------------\n";
mfile.seekg(ios_base::beg);
while( getline(mfile,line) ){
std::cout << line << "\n";
}
mfile.seekg(ios_base::end);
}
Couple of things:
When you are ready to write, you need to seekp() rather than seekg(), i.e.
mfile.seekp(ios_base::end);
Now, the problem here is that the getline() calls will set the stream flags (specifically eof), and as a result the stream is not ready for further operations, you need to clear the flags first!
try this:
string line;
mfile.seekg(ios_base::beg);
while( getline(mfile,line) ){
std::cout << line << endl;
}
mfile.seekp(ios_base::end); // seekp
mfile.clear(); // clear any flags
mfile << "Line 1" << endl; // now we're good
mfile << "Line 2" << endl;
mfile << "---------------------------------" << endl;
mfile.seekg(ios_base::beg);
while( getline(mfile,line) ){
std::cout << line << endl;
}
Also, use std::endl rather than "\n", this will trigger a flush of the buffers to the file at the OS's convinience...