Downloaded page source is different than the rendered page source - html

I'm planning to get data from this website
http://www.gpw.pl/akcje_i_pda_notowania_ciagle
(it's a site of the main stock market in Poland)
I've got a program written in C++ that downloads source of the site to the file.
But the problem is that it doesn't contain thing I'm interested in
(stocks' value of course).
If you compare this source of the site to the option "View element" ( RMB -> View element)
you can see that "View element" does contain the stocks' values.
<td>75.6</td>
<tr class="even red">
etc etc...
The downloaded source of the site doesn't have this information.
So we've got 2 questions
1) Why does source of the site is different from the "View element" option?
2) How to transfer my program so that it can download the right code?
#include <string>
#include <iostream>
#include "curl/curl.h"
#include <cstdlib>
using namespace std;
// Write any errors in here
static char errorBuffer[CURL_ERROR_SIZE];
// Write all expected data in here
static string buffer;
// This is the writer call back function used by curl
static int writer(char *data, size_t size, size_t nmemb,
string *buffer)
{
// What we will return
int result = 0;
// Is there anything in the buffer?
if (buffer != NULL)
{
// Append the data to the buffer
buffer->append(data, size * nmemb);
// How much did we write?
result = size * nmemb;
}
return result;
}
// You know what this does..
void usage()
{
cout <<"curltest: \n" << endl;
cout << "Usage: curltest url\n" << endl;
}
/*
* The old favorite
*/
int main(int argc, char* argv[])
{
if (argc > 1)
{
string url(argv[1]);
cout<<"Retrieving "<< url << endl;
// Our curl objects
CURL *curl;
CURLcode result;
// Create our curl handle
curl = curl_easy_init();
if (curl)
{
// Now set up all of the curl options
curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, errorBuffer);
curl_easy_setopt(curl, CURLOPT_URL, argv[1]);
curl_easy_setopt(curl, CURLOPT_HEADER, 0);
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writer);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &buffer);
// Attempt to retrieve the remote page
result = curl_easy_perform(curl);
// Always cleanup
curl_easy_cleanup(curl);
// Did we succeed?
if (result == CURLE_OK)
{
cout << buffer << "\n";
exit(0);
}
else
{
cout << "Error: [" << result << "] - " << errorBuffer;
exit(-1);
}
}
}
return 0;
}

Because the values are filled in using JavaScript.
"View source" shows you the raw source for the page, while "View Element" shows you the state the document tree is in at the moment.
There's no simple way to fix it, because you need to either execute the JavaScript or port it to C++ (and it would probably make you unpopular at the exchange).

When I save the page as an html file (file/save as), I get a file containing all data displayed in browser and which was not found in page source (I use Chrome).
So I suggest that you add one step in your code:
Download page from a javascript enabled browser that support command line or some sort of API (If curl can't do it, maybe wget or lynx/links/links2/elinks on linux can help you?).
Parse data.

Related

Trying to get an image to show up on an HTML file in a C web server

I'm trying to get more familiar with C by writing a web server, and I managed to get a method to create HTTP headers for html files yesterday but I have been unable to get images within that html file to load.
Right now I generate my header by opening the html file, and creating a file stream to write the start of the header, the size of it, and then I loop through the file to send each character to the stream. I them send that stream as a char pointer back to the main method which sends it as a response over the socket.
I'm imagining that there is some more work I need to do here, but I haven't been able to find a good solution or anything too helpful to point me in the right direction of how exactly to get it to display. I appreciate any responses/insight.
test.html
<!DOCTYPE html>
<html>
<head>
<title>Nick's test website</title>
</head>
<body>
<h1>Welcome to my website programmed from scratch in C</h1>
<p>I'm doing this project to practice C</p>
<table>
<tr>
<td>test1</td>
<td>test2</td>
<td>test2</td>
</tr>
</table>
<img src="pic.jpg"/>
</body>
</html>
headermaker.c
char * headermaker(char * file_name){
char ch;
FILE * fp;
fp = fopen(file_name, "r");
if(fp == NULL){
perror("Error while opening file.\n");
exit(-1);
}
//print/save size of file
fseek(fp, 0, SEEK_END);
int size = ftell(fp);
fseek(fp, 0, SEEK_SET);
printf("File size is %d\n", size);
//create filestream
FILE * stream;
char * buf;
size_t len;
stream = open_memstream(&buf, &len);
//start header
fprintf(stream, "HTTP/1.1 200 OK\\nDate: Sun, 28 Aug 2022 01:07:00 GMT\\nServer: Apache/2.2.14 (Win32)\\nLast-Modified: Sun, 28 Aug 2022 19:15:56 GMT\\nContent-Length: ");
fprintf(stream, "%d\n", size);
fprintf(stream, "Content-Type: text/html\n\n");
//loop through each character
while((ch = fgetc(fp)) != EOF)
fprintf(stream, "%c", ch);
fclose(stream);
fclose(fp);
return buf;
}
Using a modified version of provided code to setup a web server using netcat and needed to see explanation of how to send jpeg using netcat
./one | nc -l 45231 ; { ./two && cat pic.jpeg; } | nc -l 45231;
Chrome browser can open http://localhost:45231 and will show the web page with an image. Also, can observe the network request - response sequence using "View->Developer->Developer Tools".
The code was built like this:
gcc -DONE -o one main.c && gcc -DTWO -o two main.c
The modified code:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
char * headermaker(char * file_name, char * content_type ){
char ch;
FILE * fp;
fp = fopen(file_name, "r");
if(fp == NULL){
perror("Error while opening file.\n");
exit(-1);
}
//print/save size of file
fseek(fp, 0, SEEK_END);
int size = ftell(fp);
fseek(fp, 0, SEEK_SET);
//printf("File size is %d\n", size);
//create filestream
FILE * stream;
char * buf;
size_t len;
stream = open_memstream(&buf, &len);
//start header
fprintf(stream, "HTTP/1.1 200 OK\n");
fprintf(stream, "Server: netcat!\n");
fprintf(stream, "Content-Type: %s\n",content_type);
fprintf(stream, "Content-Length: %d\n", size);
fprintf(stream, "\n");
//loop through each character
#ifdef ONE
while((ch = fgetc(fp)) != EOF)
fprintf(stream, "%c", ch);
#endif //#ifdef ONE
fclose(stream);
fclose(fp);
return buf;
}
int main( )
{
#ifdef ONE
char *buf = headermaker( "test.html", "text/html" );
printf( "%s", buf );
free(buf);
#endif //#ifdef ONE
#ifdef TWO
char *buf = headermaker( "pic.jpeg", "image/jpeg" );
printf( "%s", buf );
free(buf);
#endif //#ifdef TWO
return 0;
}
Another helpful debug tool was curl:
curl -vvv localhost:45231 > page.html
curl -vvv localhost:45231 > image.jpeg

Extract all URLs from HTML in C

How can I extract all URLs in a HTML using C standard library?
I am trying to deal with it using sscanf(), but the valgrind gives error (and I am even not sure if the code can meet my requirement after debugging successfully, so if there are other ways, please tell me). I stored the html content in a string pointer, there are multiple URLs (including absolute URL and relative URL, e.g.http://www.google.com, //www.google.com, /a.html, a.html and so on) in it. I want to extract them one by one and store them separately into another string pointer.
I am also thinking about using strstr(), but then I have no idea about how to get the second url.
My code (I skip the assert here) using sscanf:
int
main(int argc, char* argv[]) {
char *remain_html = (char *)malloc(sizeof(char) * 1001);
char *url = (char *)malloc(sizeof(char) * 101);
char *html = "navigation"
"search";
printf("html: %s\n\n", html);
sscanf(html, "<a href=\"%s", remain_html);
printf("after first href tag: %s\n\n", remain_html);
sscanf(remain_html, "%s\">", url);
printf("first web: %s\n\n", url);
sscanf(remain_html, "<a href=\"%s", remain_html);
printf("after second href tag: %s\n\n", remain_html);
free(remain_html);
free(url);
}
The valgrind gives: Conditional jump or move depends on uninitialised value(s).
If anybody could help, thank you so much!
valgrind warn you about non initialized data (used in test), considering your program only does sscanf and printf that means you very probably have a problem with your scanf
if I change a little your program to print the result of sscanf, so show much elements it get :
int
main(int argc, char* argv[]) {
char *remain_html = (char *)malloc(sizeof(char) * 1001);
char *url = (char *)malloc(sizeof(char) * 101);
char *html = "<A class=\"mw-jump-link\" HREF=\"#mw-head\">Jump to navigation</a>"
"<a class=\"mw-jump-link\" href=\"#p-search\">Jump to search</a>";
printf("html: %s\n\n", html);
printf("%d\n", sscanf(html, "<a href=\"%s", remain_html));
printf("after first href tag: %s\n\n", remain_html);
printf("%d\n", sscanf(remain_html, "%s\">", url));
printf("first web: %s\n\n", url);
printf("%d\n", sscanf(remain_html, "<a href=\"%s", remain_html));
printf("after second href tag: %s\n\n", remain_html);
free(remain_html);
free(url);
}
the execution is :
pi#raspberrypi:/tmp $ ./a.out
html: <A class="mw-jump-link" HREF="#mw-head">Jump to navigation</a><a class="mw-jump-link" href="#p-search">Jump to search</a>
0
after first href tag:
-1
first web:
-1
after second href tag:
pi#raspberrypi:/tmp $
so the first scanf got nothing (0 element), that means it does not set remain_html and that one is non initialized when it is used by the next sscanf with an undefined behavior
Because of the format
"<a href=\"%s"
the first sscanf waits for a string starting by
<a href="
but html starts by
<A class=
which is different, so it stop from the second character and does not set remain_html
To use sscanf is not the right way, search for the prefix <a href=" may be in uppercase for instance using strcasestr, then extract the URL up to the closing "
Example :
#include <stdio.h>
#include <string.h>
#include <ctype.h>
/* in case you do not have that function */
char * strcasestr(char * haystack, char *needle)
{
while (*haystack) {
char * ha = haystack;
char * ne = needle;
while (tolower(*ha) == tolower(*ne)) {
if (!*++ne)
return haystack;
ha += 1;
}
haystack += 1;
}
return NULL;
}
int main(int argc, char* argv[]) {
char *html = "navigation"
"search";
char * begin = html;
char * end;
printf("html: %s\n", html);
while ((begin = strcasestr(begin, "<a href=\"")) != NULL) {
begin += 9; /* bypass the header */
end = strchr(begin, '"');
if (end != NULL) {
printf("found '%.*s'\n", (int) (end - begin), begin);
begin = end + 1;
}
else {
puts("invalid url");
return -1;
}
}
}
Compilation and execution :
pi#raspberrypi:/tmp $ gcc -Wall a.c
pi#raspberrypi:/tmp $ ./a.out
html: navigationsearch
found 'http://www.google.com'
found '/a.html'
pi#raspberrypi:/tmp $
Note I know the second parameter of strcasestr is in lower case so it is useless to do do tolower(*ne) and *ne is enough, but I given a definition of the function out of the current context

How to log line number of coder in boost log 2.0?

Can I use LineID attribute for this?
I hope I could use sink::set_formatter to do this instead of using
__LINE__
and
__FILE__
in each log statement.
I struggled with this, until I found this snippet
#define LFC1_LOG_TRACE(logger) \
BOOST_LOG_SEV(logger, trivial::trace) << "(" << __FILE__ << ", " << __LINE__ << ") "
Works like a charm
The LineID attribute is a sequential number that is incremented for each logging message. So you can't use that.
You can use attributes to log the line numbers etc. This allows you flexible formatting using the format string, whereas using Chris' answer your format is fixed.
Register global attributes in your logging initialization function:
using namespace boost::log;
core::get()->add_global_attribute("Line", attributes::mutable_constant<int>(5));
core::get()->add_global_attribute("File", attributes::mutable_constant<std::string>(""));
core::get()->add_global_attribute("Function", attributes::mutable_constant<std::string>(""));
Setting these attributes in your logging macro:
#define logInfo(methodname, message) do { \
LOG_LOCATION; \
BOOST_LOG_SEV(_log, boost::log::trivial::severity_level::info) << message; \
} while (false)
#define LOG_LOCATION \
boost::log::attribute_cast<boost::log::attributes::mutable_constant<int>>(boost::log::core::get()->get_global_attributes()["Line"]).set(__LINE__); \
boost::log::attribute_cast<boost::log::attributes::mutable_constant<std::string>>(boost::log::core::get()->get_global_attributes()["File"]).set(__FILE__); \
boost::log::attribute_cast<boost::log::attributes::mutable_constant<std::string>>(boost::log::core::get()->get_global_attributes()["Function"]).set(__func__);
Not exactly beautiful, but it works and it was a long way for me. It's a pity boost doesn't offer this feature out of the box.
The do {... } while(false) is to make the macro semantically neutral.
The solution shown by Chris works, but if you want to customize the format or choose which information appears in each sink, you need to use mutable constant attributes:
logging::core::get()->add_global_attribute("File", attrs::mutable_constant<std::string>(""));
logging::core::get()->add_global_attribute("Line", attrs::mutable_constant<int>(0));
Then, you make a custom macro that includes these new attributes:
// New macro that includes severity, filename and line number
#define CUSTOM_LOG(logger, sev) \
BOOST_LOG_STREAM_WITH_PARAMS( \
(logger), \
(set_get_attrib("File", path_to_filename(__FILE__))) \
(set_get_attrib("Line", __LINE__)) \
(::boost::log::keywords::severity = (boost::log::trivial::sev)) \
)
// Set attribute and return the new value
template<typename ValueType>
ValueType set_get_attrib(const char* name, ValueType value) {
auto attr = logging::attribute_cast<attrs::mutable_constant<ValueType>>(logging::core::get()->get_global_attributes()[name]);
attr.set(value);
return attr.get();
}
// Convert file path to only the filename
std::string path_to_filename(std::string path) {
return path.substr(path.find_last_of("/\\")+1);
}
The next complete source code create two sinks. The first uses File and Line attributes, the second not.
#include <boost/log/trivial.hpp>
#include <boost/log/sources/severity_logger.hpp>
#include <boost/log/utility/setup/file.hpp>
#include <boost/log/utility/setup/console.hpp>
#include <boost/log/expressions.hpp>
#include <boost/log/utility/setup/common_attributes.hpp>
#include <boost/log/attributes/mutable_constant.hpp>
#include <boost/date_time/posix_time/posix_time_types.hpp>
#include <boost/log/support/date_time.hpp>
#include <boost/log/attributes/mutable_constant.hpp>
namespace logging = boost::log;
namespace attrs = boost::log::attributes;
namespace expr = boost::log::expressions;
namespace src = boost::log::sources;
namespace keywords = boost::log::keywords;
// New macro that includes severity, filename and line number
#define CUSTOM_LOG(logger, sev) \
BOOST_LOG_STREAM_WITH_PARAMS( \
(logger), \
(set_get_attrib("File", path_to_filename(__FILE__))) \
(set_get_attrib("Line", __LINE__)) \
(::boost::log::keywords::severity = (boost::log::trivial::sev)) \
)
// Set attribute and return the new value
template<typename ValueType>
ValueType set_get_attrib(const char* name, ValueType value) {
auto attr = logging::attribute_cast<attrs::mutable_constant<ValueType>>(logging::core::get()->get_global_attributes()[name]);
attr.set(value);
return attr.get();
}
// Convert file path to only the filename
std::string path_to_filename(std::string path) {
return path.substr(path.find_last_of("/\\")+1);
}
void init() {
// New attributes that hold filename and line number
logging::core::get()->add_global_attribute("File", attrs::mutable_constant<std::string>(""));
logging::core::get()->add_global_attribute("Line", attrs::mutable_constant<int>(0));
// A file log with time, severity, filename, line and message
logging::add_file_log (
keywords::file_name = "sample.log",
keywords::format = (
expr::stream
<< expr::format_date_time<boost::posix_time::ptime>("TimeStamp", "%Y-%m-%d_%H:%M:%S.%f")
<< ": <" << boost::log::trivial::severity << "> "
<< '[' << expr::attr<std::string>("File")
<< ':' << expr::attr<int>("Line") << "] "
<< expr::smessage
)
);
// A console log with only time and message
logging::add_console_log (
std::clog,
keywords::format = (
expr::stream
<< expr::format_date_time< boost::posix_time::ptime >("TimeStamp", "%Y-%m-%d %H:%M:%S")
<< " | " << expr::smessage
)
);
logging::add_common_attributes();
}
int main(int argc, char* argv[]) {
init();
src::severity_logger<logging::trivial::severity_level> lg;
CUSTOM_LOG(lg, debug) << "A regular message";
return 0;
}
The statement CUSTOM_LOG(lg, debug) << "A regular message"; generates two outputs, writing a log file with this format...
2015-10-15_15:25:12.743153: <debug> [main.cpp:61] A regular message
...and outputs to the console this:
2015-10-15 16:58:35 | A regular message
Another possibility is to add line and file attributes to each log record after they are created. This is possible since in newer releases. Attributes added later do not participate in filtering.
Assuming severity_logger identified with variable logger:
boost::log::record rec = logger.open_record(boost::log::keywords::severity = <some severity value>);
if (rec)
{
rec.attribute_values().insert(boost::log::attribute_name("Line"),
boost::log::attributes::constant<unsigned int>(__LINE__).get_value());
... other stuff appended to record ...
}
The above would, of course, get wrapped into convenient macro.
Later you can show this attribute using custom formatter for the sink:
sink->set_formatter( ...other stuff... << expr::attr<unsigned int>("Line") << ...other stuff... );
Unlike previous answer, this approach requires more custom code and can't use off-the-shelf boost logging macros.
For posterity's sake - I made this set of macros for very simple logging needs, which has served me well - for simple logging needs. But they illustrate how to do this in general, and the concept easily works with Boost. They are meant to be local to one file (which is running in multiple processes, sometimes in multiple threads in multiple processes). They are made for relative simplicity, not speed. They are safe to put in if statements etc. to not steal the else. At the beginning of a function in which one wants to log, one calls
GLogFunc("function name");
Then one can do this to log a complete line:
GLogL("this is a log entry with a string: " << some_string);
They are as so -
#define GLogFunc(x) std::stringstream logstr; \
std::string logfunc; \
logfunc = x
#define GLog(x) do { logstr << x; } while(0)
#define GLogComplete do { \
_log << "[PID:" << _my_process << " L:" << __LINE__ << "] ((" << logfunc << ")) " << logstr.str() << endl; \
logstr.str(""); \
_log.flush(); \
} while(0)
#define GLogLine(x) do { GLog(x); GLogComplete; } while(0)
#define GLogL(x) GLogLine(x)
#define GLC GLogComplete
One can also build up a log over a few lines...
GLog("I did this.");
// later
GLog("One result was " << some_number << " and then " << something_else);
// finally
GLog("And now I'm done!");
GLogComplete;
Whatever stream _log is (I open it as a file in the class constructor, which is guaranteed to be safe in this instance) gets ouput like this:
[PID:4848 L:348] ((SetTextBC)) ERROR: bad argument row:0 col:-64
And they can be conditionally turned off and all performance penalty negated by a symbol at compilation time like so:
#ifdef LOGGING_ENABLED
... do the stuff above ...
#else
#define GLogFunc(x)
#define GLog(x)
#define GLogComplete
#define GLogLine(x)
#define GLogL(x)
#endif
Here is my solution.
Setup code
auto formatter =
expr::format("[ %3% %1%:%2% :: %4%]")
% expr::attr< std::string >("File")
% expr::attr< uint32_t >("Line")
% expr::attr< boost::posix_time::ptime >("TimeStamp")
% expr::smessage
;
/* stdout sink*/
boost::shared_ptr< sinks::text_ostream_backend > backend =
boost::make_shared< sinks::text_ostream_backend >();
backend->add_stream(
boost::shared_ptr< std::ostream >(&std::clog, NullDeleter()));
// Enable auto-flushing after each log record written
backend->auto_flush(true);
// Wrap it into the frontend and register in the core.
// The backend requires synchronization in the frontend.
typedef sinks::synchronous_sink< sinks::text_ostream_backend > sink2_t;
boost::shared_ptr< sink2_t > sink_text(new sink2_t(backend));
logging::add_common_attributes();
sink_text->set_formatter(formatter);
The log usage code (short version):
rec.attribute_values().insert("File", attrs::make_attribute_value(std::string(__FILE__))); \
full version :
#define LOG(s, message) { \
src::severity_logger< severity_level > slg; \
logging::record rec = slg.open_record(keywords::severity = s); \
if (rec) \
{ \
rec.attribute_values().insert("File", attrs::make_attribute_value(boost::filesystem::path(__FILE__).filename().string())); \
rec.attribute_values().insert("Line", attrs::make_attribute_value(uint32_t(__LINE__))); \
logging::record_ostream strm(rec); \
strm << message; \
strm.flush(); \
slg.push_record(boost::move(rec)); \
} \
}\
If I define global attribute (like people adviced before), i.e.
logging::core::get()->add_global_attribute("File", attrs::mutable_constant<std::string>(""));
then I get empty files/stiring.

How do I open a URL from C++?

how can I open a URL from my C++ program?
In ruby you can do
%x(open https://google.com)
What's the equivalent in C++? I wonder if there's a platform-independent solution. But if there isn't, I'd like the Unix/Mac better :)
Here's my code:
#include <stdio.h>
#include <string.h>
#include <fstream>
int main (int argc, char *argv[])
{
char url[1000] = "https://www.google.com";
std::fstream fs;
fs.open(url);
fs.close();
return 0;
}
Your question may mean two different things:
1.) Open a web page with a browser.
#include <windows.h>
#include <shellapi.h>
...
ShellExecute(0, 0, L"http://www.google.com", 0, 0 , SW_SHOW );
This should work, it opens the file with the associated program. Should open the browser, which is usually the default web browser.
2.) Get the code of a webpage and you will render it yourself or do some other thing. For this I recommend to read this or/and this.
I hope it's at least a little helpful.
EDIT: Did not notice, what you are asking for UNIX, this only work on Windows.
Use libcurl, here is a simple example.
EDIT: If this is about starting a web browser from C++, you can invoke a shell command with system on a POSIX system:
system("<mybrowser> http://google.com");
By replacing <mybrowser> with the browser you want to launch.
Here's an example in windows code using winsock.
#include <winsock2.h>
#include <windows.h>
#include <iostream>
#include <string>
#include <locale>
#pragma comment(lib,"ws2_32.lib")
using namespace std;
string website_HTML;
locale local;
void get_Website(char *url );
int main ()
{
//open website
get_Website("www.google.com" );
//format website HTML
for (size_t i=0; i<website_HTML.length(); ++i)
website_HTML[i]= tolower(website_HTML[i],local);
//display HTML
cout <<website_HTML;
cout<<"\n\n";
return 0;
}
//***************************
void get_Website(char *url )
{
WSADATA wsaData;
SOCKET Socket;
SOCKADDR_IN SockAddr;
int lineCount=0;
int rowCount=0;
struct hostent *host;
char *get_http= new char[256];
memset(get_http,' ', sizeof(get_http) );
strcpy(get_http,"GET / HTTP/1.1\r\nHost: ");
strcat(get_http,url);
strcat(get_http,"\r\nConnection: close\r\n\r\n");
if (WSAStartup(MAKEWORD(2,2), &wsaData) != 0)
{
cout << "WSAStartup failed.\n";
system("pause");
//return 1;
}
Socket=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
host = gethostbyname(url);
SockAddr.sin_port=htons(80);
SockAddr.sin_family=AF_INET;
SockAddr.sin_addr.s_addr = *((unsigned long*)host->h_addr);
cout << "Connecting to "<< url<<" ...\n";
if(connect(Socket,(SOCKADDR*)(&SockAddr),sizeof(SockAddr)) != 0)
{
cout << "Could not connect";
system("pause");
//return 1;
}
cout << "Connected.\n";
send(Socket,get_http, strlen(get_http),0 );
char buffer[10000];
int nDataLength;
while ((nDataLength = recv(Socket,buffer,10000,0)) > 0)
{
int i = 0;
while (buffer[i] >= 32 || buffer[i] == '\n' || buffer[i] == '\r')
{
website_HTML+=buffer[i];
i += 1;
}
}
closesocket(Socket);
WSACleanup();
delete[] get_http;
}
I was having the exact same problem in Windows.
I noticed that in OP's gist, he uses string("open ") in line 21, however, by using it one comes across this error:
'open' is not recognized as an internal or external command
After researching, I have found that open is MacOS the default command to open things. It is different on Windows or Linux.
Linux: xdg-open <URL>
Windows: start <URL>
For those of you that are using Windows, as I am, you can use the following:
std::string op = std::string("start ").append(url);
system(op.c_str());
I've had MUCH better luck using ShellExecuteA(). I've heard that there are a lot of security risks when you use "system()". This is what I came up with for my own code.
void SearchWeb( string word )
{
string base_URL = "http://www.bing.com/search?q=";
string search_URL = "dummy";
search_URL = base_URL + word;
cout << "Searching for: \"" << word << "\"\n";
ShellExecuteA(NULL, "open", search_URL.c_str(), NULL, NULL, SW_SHOWNORMAL);
}
p.s. Its using WinAPI if i'm correct. So its not multiplatform solution.
There're already answers for windows. In linux, I noticed open https://www.google.com always launch browser from shell, so you can try:
system("open https://your.domain/uri");
that's say
system(("open "s + url).c_str()); // c++
https://linux.die.net/man/1/open
C isn't as high-level as the scripting language you mention. But if you want to stay away from socket-based programming, try Curl. Curl is a great C library and has many features. I have used it for years and always recommend it. It also includes some stand alone programs for testing or shell use.
For linux environments, you can use xdg-open. It is installed by default on most distributions. The benefit over the accepted answer is that it opens the user's preferred browser.
$ xdg-open https://google.com
$ xdg-open steam://run/10
Of course you can wrap this in a system() call.
Create a function and copy the code using winsock which is mentioned already by Software_Developer.
For Instance:
#ifdef _WIN32
// this is required only for windows
if (WSAStartup(MAKEWORD(2,2), &wsaData) != 0)
{
//...
}
#endif
winsock code here
#ifdef _WIN32
WSACleanup();
#endif

How to use tcl apis in a c code

I want to use some of the functionalities(APIs) of my tcl code in another "c" code file. But i am not getting how to do that especiallly how to link them. For that i have taken a very simple tcl code which contains one API which adds two numbers and prints the sum. Can anybody tell me how can i call this tcl code to get the sum. How can i write a c wrapper that will call this tcl code. Below is my sample tcl program that i am using :
#!/usr/bin/env tclsh8.5
proc add_two_nos { } {
set a 10
set b 20
set c [expr { $a + $b } ]
puts " c is $c ......."
}
To evaluate a script from C code, use Tcl_Eval() or one of its close relatives. In order to use that API, you need to link in the Tcl library, initialize the Tcl library and create an interpreter to hold the execution context. Plus you really ought to do some work to retrieve the result and print it out (printing script errors out is particularly important, as that helps a lot with debugging!)
Thus, you get something like this:
#include <tcl.h>
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char **argv) {
Tcl_Interp *interp;
int code;
char *result;
Tcl_FindExecutable(argv[0]);
interp = Tcl_CreateInterp();
code = Tcl_Eval(interp, "source myscript.tcl; add_two_nos");
/* Retrieve the result... */
result = Tcl_GetString(Tcl_GetObjResult(interp));
/* Check for error! If an error, message is result. */
if (code == TCL_ERROR) {
fprintf(stderr, "ERROR in script: %s\n", result);
exit(1);
}
/* Print (normal) result if non-empty; we'll skip handling encodings for now */
if (strlen(result)) {
printf("%s\n", result);
}
/* Clean up */
Tcl_DeleteInterp(interp);
exit(0);
}
I think i have sloved it out. You were correct. The problem was with the include method that i was using. I have the files tcl.h, tclDecls.h and tclPlatDecls.h included in the c code but these files were not existing in the path /usr/include so i was copying these files to that directory, may be it was not a proper way to do. Finally i have not copied those files to /usr/include and gave the include path while compiling. I have created executable and it is givingthe proper result on terminal. Thanks for your help.
Here is the exact c code i am using :
#include <tcl.h>
#include <tclDecls.h>
#include <tclPlatDecls.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main (int argc, char **argv) {
Tcl_Interp *interp;
int code;
char *result;
printf("inside main function \n");
// Tcl_InitStubs(interp, "8.5", 0);
Tcl_FindExecutable(argv[0]);
interp = Tcl_CreateInterp();
code = Tcl_Eval(interp, "source simple_addition.tcl; add_two_nos");
/* Retrieve the result... */
result = Tcl_GetString(Tcl_GetObjResult(interp));
/* Check for error! If an error, message is result. */
if (code == TCL_ERROR) {
fprintf(stderr, "ERROR in script: %s\n", result);
exit(1);
}
/* Print (normal) result if non-empty; we'll skip handling encodings for now */
if (strlen(result)) {
printf("%s\n", result);
}
/* Clean up */
Tcl_DeleteInterp(interp);
exit(0);
}
And to compile this code and to generate executable file i am using below command :
gcc simple_addition_wrapper_new.c -I/usr/include/tcl8.5/ -ltcl8.5 -o simple_addition_op
I have executed the file simple_addition_op and got below result which was proper
inside main function
c is 30 .......
My special thanks to Donal Fellows and Johannes